lib/util/charset rename iconv_convenience to iconv_handle
[ira/wip.git] / source3 / lib / events.c
1 /*
2    Unix SMB/CIFS implementation.
3    Timed event library.
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Volker Lendecke 2005
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include <tevent_internal.h>
23 #include "../lib/util/select.h"
24 #include "system/select.h"
25
26 struct tevent_poll_private {
27         /*
28          * Index from file descriptor into the pollfd array
29          */
30         int *pollfd_idx;
31
32         /*
33          * Cache for s3_event_loop_once to avoid reallocs
34          */
35         struct pollfd *pfds;
36 };
37
38 static struct tevent_poll_private *tevent_get_poll_private(
39         struct tevent_context *ev)
40 {
41         struct tevent_poll_private *state;
42
43         state = (struct tevent_poll_private *)ev->additional_data;
44         if (state == NULL) {
45                 state = TALLOC_ZERO_P(ev, struct tevent_poll_private);
46                 ev->additional_data = (void *)state;
47                 if (state == NULL) {
48                         DEBUG(10, ("talloc failed\n"));
49                 }
50         }
51         return state;
52 }
53
54 static void count_fds(struct tevent_context *ev,
55                       int *pnum_fds, int *pmax_fd)
56 {
57         struct tevent_fd *fde;
58         int num_fds = 0;
59         int max_fd = 0;
60
61         for (fde = ev->fd_events; fde != NULL; fde = fde->next) {
62                 if (fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) {
63                         num_fds += 1;
64                         if (fde->fd > max_fd) {
65                                 max_fd = fde->fd;
66                         }
67                 }
68         }
69         *pnum_fds = num_fds;
70         *pmax_fd = max_fd;
71 }
72
73 bool event_add_to_poll_args(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
74                             struct pollfd **pfds, int *pnum_pfds,
75                             int *ptimeout)
76 {
77         struct tevent_poll_private *state;
78         struct tevent_fd *fde;
79         int i, num_fds, max_fd, num_pollfds, idx_len;
80         struct pollfd *fds;
81         struct timeval now, diff;
82         int timeout;
83
84         state = tevent_get_poll_private(ev);
85         if (state == NULL) {
86                 return false;
87         }
88         count_fds(ev, &num_fds, &max_fd);
89
90         idx_len = max_fd+1;
91
92         if (talloc_array_length(state->pollfd_idx) < idx_len) {
93                 state->pollfd_idx = TALLOC_REALLOC_ARRAY(
94                         state, state->pollfd_idx, int, idx_len);
95                 if (state->pollfd_idx == NULL) {
96                         DEBUG(10, ("talloc_realloc failed\n"));
97                         return false;
98                 }
99         }
100
101         fds = *pfds;
102         num_pollfds = *pnum_pfds;
103
104         /*
105          * The +1 is for the sys_poll calling convention. It expects
106          * an array 1 longer for the signal pipe
107          */
108
109         if (talloc_array_length(fds) < num_pollfds + num_fds + 1) {
110                 fds = TALLOC_REALLOC_ARRAY(mem_ctx, fds, struct pollfd,
111                                            num_pollfds + num_fds + 1);
112                 if (fds == NULL) {
113                         DEBUG(10, ("talloc_realloc failed\n"));
114                         return false;
115                 }
116         }
117
118         memset(&fds[num_pollfds], 0, sizeof(struct pollfd) * num_fds);
119
120         /*
121          * This needs tuning. We need to cope with multiple fde's for a file
122          * descriptor. The problem is that we need to re-use pollfd_idx across
123          * calls for efficiency. One way would be a direct bitmask that might
124          * be initialized quicker, but our bitmap_init implementation is
125          * pretty heavy-weight as well.
126          */
127         for (i=0; i<idx_len; i++) {
128                 state->pollfd_idx[i] = -1;
129         }
130
131         for (fde = ev->fd_events; fde; fde = fde->next) {
132                 struct pollfd *pfd;
133
134                 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) == 0) {
135                         continue;
136                 }
137
138                 if (state->pollfd_idx[fde->fd] == -1) {
139                         /*
140                          * We haven't seen this fd yet. Allocate a new pollfd.
141                          */
142                         state->pollfd_idx[fde->fd] = num_pollfds;
143                         pfd = &fds[num_pollfds];
144                         num_pollfds += 1;
145                 } else {
146                         /*
147                          * We have already seen this fd. OR in the flags.
148                          */
149                         pfd = &fds[state->pollfd_idx[fde->fd]];
150                 }
151
152                 pfd->fd = fde->fd;
153
154                 if (fde->flags & EVENT_FD_READ) {
155                         pfd->events |= (POLLIN|POLLHUP);
156                 }
157                 if (fde->flags & EVENT_FD_WRITE) {
158                         pfd->events |= POLLOUT;
159                 }
160         }
161         *pfds = fds;
162         *pnum_pfds = num_pollfds;
163
164         if (ev->immediate_events != NULL) {
165                 *ptimeout = 0;
166                 return true;
167         }
168         if (ev->timer_events == NULL) {
169                 *ptimeout = INT_MAX;
170                 return true;
171         }
172
173         now = timeval_current();
174         diff = timeval_until(&now, &ev->timer_events->next_event);
175         timeout = timeval_to_msec(diff);
176
177         if (timeout < *ptimeout) {
178                 *ptimeout = timeout;
179         }
180
181         return true;
182 }
183
184 bool run_events_poll(struct tevent_context *ev, int pollrtn,
185                      struct pollfd *pfds, int num_pfds)
186 {
187         struct tevent_poll_private *state;
188         int *pollfd_idx;
189         struct tevent_fd *fde;
190         struct timeval now;
191
192         if (ev->signal_events &&
193             tevent_common_check_signal(ev)) {
194                 return true;
195         }
196
197         if (ev->immediate_events &&
198             tevent_common_loop_immediate(ev)) {
199                 return true;
200         }
201
202         GetTimeOfDay(&now);
203
204         if ((ev->timer_events != NULL)
205             && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
206                 /* this older events system did not auto-free timed
207                    events on running them, and had a race condition
208                    where the event could be called twice if the
209                    talloc_free of the te happened after the callback
210                    made a call which invoked the event loop. To avoid
211                    this while still allowing old code which frees the
212                    te, we need to create a temporary context which
213                    will be used to ensure the te is freed. We also
214                    remove the te from the timed event list before we
215                    call the handler, to ensure we can't loop */
216
217                 struct tevent_timer *te = ev->timer_events;
218                 TALLOC_CTX *tmp_ctx = talloc_new(ev);
219
220                 DEBUG(10, ("Running timed event \"%s\" %p\n",
221                            ev->timer_events->handler_name, ev->timer_events));
222
223                 DLIST_REMOVE(ev->timer_events, te);
224                 talloc_steal(tmp_ctx, te);
225
226                 te->handler(ev, te, now, te->private_data);
227
228                 talloc_free(tmp_ctx);
229                 return true;
230         }
231
232         if (pollrtn <= 0) {
233                 /*
234                  * No fd ready
235                  */
236                 return false;
237         }
238
239         state = (struct tevent_poll_private *)ev->additional_data;
240         pollfd_idx = state->pollfd_idx;
241
242         for (fde = ev->fd_events; fde; fde = fde->next) {
243                 struct pollfd *pfd;
244                 uint16 flags = 0;
245
246                 if (pollfd_idx[fde->fd] >= num_pfds) {
247                         DEBUG(1, ("internal error: pollfd_idx[fde->fd] (%d) "
248                                   ">= num_pfds (%d)\n", pollfd_idx[fde->fd],
249                                   num_pfds));
250                         return false;
251                 }
252                 pfd = &pfds[pollfd_idx[fde->fd]];
253
254                 if (pfd->fd != fde->fd) {
255                         DEBUG(1, ("internal error: pfd->fd (%d) "
256                                   "!= fde->fd (%d)\n", pollfd_idx[fde->fd],
257                                   num_pfds));
258                         return false;
259                 }
260
261                 if (pfd->revents & (POLLIN|POLLHUP|POLLERR)) {
262                         flags |= EVENT_FD_READ;
263                 }
264                 if (pfd->revents & POLLOUT) {
265                         flags |= EVENT_FD_WRITE;
266                 }
267                 if (flags & fde->flags) {
268                         DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
269                         fde->handler(ev, fde, flags, fde->private_data);
270                         return true;
271                 }
272         }
273
274         return false;
275 }
276
277 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
278                                          struct timeval *to_ret)
279 {
280         struct timeval now;
281
282         if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
283                 return NULL;
284         }
285         if (ev->immediate_events != NULL) {
286                 *to_ret = timeval_zero();
287                 return to_ret;
288         }
289
290         now = timeval_current();
291         *to_ret = timeval_until(&now, &ev->timer_events->next_event);
292
293         DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
294                 (int)to_ret->tv_usec));
295
296         return to_ret;
297 }
298
299 static int s3_event_loop_once(struct tevent_context *ev, const char *location)
300 {
301         struct tevent_poll_private *state;
302         int timeout;
303         int num_pfds;
304         int ret;
305
306         timeout = INT_MAX;
307
308         state = tevent_get_poll_private(ev);
309         if (state == NULL) {
310                 errno = ENOMEM;
311                 return -1;
312         }
313
314         if (run_events_poll(ev, 0, NULL, 0)) {
315                 return 0;
316         }
317
318         num_pfds = 0;
319         if (!event_add_to_poll_args(ev, state,
320                                     &state->pfds, &num_pfds, &timeout)) {
321                 return -1;
322         }
323
324         ret = sys_poll(state->pfds, num_pfds, timeout);
325         if (ret == -1 && errno != EINTR) {
326                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
327                              "poll() failed: %d:%s\n",
328                              errno, strerror(errno));
329                 return -1;
330         }
331
332         run_events_poll(ev, ret, state->pfds, num_pfds);
333         return 0;
334 }
335
336 static int s3_event_context_init(struct tevent_context *ev)
337 {
338         return 0;
339 }
340
341 void dump_event_list(struct tevent_context *ev)
342 {
343         struct tevent_timer *te;
344         struct tevent_fd *fe;
345         struct timeval evt, now;
346
347         if (!ev) {
348                 return;
349         }
350
351         now = timeval_current();
352
353         DEBUG(10,("dump_event_list:\n"));
354
355         for (te = ev->timer_events; te; te = te->next) {
356
357                 evt = timeval_until(&now, &te->next_event);
358
359                 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
360                            te->handler_name,
361                            te,
362                            (int)evt.tv_sec,
363                            http_timestring(talloc_tos(), te->next_event.tv_sec)));
364         }
365
366         for (fe = ev->fd_events; fe; fe = fe->next) {
367
368                 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
369                            fe->fd,
370                            fe,
371                            fe->flags));
372         }
373 }
374
375 static const struct tevent_ops s3_event_ops = {
376         .context_init           = s3_event_context_init,
377         .add_fd                 = tevent_common_add_fd,
378         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
379         .get_fd_flags           = tevent_common_fd_get_flags,
380         .set_fd_flags           = tevent_common_fd_set_flags,
381         .add_timer              = tevent_common_add_timer,
382         .schedule_immediate     = tevent_common_schedule_immediate,
383         .add_signal             = tevent_common_add_signal,
384         .loop_once              = s3_event_loop_once,
385         .loop_wait              = tevent_common_loop_wait,
386 };
387
388 static bool s3_tevent_init(void)
389 {
390         static bool initialized;
391         if (initialized) {
392                 return true;
393         }
394         initialized = tevent_register_backend("s3", &s3_event_ops);
395         tevent_set_default_backend("s3");
396         return initialized;
397 }
398
399 /*
400   this is used to catch debug messages from events
401 */
402 static void s3_event_debug(void *context, enum tevent_debug_level level,
403                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
404
405 static void s3_event_debug(void *context, enum tevent_debug_level level,
406                            const char *fmt, va_list ap)
407 {
408         int samba_level = -1;
409         char *s = NULL;
410         switch (level) {
411         case TEVENT_DEBUG_FATAL:
412                 samba_level = 0;
413                 break;
414         case TEVENT_DEBUG_ERROR:
415                 samba_level = 1;
416                 break;
417         case TEVENT_DEBUG_WARNING:
418                 samba_level = 2;
419                 break;
420         case TEVENT_DEBUG_TRACE:
421                 samba_level = 11;
422                 break;
423
424         };
425         if (vasprintf(&s, fmt, ap) == -1) {
426                 return;
427         }
428         DEBUG(samba_level, ("s3_event: %s", s));
429         free(s);
430 }
431
432 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
433 {
434         struct tevent_context *ev;
435
436         s3_tevent_init();
437
438         ev = tevent_context_init_byname(mem_ctx, "s3");
439         if (ev) {
440                 tevent_set_debug(ev, s3_event_debug, NULL);
441         }
442
443         return ev;
444 }
445