Line data Source code
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 0 : static uint16_t avahi_flags_map_to_tevent(AvahiWatchEvent event)
47 : {
48 0 : return ((event & AVAHI_WATCH_IN) ? TEVENT_FD_READ : 0)
49 0 : | ((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 0 : static AvahiWatch *avahi_watch_new(const AvahiPoll *api, int fd,
57 : AvahiWatchEvent event,
58 : AvahiWatchCallback callback,
59 : void *userdata)
60 : {
61 0 : struct avahi_poll_context *ctx = talloc_get_type_abort(
62 : api->userdata, struct avahi_poll_context);
63 0 : int num_watches = talloc_array_length(ctx->watches);
64 : AvahiWatch **tmp, *watch_ctx;
65 :
66 0 : tmp = talloc_realloc(ctx, ctx->watches, AvahiWatch *, num_watches + 1);
67 0 : if (tmp == NULL) {
68 0 : return NULL;
69 : }
70 0 : ctx->watches = tmp;
71 :
72 0 : watch_ctx = talloc(tmp, AvahiWatch);
73 0 : if (watch_ctx == NULL) {
74 0 : goto fail;
75 : }
76 0 : ctx->watches[num_watches] = watch_ctx;
77 :
78 0 : watch_ctx->ctx = ctx;
79 0 : 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 0 : if (watch_ctx->fde == NULL) {
83 0 : goto fail;
84 : }
85 0 : watch_ctx->callback = callback;
86 0 : watch_ctx->userdata = userdata;
87 0 : return watch_ctx;
88 :
89 0 : fail:
90 0 : TALLOC_FREE(watch_ctx);
91 0 : ctx->watches = talloc_realloc(ctx, ctx->watches, AvahiWatch *,
92 : num_watches);
93 0 : return NULL;
94 : }
95 :
96 0 : static void avahi_fd_handler(struct tevent_context *ev,
97 : struct tevent_fd *fde, uint16_t flags,
98 : void *private_data)
99 : {
100 0 : AvahiWatch *watch_ctx = talloc_get_type_abort(private_data, AvahiWatch);
101 :
102 0 : watch_ctx->latest_event =
103 0 : ((flags & TEVENT_FD_READ) ? AVAHI_WATCH_IN : 0)
104 0 : | ((flags & TEVENT_FD_WRITE) ? AVAHI_WATCH_OUT : 0);
105 :
106 0 : watch_ctx->callback(watch_ctx, watch_ctx->fd, watch_ctx->latest_event,
107 : watch_ctx->userdata);
108 0 : }
109 :
110 0 : static void avahi_watch_update(AvahiWatch *w, AvahiWatchEvent event)
111 : {
112 0 : tevent_fd_set_flags(w->fde, avahi_flags_map_to_tevent(event));
113 0 : }
114 :
115 0 : static AvahiWatchEvent avahi_watch_get_events(AvahiWatch *w)
116 : {
117 0 : return w->latest_event;
118 : }
119 :
120 0 : static void avahi_watch_free(AvahiWatch *w)
121 : {
122 : int i, num_watches;
123 0 : AvahiWatch **watches = w->ctx->watches;
124 : struct avahi_poll_context *ctx;
125 :
126 0 : num_watches = talloc_array_length(watches);
127 :
128 0 : for (i=0; i<num_watches; i++) {
129 0 : if (w == watches[i]) {
130 0 : break;
131 : }
132 : }
133 0 : if (i == num_watches) {
134 0 : return;
135 : }
136 0 : ctx = w->ctx;
137 0 : TALLOC_FREE(w);
138 0 : memmove(&watches[i], &watches[i+1],
139 0 : sizeof(*watches) * (num_watches - i - 1));
140 0 : 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 0 : static AvahiTimeout *avahi_timeout_new(const AvahiPoll *api,
150 : const struct timeval *tv,
151 : AvahiTimeoutCallback callback,
152 : void *userdata)
153 : {
154 0 : struct avahi_poll_context *ctx = talloc_get_type_abort(
155 : api->userdata, struct avahi_poll_context);
156 0 : int num_timeouts = talloc_array_length(ctx->timeouts);
157 : AvahiTimeout **tmp, *timeout_ctx;
158 :
159 0 : tmp = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
160 : num_timeouts + 1);
161 0 : if (tmp == NULL) {
162 0 : return NULL;
163 : }
164 0 : ctx->timeouts = tmp;
165 :
166 0 : timeout_ctx = talloc(tmp, AvahiTimeout);
167 0 : if (timeout_ctx == NULL) {
168 0 : goto fail;
169 : }
170 0 : ctx->timeouts[num_timeouts] = timeout_ctx;
171 :
172 0 : timeout_ctx->ctx = ctx;
173 0 : if (tv == NULL) {
174 0 : timeout_ctx->te = NULL;
175 : } else {
176 0 : timeout_ctx->te = tevent_add_timer(ctx->ev, timeout_ctx,
177 : *tv, avahi_timeout_handler,
178 : timeout_ctx);
179 0 : if (timeout_ctx->te == NULL) {
180 0 : goto fail;
181 : }
182 : }
183 0 : timeout_ctx->callback = callback;
184 0 : timeout_ctx->userdata = userdata;
185 0 : return timeout_ctx;
186 :
187 0 : fail:
188 0 : TALLOC_FREE(timeout_ctx);
189 0 : ctx->timeouts = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *,
190 : num_timeouts);
191 0 : return NULL;
192 : }
193 :
194 0 : 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 0 : AvahiTimeout *timeout_ctx = talloc_get_type_abort(
200 : private_data, AvahiTimeout);
201 :
202 0 : TALLOC_FREE(timeout_ctx->te);
203 0 : timeout_ctx->callback(timeout_ctx, timeout_ctx->userdata);
204 0 : }
205 :
206 0 : static void avahi_timeout_update(AvahiTimeout *t, const struct timeval *tv)
207 : {
208 0 : TALLOC_FREE(t->te);
209 :
210 0 : if (tv == NULL) {
211 : /*
212 : * Disable this timer
213 : */
214 0 : return;
215 : }
216 :
217 0 : t->te = tevent_add_timer(t->ctx->ev, t, *tv, avahi_timeout_handler, t);
218 : /*
219 : * No failure mode defined here
220 : */
221 0 : SMB_ASSERT(t->te != NULL);
222 : }
223 :
224 0 : static void avahi_timeout_free(AvahiTimeout *t)
225 : {
226 : int i, num_timeouts;
227 0 : AvahiTimeout **timeouts = t->ctx->timeouts;
228 : struct avahi_poll_context *ctx;
229 :
230 0 : num_timeouts = talloc_array_length(timeouts);
231 :
232 0 : for (i=0; i<num_timeouts; i++) {
233 0 : if (t == timeouts[i]) {
234 0 : break;
235 : }
236 : }
237 0 : if (i == num_timeouts) {
238 0 : return;
239 : }
240 0 : ctx = t->ctx;
241 0 : TALLOC_FREE(t);
242 0 : memmove(&timeouts[i], &timeouts[i+1],
243 0 : sizeof(*timeouts) * (num_timeouts - i - 1));
244 0 : ctx->timeouts = talloc_realloc(ctx, timeouts, AvahiTimeout *,
245 : num_timeouts - 1);
246 : }
247 :
248 0 : 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 0 : result = talloc(mem_ctx, struct AvahiPoll);
255 0 : if (result == NULL) {
256 0 : return result;
257 : }
258 0 : ctx = talloc_zero(result, struct avahi_poll_context);
259 0 : if (ctx == NULL) {
260 0 : TALLOC_FREE(result);
261 0 : return NULL;
262 : }
263 0 : ctx->ev = ev;
264 :
265 0 : result->watch_new = avahi_watch_new;
266 0 : result->watch_update = avahi_watch_update;
267 0 : result->watch_get_events = avahi_watch_get_events;
268 0 : result->watch_free = avahi_watch_free;
269 0 : result->timeout_new = avahi_timeout_new;
270 0 : result->timeout_update = avahi_timeout_update;
271 0 : result->timeout_free = avahi_timeout_free;
272 0 : result->userdata = ctx;
273 :
274 0 : return result;
275 : }
|