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 0 : 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 0 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
49 0 : struct tevent_fd *fde = NULL;
50 :
51 0 : if (glue->destroyed) {
52 0 : tevent_abort(ev, "add_fd wrapper use after free");
53 0 : return NULL;
54 : }
55 :
56 0 : if (glue->main_ev == NULL) {
57 0 : errno = EINVAL;
58 0 : return NULL;
59 : }
60 :
61 0 : fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
62 : handler, private_data,
63 : handler_name, location);
64 0 : if (fde == NULL) {
65 0 : return NULL;
66 : }
67 :
68 0 : fde->wrapper = glue;
69 :
70 0 : return fde;
71 : }
72 :
73 0 : 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 0 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
82 0 : struct tevent_timer *te = NULL;
83 :
84 0 : if (glue->destroyed) {
85 0 : tevent_abort(ev, "add_timer wrapper use after free");
86 0 : return NULL;
87 : }
88 :
89 0 : if (glue->main_ev == NULL) {
90 0 : errno = EINVAL;
91 0 : return NULL;
92 : }
93 :
94 0 : te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
95 : handler, private_data,
96 : handler_name, location);
97 0 : if (te == NULL) {
98 0 : return NULL;
99 : }
100 :
101 0 : te->wrapper = glue;
102 :
103 0 : return te;
104 : }
105 :
106 0 : 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 0 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
114 :
115 0 : if (glue->destroyed) {
116 0 : tevent_abort(ev, "scheduke_immediate wrapper use after free");
117 0 : return;
118 : }
119 :
120 0 : if (glue->main_ev == NULL) {
121 0 : tevent_abort(ev, location);
122 0 : errno = EINVAL;
123 0 : return;
124 : }
125 :
126 0 : _tevent_schedule_immediate(im, glue->main_ev,
127 : handler, private_data,
128 : handler_name, location);
129 :
130 0 : im->wrapper = glue;
131 :
132 0 : return;
133 : }
134 :
135 0 : 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 0 : struct tevent_wrapper_glue *glue = ev->wrapper.glue;
144 0 : struct tevent_signal *se = NULL;
145 :
146 0 : if (glue->destroyed) {
147 0 : tevent_abort(ev, "add_signal wrapper use after free");
148 0 : return NULL;
149 : }
150 :
151 0 : if (glue->main_ev == NULL) {
152 0 : errno = EINVAL;
153 0 : return NULL;
154 : }
155 :
156 0 : se = _tevent_add_signal(glue->main_ev, mem_ctx,
157 : signum, sa_flags,
158 : handler, private_data,
159 : handler_name, location);
160 0 : if (se == NULL) {
161 0 : return NULL;
162 : }
163 :
164 0 : se->wrapper = glue;
165 :
166 0 : 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 0 : static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
197 : {
198 0 : struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
199 0 : struct tevent_context *main_ev = NULL;
200 0 : struct tevent_fd *fd = NULL, *fn = NULL;
201 0 : struct tevent_timer *te = NULL, *tn = NULL;
202 0 : struct tevent_immediate *ie = NULL, *in = NULL;
203 0 : struct tevent_signal *se = NULL, *sn = NULL;
204 : #ifdef HAVE_PTHREAD
205 0 : struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
206 : #endif
207 :
208 0 : 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 0 : if (glue->destroyed && glue->busy) {
216 0 : tevent_common_check_double_free(wrap_ev,
217 : "tevent_context wrapper double free");
218 : }
219 0 : glue->destroyed = true;
220 :
221 0 : if (glue->busy) {
222 0 : return -1;
223 : }
224 :
225 0 : main_ev = glue->main_ev;
226 0 : if (main_ev == NULL) {
227 0 : return 0;
228 : }
229 :
230 0 : tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
231 : "Destroying wrapper context %p \"%s\"\n",
232 0 : wrap_ev, talloc_get_name(glue->private_state));
233 :
234 0 : glue->main_ev = NULL;
235 0 : DLIST_REMOVE(main_ev->wrapper.list, glue);
236 :
237 : #ifdef HAVE_PTHREAD
238 0 : 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 0 : for (fd = main_ev->fd_events; fd; fd = fn) {
271 0 : fn = fd->next;
272 :
273 0 : if (fd->wrapper != glue) {
274 0 : continue;
275 : }
276 :
277 0 : tevent_fd_set_flags(fd, 0);
278 :
279 0 : fd->wrapper = NULL;
280 0 : fd->event_ctx = NULL;
281 0 : DLIST_REMOVE(main_ev->fd_events, fd);
282 : }
283 :
284 0 : for (te = main_ev->timer_events; te; te = tn) {
285 0 : tn = te->next;
286 :
287 0 : if (te->wrapper != glue) {
288 0 : continue;
289 : }
290 :
291 0 : te->wrapper = NULL;
292 0 : te->event_ctx = NULL;
293 :
294 0 : if (main_ev->last_zero_timer == te) {
295 0 : main_ev->last_zero_timer = DLIST_PREV(te);
296 : }
297 0 : DLIST_REMOVE(main_ev->timer_events, te);
298 : }
299 :
300 0 : for (ie = main_ev->immediate_events; ie; ie = in) {
301 0 : in = ie->next;
302 :
303 0 : if (ie->wrapper != glue) {
304 0 : continue;
305 : }
306 :
307 0 : ie->wrapper = NULL;
308 0 : ie->event_ctx = NULL;
309 0 : ie->cancel_fn = NULL;
310 0 : DLIST_REMOVE(main_ev->immediate_events, ie);
311 : }
312 :
313 0 : 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 0 : 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 0 : void **ppstate = (void **)pstate;
336 0 : struct tevent_context *ev = NULL;
337 :
338 0 : 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 0 : 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 0 : ev = talloc_zero(mem_ctx, struct tevent_context);
361 0 : if (ev == NULL) {
362 0 : return NULL;
363 : }
364 0 : ev->ops = &tevent_wrapper_glue_ops;
365 :
366 0 : ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
367 0 : if (ev->wrapper.glue == NULL) {
368 0 : talloc_free(ev);
369 0 : return NULL;
370 : }
371 :
372 0 : talloc_set_destructor(ev, tevent_wrapper_context_destructor);
373 :
374 0 : ev->wrapper.glue->wrap_ev = ev;
375 0 : ev->wrapper.glue->main_ev = main_ev;
376 0 : ev->wrapper.glue->ops = ops;
377 0 : ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
378 0 : if (ev->wrapper.glue->private_state == NULL) {
379 0 : talloc_free(ev);
380 0 : return NULL;
381 : }
382 0 : talloc_set_name_const(ev->wrapper.glue->private_state, type);
383 :
384 0 : DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
385 :
386 0 : *ppstate = ev->wrapper.glue->private_state;
387 0 : 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 2492 : struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
401 : {
402 2492 : if (ev == NULL) {
403 52 : return NULL;
404 : }
405 :
406 2440 : if (ev->wrapper.glue == NULL) {
407 2440 : return ev;
408 : }
409 :
410 0 : 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 0 : 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 0 : if (unlikely(ev->wrapper.glue != wrapper)) {
437 0 : tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
438 0 : return;
439 : }
440 :
441 0 : if (wrapper != NULL) {
442 0 : if (unlikely(wrapper->busy)) {
443 0 : tevent_abort(ev, "wrapper already busy!");
444 0 : return;
445 : }
446 0 : wrapper->busy = true;
447 : }
448 :
449 0 : 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 0 : wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
455 : .ev_ptr = ev,
456 : .wrapper = wrapper,
457 : };
458 0 : wrapper_stack_idx++;
459 : }
460 :
461 : _PRIVATE_
462 0 : void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
463 : struct tevent_wrapper_glue *wrapper)
464 : {
465 0 : 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 0 : if (wrapper != NULL) {
474 0 : main_ev = wrapper->main_ev;
475 : }
476 :
477 0 : if (unlikely(wrapper_stack_idx == 0)) {
478 0 : tevent_abort(main_ev, "tevent_wrapper stack already empty");
479 0 : return;
480 : }
481 0 : wrapper_stack_idx--;
482 :
483 0 : if (wrapper != NULL) {
484 0 : wrapper->busy = false;
485 : }
486 :
487 0 : 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 0 : 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 0 : if (wrapper == NULL) {
497 0 : return;
498 : }
499 :
500 0 : 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 0 : talloc_free(wrapper->wrap_ev);
507 : }
508 : }
509 :
510 0 : bool _tevent_context_push_use(struct tevent_context *ev,
511 : const char *location)
512 : {
513 : bool ok;
514 :
515 0 : if (ev->wrapper.glue == NULL) {
516 0 : tevent_wrapper_push_use_internal(ev, NULL);
517 0 : return true;
518 : }
519 :
520 0 : if (ev->wrapper.glue->main_ev == NULL) {
521 0 : return false;
522 : }
523 :
524 0 : tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
525 0 : 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 0 : 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 0 : void _tevent_context_pop_use(struct tevent_context *ev,
538 : const char *location)
539 : {
540 0 : tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
541 :
542 0 : if (ev->wrapper.glue == NULL) {
543 0 : return;
544 : }
545 :
546 0 : if (ev->wrapper.glue->main_ev == NULL) {
547 0 : return;
548 : }
549 :
550 0 : 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 : }
|