Revert manifest to default one
[external/cups.git] / scheduler / avahi.c
1 /*
2  * "$Id$"
3  *
4  *   Avahi poll implementation for the CUPS scheduler.
5  *
6  *   Copyright (C) 2010 Red Hat, Inc.
7  *   Authors:
8  *    Tim Waugh <twaugh@redhat.com>
9  *
10  *   Distribution and use rights are outlined in the file "LICENSE.txt"
11  *   "LICENSE" which should have been included with this file.  If this
12  *   file is missing or damaged, see the license at "http://www.cups.org/".
13  *
14  * Contents:
15  *
16  *   watch_read_cb         - Read callback for file descriptor
17  *   watch_write_cb        - Write callback for file descriptor
18  *   watched_fd_add_select() - Call cupsdAddSelect() as needed
19  *   watch_new()           - Create a new file descriptor watch
20  *   watch_free()          - Free a file descriptor watch
21  *   watch_update()        - Update watched events for a file descriptor
22  *   watch_get_events()    - Get events that happened for a file descriptor
23  *   timeout_cb()          - Run a timed Avahi callback
24  *   timeout_new()         - Set a wakeup time
25  *   timeout_update()      - Update the expiration time for a timeout
26  *   timeout_free()        - Free a timeout
27  *   compare_watched_fds() - Compare watched file descriptors for array sorting
28  *   compare_timeouts()    - Compare timeouts for array sorting
29  *   avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
30  *   avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
31  *   avahi_cups_poll_get() - Get the abstract poll API structure
32  */
33
34 #include <config.h>
35
36 #ifdef HAVE_AVAHI /* Applies to entire file... */
37
38 /*
39  * Include necessary headers...
40  */
41
42 #include "cupsd.h"
43
44 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
45 #  include <malloc.h>
46 #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
47
48 #ifdef HAVE_AVAHI
49 #  include <avahi-common/timeval.h>
50 #endif /* HAVE_AVAHI */
51
52
53 typedef struct
54 {
55   AvahiCupsPoll *cups_poll;
56
57   int fd;
58   AvahiWatchEvent occurred;
59   cups_array_t *watches;
60 } cupsd_watched_fd_t;
61
62 struct AvahiWatch
63 {
64   cupsd_watched_fd_t *watched_fd;
65
66   AvahiWatchEvent events;
67   AvahiWatchCallback callback;
68   void *userdata;
69 };
70
71 struct AvahiTimeout
72 {
73   AvahiCupsPoll *cups_poll;
74   AvahiTimeoutCallback callback;
75   void *userdata;
76   cupsd_timeout_t *cupsd_timeout;
77 };
78
79 /*
80  * Local functions...
81  */
82
83 static AvahiWatch *     watch_new(const AvahiPoll *api,
84                                   int fd,
85                                   AvahiWatchEvent events,
86                                   AvahiWatchCallback callback,
87                                   void *userdata);
88 static void             watch_free(AvahiWatch *watch);
89 static void             watch_update(AvahiWatch *watch,
90                                      AvahiWatchEvent events);
91 static AvahiWatchEvent  watch_get_events(AvahiWatch *watch);
92 static int              compare_watches(AvahiWatch *p0,
93                                         AvahiWatch *p1);
94
95
96 /*
97  * 'watch_read_cb' - Read callback for file descriptor
98  */
99
100 static void
101 watch_read_cb (void *userdata)
102 {
103   AvahiWatch *watch;
104   cupsd_watched_fd_t *watched_fd = userdata;
105   watched_fd->occurred |= AVAHI_WATCH_IN;
106   for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
107        watch;
108        watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
109     if (watch->events & watched_fd->occurred) {
110       (watch->callback) (watch, watched_fd->fd,
111                          AVAHI_WATCH_IN, watch->userdata);
112       watched_fd->occurred &= ~AVAHI_WATCH_IN;
113       break;
114     }
115   }
116 }
117
118
119 /*
120  * 'watch_write_cb' - Write callback for file descriptor
121  */
122
123 static void
124 watch_write_cb (void *userdata)
125 {
126   AvahiWatch *watch;
127   cupsd_watched_fd_t *watched_fd = userdata;
128   watched_fd->occurred |= AVAHI_WATCH_OUT;
129   for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
130        watch;
131        watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
132     if (watch->events & watched_fd->occurred) {
133       (watch->callback) (watch, watched_fd->fd,
134                          AVAHI_WATCH_OUT, watch->userdata);
135       watched_fd->occurred &= ~AVAHI_WATCH_OUT;
136       break;
137     }
138   }
139 }
140
141
142 /*
143  * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
144  */
145
146 static int                                              /* O - Watches? */
147 watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
148 {
149   AvahiWatch *watch;
150   cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
151
152   for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
153        watch;
154        watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
155     if (watch->events & (AVAHI_WATCH_IN |
156                              AVAHI_WATCH_ERR |
157                              AVAHI_WATCH_HUP)) {
158       read_cb = (cupsd_selfunc_t)watch_read_cb;
159       if (write_cb != NULL)
160         break;
161     }
162
163     if (watch->events & AVAHI_WATCH_OUT) {
164       write_cb = (cupsd_selfunc_t)watch_write_cb;
165       if (read_cb != NULL)
166         break;
167     }
168   }
169
170   if (read_cb || write_cb)
171     cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
172   else
173     cupsdRemoveSelect (watched_fd->fd);
174
175   return (read_cb || write_cb);
176 }
177
178 /*
179  * 'watch_new' - Create a new file descriptor watch
180  */
181
182 static AvahiWatch *
183 watch_new (const AvahiPoll *api,
184            int fd,
185            AvahiWatchEvent events,
186            AvahiWatchCallback callback,
187            void *userdata)
188 {
189   cupsd_watched_fd_t key, *watched_fd;
190   AvahiCupsPoll *cups_poll = api->userdata;
191   AvahiWatch *watch = malloc(sizeof(AvahiWatch));
192   if (watch == NULL)
193     return (NULL);
194
195   watch->events = events;
196   watch->callback = callback;
197   watch->userdata = userdata;
198
199   key.fd = fd;
200   watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
201   if (watched_fd == NULL) {
202     watched_fd = malloc(sizeof(cupsd_watched_fd_t));
203     if (watched_fd == NULL) {
204       free (watch);
205       return (NULL);
206     }
207
208     watched_fd->fd = fd;
209     watched_fd->occurred = 0;
210     watched_fd->cups_poll = cups_poll;
211     watched_fd->watches = cupsArrayNew ((cups_array_func_t)compare_watches,
212                                         NULL);
213   }
214
215   watch->watched_fd = watched_fd;
216   cupsArrayAdd(watched_fd->watches, watch);
217   watched_fd_add_select (watched_fd);
218   return (watch);
219 }
220
221
222 /*
223  * 'watch_free' - Free a file descriptor watch
224  */
225
226 static void
227 watch_free (AvahiWatch *watch)
228 {
229   cupsd_watched_fd_t *watched_fd = watch->watched_fd;
230   AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
231
232   cupsArrayRemove (watched_fd->watches, watch);
233   free (watch);
234
235   if (!watched_fd_add_select (watched_fd)) {
236     /* No more watches */
237     cupsArrayRemove (cups_poll->watched_fds, watched_fd);
238     free (watched_fd);
239   }
240 }
241
242
243 /*
244  * 'watch_update' - Update watched events for a file descriptor
245  */
246
247 static void
248 watch_update (AvahiWatch *watch,
249               AvahiWatchEvent events)
250 {
251   watch->events = events;
252   watched_fd_add_select (watch->watched_fd);
253 }
254
255
256 /*
257  * 'watch_get_events' - Get events that happened for a file descriptor
258  */
259
260 static AvahiWatchEvent
261 watch_get_events (AvahiWatch *watch)
262 {
263   return (watch->watched_fd->occurred);
264 }
265
266
267 /*
268  * 'compare_watches' - Compare watches for array sorting
269  */
270
271 static int
272 compare_watches (AvahiWatch *p0,
273                  AvahiWatch *p1)
274 {
275   if (p0->watched_fd->fd < p1->watched_fd->fd)
276     return (-1);
277
278   return ((p0->watched_fd->fd == p1->watched_fd->fd) ? 0 : 1);
279 }
280
281
282 /*
283  * 'timeout_cb()' - Run a timed Avahi callback
284  */
285
286 static void
287 timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
288 {
289   AvahiTimeout *timeout = userdata;
290   (timeout->callback) (timeout, timeout->userdata);
291 }
292
293
294 /*
295  * 'timeout_new' - Set a wakeup time
296  */
297
298 static AvahiTimeout *
299 timeout_new (const AvahiPoll *api,
300              const struct timeval *tv,
301              AvahiTimeoutCallback callback,
302              void *userdata)
303 {
304   AvahiTimeout *timeout;
305   AvahiCupsPoll *cups_poll = api->userdata;
306
307   timeout = malloc(sizeof(AvahiTimeout));
308   if (timeout == NULL)
309     return (NULL);
310
311   timeout->cups_poll = cups_poll;
312   timeout->callback = callback;
313   timeout->userdata = userdata;
314   timeout->cupsd_timeout = cupsdAddTimeout (tv,
315                                             (cupsd_timeoutfunc_t)timeout_cb,
316                                             timeout);
317   cupsArrayAdd (cups_poll->timeouts, timeout);
318   return (timeout);
319 }
320
321
322 /*
323  * 'timeout_update' - Update the expiration time for a timeout
324  */
325
326 static void
327 timeout_update (AvahiTimeout *timeout,
328                 const struct timeval *tv)
329 {
330   cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
331 }
332
333
334 /*
335  * ' timeout_free' - Free a timeout
336  */
337
338 static void
339 timeout_free (AvahiTimeout *timeout)
340 {
341   cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
342   cupsdRemoveTimeout (timeout->cupsd_timeout);
343   free (timeout);
344 }
345
346
347 /*
348  * 'compare_watched_fds' - Compare watched file descriptors for array sorting
349  */
350 static int
351 compare_watched_fds(cupsd_watched_fd_t *p0,
352                     cupsd_watched_fd_t *p1)
353 {
354   if (p0->fd != p1->fd)
355     return (p0->fd < p1->fd ? -1 : 1);
356
357   if (p0 == p1)
358     return (0);
359
360   return (p0 < p1 ? -1 : 1);
361 }
362
363
364 /*
365  * 'compare_timeouts' - Compare timeouts for array sorting
366  */
367 static int
368 compare_timeouts(AvahiTimeout *p0,
369                  AvahiTimeout *p1)
370 {
371  /*
372   * Just compare pointers to make it a stable sort.
373   */
374
375   if (p0->cupsd_timeout < p1->cupsd_timeout)
376     return (-1);
377   return ((p0->cupsd_timeout == p1->cupsd_timeout) ? 0 : 1);
378 }
379
380
381 /*
382  * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
383  */
384
385 AvahiCupsPoll *
386 avahi_cups_poll_new (void)
387 {
388   AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
389   if (cups_poll == NULL)
390     return (NULL);
391
392   cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
393                                          NULL);
394   cups_poll->timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts,
395                                       NULL);
396
397   cups_poll->api.userdata = cups_poll;
398   cups_poll->api.watch_new = watch_new;
399   cups_poll->api.watch_free = watch_free;
400   cups_poll->api.watch_update = watch_update;
401   cups_poll->api.watch_get_events = watch_get_events;
402
403   cups_poll->api.timeout_new = timeout_new;
404   cups_poll->api.timeout_update = timeout_update;
405   cups_poll->api.timeout_free = timeout_free;
406
407   return (cups_poll);
408 }
409
410
411 /*
412  * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
413  */
414 void
415 avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
416 {
417   cupsd_watched_fd_t *watched_fd;
418
419   for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
420        watched_fd;
421        watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds)){
422     cupsArrayClear (watched_fd->watches);
423   }
424
425   cupsArrayClear (cups_poll->watched_fds);
426   cupsArrayClear (cups_poll->timeouts);
427 }
428
429
430 /*
431  * 'avahi_cups_poll_get' - Get the abstract poll API structure
432  */
433
434 const AvahiPoll *
435 avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
436 {
437   return (&cups_poll->api);
438 }
439
440
441 #endif /* HAVE_AVAHI ... from top of file */
442
443 /*
444  * End of "$Id$".
445  */