D-Bus 1.4.1
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-watch.c DBusWatch implementation 00003 * 00004 * Copyright (C) 2002, 2003 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-internals.h" 00026 #include "dbus-watch.h" 00027 #include "dbus-list.h" 00028 00040 struct DBusWatch 00041 { 00042 int refcount; 00043 int fd; 00044 unsigned int flags; 00046 DBusWatchHandler handler; 00047 void *handler_data; 00048 DBusFreeFunction free_handler_data_function; 00050 void *data; 00051 DBusFreeFunction free_data_function; 00052 unsigned int enabled : 1; 00053 }; 00054 00055 dbus_bool_t 00056 _dbus_watch_get_enabled (DBusWatch *watch) 00057 { 00058 return watch->enabled; 00059 } 00060 00073 DBusWatch* 00074 _dbus_watch_new (int fd, 00075 unsigned int flags, 00076 dbus_bool_t enabled, 00077 DBusWatchHandler handler, 00078 void *data, 00079 DBusFreeFunction free_data_function) 00080 { 00081 DBusWatch *watch; 00082 00083 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) 00084 00085 _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); 00086 00087 watch = dbus_new0 (DBusWatch, 1); 00088 if (watch == NULL) 00089 return NULL; 00090 00091 watch->refcount = 1; 00092 watch->fd = fd; 00093 watch->flags = flags; 00094 watch->enabled = enabled; 00095 00096 watch->handler = handler; 00097 watch->handler_data = data; 00098 watch->free_handler_data_function = free_data_function; 00099 00100 return watch; 00101 } 00102 00109 DBusWatch * 00110 _dbus_watch_ref (DBusWatch *watch) 00111 { 00112 watch->refcount += 1; 00113 00114 return watch; 00115 } 00116 00123 void 00124 _dbus_watch_unref (DBusWatch *watch) 00125 { 00126 _dbus_assert (watch != NULL); 00127 _dbus_assert (watch->refcount > 0); 00128 00129 watch->refcount -= 1; 00130 if (watch->refcount == 0) 00131 { 00132 dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ 00133 00134 if (watch->free_handler_data_function) 00135 (* watch->free_handler_data_function) (watch->handler_data); 00136 00137 dbus_free (watch); 00138 } 00139 } 00140 00151 void 00152 _dbus_watch_invalidate (DBusWatch *watch) 00153 { 00154 watch->fd = -1; 00155 watch->flags = 0; 00156 } 00157 00167 void 00168 _dbus_watch_sanitize_condition (DBusWatch *watch, 00169 unsigned int *condition) 00170 { 00171 if (!(watch->flags & DBUS_WATCH_READABLE)) 00172 *condition &= ~DBUS_WATCH_READABLE; 00173 if (!(watch->flags & DBUS_WATCH_WRITABLE)) 00174 *condition &= ~DBUS_WATCH_WRITABLE; 00175 } 00176 00177 00197 struct DBusWatchList 00198 { 00199 DBusList *watches; 00201 DBusAddWatchFunction add_watch_function; 00202 DBusRemoveWatchFunction remove_watch_function; 00203 DBusWatchToggledFunction watch_toggled_function; 00204 void *watch_data; 00205 DBusFreeFunction watch_free_data_function; 00206 }; 00207 00214 DBusWatchList* 00215 _dbus_watch_list_new (void) 00216 { 00217 DBusWatchList *watch_list; 00218 00219 watch_list = dbus_new0 (DBusWatchList, 1); 00220 if (watch_list == NULL) 00221 return NULL; 00222 00223 return watch_list; 00224 } 00225 00231 void 00232 _dbus_watch_list_free (DBusWatchList *watch_list) 00233 { 00234 /* free watch_data and removes watches as a side effect */ 00235 _dbus_watch_list_set_functions (watch_list, 00236 NULL, NULL, NULL, NULL, NULL); 00237 _dbus_list_foreach (&watch_list->watches, 00238 (DBusForeachFunction) _dbus_watch_unref, 00239 NULL); 00240 _dbus_list_clear (&watch_list->watches); 00241 00242 dbus_free (watch_list); 00243 } 00244 00259 dbus_bool_t 00260 _dbus_watch_list_set_functions (DBusWatchList *watch_list, 00261 DBusAddWatchFunction add_function, 00262 DBusRemoveWatchFunction remove_function, 00263 DBusWatchToggledFunction toggled_function, 00264 void *data, 00265 DBusFreeFunction free_data_function) 00266 { 00267 /* Add watches with the new watch function, failing on OOM */ 00268 if (add_function != NULL) 00269 { 00270 DBusList *link; 00271 00272 link = _dbus_list_get_first_link (&watch_list->watches); 00273 while (link != NULL) 00274 { 00275 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00276 link); 00277 00278 #ifdef DBUS_ENABLE_VERBOSE_MODE 00279 { 00280 const char *watch_type; 00281 int flags; 00282 00283 flags = dbus_watch_get_flags (link->data); 00284 if ((flags & DBUS_WATCH_READABLE) && 00285 (flags & DBUS_WATCH_WRITABLE)) 00286 watch_type = "readwrite"; 00287 else if (flags & DBUS_WATCH_READABLE) 00288 watch_type = "read"; 00289 else if (flags & DBUS_WATCH_WRITABLE) 00290 watch_type = "write"; 00291 else 00292 watch_type = "not read or write"; 00293 00294 _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", 00295 watch_type, 00296 dbus_watch_get_socket (link->data)); 00297 } 00298 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00299 00300 if (!(* add_function) (link->data, data)) 00301 { 00302 /* remove it all again and return FALSE */ 00303 DBusList *link2; 00304 00305 link2 = _dbus_list_get_first_link (&watch_list->watches); 00306 while (link2 != link) 00307 { 00308 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00309 link2); 00310 00311 _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", 00312 dbus_watch_get_socket (link2->data)); 00313 00314 (* remove_function) (link2->data, data); 00315 00316 link2 = next; 00317 } 00318 00319 return FALSE; 00320 } 00321 00322 link = next; 00323 } 00324 } 00325 00326 /* Remove all current watches from previous watch handlers */ 00327 00328 if (watch_list->remove_watch_function != NULL) 00329 { 00330 _dbus_verbose ("Removing all pre-existing watches\n"); 00331 00332 _dbus_list_foreach (&watch_list->watches, 00333 (DBusForeachFunction) watch_list->remove_watch_function, 00334 watch_list->watch_data); 00335 } 00336 00337 if (watch_list->watch_free_data_function != NULL) 00338 (* watch_list->watch_free_data_function) (watch_list->watch_data); 00339 00340 watch_list->add_watch_function = add_function; 00341 watch_list->remove_watch_function = remove_function; 00342 watch_list->watch_toggled_function = toggled_function; 00343 watch_list->watch_data = data; 00344 watch_list->watch_free_data_function = free_data_function; 00345 00346 return TRUE; 00347 } 00348 00357 dbus_bool_t 00358 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 00359 DBusWatch *watch) 00360 { 00361 if (!_dbus_list_append (&watch_list->watches, watch)) 00362 return FALSE; 00363 00364 _dbus_watch_ref (watch); 00365 00366 if (watch_list->add_watch_function != NULL) 00367 { 00368 _dbus_verbose ("Adding watch on fd %d\n", 00369 dbus_watch_get_socket (watch)); 00370 00371 if (!(* watch_list->add_watch_function) (watch, 00372 watch_list->watch_data)) 00373 { 00374 _dbus_list_remove_last (&watch_list->watches, watch); 00375 _dbus_watch_unref (watch); 00376 return FALSE; 00377 } 00378 } 00379 00380 return TRUE; 00381 } 00382 00390 void 00391 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 00392 DBusWatch *watch) 00393 { 00394 if (!_dbus_list_remove (&watch_list->watches, watch)) 00395 _dbus_assert_not_reached ("Nonexistent watch was removed"); 00396 00397 if (watch_list->remove_watch_function != NULL) 00398 { 00399 _dbus_verbose ("Removing watch on fd %d\n", 00400 dbus_watch_get_socket (watch)); 00401 00402 (* watch_list->remove_watch_function) (watch, 00403 watch_list->watch_data); 00404 } 00405 00406 _dbus_watch_unref (watch); 00407 } 00408 00417 void 00418 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 00419 DBusWatch *watch, 00420 dbus_bool_t enabled) 00421 { 00422 enabled = !!enabled; 00423 00424 if (enabled == watch->enabled) 00425 return; 00426 00427 watch->enabled = enabled; 00428 00429 if (watch_list->watch_toggled_function != NULL) 00430 { 00431 _dbus_verbose ("Toggling watch %p on fd %d to %d\n", 00432 watch, dbus_watch_get_socket (watch), watch->enabled); 00433 00434 (* watch_list->watch_toggled_function) (watch, 00435 watch_list->watch_data); 00436 } 00437 } 00438 00451 void 00452 _dbus_watch_set_handler (DBusWatch *watch, 00453 DBusWatchHandler handler, 00454 void *data, 00455 DBusFreeFunction free_data_function) 00456 { 00457 if (watch->free_handler_data_function) 00458 (* watch->free_handler_data_function) (watch->handler_data); 00459 00460 watch->handler = handler; 00461 watch->handler_data = data; 00462 watch->free_handler_data_function = free_data_function; 00463 } 00464 00496 int 00497 dbus_watch_get_fd (DBusWatch *watch) 00498 { 00499 _dbus_return_val_if_fail (watch != NULL, -1); 00500 00501 return dbus_watch_get_unix_fd(watch); 00502 } 00503 00517 int 00518 dbus_watch_get_unix_fd (DBusWatch *watch) 00519 { 00520 _dbus_return_val_if_fail (watch != NULL, -1); 00521 00522 /* FIXME remove #ifdef and do this on a lower level 00523 * (watch should have set_socket and set_unix_fd and track 00524 * which it has, and the transport should provide the 00525 * appropriate watch type) 00526 */ 00527 #ifdef DBUS_UNIX 00528 return watch->fd; 00529 #else 00530 return dbus_watch_get_socket( watch ); 00531 #endif 00532 } 00533 00546 int 00547 dbus_watch_get_socket (DBusWatch *watch) 00548 { 00549 _dbus_return_val_if_fail (watch != NULL, -1); 00550 00551 return watch->fd; 00552 } 00553 00567 unsigned int 00568 dbus_watch_get_flags (DBusWatch *watch) 00569 { 00570 _dbus_return_val_if_fail (watch != NULL, 0); 00571 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 00572 00573 return watch->flags; 00574 } 00575 00583 void* 00584 dbus_watch_get_data (DBusWatch *watch) 00585 { 00586 _dbus_return_val_if_fail (watch != NULL, NULL); 00587 00588 return watch->data; 00589 } 00590 00602 void 00603 dbus_watch_set_data (DBusWatch *watch, 00604 void *data, 00605 DBusFreeFunction free_data_function) 00606 { 00607 _dbus_return_if_fail (watch != NULL); 00608 00609 _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", 00610 dbus_watch_get_socket (watch), 00611 data, free_data_function, watch->data, watch->free_data_function); 00612 00613 if (watch->free_data_function != NULL) 00614 (* watch->free_data_function) (watch->data); 00615 00616 watch->data = data; 00617 watch->free_data_function = free_data_function; 00618 } 00619 00627 dbus_bool_t 00628 dbus_watch_get_enabled (DBusWatch *watch) 00629 { 00630 _dbus_return_val_if_fail (watch != NULL, FALSE); 00631 00632 return watch->enabled; 00633 } 00634 00635 00658 dbus_bool_t 00659 dbus_watch_handle (DBusWatch *watch, 00660 unsigned int flags) 00661 { 00662 _dbus_return_val_if_fail (watch != NULL, FALSE); 00663 00664 #ifndef DBUS_DISABLE_CHECKS 00665 if (watch->fd < 0 || watch->flags == 0) 00666 { 00667 _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n"); 00668 return TRUE; 00669 } 00670 #endif 00671 00672 _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); 00673 00674 _dbus_watch_sanitize_condition (watch, &flags); 00675 00676 if (flags == 0) 00677 { 00678 _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", 00679 watch->fd); 00680 return TRUE; 00681 } 00682 else 00683 return (* watch->handler) (watch, flags, 00684 watch->handler_data); 00685 } 00686 00687