/** Set a callback for the request. * * Used when a module needs to read from an FD. Typically the callback is set, and then the * module returns unlang_module_yield(). * * @note The callback is automatically removed on unlang_interpret_resumable(). * * @param[in] request The current request. * @param[in] read callback. Used for receiving and demuxing/decoding data. * @param[in] write callback. Used for writing and encoding data. * Where a 3rd party library is used, this should be the function * issuing queries, and writing data to the socket. This should * not be done in the module itself. * This allows write operations to be retried in some instances, * and means if the write buffer is full, the request is kept in * a suspended state. * @param[in] error callback. If the fd enters an error state. Should cleanup any * handles wrapping the file descriptor, and any outstanding requests. * @param[in] ctx for the callback. * @param[in] fd to watch. * @return * - 0 on success. * - <0 on error. */ int unlang_module_fd_add(REQUEST *request, fr_unlang_module_fd_event_t read, fr_unlang_module_fd_event_t write, fr_unlang_module_fd_event_t error, void const *ctx, int fd) { unlang_stack_t *stack = request->stack; unlang_stack_frame_t *frame = &stack->frame[stack->depth]; unlang_module_event_t *ev; unlang_module_t *sp; unlang_frame_state_module_t *ms = talloc_get_type_abort(frame->state, unlang_frame_state_module_t); rad_assert(stack->depth > 0); rad_assert((frame->instruction->type == UNLANG_TYPE_MODULE) || (frame->instruction->type == UNLANG_TYPE_RESUME)); sp = unlang_generic_to_module(frame->instruction); ev = talloc_zero(request, unlang_module_event_t); if (!ev) return -1; ev->request = request; ev->fd = fd; ev->fd_read = read; ev->fd_write = write; ev->fd_error = error; ev->inst = sp->module_instance->dl_inst->data; ev->thread = ms->thread; ev->ctx = ctx; /* * Register for events on the file descriptor */ if (fr_event_fd_insert(request, request->el, fd, ev->fd_read ? unlang_event_fd_read_handler : NULL, ev->fd_write ? unlang_event_fd_write_handler : NULL, ev->fd_error ? unlang_event_fd_error_handler: NULL, ev) < 0) { talloc_free(ev); return -1; } (void) request_data_talloc_add(request, ctx, fd, unlang_module_event_t, ev, true, false, false); talloc_set_destructor(ev, _unlang_event_free); return 0; }
/** Adds subcapture values to request data * * Allows use of %{n} expansions. * * @note If preg was runtime-compiled, it will be consumed and *preg will be set to NULL. * @note regmatch will be consumed and *regmatch will be set to NULL. * @note Their lifetimes will be bound to the match request data. * * @param[in] request Current request. * @param[in,out] preg Compiled pattern. May be set to NULL if * reparented to the regcapture struct. * @param[in,out] regmatch Pointers into value. May be set to NULL if * reparented to the regcapture struct. */ void regex_sub_to_request(REQUEST *request, regex_t **preg, fr_regmatch_t **regmatch) { fr_regcapture_t *old_rc, *new_rc; /* lldb doesn't like bare new *sigh* */ /* * Clear out old_rc matches */ old_rc = request_data_get(request, request, REQUEST_DATA_REGEX); if (old_rc) { DEBUG4("Clearing %zu matches", old_rc->regmatch->used); talloc_free(old_rc); } else { DEBUG4("No matches"); } if (!regmatch || ((*regmatch)->used == 0)) return; rad_assert(preg && *preg); rad_assert(regmatch); DEBUG4("Adding %zu matches", (*regmatch)->used); /* * Container struct for all the match data */ MEM(new_rc = talloc(request, fr_regcapture_t)); /* * Steal runtime pregs, leave precompiled ones */ #if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2) if (!(*preg)->precompiled) { new_rc->preg = talloc_steal(new_rc, *preg); *preg = NULL; } else { new_rc->preg = *preg; /* Compiled on startup, will hopefully stick around */ } #endif /* * Steal match data */ new_rc->regmatch = talloc_steal(new_rc, *regmatch); *regmatch = NULL; request_data_talloc_add(request, request, REQUEST_DATA_REGEX, fr_regcapture_t, new_rc, true, false, false); }
/** Set a timeout for the request. * * Used when a module needs wait for an event. Typically the callback is set, and then the * module returns unlang_module_yield(). * * @note The callback is automatically removed on unlang_interpret_resumable(). * * param[in] request the current request. * param[in] callback to call. * param[in] ctx for the callback. * param[in] timeout when to call the timeout (i.e. now + timeout). * @return * - 0 on success. * - <0 on error. */ int unlang_module_timeout_add(REQUEST *request, fr_unlang_module_timeout_t callback, void const *ctx, struct timeval *when) { unlang_stack_t *stack = request->stack; unlang_stack_frame_t *frame = &stack->frame[stack->depth]; unlang_module_event_t *ev; unlang_module_t *sp; unlang_frame_state_module_t *ms = talloc_get_type_abort(frame->state, unlang_frame_state_module_t); rad_assert(stack->depth > 0); rad_assert((frame->instruction->type == UNLANG_TYPE_MODULE) || (frame->instruction->type == UNLANG_TYPE_RESUME)); sp = unlang_generic_to_module(frame->instruction); ev = talloc_zero(request, unlang_module_event_t); if (!ev) return -1; ev->request = request; ev->fd = -1; ev->timeout = callback; ev->inst = sp->module_instance->dl_inst->data; ev->thread = ms->thread; ev->ctx = ctx; if (fr_event_timer_insert(request, request->el, &ev->ev, when, unlang_module_event_timeout_handler, ev) < 0) { RPEDEBUG("Failed inserting event"); talloc_free(ev); return -1; } (void) request_data_talloc_add(request, ctx, UNLANG_TYPE_MODULE, unlang_module_event_t, ev, true, false, false); talloc_set_destructor(ev, _unlang_event_free); return 0; }