Home | History | Annotate | Download | only in dbus
      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