build: Do not install testing binaries
[kai/samba.git] / source3 / lib / avahi.c
1 /*
2    Unix SMB/CIFS implementation.
3    Connect avahi to lib/tevents
4    Copyright (C) Volker Lendecke 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22 #include <avahi-common/watch.h>
23
24 struct avahi_poll_context {
25         struct tevent_context *ev;
26         AvahiWatch **watches;
27         AvahiTimeout **timeouts;
28 };
29
30 struct AvahiWatch {
31         struct avahi_poll_context *ctx;
32         struct tevent_fd *fde;
33         int fd;
34         AvahiWatchEvent latest_event;
35         AvahiWatchCallback callback;
36         void *userdata;
37 };
38
39 struct AvahiTimeout {
40         struct avahi_poll_context *ctx;
41         struct tevent_timer *te;
42         AvahiTimeoutCallback callback;
43         void *userdata;
44 };
45
46 static uint16_t avahi_flags_map_to_tevent(AvahiWatchEvent event)
47 {
48         return ((event & AVAHI_WATCH_IN) ? TEVENT_FD_READ : 0)
49                 | ((event & AVAHI_WATCH_OUT) ? TEVENT_FD_WRITE : 0);
50 }
51
52 static void avahi_fd_handler(struct tevent_context *ev,
53                              struct tevent_fd *fde, uint16_t flags,
54                              void *private_data);
55
56 static AvahiWatch *avahi_watch_new(const AvahiPoll *api, int fd,
57                                    AvahiWatchEvent event,
58                                    AvahiWatchCallback callback,
59                                    void *userdata)
60 {
61         struct avahi_poll_context *ctx = talloc_get_type_abort(
62                 api->userdata, struct avahi_poll_context);
63         int num_watches = talloc_array_length(ctx->watches);
64         AvahiWatch **tmp, *watch_ctx;
65
66         tmp = talloc_realloc(ctx, ctx->watches, AvahiWatch *, num_watches + 1);
67         if (tmp == NULL) {
68                 return NULL;
69         }
70         ctx->watches = tmp;
71
72         watch_ctx = talloc(tmp, AvahiWatch);
73         if (watch_ctx == NULL) {
74                 goto fail;
75         }
76         ctx->watches[num_watches] = watch_ctx;
77
78         watch_ctx->ctx = ctx;
79         watch_ctx->fde = tevent_add_fd(ctx->ev, watch_ctx, fd,
80                                        avahi_flags_map_to_tevent(event),
81                                        avahi_fd_handler, watch_ctx);
82         if (watch_ctx->fde == NULL) {
83                 goto fail;
84         }
85         watch_ctx->callback = callback;
86         watch_ctx->userdata = userdata;
87         return watch_ctx;
88
89  fail:
90         TALLOC_FREE(watch_ctx);
91         ctx->watches = talloc_realloc(ctx, ctx->watches, AvahiWatch *,
92                                       num_watches);
93         return NULL;
94 }
95
96 static void avahi_fd_handler(struct tevent_context *ev,
97                              struct tevent_fd *fde, uint16_t flags,
98                              void *private_data)
99 {
100         AvahiWatch *watch_ctx = talloc_get_type_abort(private_data, AvahiWatch);
101
102         watch_ctx->latest_event =
103                 ((flags & TEVENT_FD_READ) ? AVAHI_WATCH_IN : 0)
104                 | ((flags & TEVENT_FD_WRITE) ? AVAHI_WATCH_OUT : 0);
105
106         watch_ctx->callback(watch_ctx, watch_ctx->fd, watch_ctx->latest_event,
107                             watch_ctx->userdata);
108 }
109
110 static void avahi_watch_update(AvahiWatch *w, AvahiWatchEvent event)
111 {
112         tevent_fd_set_flags(w->fde, avahi_flags_map_to_tevent(event));
113 }
114
115 static AvahiWatchEvent avahi_watch_get_events(AvahiWatch *w)
116 {
117         return w->latest_event;
118 }
119
120 static void avahi_watch_free(AvahiWatch *w)
121 {
122         int i, num_watches;
123         AvahiWatch **watches = w->ctx->watches;
124         struct avahi_poll_context *ctx;
125
126         num_watches = talloc_array_length(watches);
127
128         for (i=0; i<num_watches; i++) {
129                 if (w == watches[i]) {
130                         break;
131                 }
132         }
133         if (i == num_watches) {
134                 return;
135         }
136         ctx = w->ctx;
137         TALLOC_FREE(w);
138         memmove(&watches[i], &watches[i+1],
139                 sizeof(*watches) * (num_watches - i - 1));
140         ctx->watches = talloc_realloc(ctx, watches, AvahiWatch *,
141                                       num_watches - 1);
142 }
143
144 static void avahi_timeout_handler(struct tevent_context *ev,
145                                   struct tevent_timer *te,
146                                   struct timeval current_time,
147                                   void *private_data);
148
149 static AvahiTimeout *avahi_timeout_new(const AvahiPoll *api,
150                                        const struct timeval *tv,
151                                        AvahiTimeoutCallback callback,
152                                        void *userdata)
153 {
154         struct avahi_poll_context *ctx = talloc_get_type_abort(
155                 api->userdata, struct avahi_poll_context);
156         int num_timeouts = talloc_array_length(ctx->timeouts);
157         AvahiTimeout **tmp, *timeout_ctx;
158
159         tmp = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
160                              num_timeouts + 1);
161         if (tmp == NULL) {
162                 return NULL;
163         }
164         ctx->timeouts = tmp;
165
166         timeout_ctx = talloc(tmp, AvahiTimeout);
167         if (timeout_ctx == NULL) {
168                 goto fail;
169         }
170         ctx->timeouts[num_timeouts] = timeout_ctx;
171
172         timeout_ctx->ctx = ctx;
173         if (tv == NULL) {
174                 timeout_ctx->te = NULL;
175         } else {
176                 timeout_ctx->te = tevent_add_timer(ctx->ev, timeout_ctx,
177                                                    *tv, avahi_timeout_handler,
178                                                    timeout_ctx);
179                 if (timeout_ctx->te == NULL) {
180                         goto fail;
181                 }
182         }
183         timeout_ctx->callback = callback;
184         timeout_ctx->userdata = userdata;
185         return timeout_ctx;
186
187  fail:
188         TALLOC_FREE(timeout_ctx);
189         ctx->timeouts = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
190                                        num_timeouts);
191         return NULL;
192 }
193
194 static void avahi_timeout_handler(struct tevent_context *ev,
195                                   struct tevent_timer *te,
196                                   struct timeval current_time,
197                                   void *private_data)
198 {
199         AvahiTimeout *timeout_ctx = talloc_get_type_abort(
200                 private_data, AvahiTimeout);
201
202         TALLOC_FREE(timeout_ctx->te);
203         timeout_ctx->callback(timeout_ctx, timeout_ctx->userdata);
204 }
205
206 static void avahi_timeout_update(AvahiTimeout *t, const struct timeval *tv)
207 {
208         TALLOC_FREE(t->te);
209
210         if (tv == NULL) {
211                 /*
212                  * Disable this timer
213                  */
214                 return;
215         }
216
217         t->te = tevent_add_timer(t->ctx->ev, t, *tv, avahi_timeout_handler, t);
218         /*
219          * No failure mode defined here
220          */
221         SMB_ASSERT(t->te != NULL);
222 }
223
224 static void avahi_timeout_free(AvahiTimeout *t)
225 {
226         int i, num_timeouts;
227         AvahiTimeout **timeouts = t->ctx->timeouts;
228         struct avahi_poll_context *ctx;
229
230         num_timeouts = talloc_array_length(timeouts);
231
232         for (i=0; i<num_timeouts; i++) {
233                 if (t == timeouts[i]) {
234                         break;
235                 }
236         }
237         if (i == num_timeouts) {
238                 return;
239         }
240         ctx = t->ctx;
241         TALLOC_FREE(t);
242         memmove(&timeouts[i], &timeouts[i+1],
243                 sizeof(*timeouts) * (num_timeouts - i - 1));
244         ctx->timeouts = talloc_realloc(ctx, timeouts, AvahiTimeout *,
245                                        num_timeouts - 1);
246 }
247
248 struct AvahiPoll *tevent_avahi_poll(TALLOC_CTX *mem_ctx,
249                                     struct tevent_context *ev)
250 {
251         struct AvahiPoll *result;
252         struct avahi_poll_context *ctx;
253
254         result = talloc(mem_ctx, struct AvahiPoll);
255         if (result == NULL) {
256                 return result;
257         }
258         ctx = talloc_zero(result, struct avahi_poll_context);
259         if (ctx == NULL) {
260                 TALLOC_FREE(result);
261                 return NULL;
262         }
263         ctx->ev = ev;
264
265         result->watch_new               = avahi_watch_new;
266         result->watch_update            = avahi_watch_update;
267         result->watch_get_events        = avahi_watch_get_events;
268         result->watch_free              = avahi_watch_free;
269         result->timeout_new             = avahi_timeout_new;
270         result->timeout_update          = avahi_timeout_update;
271         result->timeout_free            = avahi_timeout_free;
272         result->userdata                = ctx;
273
274         return result;
275 }