1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-watch.c DBusWatch implementation 3 * 4 * Copyright (C) 2002, 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-internals.h" 25 #include "dbus-watch.h" 26 #include "dbus-list.h" 27 28 /** 29 * @defgroup DBusWatchInternals DBusWatch implementation details 30 * @ingroup DBusInternals 31 * @brief implementation details for DBusWatch 32 * 33 * @{ 34 */ 35 36 /** 37 * Implementation of DBusWatch 38 */ 39 struct DBusWatch 40 { 41 int refcount; /**< Reference count */ 42 int fd; /**< File descriptor. */ 43 unsigned int flags; /**< Conditions to watch. */ 44 45 DBusWatchHandler handler; /**< Watch handler. */ 46 void *handler_data; /**< Watch handler data. */ 47 DBusFreeFunction free_handler_data_function; /**< Free the watch handler data. */ 48 49 void *data; /**< Application data. */ 50 DBusFreeFunction free_data_function; /**< Free the application data. */ 51 unsigned int enabled : 1; /**< Whether it's enabled. */ 52 }; 53 54 /** 55 * Creates a new DBusWatch. Used to add a file descriptor to be polled 56 * by a main loop. 57 * 58 * @param fd the file descriptor to be watched. 59 * @param flags the conditions to watch for on the descriptor. 60 * @param enabled the initial enabled state 61 * @param handler the handler function 62 * @param data data for handler function 63 * @param free_data_function function to free the data 64 * @returns the new DBusWatch object. 65 */ 66 DBusWatch* 67 _dbus_watch_new (int fd, 68 unsigned int flags, 69 dbus_bool_t enabled, 70 DBusWatchHandler handler, 71 void *data, 72 DBusFreeFunction free_data_function) 73 { 74 DBusWatch *watch; 75 76 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) 77 78 _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); 79 80 watch = dbus_new0 (DBusWatch, 1); 81 if (watch == NULL) 82 return NULL; 83 84 watch->refcount = 1; 85 watch->fd = fd; 86 watch->flags = flags; 87 watch->enabled = enabled; 88 89 watch->handler = handler; 90 watch->handler_data = data; 91 watch->free_handler_data_function = free_data_function; 92 93 return watch; 94 } 95 96 /** 97 * Increments the reference count of a DBusWatch object. 98 * 99 * @param watch the watch object. 100 * @returns the watch object. 101 */ 102 DBusWatch * 103 _dbus_watch_ref (DBusWatch *watch) 104 { 105 watch->refcount += 1; 106 107 return watch; 108 } 109 110 /** 111 * Decrements the reference count of a DBusWatch object 112 * and finalizes the object if the count reaches zero. 113 * 114 * @param watch the watch object. 115 */ 116 void 117 _dbus_watch_unref (DBusWatch *watch) 118 { 119 _dbus_assert (watch != NULL); 120 _dbus_assert (watch->refcount > 0); 121 122 watch->refcount -= 1; 123 if (watch->refcount == 0) 124 { 125 dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ 126 127 if (watch->free_handler_data_function) 128 (* watch->free_handler_data_function) (watch->handler_data); 129 130 dbus_free (watch); 131 } 132 } 133 134 /** 135 * Clears the file descriptor from a now-invalid watch object so that 136 * no one tries to use it. This is because a watch may stay alive due 137 * to reference counts after the file descriptor is closed. 138 * Invalidation makes it easier to catch bugs. It also 139 * keeps people from doing dorky things like assuming file descriptors 140 * are unique (never recycled). 141 * 142 * @param watch the watch object. 143 */ 144 void 145 _dbus_watch_invalidate (DBusWatch *watch) 146 { 147 watch->fd = -1; 148 watch->flags = 0; 149 } 150 151 /** 152 * Sanitizes the given condition so that it only contains 153 * flags that the DBusWatch requested. e.g. if the 154 * watch is a DBUS_WATCH_READABLE watch then 155 * DBUS_WATCH_WRITABLE will be stripped from the condition. 156 * 157 * @param watch the watch object. 158 * @param condition address of the condition to sanitize. 159 */ 160 void 161 _dbus_watch_sanitize_condition (DBusWatch *watch, 162 unsigned int *condition) 163 { 164 if (!(watch->flags & DBUS_WATCH_READABLE)) 165 *condition &= ~DBUS_WATCH_READABLE; 166 if (!(watch->flags & DBUS_WATCH_WRITABLE)) 167 *condition &= ~DBUS_WATCH_WRITABLE; 168 } 169 170 171 /** 172 * @typedef DBusWatchList 173 * 174 * Opaque data type representing a list of watches 175 * and a set of DBusAddWatchFunction/DBusRemoveWatchFunction. 176 * Automatically handles removing/re-adding watches 177 * when the DBusAddWatchFunction is updated or changed. 178 * Holds a reference count to each watch. 179 * 180 * Used in the implementation of both DBusServer and 181 * DBusClient. 182 * 183 */ 184 185 /** 186 * DBusWatchList implementation details. All fields 187 * are private. 188 * 189 */ 190 struct DBusWatchList 191 { 192 DBusList *watches; /**< Watch objects. */ 193 194 DBusAddWatchFunction add_watch_function; /**< Callback for adding a watch. */ 195 DBusRemoveWatchFunction remove_watch_function; /**< Callback for removing a watch. */ 196 DBusWatchToggledFunction watch_toggled_function; /**< Callback on toggling enablement */ 197 void *watch_data; /**< Data for watch callbacks */ 198 DBusFreeFunction watch_free_data_function; /**< Free function for watch callback data */ 199 }; 200 201 /** 202 * Creates a new watch list. Returns #NULL if insufficient 203 * memory exists. 204 * 205 * @returns the new watch list, or #NULL on failure. 206 */ 207 DBusWatchList* 208 _dbus_watch_list_new (void) 209 { 210 DBusWatchList *watch_list; 211 212 watch_list = dbus_new0 (DBusWatchList, 1); 213 if (watch_list == NULL) 214 return NULL; 215 216 return watch_list; 217 } 218 219 /** 220 * Frees a DBusWatchList. 221 * 222 * @param watch_list the watch list. 223 */ 224 void 225 _dbus_watch_list_free (DBusWatchList *watch_list) 226 { 227 /* free watch_data and removes watches as a side effect */ 228 _dbus_watch_list_set_functions (watch_list, 229 NULL, NULL, NULL, NULL, NULL); 230 _dbus_list_foreach (&watch_list->watches, 231 (DBusForeachFunction) _dbus_watch_unref, 232 NULL); 233 _dbus_list_clear (&watch_list->watches); 234 235 dbus_free (watch_list); 236 } 237 238 /** 239 * Sets the watch functions. This function is the "backend" 240 * for dbus_connection_set_watch_functions() and 241 * dbus_server_set_watch_functions(). 242 * 243 * @param watch_list the watch list. 244 * @param add_function the add watch function. 245 * @param remove_function the remove watch function. 246 * @param toggled_function function on toggling enabled flag, or #NULL 247 * @param data the data for those functions. 248 * @param free_data_function the function to free the data. 249 * @returns #FALSE if not enough memory 250 * 251 */ 252 dbus_bool_t 253 _dbus_watch_list_set_functions (DBusWatchList *watch_list, 254 DBusAddWatchFunction add_function, 255 DBusRemoveWatchFunction remove_function, 256 DBusWatchToggledFunction toggled_function, 257 void *data, 258 DBusFreeFunction free_data_function) 259 { 260 /* Add watches with the new watch function, failing on OOM */ 261 if (add_function != NULL) 262 { 263 DBusList *link; 264 265 link = _dbus_list_get_first_link (&watch_list->watches); 266 while (link != NULL) 267 { 268 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 269 link); 270 271 #ifdef DBUS_ENABLE_VERBOSE_MODE 272 { 273 const char *watch_type; 274 int flags; 275 276 flags = dbus_watch_get_flags (link->data); 277 if ((flags & DBUS_WATCH_READABLE) && 278 (flags & DBUS_WATCH_WRITABLE)) 279 watch_type = "readwrite"; 280 else if (flags & DBUS_WATCH_READABLE) 281 watch_type = "read"; 282 else if (flags & DBUS_WATCH_WRITABLE) 283 watch_type = "write"; 284 else 285 watch_type = "not read or write"; 286 287 _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", 288 watch_type, 289 dbus_watch_get_fd (link->data)); 290 } 291 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 292 293 if (!(* add_function) (link->data, data)) 294 { 295 /* remove it all again and return FALSE */ 296 DBusList *link2; 297 298 link2 = _dbus_list_get_first_link (&watch_list->watches); 299 while (link2 != link) 300 { 301 DBusList *next = _dbus_list_get_next_link (&watch_list->watches, 302 link2); 303 304 _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", 305 dbus_watch_get_fd (link2->data)); 306 307 (* remove_function) (link2->data, data); 308 309 link2 = next; 310 } 311 312 return FALSE; 313 } 314 315 link = next; 316 } 317 } 318 319 /* Remove all current watches from previous watch handlers */ 320 321 if (watch_list->remove_watch_function != NULL) 322 { 323 _dbus_verbose ("Removing all pre-existing watches\n"); 324 325 _dbus_list_foreach (&watch_list->watches, 326 (DBusForeachFunction) watch_list->remove_watch_function, 327 watch_list->watch_data); 328 } 329 330 if (watch_list->watch_free_data_function != NULL) 331 (* watch_list->watch_free_data_function) (watch_list->watch_data); 332 333 watch_list->add_watch_function = add_function; 334 watch_list->remove_watch_function = remove_function; 335 watch_list->watch_toggled_function = toggled_function; 336 watch_list->watch_data = data; 337 watch_list->watch_free_data_function = free_data_function; 338 339 return TRUE; 340 } 341 342 /** 343 * Adds a new watch to the watch list, invoking the 344 * application DBusAddWatchFunction if appropriate. 345 * 346 * @param watch_list the watch list. 347 * @param watch the watch to add. 348 * @returns #TRUE on success, #FALSE if no memory. 349 */ 350 dbus_bool_t 351 _dbus_watch_list_add_watch (DBusWatchList *watch_list, 352 DBusWatch *watch) 353 { 354 if (!_dbus_list_append (&watch_list->watches, watch)) 355 return FALSE; 356 357 _dbus_watch_ref (watch); 358 359 if (watch_list->add_watch_function != NULL) 360 { 361 _dbus_verbose ("Adding watch on fd %d\n", 362 dbus_watch_get_fd (watch)); 363 364 if (!(* watch_list->add_watch_function) (watch, 365 watch_list->watch_data)) 366 { 367 _dbus_list_remove_last (&watch_list->watches, watch); 368 _dbus_watch_unref (watch); 369 return FALSE; 370 } 371 } 372 373 return TRUE; 374 } 375 376 /** 377 * Removes a watch from the watch list, invoking the 378 * application's DBusRemoveWatchFunction if appropriate. 379 * 380 * @param watch_list the watch list. 381 * @param watch the watch to remove. 382 */ 383 void 384 _dbus_watch_list_remove_watch (DBusWatchList *watch_list, 385 DBusWatch *watch) 386 { 387 if (!_dbus_list_remove (&watch_list->watches, watch)) 388 _dbus_assert_not_reached ("Nonexistent watch was removed"); 389 390 if (watch_list->remove_watch_function != NULL) 391 { 392 _dbus_verbose ("Removing watch on fd %d\n", 393 dbus_watch_get_fd (watch)); 394 395 (* watch_list->remove_watch_function) (watch, 396 watch_list->watch_data); 397 } 398 399 _dbus_watch_unref (watch); 400 } 401 402 /** 403 * Sets a watch to the given enabled state, invoking the 404 * application's DBusWatchToggledFunction if appropriate. 405 * 406 * @param watch_list the watch list. 407 * @param watch the watch to toggle. 408 * @param enabled #TRUE to enable 409 */ 410 void 411 _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, 412 DBusWatch *watch, 413 dbus_bool_t enabled) 414 { 415 enabled = !!enabled; 416 417 if (enabled == watch->enabled) 418 return; 419 420 watch->enabled = enabled; 421 422 if (watch_list->watch_toggled_function != NULL) 423 { 424 _dbus_verbose ("Toggling watch %p on fd %d to %d\n", 425 watch, dbus_watch_get_fd (watch), watch->enabled); 426 427 (* watch_list->watch_toggled_function) (watch, 428 watch_list->watch_data); 429 } 430 } 431 432 /** 433 * Sets the handler for the watch. 434 * 435 * @todo this function only exists because of the weird 436 * way connection watches are done, see the note 437 * in docs for _dbus_connection_handle_watch(). 438 * 439 * @param watch the watch 440 * @param handler the new handler 441 * @param data the data 442 * @param free_data_function free data with this 443 */ 444 void 445 _dbus_watch_set_handler (DBusWatch *watch, 446 DBusWatchHandler handler, 447 void *data, 448 DBusFreeFunction free_data_function) 449 { 450 if (watch->free_handler_data_function) 451 (* watch->free_handler_data_function) (watch->handler_data); 452 453 watch->handler = handler; 454 watch->handler_data = data; 455 watch->free_handler_data_function = free_data_function; 456 } 457 458 /** @} */ 459 460 /** 461 * @defgroup DBusWatch DBusWatch 462 * @ingroup DBus 463 * @brief Object representing a file descriptor to be watched. 464 * 465 * Types and functions related to DBusWatch. A watch represents 466 * a file descriptor that the main loop needs to monitor, 467 * as in Qt's QSocketNotifier or GLib's g_io_add_watch(). 468 * 469 * Use dbus_connection_set_watch_functions() or dbus_server_set_watch_functions() 470 * to be notified when libdbus needs to add or remove watches. 471 * 472 * @{ 473 */ 474 475 /** 476 * @typedef DBusWatch 477 * 478 * Opaque object representing a file descriptor 479 * to be watched for changes in readability, 480 * writability, or hangup. 481 */ 482 483 /** 484 * Gets the file descriptor that should be watched. 485 * 486 * On Windows, this will be a socket. On UNIX right now it will be a 487 * socket but in principle it could be something else. 488 * 489 * @param watch the DBusWatch object. 490 * @returns the file descriptor to watch. 491 */ 492 int 493 dbus_watch_get_fd (DBusWatch *watch) 494 { 495 return watch->fd; 496 } 497 498 /** 499 * Gets flags from DBusWatchFlags indicating 500 * what conditions should be monitored on the 501 * file descriptor. 502 * 503 * The flags returned will only contain DBUS_WATCH_READABLE 504 * and DBUS_WATCH_WRITABLE, never DBUS_WATCH_HANGUP or 505 * DBUS_WATCH_ERROR; all watches implicitly include a watch 506 * for hangups, errors, and other exceptional conditions. 507 * 508 * @param watch the DBusWatch object. 509 * @returns the conditions to watch. 510 */ 511 unsigned int 512 dbus_watch_get_flags (DBusWatch *watch) 513 { 514 _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); 515 516 return watch->flags; 517 } 518 519 /** 520 * Gets data previously set with dbus_watch_set_data() 521 * or #NULL if none. 522 * 523 * @param watch the DBusWatch object. 524 * @returns previously-set data. 525 */ 526 void* 527 dbus_watch_get_data (DBusWatch *watch) 528 { 529 return watch->data; 530 } 531 532 /** 533 * Sets data which can be retrieved with dbus_watch_get_data(). 534 * Intended for use by the DBusAddWatchFunction and 535 * DBusRemoveWatchFunction to store their own data. For example with 536 * Qt you might store the QSocketNotifier for this watch and with GLib 537 * you might store a GSource. 538 * 539 * @param watch the DBusWatch object. 540 * @param data the data. 541 * @param free_data_function function to be called to free the data. 542 */ 543 void 544 dbus_watch_set_data (DBusWatch *watch, 545 void *data, 546 DBusFreeFunction free_data_function) 547 { 548 _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", 549 dbus_watch_get_fd (watch), 550 data, free_data_function, watch->data, watch->free_data_function); 551 552 if (watch->free_data_function != NULL) 553 (* watch->free_data_function) (watch->data); 554 555 watch->data = data; 556 watch->free_data_function = free_data_function; 557 } 558 559 /** 560 * Returns whether a watch is enabled or not. If not 561 * enabled, it should not be polled by the main loop. 562 * 563 * @param watch the DBusWatch object 564 * @returns #TRUE if the watch is enabled 565 */ 566 dbus_bool_t 567 dbus_watch_get_enabled (DBusWatch *watch) 568 { 569 _dbus_assert (watch != NULL); 570 return watch->enabled; 571 } 572 573 574 /** 575 * Called to notify the D-Bus library when a previously-added watch is 576 * ready for reading or writing, or has an exception such as a hangup. 577 * 578 * If this function returns #FALSE, then the file descriptor may still 579 * be ready for reading or writing, but more memory is needed in order 580 * to do the reading or writing. If you ignore the #FALSE return, your 581 * application may spin in a busy loop on the file descriptor until 582 * memory becomes available, but nothing more catastrophic should 583 * happen. 584 * 585 * dbus_watch_handle() cannot be called during the 586 * DBusAddWatchFunction, as the connection will not be ready to handle 587 * that watch yet. 588 * 589 * It is not allowed to reference a DBusWatch after it has been passed 590 * to remove_function. 591 * 592 * @param watch the DBusWatch object. 593 * @param flags the poll condition using #DBusWatchFlags values 594 * @returns #FALSE if there wasn't enough memory 595 */ 596 dbus_bool_t 597 dbus_watch_handle (DBusWatch *watch, 598 unsigned int flags) 599 { 600 #ifndef DBUS_DISABLE_CHECKS 601 if (watch->fd < 0 || watch->flags == 0) 602 { 603 _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n", 604 _DBUS_FUNCTION_NAME); 605 return TRUE; 606 } 607 #endif 608 609 _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); 610 611 _dbus_watch_sanitize_condition (watch, &flags); 612 613 if (flags == 0) 614 { 615 _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", 616 watch->fd); 617 return TRUE; 618 } 619 else 620 return (* watch->handler) (watch, flags, 621 watch->handler_data); 622 } 623 624 625 /** @} */ 626