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