LCOV - code coverage report
Current view: top level - lib/tevent - tevent_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 133 238 55.9 %
Date: 2024-04-21 15:09:00 Functions: 11 16 68.8 %

          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             : }

Generated by: LCOV version 1.14