D-Bus  1.4.10
dbus-watch.c
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 
40 struct DBusWatch
41 {
42  int refcount;
43  int fd;
44  unsigned int flags;
47  void *handler_data;
50  void *data;
52  unsigned int enabled : 1;
53 };
54 
56 _dbus_watch_get_enabled (DBusWatch *watch)
57 {
58  return watch->enabled;
59 }
60 
73 DBusWatch*
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 
109 DBusWatch *
111 {
112  watch->refcount += 1;
113 
114  return watch;
115 }
116 
123 void
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 
151 void
153 {
154  watch->fd = -1;
155  watch->flags = 0;
156 }
157 
167 void
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 
198 {
204  void *watch_data;
206 };
207 
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 
231 void
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,
239  NULL);
240  _dbus_list_clear (&watch_list->watches);
241 
242  dbus_free (watch_list);
243 }
244 
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,
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 
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 
390 void
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 
417 void
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 
451 void
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 
496 int
498 {
499  _dbus_return_val_if_fail (watch != NULL, -1);
500 
501  return dbus_watch_get_unix_fd(watch);
502 }
503 
517 int
519 {
520  _dbus_return_val_if_fail (watch != NULL, -1);
521 
522  /* FIXME remove #ifdef and do this on a lower level
523  * (watch should have set_socket and set_unix_fd and track
524  * which it has, and the transport should provide the
525  * appropriate watch type)
526  */
527 #ifdef DBUS_UNIX
528  return watch->fd;
529 #else
530  return dbus_watch_get_socket( watch );
531 #endif
532 }
533 
546 int
548 {
549  _dbus_return_val_if_fail (watch != NULL, -1);
550 
551  return watch->fd;
552 }
553 
567 unsigned int
569 {
570  _dbus_return_val_if_fail (watch != NULL, 0);
571  _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
572 
573  return watch->flags;
574 }
575 
583 void*
585 {
586  _dbus_return_val_if_fail (watch != NULL, NULL);
587 
588  return watch->data;
589 }
590 
602 void
604  void *data,
605  DBusFreeFunction free_data_function)
606 {
607  _dbus_return_if_fail (watch != NULL);
608 
609  _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
610  dbus_watch_get_socket (watch),
611  data, free_data_function, watch->data, watch->free_data_function);
612 
613  if (watch->free_data_function != NULL)
614  (* watch->free_data_function) (watch->data);
615 
616  watch->data = data;
617  watch->free_data_function = free_data_function;
618 }
619 
629 {
630  _dbus_return_val_if_fail (watch != NULL, FALSE);
631 
632  return watch->enabled;
633 }
634 
635 
660  unsigned int flags)
661 {
662  _dbus_return_val_if_fail (watch != NULL, FALSE);
663 
664 #ifndef DBUS_DISABLE_CHECKS
665  if (watch->fd < 0 || watch->flags == 0)
666  {
667  _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n");
668  return TRUE;
669  }
670 #endif
671 
672  _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
673 
674  _dbus_watch_sanitize_condition (watch, &flags);
675 
676  if (flags == 0)
677  {
678  _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
679  watch->fd);
680  return TRUE;
681  }
682  else
683  return (* watch->handler) (watch, flags,
684  watch->handler_data);
685 }
686 
687