D-Bus 1.2.24
|
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 "dbus-internals.h" 00025 #include "dbus-watch.h" 00026 #include "dbus-list.h" 00027 00039 struct DBusWatch 00040 { 00041 int refcount; 00042 int fd; 00043 unsigned int flags; 00045 DBusWatchHandler handler; 00046 void *handler_data; 00047 DBusFreeFunction free_handler_data_function; 00049 void *data; 00050 DBusFreeFunction free_data_function; 00051 unsigned int enabled : 1; 00052 }; 00053 00054 dbus_bool_t 00055 _dbus_watch_get_enabled (DBusWatch *watch) 00056 { 00057 return watch->enabled; 00058 } 00059 00072 DBusWatch* 00073 _dbus_watch_new (int fd, 00074 unsigned int flags, 00075 dbus_bool_t enabled, 00076 DBusWatchHandler handler, 00077 void *data, 00078 DBusFreeFunction free_data_function) 00079 { 00080 DBusWatch *watch; 00081 00082 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) 00083 00084 _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); 00085 00086 watch = dbus_new0 (DBusWatch, 1); 00087 if (watch == NULL) 00088 return NULL; 00089 00090 watch->refcount = 1; 00091 watch->fd = fd; 00092 watch->flags = flags; 00093 watch->enabled = enabled; 00094 00095 watch->handler = handler; 00096 watch->handler_data = data; 00097 watch->free_handler_data_function = free_data_function; 00098 00099 return watch; 00100 } 00101 00108 DBusWatch * 00109 _dbus_watch_ref (DBusWatch *watch) 00110 { 00111 watch->refcount += 1; 00112 00113 return watch; 00114 } 00115 00122 void 00123 _dbus_watch_unref (DBusWatch *watch) 00124 { 00125 _dbus_assert (watch != NULL); 00126 _dbus_assert (watch->refcount > 0); 00127 00128 watch->refcount -= 1; 00129 if (watch->refcount == 0) 00130 { 00131 dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ 00132 00133 if (watch->free_handler_data_function) 00134 (* watch->free_handler_data_function) (watch->handler_data); 00135 00136 dbus_free (watch); 00137 } 00138 } 00139 00150 void 00151 _dbus_watch_invalidate (DBusWatch *watch) 00152 { 00153 watch->fd = -1; 00154 watch->flags = 0; 00155 } 00156 00166 void 00167 _dbus_watch_sanitize_condition (DBusWatch *watch, 00168 unsigned int *condition) 00169 { 00170 if (!(watch->flags & DBUS_WATCH_READABLE)) 00171 *condition &= ~DBUS_WATCH_READABLE; 00172 if (!(watch->flags & DBUS_WATCH_WRITABLE)) 00173 *condition &= ~DBUS_WATCH_WRITABLE; 00174 } 00175 00176 00196 struct DBusWatchList 00197 { 00198 DBusList *watches; 00200 DBusAddWatchFunction add_watch_function; 00201 DBusRemoveWatchFunction remove_watch_function; 00202 DBusWatchToggledFunction watch_toggled_function; 00203 void *watch_data; 00204 DBusFreeFunction watch_free_data_function; 00205 }; 00206 00213 DBusWatchList* 00214 _dbus_watch_list_new (void) 00215 { 00216 DBusWatchList *watch_list; 00217 00218 watch_list = dbus_new0 (DBusWatchList, 1); 00219 if (watch_list == NULL) 00220 return NULL; 00221 00222 return watch_list; 00223 } 00224 00230 void 00231 _dbus_watch_list_free (DBusWatchList *watch_list) 00232 { 00233 /* free watch_data and removes watches as a side effect */ 00234 _dbus_watch_list_set_functions (watch_list, 00235 NULL, NULL, NULL, NULL, NULL); 00236 _dbus_list_foreach (&watch_list->watches, 00237 (DBusForeachFunction) _dbus_watch_unref, 00238 NULL); 00239 _dbus_list_clear (&watch_list->watches); 00240 00241 dbus_free (watch_list); 00242 } 00243 00258 dbus_bool_t 00259 _dbus_watch_list_set_functions (DBusWatchList *watch_list, 00260 DBusAddWatchFunction add_function, 00261 DBusRemoveWatchFunction remove_function, 00262 DBusWatchToggledFunction toggled_function, 00263 void *data, 00264 DBusFreeFunction free_data_function) 00265 { 00266 /* Add watches with the new watch function, failing on OOM */ 00267 if (add_function != NULL) 00268 { 00269 DBusList *link; 00270 00271 link = _dbus_list_get_first_link (&watch_list->watches); 00272 while (link != NULL) 00273 { 00274 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00275 link); 00276 00277 #ifdef DBUS_ENABLE_VERBOSE_MODE 00278 { 00279 const char *watch_type; 00280 int flags; 00281 00282 flags = dbus_watch_get_flags (link->data); 00283 if ((flags & DBUS_WATCH_READABLE) && 00284 (flags & DBUS_WATCH_WRITABLE)) 00285 watch_type = "readwrite"; 00286 else if (flags & DBUS_WATCH_READABLE) 00287 watch_type = "read"; 00288 else if (flags & DBUS_WATCH_WRITABLE) 00289 watch_type = "write"; 00290 else 00291 watch_type = "not read or write"; 00292 00293 _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", 00294 watch_type, 00295 dbus_watch_get_socket (link->data)); 00296 } 00297 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00298 00299 if (!(* add_function) (link->data, data)) 00300 { 00301 /* remove it all again and return FALSE */ 00302 DBusList *link2; 00303 00304 link2 = _dbus_list_get_first_link (&watch_list->watches); 00305 while (link2 != link) 00306 { 00307 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 00308 link2); 00309 00310 _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", 00311 dbus_watch_get_socket (link2->data)); 00312 00313 (* remove_function) (link2->data, data); 00314 00315 link2 = next; 00316 } 00317 00318 return FALSE; 00319 } 00320 00321 link = next; 00322 } 00323 } 00324 00325 /* Remove all current watches from previous watch handlers */ 00326 00327 if (watch_list->remove_watch_function != NULL) 00328 { 00329 _dbus_verbose ("Removing all pre-existing watches\n"); 00330 00331 _dbus_list_foreach (&watch_list->watches, 00332 (DBusForeachFunction) watch_list->remove_watch_function, 00333 watch_list->watch_data); 00334 } 00335 00336 if (watch_list->watch_free_data_function != NULL) 00337 (* watch_list->watch_free_data_function) (watch_list->watch_data); 00338 00339 watch_list->add_watch_function = add_function; 00340 watch_list->remove_watch_function = remove_function; 00341 watch_list->watch_toggled_function = toggled_function; 00342 watch_list->watch_data = data; 00343 watch_list->watch_free_data_function = free_data_function; 00344 00345 return TRUE; 00346 } 00347 00356 dbus_bool_t 00357 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 00358 DBusWatch *watch) 00359 { 00360 if (!_dbus_list_append (&watch_list->watches, watch)) 00361 return FALSE; 00362 00363 _dbus_watch_ref (watch); 00364 00365 if (watch_list->add_watch_function != NULL) 00366 { 00367 _dbus_verbose ("Adding watch on fd %d\n", 00368 dbus_watch_get_socket (watch)); 00369 00370 if (!(* watch_list->add_watch_function) (watch, 00371 watch_list->watch_data)) 00372 { 00373 _dbus_list_remove_last (&watch_list->watches, watch); 00374 _dbus_watch_unref (watch); 00375 return FALSE; 00376 } 00377 } 00378 00379 return TRUE; 00380 } 00381 00389 void 00390 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 00391 DBusWatch *watch) 00392 { 00393 if (!_dbus_list_remove (&watch_list->watches, watch)) 00394 _dbus_assert_not_reached ("Nonexistent watch was removed"); 00395 00396 if (watch_list->remove_watch_function != NULL) 00397 { 00398 _dbus_verbose ("Removing watch on fd %d\n", 00399 dbus_watch_get_socket (watch)); 00400 00401 (* watch_list->remove_watch_function) (watch, 00402 watch_list->watch_data); 00403 } 00404 00405 _dbus_watch_unref (watch); 00406 } 00407 00416 void 00417 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 00418 DBusWatch *watch, 00419 dbus_bool_t enabled) 00420 { 00421 enabled = !!enabled; 00422 00423 if (enabled == watch->enabled) 00424 return; 00425 00426 watch->enabled = enabled; 00427 00428 if (watch_list->watch_toggled_function != NULL) 00429 { 00430 _dbus_verbose ("Toggling watch %p on fd %d to %d\n", 00431 watch, dbus_watch_get_socket (watch), watch->enabled); 00432 00433 (* watch_list->watch_toggled_function) (watch, 00434 watch_list->watch_data); 00435 } 00436 } 00437 00450 void 00451 _dbus_watch_set_handler (DBusWatch *watch, 00452 DBusWatchHandler handler, 00453 void *data, 00454 DBusFreeFunction free_data_function) 00455 { 00456 if (watch->free_handler_data_function) 00457 (* watch->free_handler_data_function) (watch->handler_data); 00458 00459 watch->handler = handler; 00460 watch->handler_data = data; 00461 watch->free_handler_data_function = free_data_function; 00462 } 00463 00495 int 00496 dbus_watch_get_fd (DBusWatch *watch) 00497 { 00498 return dbus_watch_get_unix_fd(watch); 00499 } 00500 00514 int 00515 dbus_watch_get_unix_fd (DBusWatch *watch) 00516 { 00517 /* FIXME remove #ifdef and do this on a lower level 00518 * (watch should have set_socket and set_unix_fd and track 00519 * which it has, and the transport should provide the 00520 * appropriate watch type) 00521 */ 00522 #ifdef DBUS_UNIX 00523 return watch->fd; 00524 #else 00525 return -1; 00526 #endif 00527 } 00528 00541 int 00542 dbus_watch_get_socket (DBusWatch *watch) 00543 { 00544 return watch->fd; 00545 } 00546 00560 unsigned int 00561 dbus_watch_get_flags (DBusWatch *watch) 00562 { 00563 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 00564 00565 return watch->flags; 00566 } 00567 00575 void* 00576 dbus_watch_get_data (DBusWatch *watch) 00577 { 00578 return watch->data; 00579 } 00580 00592 void 00593 dbus_watch_set_data (DBusWatch *watch, 00594 void *data, 00595 DBusFreeFunction free_data_function) 00596 { 00597 _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", 00598 dbus_watch_get_socket (watch), 00599 data, free_data_function, watch->data, watch->free_data_function); 00600 00601 if (watch->free_data_function != NULL) 00602 (* watch->free_data_function) (watch->data); 00603 00604 watch->data = data; 00605 watch->free_data_function = free_data_function; 00606 } 00607 00615 dbus_bool_t 00616 dbus_watch_get_enabled (DBusWatch *watch) 00617 { 00618 _dbus_assert (watch != NULL); 00619 return watch->enabled; 00620 } 00621 00622 00645 dbus_bool_t 00646 dbus_watch_handle (DBusWatch *watch, 00647 unsigned int flags) 00648 { 00649 #ifndef DBUS_DISABLE_CHECKS 00650 if (watch->fd < 0 || watch->flags == 0) 00651 { 00652 _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n", 00653 _DBUS_FUNCTION_NAME); 00654 return TRUE; 00655 } 00656 #endif 00657 00658 _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); 00659 00660 _dbus_watch_sanitize_condition (watch, &flags); 00661 00662 if (flags == 0) 00663 { 00664 _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", 00665 watch->fd); 00666 return TRUE; 00667 } 00668 else 00669 return (* watch->handler) (watch, flags, 00670 watch->handler_data); 00671 } 00672 00673