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
tevent_wrapper_glue_context_init(struct tevent_context * ev)33 static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
34 {
35 tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
36 errno = ENOSYS;
37 return -1;
38 }
39
tevent_wrapper_glue_add_fd(struct tevent_context * ev,TALLOC_CTX * mem_ctx,int fd,uint16_t flags,tevent_fd_handler_t handler,void * private_data,const char * handler_name,const char * location)40 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 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
49 struct tevent_fd *fde = NULL;
50
51 if (glue->destroyed) {
52 tevent_abort(ev, "add_fd wrapper use after free");
53 return NULL;
54 }
55
56 if (glue->main_ev == NULL) {
57 errno = EINVAL;
58 return NULL;
59 }
60
61 fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
62 handler, private_data,
63 handler_name, location);
64 if (fde == NULL) {
65 return NULL;
66 }
67
68 fde->wrapper = glue;
69
70 return fde;
71 }
72
tevent_wrapper_glue_add_timer(struct tevent_context * ev,TALLOC_CTX * mem_ctx,struct timeval next_event,tevent_timer_handler_t handler,void * private_data,const char * handler_name,const char * location)73 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 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
82 struct tevent_timer *te = NULL;
83
84 if (glue->destroyed) {
85 tevent_abort(ev, "add_timer wrapper use after free");
86 return NULL;
87 }
88
89 if (glue->main_ev == NULL) {
90 errno = EINVAL;
91 return NULL;
92 }
93
94 te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
95 handler, private_data,
96 handler_name, location);
97 if (te == NULL) {
98 return NULL;
99 }
100
101 te->wrapper = glue;
102
103 return te;
104 }
105
tevent_wrapper_glue_schedule_immediate(struct tevent_immediate * im,struct tevent_context * ev,tevent_immediate_handler_t handler,void * private_data,const char * handler_name,const char * location)106 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 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
114
115 if (glue->destroyed) {
116 tevent_abort(ev, "scheduke_immediate wrapper use after free");
117 return;
118 }
119
120 if (glue->main_ev == NULL) {
121 tevent_abort(ev, location);
122 errno = EINVAL;
123 return;
124 }
125
126 _tevent_schedule_immediate(im, glue->main_ev,
127 handler, private_data,
128 handler_name, location);
129
130 im->wrapper = glue;
131
132 return;
133 }
134
tevent_wrapper_glue_add_signal(struct tevent_context * ev,TALLOC_CTX * mem_ctx,int signum,int sa_flags,tevent_signal_handler_t handler,void * private_data,const char * handler_name,const char * location)135 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 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
144 struct tevent_signal *se = NULL;
145
146 if (glue->destroyed) {
147 tevent_abort(ev, "add_signal wrapper use after free");
148 return NULL;
149 }
150
151 if (glue->main_ev == NULL) {
152 errno = EINVAL;
153 return NULL;
154 }
155
156 se = _tevent_add_signal(glue->main_ev, mem_ctx,
157 signum, sa_flags,
158 handler, private_data,
159 handler_name, location);
160 if (se == NULL) {
161 return NULL;
162 }
163
164 se->wrapper = glue;
165
166 return se;
167 }
168
tevent_wrapper_glue_loop_once(struct tevent_context * ev,const char * location)169 static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
170 {
171 tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
172 errno = ENOSYS;
173 return -1;
174 }
175
tevent_wrapper_glue_loop_wait(struct tevent_context * ev,const char * location)176 static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
177 {
178 tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
179 errno = ENOSYS;
180 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
tevent_wrapper_context_destructor(struct tevent_context * wrap_ev)196 static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
197 {
198 struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
199 struct tevent_context *main_ev = NULL;
200 struct tevent_fd *fd = NULL, *fn = NULL;
201 struct tevent_timer *te = NULL, *tn = NULL;
202 struct tevent_immediate *ie = NULL, *in = NULL;
203 struct tevent_signal *se = NULL, *sn = NULL;
204 #ifdef HAVE_PTHREAD
205 struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
206 #endif
207
208 if (glue == NULL) {
209 tevent_abort(wrap_ev,
210 "tevent_wrapper_context_destructor() active on main");
211 }
212
213 if (glue->destroyed && glue->busy) {
214 tevent_common_check_double_free(wrap_ev,
215 "tevent_context wrapper double free");
216 }
217 glue->destroyed = true;
218
219 if (glue->busy) {
220 return -1;
221 }
222
223 main_ev = glue->main_ev;
224 if (main_ev == NULL) {
225 return 0;
226 }
227
228 tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
229 "Destroying wrapper context %p \"%s\"\n",
230 wrap_ev, talloc_get_name(glue->private_state));
231
232 glue->main_ev = NULL;
233 DLIST_REMOVE(main_ev->wrapper.list, glue);
234
235 #ifdef HAVE_PTHREAD
236 for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
237 int ret;
238
239 tctxn = tctx->next;
240
241 if (tctx->event_ctx != glue->wrap_ev) {
242 continue;
243 }
244
245 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
246 if (ret != 0) {
247 abort();
248 }
249
250 /*
251 * Indicate to the thread that the tevent_context is
252 * gone. The counterpart of this is in
253 * _tevent_threaded_schedule_immediate, there we read
254 * this under the threaded_context's mutex.
255 */
256
257 tctx->event_ctx = NULL;
258
259 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
260 if (ret != 0) {
261 abort();
262 }
263
264 DLIST_REMOVE(main_ev->threaded_contexts, tctx);
265 }
266 #endif
267
268 for (fd = main_ev->fd_events; fd; fd = fn) {
269 fn = fd->next;
270
271 if (fd->wrapper != glue) {
272 continue;
273 }
274
275 tevent_fd_set_flags(fd, 0);
276
277 fd->wrapper = NULL;
278 fd->event_ctx = NULL;
279 DLIST_REMOVE(main_ev->fd_events, fd);
280 }
281
282 for (te = main_ev->timer_events; te; te = tn) {
283 tn = te->next;
284
285 if (te->wrapper != glue) {
286 continue;
287 }
288
289 te->wrapper = NULL;
290 te->event_ctx = NULL;
291
292 if (main_ev->last_zero_timer == te) {
293 main_ev->last_zero_timer = DLIST_PREV(te);
294 }
295 DLIST_REMOVE(main_ev->timer_events, te);
296 }
297
298 for (ie = main_ev->immediate_events; ie; ie = in) {
299 in = ie->next;
300
301 if (ie->wrapper != glue) {
302 continue;
303 }
304
305 ie->wrapper = NULL;
306 ie->event_ctx = NULL;
307 ie->cancel_fn = NULL;
308 DLIST_REMOVE(main_ev->immediate_events, ie);
309 }
310
311 for (se = main_ev->signal_events; se; se = sn) {
312 sn = se->next;
313
314 if (se->wrapper != glue) {
315 continue;
316 }
317
318 se->wrapper = NULL;
319 tevent_cleanup_pending_signal_handlers(se);
320 }
321
322 return 0;
323 }
324
_tevent_context_wrapper_create(struct tevent_context * main_ev,TALLOC_CTX * mem_ctx,const struct tevent_wrapper_ops * ops,void * pstate,size_t psize,const char * type,const char * location)325 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 void **ppstate = (void **)pstate;
334 struct tevent_context *ev = NULL;
335
336 if (main_ev->wrapper.glue != NULL) {
337 /*
338 * stacking of wrappers is not supported
339 */
340 tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
341 "%s: %s() stacking not allowed\n",
342 __func__, location);
343 errno = EINVAL;
344 return NULL;
345 }
346
347 if (main_ev->nesting.allowed) {
348 /*
349 * wrappers conflict with nesting
350 */
351 tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
352 "%s: %s() conflicts with nesting\n",
353 __func__, location);
354 errno = EINVAL;
355 return NULL;
356 }
357
358 ev = talloc_zero(mem_ctx, struct tevent_context);
359 if (ev == NULL) {
360 return NULL;
361 }
362 ev->ops = &tevent_wrapper_glue_ops;
363
364 ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
365 if (ev->wrapper.glue == NULL) {
366 talloc_free(ev);
367 return NULL;
368 }
369
370 talloc_set_destructor(ev, tevent_wrapper_context_destructor);
371
372 ev->wrapper.glue->wrap_ev = ev;
373 ev->wrapper.glue->main_ev = main_ev;
374 ev->wrapper.glue->ops = ops;
375 ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
376 if (ev->wrapper.glue->private_state == NULL) {
377 talloc_free(ev);
378 return NULL;
379 }
380 talloc_set_name_const(ev->wrapper.glue->private_state, type);
381
382 DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
383
384 *ppstate = ev->wrapper.glue->private_state;
385 return ev;
386 }
387
tevent_context_is_wrapper(struct tevent_context * ev)388 bool tevent_context_is_wrapper(struct tevent_context *ev)
389 {
390 if (ev->wrapper.glue != NULL) {
391 return true;
392 }
393
394 return false;
395 }
396
397 _PRIVATE_
tevent_wrapper_main_ev(struct tevent_context * ev)398 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
399 {
400 if (ev == NULL) {
401 return NULL;
402 }
403
404 if (ev->wrapper.glue == NULL) {
405 return ev;
406 }
407
408 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_
tevent_wrapper_push_use_internal(struct tevent_context * ev,struct tevent_wrapper_glue * wrapper)426 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 if (unlikely(ev->wrapper.glue != wrapper)) {
435 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
436 return;
437 }
438
439 if (wrapper != NULL) {
440 if (unlikely(wrapper->busy)) {
441 tevent_abort(ev, "wrapper already busy!");
442 return;
443 }
444 wrapper->busy = true;
445 }
446
447 if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
448 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
449 return;
450 }
451
452 wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
453 .ev_ptr = ev,
454 .wrapper = wrapper,
455 };
456 wrapper_stack_idx++;
457 }
458
459 _PRIVATE_
tevent_wrapper_pop_use_internal(const struct tevent_context * __ev_ptr,struct tevent_wrapper_glue * wrapper)460 void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
461 struct tevent_wrapper_glue *wrapper)
462 {
463 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 if (wrapper != NULL) {
472 main_ev = wrapper->main_ev;
473 }
474
475 if (unlikely(wrapper_stack_idx == 0)) {
476 tevent_abort(main_ev, "tevent_wrapper stack already empty");
477 return;
478 }
479 wrapper_stack_idx--;
480
481 if (wrapper != NULL) {
482 wrapper->busy = false;
483 }
484
485 if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
486 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
487 return;
488 }
489 if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
490 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
491 return;
492 }
493
494 if (wrapper == NULL) {
495 return;
496 }
497
498 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 talloc_free(wrapper->wrap_ev);
505 }
506 }
507
_tevent_context_push_use(struct tevent_context * ev,const char * location)508 bool _tevent_context_push_use(struct tevent_context *ev,
509 const char *location)
510 {
511 bool ok;
512
513 if (ev->wrapper.glue == NULL) {
514 tevent_wrapper_push_use_internal(ev, NULL);
515 return true;
516 }
517
518 if (ev->wrapper.glue->main_ev == NULL) {
519 return false;
520 }
521
522 tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
523 ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
524 ev->wrapper.glue->private_state,
525 ev->wrapper.glue->main_ev,
526 location);
527 if (!ok) {
528 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
529 return false;
530 }
531
532 return true;
533 }
534
_tevent_context_pop_use(struct tevent_context * ev,const char * location)535 void _tevent_context_pop_use(struct tevent_context *ev,
536 const char *location)
537 {
538 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
539
540 if (ev->wrapper.glue == NULL) {
541 return;
542 }
543
544 if (ev->wrapper.glue->main_ev == NULL) {
545 return;
546 }
547
548 ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
549 ev->wrapper.glue->private_state,
550 ev->wrapper.glue->main_ev,
551 location);
552 }
553
tevent_context_same_loop(struct tevent_context * ev1,struct tevent_context * ev2)554 bool tevent_context_same_loop(struct tevent_context *ev1,
555 struct tevent_context *ev2)
556 {
557 struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
558 struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
559
560 if (main_ev1 == NULL) {
561 return false;
562 }
563
564 if (main_ev1 == main_ev2) {
565 return true;
566 }
567
568 return false;
569 }
570