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