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