]> git.meshlink.io Git - catta/blob - avahi-glib/glib-watch.c
* strip glib from avahi-core
[catta] / avahi-glib / glib-watch.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 <avahi-common/llist.h>
27 #include <avahi-common/malloc.h>
28
29 #include "glib-watch.h"
30
31 struct AvahiWatch {
32     AvahiGLibPoll *glib_poll;
33     int dead;
34     GPollFD pollfd;
35     int pollfd_added;
36     AvahiWatchCallback callback;
37     void *userdata;
38
39     AVAHI_LLIST_FIELDS(AvahiWatch, watches);
40 };
41
42 struct AvahiGLibPoll {
43     GSource source;
44     AvahiPoll api;
45     GMainContext *context;
46
47     struct timeval wakeup;
48     AvahiWakeupCallback wakeup_callback;
49     void *wakeup_userdata;
50     
51     int req_cleanup;
52     
53      AVAHI_LLIST_HEAD(AvahiWatch, watches);
54 };
55
56 static void destroy_watch(AvahiWatch *w) {
57     assert(w);
58
59     if (w->pollfd_added)
60         g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
61
62     AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->glib_poll->watches, w);
63
64     avahi_free(w);
65 }
66
67 static void cleanup(AvahiGLibPoll *g, int all) {
68     AvahiWatch *w, *next;
69     assert(g);
70
71     for (w = g->watches; w; w = next) {
72         next = w->watches_next;
73
74         if (all || w->dead)
75             destroy_watch(w);
76     }
77
78     g->req_cleanup = 0;
79 }
80
81 static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
82     AvahiWatch *w;
83     AvahiGLibPoll *g;
84     
85     assert(api);
86     assert(fd >= 0);
87     assert(callback);
88
89     g = api->userdata;
90     assert(g);
91
92     if (!(w = avahi_new(AvahiWatch, 1)))
93         return NULL;
94     
95     w->glib_poll = g;
96     w->pollfd.fd = fd;
97     w->pollfd.events =
98         (event & AVAHI_WATCH_IN ? G_IO_IN : 0) |
99         (event & AVAHI_WATCH_OUT ? G_IO_OUT : 0) |
100         (event & AVAHI_WATCH_ERR ? G_IO_ERR : 0) |
101         (event & AVAHI_WATCH_HUP ? G_IO_HUP : 0);
102         ;
103     w->callback = callback;
104     w->userdata = userdata;
105     w->dead = 0;
106
107     g_source_add_poll(&g->source, &w->pollfd);
108     w->pollfd_added = 1;
109
110     AVAHI_LLIST_PREPEND(AvahiWatch, watches, g->watches, w);
111
112     return w;
113 }
114
115 static void watch_update(AvahiWatch *w, AvahiWatchEvent events) {
116     assert(w);
117     assert(!w->dead);
118
119     w->pollfd.events = events;
120 }
121
122 static void watch_free(AvahiWatch *w) {
123     assert(w);
124     assert(!w->dead);
125
126     if (w->pollfd_added) {
127         g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
128         w->pollfd_added = 0;
129     }
130     
131     w->dead = 1;
132     w->glib_poll->req_cleanup = 1;
133 }
134
135 static void set_wakeup(AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) {
136     AvahiGLibPoll *g;
137
138     assert(api);
139     g = api->userdata;
140
141     if (callback) {
142         if (tv) 
143             g->wakeup = *tv;
144         else {
145             g->wakeup.tv_sec = 0;
146             g->wakeup.tv_usec = 0;
147         }
148             
149         g->wakeup_callback = callback;
150         g->wakeup_userdata = userdata;
151     } else
152         g->wakeup_callback = NULL;
153 }
154
155 static void start_wakeup_callback(AvahiGLibPoll *g) {
156     AvahiWakeupCallback callback;
157     void *userdata;
158
159     assert(g);
160
161     /* Reset the wakeup functions, but allow changing of the two
162        values from the callback function */
163
164     callback = g->wakeup_callback;
165     userdata = g->wakeup_userdata;
166     g->wakeup_callback = NULL;
167     g->wakeup_userdata = NULL;
168
169     assert(callback);
170     
171     callback(&g->api, userdata);
172 }
173
174 static gboolean prepare_func(GSource *source, gint *timeout) {
175     AvahiGLibPoll *g = (AvahiGLibPoll*) source;
176
177     g_assert(g);
178     g_assert(timeout);
179
180     if (g->req_cleanup)
181         cleanup(g, 0);
182     
183     if (g->wakeup_callback) {
184         GTimeVal now;
185         struct timeval tvnow;
186         AvahiUsec usec;
187
188         g_source_get_current_time(source, &now);
189         tvnow.tv_sec = now.tv_sec;
190         tvnow.tv_usec = now.tv_usec;
191     
192         usec = avahi_timeval_diff(&g->wakeup, &tvnow);
193
194         if (usec <= 0)
195             return TRUE;
196
197         *timeout = (gint) (usec / 1000);
198     }
199         
200     return FALSE;
201 }
202
203 static gboolean check_func(GSource *source) {
204     AvahiGLibPoll *g = (AvahiGLibPoll*) source;
205     AvahiWatch *w;
206
207     g_assert(g);
208
209     if (g->wakeup_callback) {
210         GTimeVal now;
211         struct timeval tvnow;
212         g_source_get_current_time(source, &now);
213         tvnow.tv_sec = now.tv_sec;
214         tvnow.tv_usec = now.tv_usec;
215         
216         if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0)
217             return TRUE;
218     }
219
220     for (w = g->watches; w; w = w->watches_next)
221         if (w->pollfd.revents > 0)
222             return TRUE;
223     
224     return FALSE;
225 }
226
227 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
228     AvahiGLibPoll* g = (AvahiGLibPoll*) source;
229     AvahiWatch *w;
230     
231     g_assert(g);
232
233     if (g->wakeup_callback) {
234         GTimeVal now;
235         struct timeval tvnow;
236         g_source_get_current_time(source, &now);
237         tvnow.tv_sec = now.tv_sec;
238         tvnow.tv_usec = now.tv_usec;
239         
240         if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0) {
241             start_wakeup_callback(g);
242             return TRUE;
243         }
244     }
245     
246     for (w = g->watches; w; w = w->watches_next)
247         if (w->pollfd.revents > 0) {
248             assert(w->callback);
249             w->callback(w, w->pollfd.fd, w->pollfd.revents, w->userdata);
250             w->pollfd.revents = 0;
251             return TRUE;
252         }
253
254     return TRUE;
255 }
256
257 AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context) {
258     AvahiGLibPoll *g;
259     
260     static GSourceFuncs source_funcs = {
261         prepare_func,
262         check_func,
263         dispatch_func,
264         NULL,
265         NULL,
266         NULL
267     };
268
269     g = (AvahiGLibPoll*) g_source_new(&source_funcs, sizeof(AvahiGLibPoll));
270     g_main_context_ref(g->context = context ? context : g_main_context_default());
271
272     g->api.userdata = g;
273     g->api.watch_new = watch_new;
274     g->api.watch_free = watch_free;
275     g->api.watch_update = watch_update;
276     g->api.set_wakeup = set_wakeup;
277
278     g->wakeup_callback = NULL;
279     g->req_cleanup = 0;
280     
281     AVAHI_LLIST_HEAD_INIT(AvahiWatch, g->watches);
282     
283     g_source_attach(&g->source, g->context);
284
285     return g;
286 }
287
288 void avahi_glib_poll_free(AvahiGLibPoll *g) {
289     GSource *s = &g->source;
290     assert(g);
291
292 /*     g_message("BEFORE"); */
293     cleanup(g, 1);
294
295 /*     g_message("MIDDLE"); */
296     g_main_context_unref(g->context);
297     g_source_destroy(s);
298     g_source_unref(s);
299 /*     g_message("AFTER"); */
300 }
301
302 AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) {
303     assert(g);
304
305     return &g->api;
306 }