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