Line data Source code
1 : /*
2 : Infrastructure for event context wrappers
3 :
4 : Copyright (C) Stefan Metzmacher 2014
5 :
6 : ** NOTE! The following LGPL license applies to the tevent
7 : ** library. This does NOT imply that all of Samba is released
8 : ** under the LGPL
9 :
10 : This library is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU Lesser General Public
12 : License as published by the Free Software Foundation; either
13 : version 3 of the License, or (at your option) any later version.
14 :
15 : This library is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : Lesser General Public License for more details.
19 :
20 : You should have received a copy of the GNU Lesser General Public
21 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "replace.h"
25 : #ifdef HAVE_PTHREAD
26 : #include "system/threads.h"
27 : #endif
28 : #define TEVENT_DEPRECATED 1
29 : #include "tevent.h"
30 : #include "tevent_internal.h"
31 : #include "tevent_util.h"
32 :
33 0 : static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
34 : {
35 0 : tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
36 0 : errno = ENOSYS;
37 0 : return -1;
38 : }
39 :
40 8 : static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
41 : TALLOC_CTX *mem_ctx,
42 : int fd, uint16_t flags,
43 : tevent_fd_handler_t handler,
44 : void *private_data,
45 : const char *handler_name,
46 : const char *location)
47 : {
48 8 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
49 8 : struct tevent_fd *fde = NULL;
50 :
51 8 : if (glue->destroyed) {
52 0 : tevent_abort(ev, "add_fd wrapper use after free");
53 0 : return NULL;
54 : }
55 :
56 8 : if (glue->main_ev == NULL) {
57 0 : errno = EINVAL;
58 0 : return NULL;
59 : }
60 :
61 8 : fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
62 : handler, private_data,
63 : handler_name, location);
64 8 : if (fde == NULL) {
65 0 : return NULL;
66 : }
67 :
68 8 : fde->wrapper = glue;
69 :
70 8 : return fde;
71 : }
72 :
73 8 : static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
74 : TALLOC_CTX *mem_ctx,
75 : struct timeval next_event,
76 : tevent_timer_handler_t handler,
77 : void *private_data,
78 : const char *handler_name,
79 : const char *location)
80 : {
81 8 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
82 8 : struct tevent_timer *te = NULL;
83 :
84 8 : if (glue->destroyed) {
85 0 : tevent_abort(ev, "add_timer wrapper use after free");
86 0 : return NULL;
87 : }
88 :
89 8 : if (glue->main_ev == NULL) {
90 0 : errno = EINVAL;
91 0 : return NULL;
92 : }
93 :
94 8 : te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
95 : handler, private_data,
96 : handler_name, location);
97 8 : if (te == NULL) {
98 0 : return NULL;
99 : }
100 :
101 8 : te->wrapper = glue;
102 :
103 8 : return te;
104 : }
105 :
106 8 : static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
107 : struct tevent_context *ev,
108 : tevent_immediate_handler_t handler,
109 : void *private_data,
110 : const char *handler_name,
111 : const char *location)
112 : {
113 8 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
114 :
115 8 : if (glue->destroyed) {
116 0 : tevent_abort(ev, "scheduke_immediate wrapper use after free");
117 0 : return;
118 : }
119 :
120 8 : if (glue->main_ev == NULL) {
121 0 : tevent_abort(ev, location);
122 0 : errno = EINVAL;
123 0 : return;
124 : }
125 :
126 8 : _tevent_schedule_immediate(im, glue->main_ev,
127 : handler, private_data,
128 : handler_name, location);
129 :
130 8 : im->wrapper = glue;
131 :
132 8 : return;
133 : }
134 :
135 8 : static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
136 : TALLOC_CTX *mem_ctx,
137 : int signum, int sa_flags,
138 : tevent_signal_handler_t handler,
139 : void *private_data,
140 : const char *handler_name,
141 : const char *location)
142 : {
143 8 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
144 8 : struct tevent_signal *se = NULL;
145 :
146 8 : if (glue->destroyed) {
147 0 : tevent_abort(ev, "add_signal wrapper use after free");
148 0 : return NULL;
149 : }
150 :
151 8 : if (glue->main_ev == NULL) {
152 0 : errno = EINVAL;
153 0 : return NULL;
154 : }
155 :
156 8 : se = _tevent_add_signal(glue->main_ev, mem_ctx,
157 : signum, sa_flags,
158 : handler, private_data,
159 : handler_name, location);
160 8 : if (se == NULL) {
161 0 : return NULL;
162 : }
163 :
164 8 : se->wrapper = glue;
165 :
166 8 : return se;
167 : }
168 :
169 0 : static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
170 : {
171 0 : tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
172 0 : errno = ENOSYS;
173 0 : return -1;
174 : }
175 :
176 0 : static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
177 : {
178 0 : tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
179 0 : errno = ENOSYS;
180 0 : return -1;
181 : }
182 :
183 : static const struct tevent_ops tevent_wrapper_glue_ops = {
184 : .context_init = tevent_wrapper_glue_context_init,
185 : .add_fd = tevent_wrapper_glue_add_fd,
186 : .set_fd_close_fn = tevent_common_fd_set_close_fn,
187 : .get_fd_flags = tevent_common_fd_get_flags,
188 : .set_fd_flags = tevent_common_fd_set_flags,
189 : .add_timer = tevent_wrapper_glue_add_timer,
190 : .schedule_immediate = tevent_wrapper_glue_schedule_immediate,
191 : .add_signal = tevent_wrapper_glue_add_signal,
192 : .loop_once = tevent_wrapper_glue_loop_once,
193 : .loop_wait = tevent_wrapper_glue_loop_wait,
194 : };
195 :
196 12 : static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
197 : {
198 12 : struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
199 12 : struct tevent_context *main_ev = NULL;
200 12 : struct tevent_fd *fd = NULL, *fn = NULL;
201 12 : struct tevent_timer *te = NULL, *tn = NULL;
202 12 : struct tevent_immediate *ie = NULL, *in = NULL;
203 12 : struct tevent_signal *se = NULL, *sn = NULL;
204 : #ifdef HAVE_PTHREAD
205 12 : struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
206 : #endif
207 :
208 12 : if (glue == NULL) {
209 0 : tevent_abort(wrap_ev,
210 : "tevent_wrapper_context_destructor() active on main");
211 : /* static checker support, return below is never reached */
212 0 : return -1;
213 : }
214 :
215 12 : if (glue->destroyed && glue->busy) {
216 0 : tevent_common_check_double_free(wrap_ev,
217 : "tevent_context wrapper double free");
218 : }
219 12 : glue->destroyed = true;
220 :
221 12 : if (glue->busy) {
222 0 : return -1;
223 : }
224 :
225 8 : main_ev = glue->main_ev;
226 8 : if (main_ev == NULL) {
227 0 : return 0;
228 : }
229 :
230 8 : tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
231 : "Destroying wrapper context %p \"%s\"\n",
232 8 : wrap_ev, talloc_get_name(glue->private_state));
233 :
234 8 : glue->main_ev = NULL;
235 8 : DLIST_REMOVE(main_ev->wrapper.list, glue);
236 :
237 : #ifdef HAVE_PTHREAD
238 16 : for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
239 : int ret;
240 :
241 0 : tctxn = tctx->next;
242 :
243 0 : if (tctx->event_ctx != glue->wrap_ev) {
244 0 : continue;
245 : }
246 :
247 0 : ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
248 0 : if (ret != 0) {
249 0 : abort();
250 : }
251 :
252 : /*
253 : * Indicate to the thread that the tevent_context is
254 : * gone. The counterpart of this is in
255 : * _tevent_threaded_schedule_immediate, there we read
256 : * this under the threaded_context's mutex.
257 : */
258 :
259 0 : tctx->event_ctx = NULL;
260 :
261 0 : ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
262 0 : if (ret != 0) {
263 0 : abort();
264 : }
265 :
266 0 : DLIST_REMOVE(main_ev->threaded_contexts, tctx);
267 : }
268 : #endif
269 :
270 28 : for (fd = main_ev->fd_events; fd; fd = fn) {
271 12 : fn = fd->next;
272 :
273 12 : if (fd->wrapper != glue) {
274 8 : continue;
275 : }
276 :
277 4 : tevent_fd_set_flags(fd, 0);
278 :
279 4 : fd->wrapper = NULL;
280 4 : fd->event_ctx = NULL;
281 4 : DLIST_REMOVE(main_ev->fd_events, fd);
282 : }
283 :
284 20 : for (te = main_ev->timer_events; te; te = tn) {
285 4 : tn = te->next;
286 :
287 4 : if (te->wrapper != glue) {
288 0 : continue;
289 : }
290 :
291 4 : te->wrapper = NULL;
292 4 : te->event_ctx = NULL;
293 :
294 4 : if (main_ev->last_zero_timer == te) {
295 0 : main_ev->last_zero_timer = DLIST_PREV(te);
296 : }
297 4 : DLIST_REMOVE(main_ev->timer_events, te);
298 : }
299 :
300 20 : for (ie = main_ev->immediate_events; ie; ie = in) {
301 4 : in = ie->next;
302 :
303 4 : if (ie->wrapper != glue) {
304 0 : continue;
305 : }
306 :
307 4 : ie->wrapper = NULL;
308 4 : ie->event_ctx = NULL;
309 4 : ie->cancel_fn = NULL;
310 4 : DLIST_REMOVE(main_ev->immediate_events, ie);
311 : }
312 :
313 16 : for (se = main_ev->signal_events; se; se = sn) {
314 0 : sn = se->next;
315 :
316 0 : if (se->wrapper != glue) {
317 0 : continue;
318 : }
319 :
320 0 : se->wrapper = NULL;
321 0 : tevent_cleanup_pending_signal_handlers(se);
322 : }
323 :
324 0 : return 0;
325 : }
326 :
327 8 : struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
328 : TALLOC_CTX *mem_ctx,
329 : const struct tevent_wrapper_ops *ops,
330 : void *pstate,
331 : size_t psize,
332 : const char *type,
333 : const char *location)
334 : {
335 8 : void **ppstate = (void **)pstate;
336 8 : struct tevent_context *ev = NULL;
337 :
338 8 : if (main_ev->wrapper.glue != NULL) {
339 : /*
340 : * stacking of wrappers is not supported
341 : */
342 0 : tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
343 : "%s: %s() stacking not allowed\n",
344 : __func__, location);
345 0 : errno = EINVAL;
346 0 : return NULL;
347 : }
348 :
349 8 : if (main_ev->nesting.allowed) {
350 : /*
351 : * wrappers conflict with nesting
352 : */
353 0 : tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
354 : "%s: %s() conflicts with nesting\n",
355 : __func__, location);
356 0 : errno = EINVAL;
357 0 : return NULL;
358 : }
359 :
360 8 : ev = talloc_zero(mem_ctx, struct tevent_context);
361 8 : if (ev == NULL) {
362 0 : return NULL;
363 : }
364 8 : ev->ops = &tevent_wrapper_glue_ops;
365 :
366 8 : ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
367 8 : if (ev->wrapper.glue == NULL) {
368 0 : talloc_free(ev);
369 0 : return NULL;
370 : }
371 :
372 8 : talloc_set_destructor(ev, tevent_wrapper_context_destructor);
373 :
374 8 : ev->wrapper.glue->wrap_ev = ev;
375 8 : ev->wrapper.glue->main_ev = main_ev;
376 8 : ev->wrapper.glue->ops = ops;
377 8 : ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
378 8 : if (ev->wrapper.glue->private_state == NULL) {
379 0 : talloc_free(ev);
380 0 : return NULL;
381 : }
382 8 : talloc_set_name_const(ev->wrapper.glue->private_state, type);
383 :
384 8 : DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
385 :
386 8 : *ppstate = ev->wrapper.glue->private_state;
387 8 : return ev;
388 : }
389 :
390 0 : bool tevent_context_is_wrapper(struct tevent_context *ev)
391 : {
392 0 : if (ev->wrapper.glue != NULL) {
393 0 : return true;
394 : }
395 :
396 0 : return false;
397 : }
398 :
399 : _PRIVATE_
400 216966 : struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
401 : {
402 216966 : if (ev == NULL) {
403 1264 : return NULL;
404 : }
405 :
406 215695 : if (ev->wrapper.glue == NULL) {
407 186438 : return ev;
408 : }
409 :
410 8 : return ev->wrapper.glue->main_ev;
411 : }
412 :
413 : /*
414 : * 32 stack elements should be more than enough
415 : *
416 : * e.g. Samba uses just 8 elements for [un]become_{root,user}()
417 : */
418 : #define TEVENT_WRAPPER_STACK_SIZE 32
419 :
420 : static struct tevent_wrapper_stack {
421 : const void *ev_ptr;
422 : const struct tevent_wrapper_glue *wrapper;
423 : } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
424 :
425 : static size_t wrapper_stack_idx;
426 :
427 : _PRIVATE_
428 28 : void tevent_wrapper_push_use_internal(struct tevent_context *ev,
429 : struct tevent_wrapper_glue *wrapper)
430 : {
431 : /*
432 : * ev and wrapper need to belong together!
433 : * It's also fine to only have a raw ev
434 : * without a wrapper.
435 : */
436 28 : if (unlikely(ev->wrapper.glue != wrapper)) {
437 0 : tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
438 0 : return;
439 : }
440 :
441 28 : if (wrapper != NULL) {
442 24 : if (unlikely(wrapper->busy)) {
443 0 : tevent_abort(ev, "wrapper already busy!");
444 0 : return;
445 : }
446 24 : wrapper->busy = true;
447 : }
448 :
449 28 : if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
450 0 : tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
451 0 : return;
452 : }
453 :
454 28 : wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
455 : .ev_ptr = ev,
456 : .wrapper = wrapper,
457 : };
458 28 : wrapper_stack_idx++;
459 : }
460 :
461 : _PRIVATE_
462 28 : void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
463 : struct tevent_wrapper_glue *wrapper)
464 : {
465 28 : struct tevent_context *main_ev = NULL;
466 :
467 : /*
468 : * Note that __ev_ptr might a a stale pointer and should not
469 : * be touched, we just compare the pointer value in order
470 : * to enforce the stack order.
471 : */
472 :
473 28 : if (wrapper != NULL) {
474 24 : main_ev = wrapper->main_ev;
475 : }
476 :
477 28 : if (unlikely(wrapper_stack_idx == 0)) {
478 0 : tevent_abort(main_ev, "tevent_wrapper stack already empty");
479 0 : return;
480 : }
481 28 : wrapper_stack_idx--;
482 :
483 28 : if (wrapper != NULL) {
484 24 : wrapper->busy = false;
485 : }
486 :
487 28 : if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
488 0 : tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
489 0 : return;
490 : }
491 28 : if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
492 0 : tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
493 0 : return;
494 : }
495 :
496 28 : if (wrapper == NULL) {
497 0 : return;
498 : }
499 :
500 24 : if (wrapper->destroyed) {
501 : /*
502 : * Notice that we can't use TALLOC_FREE()
503 : * here because wrapper is a talloc child
504 : * of wrapper->wrap_ev.
505 : */
506 4 : talloc_free(wrapper->wrap_ev);
507 : }
508 : }
509 :
510 8 : bool _tevent_context_push_use(struct tevent_context *ev,
511 : const char *location)
512 : {
513 : bool ok;
514 :
515 8 : if (ev->wrapper.glue == NULL) {
516 4 : tevent_wrapper_push_use_internal(ev, NULL);
517 4 : return true;
518 : }
519 :
520 4 : if (ev->wrapper.glue->main_ev == NULL) {
521 0 : return false;
522 : }
523 :
524 4 : tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
525 4 : ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
526 0 : ev->wrapper.glue->private_state,
527 0 : ev->wrapper.glue->main_ev,
528 : location);
529 4 : if (!ok) {
530 0 : tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
531 0 : return false;
532 : }
533 :
534 0 : return true;
535 : }
536 :
537 8 : void _tevent_context_pop_use(struct tevent_context *ev,
538 : const char *location)
539 : {
540 8 : tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
541 :
542 8 : if (ev->wrapper.glue == NULL) {
543 0 : return;
544 : }
545 :
546 4 : if (ev->wrapper.glue->main_ev == NULL) {
547 0 : return;
548 : }
549 :
550 4 : ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
551 0 : ev->wrapper.glue->private_state,
552 0 : ev->wrapper.glue->main_ev,
553 : location);
554 : }
555 :
556 0 : bool tevent_context_same_loop(struct tevent_context *ev1,
557 : struct tevent_context *ev2)
558 : {
559 0 : struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
560 0 : struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
561 :
562 0 : if (main_ev1 == NULL) {
563 0 : return false;
564 : }
565 :
566 0 : if (main_ev1 == main_ev2) {
567 0 : return true;
568 : }
569 :
570 0 : return false;
571 : }
|