Ejemplo n.º 1
0
/** Send a signal (usually stop) to a request
 *
 * This is typically called via an "async" action, i.e. an action
 * outside of the normal processing of the request.
 *
 * If there is no #fr_unlang_module_signal_t callback defined, the action is ignored.
 *
 * @param[in] request		The current request.
 * @param[in] rctx		createed by #unlang_module.
 * @param[in] action		to signal.
 */
static void unlang_module_signal(REQUEST *request, void *rctx, fr_state_signal_t action)
{
	unlang_stack_frame_t		*frame;
	unlang_stack_t			*stack = request->stack;
	unlang_resume_t			*mr;
	unlang_module_t		*mc;
	char const 			*caller;

	unlang_frame_state_module_t	*ms = NULL;

	rad_assert(stack->depth > 0);

	frame = &stack->frame[stack->depth];

	mr = unlang_generic_to_resume(frame->instruction);
	if (!mr->signal) return;

	mc = unlang_generic_to_module(mr->parent);
	ms = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);

	caller = request->module;
	request->module = mc->module_instance->name;
	((fr_unlang_module_signal_t)mr->signal)(request,
						mc->module_instance->dl_inst->data, ms->thread->data,
						rctx, action);
	request->module = caller;
}
Ejemplo n.º 2
0
/** 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;
}
Ejemplo n.º 3
0
static unlang_action_t unlang_module_resume(REQUEST *request, rlm_rcode_t *presult, UNUSED void *rctx)
{
	unlang_stack_t			*stack = request->stack;
	unlang_stack_frame_t		*frame = &stack->frame[stack->depth];
	unlang_t			*instruction = frame->instruction;
	unlang_resume_t			*mr = unlang_generic_to_resume(instruction);
	unlang_module_t			*mc = unlang_generic_to_module(mr->parent);
	int				stack_depth = stack->depth;
	char const			*caller;

	unlang_frame_state_module_t	*ms = NULL;

	rad_assert(mr->parent->type == UNLANG_TYPE_MODULE);

	ms = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);

	/*
	 *	Lock is noop unless instance->mutex is set.
	 */
	caller = request->module;
	request->module = mc->module_instance->name;
	safe_lock(mc->module_instance);
	*presult = request->rcode = ((fr_unlang_module_resume_t)mr->resume)(request,
									    mc->module_instance->dl_inst->data,
									    ms->thread->data, mr->rctx);
	safe_unlock(mc->module_instance);
	request->module = caller;

	if (*presult != RLM_MODULE_YIELD) ms->thread->active_callers--;

	RDEBUG2("%s (%s)", instruction->name ? instruction->name : "",
		fr_int2str(mod_rcode_table, *presult, "<invalid>"));

	switch (*presult) {
	case RLM_MODULE_YIELD:
		if (stack_depth < stack->depth) return UNLANG_ACTION_PUSHED_CHILD;
		rad_assert(stack_depth == stack->depth);
		return UNLANG_ACTION_YIELD;

	default:
		return UNLANG_ACTION_CALCULATE_RESULT;
	}
}
Ejemplo n.º 4
0
/** 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;
}
Ejemplo n.º 5
0
static unlang_action_t unlang_module(REQUEST *request,
					  rlm_rcode_t *presult, int *priority)
{
	unlang_module_t		*sp;
	unlang_stack_t			*stack = request->stack;
	unlang_stack_frame_t		*frame = &stack->frame[stack->depth];
	unlang_t			*instruction = frame->instruction;
	unlang_frame_state_module_t	*ms;
	int				stack_depth = stack->depth;
	char const 			*caller;

#ifndef NDEBUG
	int unlang_indent		= request->log.unlang_indent;
#endif

	/*
	 *	Process a stand-alone child, and fall through
	 *	to dealing with it's parent.
	 */
	sp = unlang_generic_to_module(instruction);
	rad_assert(sp);

	RDEBUG4("[%i] %s - %s (%s)", stack->depth, __FUNCTION__,
		sp->module_instance->name, sp->module_instance->module->name);

	/*
	 *	Return administratively configured return code
	 */
	if (sp->module_instance->force) {
		*presult = request->rcode = sp->module_instance->code;
		goto done;
	}

	frame->state = ms = talloc_zero(stack, unlang_frame_state_module_t);

	/*
	 *	Grab the thread/module specific data if any exists.
	 */
	ms->thread = module_thread_instance_find(sp->module_instance);
	rad_assert(ms->thread != NULL);

	/*
	 *	For logging unresponsive children.
	 */
	ms->thread->total_calls++;

	caller = request->module;
	request->module = sp->module_instance->name;
	safe_lock(sp->module_instance);	/* Noop unless instance->mutex set */
	*presult = sp->method(sp->module_instance->dl_inst->data, ms->thread->data, request);
	safe_unlock(sp->module_instance);
	request->module = caller;

	/*
	 *	Is now marked as "stop" when it wasn't before, we must have been blocked.
	 */
	if (request->master_state == REQUEST_STOP_PROCESSING) {
		RWARN("Module %s became unblocked", sp->module_instance->module->name);
		return UNLANG_ACTION_STOP_PROCESSING;
	}

	if (*presult == RLM_MODULE_YIELD) {
		ms->thread->active_callers++;
		goto done;
	}

	/*
	 *	Module execution finished, ident should be the same.
	 */
	rad_assert(unlang_indent == request->log.unlang_indent);

	rad_assert(*presult >= RLM_MODULE_REJECT);
	rad_assert(*presult < RLM_MODULE_NUMCODES);
	*priority = instruction->actions[*presult];

	request->rcode = *presult;

done:
	/*
	 *	Must be left at RDEBUG() level otherwise RDEBUG becomes pointless
	 */
	RDEBUG("%s (%s)", instruction->name ? instruction->name : "",
	       fr_int2str(mod_rcode_table, *presult, "<invalid>"));

	switch (*presult) {
	case RLM_MODULE_YIELD:
		if (stack_depth < stack->depth) return UNLANG_ACTION_PUSHED_CHILD;
		rad_assert(stack_depth == stack->depth);
		return UNLANG_ACTION_YIELD;

	default:
		return UNLANG_ACTION_CALCULATE_RESULT;
	}
}