]> git.meshlink.io Git - catta/blob - avahi-common/dbus-watch-glue.c
35e2b455c8202193d887943f4d43d86aa9b02419
[catta] / avahi-common / dbus-watch-glue.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <stdio.h>
28
29 #include "malloc.h"
30 #include "timeval.h"
31 #include "dbus-watch-glue.h"
32
33 static AvahiWatchEvent translate_dbus_to_avahi(unsigned int f) {
34     AvahiWatchEvent e = 0;
35
36     if (f & DBUS_WATCH_READABLE)
37         e |= AVAHI_WATCH_IN;
38     if (f & DBUS_WATCH_WRITABLE)
39         e |= AVAHI_WATCH_OUT;
40     if (f & DBUS_WATCH_ERROR)
41         e |= AVAHI_WATCH_ERR;
42     if (f & DBUS_WATCH_HANGUP)
43         e |= AVAHI_WATCH_HUP;
44
45     return e;
46 }
47
48 static unsigned int translate_avahi_to_dbus(AvahiWatchEvent e) {
49     unsigned int f = 0;
50
51     if (e & AVAHI_WATCH_IN)
52         f |= DBUS_WATCH_READABLE;
53     if (e & AVAHI_WATCH_OUT)
54         f |= DBUS_WATCH_WRITABLE;
55     if (e & AVAHI_WATCH_ERR)
56         f |= DBUS_WATCH_ERROR;
57     if (e & AVAHI_WATCH_HUP)
58         f |= DBUS_WATCH_HANGUP;
59
60     return f;
61 }
62
63 typedef struct {
64     DBusConnection *connection;
65     const AvahiPoll *poll_api;
66     AvahiTimeout *dispatch_timeout;
67     int ref;
68 } ConnectionData;
69
70 static ConnectionData *connection_data_ref(ConnectionData *d) {
71     assert(d);
72     assert(d->ref >= 1);
73
74     d->ref++;
75     return d;
76 }
77
78 static void connection_data_unref(ConnectionData *d) {
79     assert(d);
80     assert(d->ref >= 1);
81
82     if (--d->ref <= 0) {
83         d->poll_api->timeout_free(d->dispatch_timeout);
84         avahi_free(d);
85     }
86 }
87
88 static void request_dispatch(ConnectionData *d, int enable) {
89     static const struct timeval tv = { 0, 0 };
90     assert(d);
91
92     if (enable) {
93         assert(dbus_connection_get_dispatch_status(d->connection) == DBUS_DISPATCH_DATA_REMAINS);
94         d->poll_api->timeout_update(d->dispatch_timeout, &tv);
95     } else
96         d->poll_api->timeout_update(d->dispatch_timeout, NULL);
97 }
98
99 static void dispatch_timeout_callback(AvahiTimeout *t, void *userdata) {
100     ConnectionData *d = userdata;
101     assert(t);
102     assert(d);
103
104     connection_data_ref(d);
105     dbus_connection_ref(d->connection);
106
107     if (dbus_connection_dispatch(d->connection) == DBUS_DISPATCH_DATA_REMAINS)
108         /* If there's still data, request that this handler is called again */
109         request_dispatch(d, 1);
110     else
111         request_dispatch(d, 0);
112
113     dbus_connection_unref(d->connection);
114     connection_data_unref(d);
115 }
116
117 static void watch_callback(AvahiWatch *avahi_watch, AVAHI_GCC_UNUSED int fd, AvahiWatchEvent events, void *userdata) {
118     DBusWatch *dbus_watch = userdata;
119     
120     assert(avahi_watch);
121     assert(dbus_watch);
122
123     dbus_watch_handle(dbus_watch, translate_avahi_to_dbus(events));
124     /* Ignore the return value */
125 }
126
127 static dbus_bool_t update_watch(const AvahiPoll *poll_api, DBusWatch *dbus_watch) {
128     AvahiWatch *avahi_watch;
129     dbus_bool_t b;
130     
131     assert(dbus_watch);
132
133     avahi_watch = dbus_watch_get_data(dbus_watch);
134
135     b = dbus_watch_get_enabled(dbus_watch);
136     
137     if (b && !avahi_watch) {
138
139         if (!(avahi_watch = poll_api->watch_new(
140                   poll_api,
141 #if (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR == 1 && DBUS_VERSION_MICRO >= 1) || (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR > 1) || (DBUS_VERSION_MAJOR > 1)
142                   dbus_watch_get_unix_fd(dbus_watch),
143 #else
144                   dbus_watch_get_fd(dbus_watch),
145 #endif
146                   translate_dbus_to_avahi(dbus_watch_get_flags(dbus_watch)),
147                   watch_callback,
148                   dbus_watch)))
149             return FALSE;
150
151         dbus_watch_set_data(dbus_watch, avahi_watch, NULL);
152         
153     } else if (!b && avahi_watch) {
154         
155         poll_api->watch_free(avahi_watch);
156         dbus_watch_set_data(dbus_watch, NULL, NULL);
157
158     } else if (avahi_watch) {
159         
160         /* Update flags */
161         poll_api->watch_update(avahi_watch, dbus_watch_get_flags(dbus_watch));
162     }
163
164     return TRUE;
165 }
166
167 static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *userdata) {
168     ConnectionData *d = userdata;
169     
170     assert(dbus_watch);
171     assert(d);
172
173     return update_watch(d->poll_api, dbus_watch);
174 }
175
176 static void remove_watch(DBusWatch *dbus_watch, void *userdata) {
177     ConnectionData *d = userdata;
178     AvahiWatch *avahi_watch;
179     
180     assert(dbus_watch);
181     assert(d);
182
183     if ((avahi_watch = dbus_watch_get_data(dbus_watch))) {
184         d->poll_api->watch_free(avahi_watch);
185         dbus_watch_set_data(dbus_watch, NULL, NULL);
186     }
187 }
188
189 static void watch_toggled(DBusWatch *dbus_watch, void *userdata) {
190     ConnectionData *d = userdata;
191     
192     assert(dbus_watch);
193     assert(d);
194
195     update_watch(d->poll_api, dbus_watch);
196 }
197
198 typedef struct TimeoutData {
199     const AvahiPoll *poll_api;
200     AvahiTimeout *avahi_timeout;
201     DBusTimeout *dbus_timeout;
202     int ref;
203 } TimeoutData;
204
205 static TimeoutData* timeout_data_ref(TimeoutData *t) {
206     assert(t);
207     assert(t->ref >= 1);
208
209     t->ref++;
210     return t;
211 }
212
213 static void timeout_data_unref(TimeoutData *t) {
214     assert(t);
215     assert(t->ref >= 1);
216
217     if (--t->ref <= 0) {
218         if (t->avahi_timeout)
219             t->poll_api->timeout_free(t->avahi_timeout);
220         
221         avahi_free(t);
222     }
223 }
224
225 static void update_timeout(TimeoutData *timeout) {
226     assert(timeout);
227     assert(timeout->ref >= 1);
228     
229     if (dbus_timeout_get_enabled(timeout->dbus_timeout)) {
230         struct timeval tv;
231         avahi_elapse_time(&tv, dbus_timeout_get_interval(timeout->dbus_timeout), 0);
232         timeout->poll_api->timeout_update(timeout->
233                                       avahi_timeout, &tv);
234     } else
235         timeout->poll_api->timeout_update(timeout->avahi_timeout, NULL);
236
237 }
238
239 static void timeout_callback(AvahiTimeout *avahi_timeout, void *userdata) {
240     TimeoutData *timeout = userdata;
241     
242     assert(avahi_timeout);
243     assert(timeout);
244
245     timeout_data_ref(timeout);
246
247     dbus_timeout_handle(timeout->dbus_timeout);
248     /* Ignore the return value */
249
250     if (timeout->avahi_timeout)
251         update_timeout(timeout);
252     
253     timeout_data_unref(timeout);
254 }
255
256 static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *userdata) {
257     TimeoutData *timeout;
258     ConnectionData *d = userdata;
259     struct timeval tv;
260     dbus_bool_t b;
261
262     assert(dbus_timeout);
263     assert(d);
264
265     if (!(timeout = avahi_new(TimeoutData, 1)))
266         return FALSE;
267
268     timeout->dbus_timeout = dbus_timeout;
269     timeout->poll_api = d->poll_api;
270     timeout->ref = 1;
271
272     if ((b = dbus_timeout_get_enabled(dbus_timeout)))
273         avahi_elapse_time(&tv, dbus_timeout_get_interval(dbus_timeout), 0);
274     
275     if (!(timeout->avahi_timeout = d->poll_api->timeout_new(
276               d->poll_api,
277               b ? &tv : NULL,
278               timeout_callback,
279               timeout))) {
280         avahi_free(timeout);
281         return FALSE;
282     }
283
284     dbus_timeout_set_data(dbus_timeout, timeout, (DBusFreeFunction) timeout_data_unref);
285     return TRUE;
286 }
287
288 static void remove_timeout(DBusTimeout *dbus_timeout, void *userdata) {
289     ConnectionData *d = userdata;
290     TimeoutData *timeout;
291
292     assert(dbus_timeout);
293     assert(d);
294
295     timeout = dbus_timeout_get_data(dbus_timeout);
296     assert(timeout);
297
298     d->poll_api->timeout_free(timeout->avahi_timeout);
299     timeout->avahi_timeout = NULL;
300 }
301
302 static void timeout_toggled(DBusTimeout *dbus_timeout, AVAHI_GCC_UNUSED void *userdata) {
303     TimeoutData *timeout;
304
305     assert(dbus_timeout);
306     timeout = dbus_timeout_get_data(dbus_timeout);
307     assert(timeout);
308
309     update_timeout(timeout);
310 }
311
312 static void dispatch_status(AVAHI_GCC_UNUSED DBusConnection *connection, DBusDispatchStatus new_status, void *userdata) {
313     ConnectionData *d = userdata;
314     
315     if (new_status == DBUS_DISPATCH_DATA_REMAINS)
316         request_dispatch(d, 1);
317  }
318
319 int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api) {
320     ConnectionData *d = NULL;
321     
322     assert(c);
323     assert(poll_api);
324
325     if (!(d = avahi_new(ConnectionData, 1)))
326         goto fail;;
327
328     d->poll_api = poll_api;
329     d->connection = c;
330     d->ref = 1;
331     
332     if (!(d->dispatch_timeout = poll_api->timeout_new(poll_api, NULL, dispatch_timeout_callback, d)))
333         goto fail;
334     
335     if (!(dbus_connection_set_watch_functions(c, add_watch, remove_watch, watch_toggled, connection_data_ref(d), (DBusFreeFunction)connection_data_unref)))
336         goto fail;
337
338     if (!(dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, timeout_toggled, connection_data_ref(d), (DBusFreeFunction)connection_data_unref)))
339         goto fail;
340
341     dbus_connection_set_dispatch_status_function(c, dispatch_status, connection_data_ref(d), (DBusFreeFunction)connection_data_unref);
342
343     if (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS)
344         request_dispatch(d, 1);
345
346     connection_data_unref(d);
347     
348     return 0;
349
350 fail:
351
352     if (d) {
353         d->poll_api->timeout_free(d->dispatch_timeout);
354
355         avahi_free(d);
356     }
357
358     return -1;
359 }