Use full path to dlinklist.h in includes.
[obnox/samba/samba-obnox.git] / source3 / lib / poll_funcs / poll_funcs_tevent.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Copyright (C) Volker Lendecke 2013,2014
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "poll_funcs_tevent.h"
20 #include "tevent.h"
21 #include "system/select.h"
22 #include "lib/util/dlinklist.h"
23
24 /*
25  * A poll_watch is asked for by the engine using this library via
26  * funcs->watch_new(). It represents interest in "fd" becoming readable or
27  * writable.
28  */
29
30 struct poll_watch {
31         struct poll_funcs_state *state;
32         unsigned slot;          /* index into state->watches[] */
33         int fd;
34         int events;
35         void (*callback)(struct poll_watch *w, int fd, short events,
36                          void *private_data);
37         void *private_data;
38 };
39
40 struct poll_funcs_state {
41         /*
42          * "watches" is the array of all watches that we have handed out via
43          * funcs->watch_new(). The "watches" array can contain NULL pointers.
44          */
45         unsigned num_watches;
46         struct poll_watch **watches;
47
48         /*
49          * "contexts is the array of tevent_contexts that serve
50          * "watches". "contexts" can contain NULL pointers.
51          */
52         unsigned num_contexts;
53         struct poll_funcs_tevent_context **contexts;
54 };
55
56 struct poll_funcs_tevent_context {
57         struct poll_funcs_tevent_handle *handles;
58         struct poll_funcs_state *state;
59         unsigned slot;          /* index into state->contexts[] */
60         struct tevent_context *ev;
61         struct tevent_fd **fdes; /* same indexes as state->watches[] */
62 };
63
64 /*
65  * poll_funcs_tevent_register() hands out a struct poll_funcs_tevent_handle as
66  * a void *. poll_funcs_tevent_register allows tevent_contexts to be
67  * registered multiple times, and we can't add a tevent_fd for the same fd's
68  * multiple times. So we have to share one poll_funcs_tevent_context.
69  */
70 struct poll_funcs_tevent_handle {
71         struct poll_funcs_tevent_handle *prev, *next;
72         struct poll_funcs_tevent_context *ctx;
73 };
74
75 static uint16_t poll_events_to_tevent(short events)
76 {
77         uint16_t ret = 0;
78
79         if (events & POLLIN) {
80                 ret |= TEVENT_FD_READ;
81         }
82         if (events & POLLOUT) {
83                 ret |= TEVENT_FD_WRITE;
84         }
85         return ret;
86 }
87
88 static short tevent_to_poll_events(uint16_t flags)
89 {
90         short ret = 0;
91
92         if (flags & TEVENT_FD_READ) {
93                 ret |= POLLIN;
94         }
95         if (flags & TEVENT_FD_WRITE) {
96                 ret |= POLLOUT;
97         }
98         return ret;
99 }
100
101 /*
102  * Find or create a free slot in state->watches[]
103  */
104 static bool poll_funcs_watch_find_slot(struct poll_funcs_state *state,
105                                        unsigned *slot)
106 {
107         struct poll_watch **watches;
108         unsigned i;
109
110         for (i=0; i<state->num_watches; i++) {
111                 if (state->watches[i] == NULL) {
112                         *slot = i;
113                         return true;
114                 }
115         }
116
117         watches = talloc_realloc(state, state->watches, struct poll_watch *,
118                                  state->num_watches + 1);
119         if (watches == NULL) {
120                 return false;
121         }
122         watches[state->num_watches] = NULL;
123         state->watches = watches;
124
125         for (i=0; i<state->num_contexts; i++) {
126                 struct tevent_fd **fdes;
127                 struct poll_funcs_tevent_context *c = state->contexts[i];
128                 if (c == NULL) {
129                         continue;
130                 }
131                 fdes = talloc_realloc(c, c->fdes, struct tevent_fd *,
132                                       state->num_watches + 1);
133                 if (fdes == NULL) {
134                         return false;
135                 }
136                 c->fdes = fdes;
137
138                 fdes[state->num_watches] = NULL;
139         }
140
141         *slot = state->num_watches;
142         state->num_watches += 1;
143
144         return true;
145 }
146
147 static void poll_funcs_fde_handler(struct tevent_context *ev,
148                                    struct tevent_fd *fde, uint16_t flags,
149                                    void *private_data);
150 static int poll_watch_destructor(struct poll_watch *w);
151
152 static struct poll_watch *tevent_watch_new(
153         const struct poll_funcs *funcs, int fd, short events,
154         void (*callback)(struct poll_watch *w, int fd, short events,
155                          void *private_data),
156         void *private_data)
157 {
158         struct poll_funcs_state *state = talloc_get_type_abort(
159                 funcs->private_data, struct poll_funcs_state);
160         struct poll_watch *w;
161         unsigned i, slot;
162
163         if (!poll_funcs_watch_find_slot(state, &slot)) {
164                 return NULL;
165         }
166
167         w = talloc(state->watches, struct poll_watch);
168         if (w == NULL) {
169                 return NULL;
170         }
171         w->state = state;
172         w->slot = slot;
173         w->fd = fd;
174         w->events = poll_events_to_tevent(events);
175         w->fd = fd;
176         w->callback = callback;
177         w->private_data = private_data;
178         state->watches[slot] = w;
179
180         talloc_set_destructor(w, poll_watch_destructor);
181
182         for (i=0; i<state->num_contexts; i++) {
183                 struct poll_funcs_tevent_context *c = state->contexts[i];
184                 if (c == NULL) {
185                         continue;
186                 }
187                 c->fdes[slot] = tevent_add_fd(c->ev, c->fdes, w->fd, w->events,
188                                               poll_funcs_fde_handler, w);
189                 if (c->fdes[slot] == NULL) {
190                         goto fail;
191                 }
192         }
193         return w;
194
195 fail:
196         TALLOC_FREE(w);
197         return NULL;
198 }
199
200 static int poll_watch_destructor(struct poll_watch *w)
201 {
202         struct poll_funcs_state *state = w->state;
203         unsigned slot = w->slot;
204         unsigned i;
205
206         TALLOC_FREE(state->watches[slot]);
207
208         for (i=0; i<state->num_contexts; i++) {
209                 struct poll_funcs_tevent_context *c = state->contexts[i];
210                 if (c == NULL) {
211                         continue;
212                 }
213                 TALLOC_FREE(c->fdes[slot]);
214         }
215
216         return 0;
217 }
218
219 static void tevent_watch_update(struct poll_watch *w, short events)
220 {
221         struct poll_funcs_state *state = w->state;
222         unsigned slot = w->slot;
223         unsigned i;
224
225         w->events = poll_events_to_tevent(events);
226
227         for (i=0; i<state->num_contexts; i++) {
228                 struct poll_funcs_tevent_context *c = state->contexts[i];
229                 if (c == NULL) {
230                         continue;
231                 }
232                 tevent_fd_set_flags(c->fdes[slot], w->events);
233         }
234 }
235
236 static short tevent_watch_get_events(struct poll_watch *w)
237 {
238         return tevent_to_poll_events(w->events);
239 }
240
241 static void tevent_watch_free(struct poll_watch *w)
242 {
243         TALLOC_FREE(w);
244 }
245
246 static struct poll_timeout *tevent_timeout_new(
247         const struct poll_funcs *funcs, const struct timeval *tv,
248         void (*callback)(struct poll_timeout *t, void *private_data),
249         void *private_data)
250 {
251         /* not implemented yet */
252         return NULL;
253 }
254
255 static void tevent_timeout_update(struct poll_timeout *t,
256                                   const struct timespec *ts)
257 {
258         return;
259 }
260
261 static void tevent_timeout_free(struct poll_timeout *t)
262 {
263         return;
264 }
265
266 static int poll_funcs_state_destructor(struct poll_funcs_state *state);
267
268 struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx)
269 {
270         struct poll_funcs *f;
271         struct poll_funcs_state *state;
272
273         f = talloc(mem_ctx, struct poll_funcs);
274         if (f == NULL) {
275                 return NULL;
276         }
277         state = talloc_zero(f, struct poll_funcs_state);
278         if (state == NULL) {
279                 TALLOC_FREE(f);
280                 return NULL;
281         }
282         talloc_set_destructor(state, poll_funcs_state_destructor);
283
284         f->watch_new = tevent_watch_new;
285         f->watch_update = tevent_watch_update;
286         f->watch_get_events = tevent_watch_get_events;
287         f->watch_free = tevent_watch_free;
288         f->timeout_new = tevent_timeout_new;
289         f->timeout_update = tevent_timeout_update;
290         f->timeout_free = tevent_timeout_free;
291         f->private_data = state;
292         return f;
293 }
294
295 static int poll_funcs_state_destructor(struct poll_funcs_state *state)
296 {
297         unsigned i;
298         /*
299          * Make sure the watches are cleared before the contexts. The watches
300          * have destructors attached to them that clean up the fde's
301          */
302         for (i=0; i<state->num_watches; i++) {
303                 TALLOC_FREE(state->watches[i]);
304         }
305         return 0;
306 }
307
308 /*
309  * Find or create a free slot in state->contexts[]
310  */
311 static bool poll_funcs_context_slot_find(struct poll_funcs_state *state,
312                                          struct tevent_context *ev,
313                                          unsigned *slot)
314 {
315         struct poll_funcs_tevent_context **contexts;
316         unsigned i;
317
318         for (i=0; i<state->num_contexts; i++) {
319                 struct poll_funcs_tevent_context *ctx = state->contexts[i];
320
321                 if ((ctx == NULL) || (ctx->ev == ev)) {
322                         *slot = i;
323                         return true;
324                 }
325         }
326
327         contexts = talloc_realloc(state, state->contexts,
328                                   struct poll_funcs_tevent_context *,
329                                   state->num_contexts + 1);
330         if (contexts == NULL) {
331                 return false;
332         }
333         state->contexts = contexts;
334         state->contexts[state->num_contexts] = NULL;
335
336         *slot = state->num_contexts;
337         state->num_contexts += 1;
338
339         return true;
340 }
341
342 static int poll_funcs_tevent_context_destructor(
343         struct poll_funcs_tevent_context *ctx);
344
345 static struct poll_funcs_tevent_context *poll_funcs_tevent_context_new(
346         TALLOC_CTX *mem_ctx, struct poll_funcs_state *state,
347         struct tevent_context *ev, unsigned slot)
348 {
349         struct poll_funcs_tevent_context *ctx;
350         unsigned i;
351
352         ctx = talloc(mem_ctx, struct poll_funcs_tevent_context);
353         if (ctx == NULL) {
354                 return NULL;
355         }
356
357         ctx->handles = NULL;
358         ctx->state = state;
359         ctx->ev = ev;
360         ctx->slot = slot;
361
362         ctx->fdes = talloc_array(ctx, struct tevent_fd *, state->num_watches);
363         if (ctx->fdes == NULL) {
364                 goto fail;
365         }
366
367         for (i=0; i<state->num_watches; i++) {
368                 struct poll_watch *w = state->watches[i];
369
370                 if (w == NULL) {
371                         ctx->fdes[i] = NULL;
372                         continue;
373                 }
374                 ctx->fdes[i] = tevent_add_fd(ev, ctx->fdes, w->fd, w->events,
375                                              poll_funcs_fde_handler, w);
376                 if (ctx->fdes[i] == NULL) {
377                         goto fail;
378                 }
379         }
380         talloc_set_destructor(ctx, poll_funcs_tevent_context_destructor);
381         return ctx;
382 fail:
383         TALLOC_FREE(ctx);
384         return NULL;
385 }
386
387 static int poll_funcs_tevent_context_destructor(
388         struct poll_funcs_tevent_context *ctx)
389 {
390         struct poll_funcs_tevent_handle *h;
391
392         ctx->state->contexts[ctx->slot] = NULL;
393
394         for (h = ctx->handles; h != NULL; h = h->next) {
395                 h->ctx = NULL;
396         }
397
398         return 0;
399 }
400
401 static void poll_funcs_fde_handler(struct tevent_context *ev,
402                                    struct tevent_fd *fde, uint16_t flags,
403                                    void *private_data)
404 {
405         struct poll_watch *w = talloc_get_type_abort(
406                 private_data, struct poll_watch);
407         short events = tevent_to_poll_events(flags);
408         w->callback(w, w->fd, events, w->private_data);
409 }
410
411 static int poll_funcs_tevent_handle_destructor(
412         struct poll_funcs_tevent_handle *handle);
413
414 void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
415                                  struct tevent_context *ev)
416 {
417         struct poll_funcs_state *state = talloc_get_type_abort(
418                 f->private_data, struct poll_funcs_state);
419         struct poll_funcs_tevent_handle *handle;
420         unsigned slot;
421
422         handle = talloc(mem_ctx, struct poll_funcs_tevent_handle);
423         if (handle == NULL) {
424                 return NULL;
425         }
426
427         if (!poll_funcs_context_slot_find(state, ev, &slot)) {
428                 goto fail;
429         }
430         if (state->contexts[slot] == NULL) {
431                 state->contexts[slot] = poll_funcs_tevent_context_new(
432                         state->contexts, state, ev, slot);
433                 if (state->contexts[slot] == NULL) {
434                         goto fail;
435                 }
436         }
437
438         handle->ctx = state->contexts[slot];
439         DLIST_ADD(handle->ctx->handles, handle);
440         talloc_set_destructor(handle, poll_funcs_tevent_handle_destructor);
441         return handle;
442 fail:
443         TALLOC_FREE(handle);
444         return NULL;
445 }
446
447 static int poll_funcs_tevent_handle_destructor(
448         struct poll_funcs_tevent_handle *handle)
449 {
450         if (handle->ctx == NULL) {
451                 return 0;
452         }
453         if (handle->ctx->handles == NULL) {
454                 abort();
455         }
456
457         DLIST_REMOVE(handle->ctx->handles, handle);
458
459         if (handle->ctx->handles == NULL) {
460                 TALLOC_FREE(handle->ctx);
461         }
462         return 0;
463 }