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 : 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 8 : for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
239 0 : 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 20 : 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 : tevent_common_fd_disarm(fd);
280 : }
281 :
282 12 : for (te = main_ev->timer_events; te; te = tn) {
283 4 : tn = te->next;
284 :
285 4 : if (te->wrapper != glue) {
286 0 : continue;
287 : }
288 :
289 4 : te->wrapper = NULL;
290 4 : te->event_ctx = NULL;
291 :
292 4 : if (main_ev->last_zero_timer == te) {
293 0 : main_ev->last_zero_timer = DLIST_PREV(te);
294 : }
295 4 : DLIST_REMOVE(main_ev->timer_events, te);
296 : }
297 :
298 12 : for (ie = main_ev->immediate_events; ie; ie = in) {
299 4 : in = ie->next;
300 :
301 4 : if (ie->wrapper != glue) {
302 0 : continue;
303 : }
304 :
305 4 : ie->wrapper = NULL;
306 4 : ie->event_ctx = NULL;
307 4 : ie->cancel_fn = NULL;
308 4 : DLIST_REMOVE(main_ev->immediate_events, ie);
309 : }
310 :
311 8 : for (se = main_ev->signal_events; se; se = sn) {
312 0 : sn = se->next;
313 :
314 0 : if (se->wrapper != glue) {
315 0 : continue;
316 : }
317 :
318 0 : se->wrapper = NULL;
319 0 : tevent_cleanup_pending_signal_handlers(se);
320 : }
321 :
322 0 : return 0;
323 : }
324 :
325 8 : struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
326 : TALLOC_CTX *mem_ctx,
327 : const struct tevent_wrapper_ops *ops,
328 : void *pstate,
329 : size_t psize,
330 : const char *type,
331 : const char *location)
332 : {
333 8 : void **ppstate = (void **)pstate;
334 8 : struct tevent_context *ev = NULL;
335 :
336 8 : if (main_ev->wrapper.glue != NULL) {
337 : /*
338 : * stacking of wrappers is not supported
339 : */
340 0 : tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
341 : "%s: %s() stacking not allowed\n",
342 : __func__, location);
343 0 : errno = EINVAL;
344 0 : return NULL;
345 : }
346 :
347 8 : if (main_ev->nesting.allowed) {
348 : /*
349 : * wrappers conflict with nesting
350 : */
351 0 : tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
352 : "%s: %s() conflicts with nesting\n",
353 : __func__, location);
354 0 : errno = EINVAL;
355 0 : return NULL;
356 : }
357 :
358 8 : ev = talloc_zero(mem_ctx, struct tevent_context);
359 8 : if (ev == NULL) {
360 0 : return NULL;
361 : }
362 8 : ev->ops = &tevent_wrapper_glue_ops;
363 :
364 8 : ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
365 8 : if (ev->wrapper.glue == NULL) {
366 0 : talloc_free(ev);
367 0 : return NULL;
368 : }
369 :
370 8 : talloc_set_destructor(ev, tevent_wrapper_context_destructor);
371 :
372 8 : ev->wrapper.glue->wrap_ev = ev;
373 8 : ev->wrapper.glue->main_ev = main_ev;
374 8 : ev->wrapper.glue->ops = ops;
375 8 : ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
376 8 : if (ev->wrapper.glue->private_state == NULL) {
377 0 : talloc_free(ev);
378 0 : return NULL;
379 : }
380 8 : talloc_set_name_const(ev->wrapper.glue->private_state, type);
381 :
382 8 : DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
383 :
384 8 : *ppstate = ev->wrapper.glue->private_state;
385 8 : return ev;
386 : }
387 :
388 0 : bool tevent_context_is_wrapper(struct tevent_context *ev)
389 : {
390 0 : if (ev->wrapper.glue != NULL) {
391 0 : return true;
392 : }
393 :
394 0 : return false;
395 : }
396 :
397 : _PRIVATE_
398 243792 : struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
399 : {
400 243792 : if (ev == NULL) {
401 116 : return NULL;
402 : }
403 :
404 243669 : if (ev->wrapper.glue == NULL) {
405 175028 : return ev;
406 : }
407 :
408 0 : return ev->wrapper.glue->main_ev;
409 : }
410 :
411 : /*
412 : * 32 stack elements should be more than enough
413 : *
414 : * e.g. Samba uses just 8 elements for [un]become_{root,user}()
415 : */
416 : #define TEVENT_WRAPPER_STACK_SIZE 32
417 :
418 : static struct tevent_wrapper_stack {
419 : const void *ev_ptr;
420 : const struct tevent_wrapper_glue *wrapper;
421 : } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
422 :
423 : static size_t wrapper_stack_idx;
424 :
425 : _PRIVATE_
426 28 : void tevent_wrapper_push_use_internal(struct tevent_context *ev,
427 : struct tevent_wrapper_glue *wrapper)
428 : {
429 : /*
430 : * ev and wrapper need to belong together!
431 : * It's also fine to only have a raw ev
432 : * without a wrapper.
433 : */
434 28 : if (unlikely(ev->wrapper.glue != wrapper)) {
435 0 : tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
436 0 : return;
437 : }
438 :
439 28 : if (wrapper != NULL) {
440 24 : if (unlikely(wrapper->busy)) {
441 0 : tevent_abort(ev, "wrapper already busy!");
442 0 : return;
443 : }
444 24 : wrapper->busy = true;
445 : }
446 :
447 28 : if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
448 0 : tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
449 0 : return;
450 : }
451 :
452 28 : wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
453 : .ev_ptr = ev,
454 : .wrapper = wrapper,
455 : };
456 28 : wrapper_stack_idx++;
457 : }
458 :
459 : _PRIVATE_
460 28 : void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
461 : struct tevent_wrapper_glue *wrapper)
462 : {
463 28 : struct tevent_context *main_ev = NULL;
464 :
465 : /*
466 : * Note that __ev_ptr might a a stale pointer and should not
467 : * be touched, we just compare the pointer value in order
468 : * to enforce the stack order.
469 : */
470 :
471 28 : if (wrapper != NULL) {
472 24 : main_ev = wrapper->main_ev;
473 : }
474 :
475 28 : if (unlikely(wrapper_stack_idx == 0)) {
476 0 : tevent_abort(main_ev, "tevent_wrapper stack already empty");
477 0 : return;
478 : }
479 28 : wrapper_stack_idx--;
480 :
481 28 : if (wrapper != NULL) {
482 24 : wrapper->busy = false;
483 : }
484 :
485 28 : if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
486 0 : tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
487 0 : return;
488 : }
489 28 : if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
490 0 : tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
491 0 : return;
492 : }
493 :
494 28 : if (wrapper == NULL) {
495 0 : return;
496 : }
497 :
498 24 : if (wrapper->destroyed) {
499 : /*
500 : * Notice that we can't use TALLOC_FREE()
501 : * here because wrapper is a talloc child
502 : * of wrapper->wrap_ev.
503 : */
504 4 : talloc_free(wrapper->wrap_ev);
505 : }
506 : }
507 :
508 8 : bool _tevent_context_push_use(struct tevent_context *ev,
509 : const char *location)
510 : {
511 8 : bool ok;
512 :
513 8 : if (ev->wrapper.glue == NULL) {
514 4 : tevent_wrapper_push_use_internal(ev, NULL);
515 4 : return true;
516 : }
517 :
518 4 : if (ev->wrapper.glue->main_ev == NULL) {
519 0 : return false;
520 : }
521 :
522 4 : tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
523 4 : ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
524 0 : ev->wrapper.glue->private_state,
525 0 : ev->wrapper.glue->main_ev,
526 : location);
527 4 : if (!ok) {
528 0 : tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
529 0 : return false;
530 : }
531 :
532 0 : return true;
533 : }
534 :
535 8 : void _tevent_context_pop_use(struct tevent_context *ev,
536 : const char *location)
537 : {
538 8 : tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
539 :
540 8 : if (ev->wrapper.glue == NULL) {
541 0 : return;
542 : }
543 :
544 4 : if (ev->wrapper.glue->main_ev == NULL) {
545 0 : return;
546 : }
547 :
548 4 : ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
549 0 : ev->wrapper.glue->private_state,
550 0 : ev->wrapper.glue->main_ev,
551 : location);
552 : }
553 :
554 0 : bool tevent_context_same_loop(struct tevent_context *ev1,
555 : struct tevent_context *ev2)
556 : {
557 0 : struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
558 0 : struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
559 :
560 0 : if (main_ev1 == NULL) {
561 0 : return false;
562 : }
563 :
564 0 : if (main_ev1 == main_ev2) {
565 0 : return true;
566 : }
567 :
568 0 : return false;
569 : }
|