]> git.meshlink.io Git - catta/blob - avahi-glib/glib-watch.c
7eab84be1a87453787feda873dc329e3ef408825
[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     gboolean use_wakeup;
49     int req_cleanup;
50     
51     AvahiGLibProcessCallback process_callback;
52     void *userdata;
53     
54     AVAHI_LLIST_HEAD(AvahiWatch, watches);
55 };
56
57 static void destroy_watch(AvahiWatch *w) {
58     assert(w);
59
60     if (w->pollfd_added)
61         g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
62
63     AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->glib_poll->watches, w);
64
65     avahi_free(w);
66 }
67
68 static void cleanup(AvahiGLibPoll *g, int all) {
69     AvahiWatch *w, *next;
70     assert(g);
71
72     for (w = g->watches; w; w = next) {
73         next = w->watches_next;
74
75         if (all || w->dead)
76             destroy_watch(w);
77     }
78
79     g->req_cleanup = 0;
80 }
81
82 static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
83     AvahiWatch *w;
84     AvahiGLibPoll *g;
85     
86     assert(api);
87     assert(fd >= 0);
88     assert(callback);
89
90     g = api->userdata;
91     assert(g);
92
93     if (!(w = avahi_new(AvahiWatch, 1)))
94         return NULL;
95     
96     w->glib_poll = g;
97     w->pollfd.fd = fd;
98     w->pollfd.events =
99         (event & AVAHI_WATCH_IN ? G_IO_IN : 0) |
100         (event & AVAHI_WATCH_OUT ? G_IO_OUT : 0) |
101         (event & AVAHI_WATCH_ERR ? G_IO_ERR : 0) |
102         (event & AVAHI_WATCH_HUP ? G_IO_HUP : 0);
103         ;
104     w->callback = callback;
105     w->userdata = userdata;
106     w->dead = 0;
107
108     g_source_add_poll(&g->source, &w->pollfd);
109     w->pollfd_added = 1;
110
111     AVAHI_LLIST_PREPEND(AvahiWatch, watches, g->watches, w);
112
113     return w;
114 }
115
116 static void watch_update(AvahiWatch *w, AvahiWatchEvent events) {
117     assert(w);
118     assert(!w->dead);
119
120     w->pollfd.events = events;
121 }
122
123 static void watch_free(AvahiWatch *w) {
124     assert(w);
125     assert(!w->dead);
126
127     if (w->pollfd_added) {
128         g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
129         w->pollfd_added = 0;
130     }
131     
132     w->dead = 1;
133     w->glib_poll->req_cleanup = 1;
134 }
135
136 static void set_wakeup_time(AvahiPoll *api, const struct timeval *tv) {
137     AvahiGLibPoll *g;
138
139     assert(api);
140     g = api->userdata;
141
142     if (tv) {
143         g->wakeup = *tv;
144         g->use_wakeup = 1;
145     } else
146         g->use_wakeup = 0;
147 }
148
149 static gboolean prepare_func(GSource *source, gint *timeout) {
150     AvahiGLibPoll *g = (AvahiGLibPoll*) source;
151
152     g_assert(g);
153     g_assert(timeout);
154
155     if (g->use_wakeup) {
156         GTimeVal now;
157         struct timeval tvnow;
158         AvahiUsec usec;
159
160         g_source_get_current_time(source, &now);
161         tvnow.tv_sec = now.tv_sec;
162         tvnow.tv_usec = now.tv_usec;
163     
164         usec = avahi_timeval_diff(&g->wakeup, &tvnow);
165
166         if (usec <= 0)
167             return TRUE;
168
169         *timeout = (gint) (usec / 1000);
170     }
171         
172     return FALSE;
173 }
174
175 static gboolean check_func(GSource *source) {
176     AvahiGLibPoll *g = (AvahiGLibPoll*) source;
177     AvahiWatch *w;
178
179     g_assert(g);
180
181     for (w = g->watches; w; w = w->watches_next)
182         if (w->pollfd.revents > 0)
183             return TRUE;
184     
185     return FALSE;
186 }
187
188 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
189     AvahiGLibPoll* g = (AvahiGLibPoll*) source;
190     AvahiWatch *w;
191     
192     g_assert(g);
193
194     if (g->req_cleanup)
195         cleanup(g, 0);
196     
197     if (g->process_callback)
198         g->process_callback(g, g->userdata);
199     
200     for (w = g->watches; w; w = w->watches_next)
201         if (w->pollfd.revents > 0) {
202             assert(w->callback);
203             w->callback(w, w->pollfd.fd, w->pollfd.revents, w->userdata);
204             w->pollfd.revents = 0;
205         }
206
207     if (g->req_cleanup)
208         cleanup(g, 0);
209     
210     return TRUE;
211 }
212
213 AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, AvahiGLibProcessCallback callback, void *userdata) {
214     AvahiGLibPoll *g;
215     
216     static GSourceFuncs source_funcs = {
217         prepare_func,
218         check_func,
219         dispatch_func,
220         NULL,
221         NULL,
222         NULL
223     };
224
225     g = (AvahiGLibPoll*) g_source_new(&source_funcs, sizeof(AvahiGLibPoll));
226     g_main_context_ref(g->context = context ? context : g_main_context_default());
227
228     g->api.userdata = g;
229     g->api.watch_new = watch_new;
230     g->api.watch_free = watch_free;
231     g->api.watch_update = watch_update;
232     g->api.set_wakeup_time = set_wakeup_time;
233
234     g->use_wakeup = 0;
235     g->process_callback = callback;
236     g->userdata = userdata;
237     g->req_cleanup = 0;
238     
239     AVAHI_LLIST_HEAD_INIT(AvahiWatch, g->watches);
240     
241     g_source_attach(&g->source, g->context);
242
243     return g;
244 }
245
246 void avahi_glib_poll_free(AvahiGLibPoll *g) {
247     GSource *s = &g->source;
248     assert(g);
249
250     cleanup(g, 1);
251     
252     g_main_context_unref(g->context);
253     g_source_destroy(s);
254     g_source_unref(s);
255 }
256
257 AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) {
258     assert(g);
259
260     return &g->api;
261 }