예제 #1
0
static int mod_detach(void *instance)
{
	rlm_unbound_t *inst = instance;

	if (inst->log_fd >= 0) {
		fr_event_fd_delete(inst->el, inst->log_fd, FR_EVENT_FILTER_IO);
		if (inst->ub) {
			ub_process(inst->ub);
			/* This can hang/leave zombies currently
			 * see upstream bug #519
			 * ...so expect valgrind to complain with -m
			 */
#if 0
			ub_ctx_delete(inst->ub);
#endif
		}
	}

	if (inst->log_pipe_stream[1]) {
		fclose(inst->log_pipe_stream[1]);
	}

	if (inst->log_pipe_stream[0]) {
		if (inst->log_pipe_in_use) {
			fr_event_fd_delete(inst->el, inst->log_pipe[0], FR_EVENT_FILTER_IO);
		}
		fclose(inst->log_pipe_stream[0]);
	}

	if (inst->log_stream) {
		fclose(inst->log_stream);
	}

	return 0;
}
static int mod_close(fr_listen_t *li)
{
	proto_detail_file_t const  *inst = talloc_get_type_abort_const(li->app_io_instance, proto_detail_file_t);
	proto_detail_file_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_detail_file_thread_t);

	if (thread->nr) (void) fr_network_socket_delete(thread->nr, inst->parent->listen);

	/*
	 *	@todo - have our OWN event loop for timers, and a
	 *	"copy timer from -> to, which means we only have to
	 *	delete our child event loop from the parent on close.
	 */
	close(thread->fd);

	if (thread->vnode_fd >= 0) {
		if (thread->nr) {
			(void) fr_network_socket_delete(thread->nr, inst->parent->listen);
		} else {
			if (fr_event_fd_delete(thread->el, thread->vnode_fd, FR_EVENT_FILTER_VNODE) < 0) {
				PERROR("Failed removing DELETE callback on detach");
			}
		}
		close(thread->vnode_fd);
		thread->vnode_fd = -1;

		pthread_mutex_destroy(&thread->worker_mutex);
	}

	return 0;
}
static void mod_vnode_delete(fr_event_list_t *el, int fd, UNUSED int fflags, void *ctx)
{
	proto_detail_file_thread_t *thread = talloc_get_type_abort(ctx, proto_detail_file_thread_t);
	proto_detail_file_t const *inst = thread->inst;

	DEBUG("proto_detail (%s): Deleted %s", thread->name, inst->filename_work);

	/*
	 *	Silently ignore notifications from the directory.  We
	 *	didn't ask for them, but libkqueue delivers them to
	 *	us.
	 */
	if (fd == thread->fd) return;

	if (fd != thread->vnode_fd) {
		ERROR("Received DELETE for FD %d, when we were expecting one on FD %d - ignoring it",
		      fd, thread->vnode_fd);
		return;
	}

	if (fr_event_fd_delete(el, fd, FR_EVENT_FILTER_VNODE) < 0) {
		PERROR("Failed removing DELETE callback after deletion");
	}
	close(fd);
	thread->vnode_fd = -1;

	/*
	 *	Re-initialize the state machine.
	 *
	 *	Note that a "delete" may be the result of an atomic
	 *	"move", which both deletes the old file, and creates
	 *	the new one.
	 */
	work_init(thread);
}
예제 #4
0
static void rs_got_packet(UNUSED fr_event_list_t *el, int fd, void *ctx)
{
	static uint64_t	count = 0;	/* Packets seen */
	rs_event_t	*event = ctx;
	pcap_t		*handle = event->in->handle;

	int i;
	int ret;
	const uint8_t *data;
	struct pcap_pkthdr *header;

	for (i = 0; (event->in->type == PCAP_FILE_IN) || (i < RS_FORCE_YIELD); i++) {
		ret = pcap_next_ex(handle, &header, &data);
		if (ret == 0) {
			/* No more packets available at this time */
			return;
		}
		if (ret == -2 && (event->in->type == PCAP_FILE_IN)) {
			INFO("Done reading packets (%s)", event->in->name);
			fr_event_fd_delete(events, 0, fd);
			return;
		}
		if (ret < 0) {
			ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
			return;
		}

		count++;
		rs_packet_process(count, event, header, data);
	}
}
예제 #5
0
/** Called by libcurl to register a socket that it's interested in receiving IO events for
 *
 *
 * @param[in] easy	handle this fd relates to.
 * @param[in] fd	File descriptor curl wants to be notified about.
 * @param[in] what	Which events libcurl wants to be notified of, may be one of:
 *			- CURL_POLL_IN		Wait for incoming data. For the socket
 *						to become readable.
 *			- CURL_POLL_OUT		Wait for outgoing data. For the socket
 *						to become writable.
 *			- CURL_POLL_INOUT	Wait for incoming and outgoing data.
 *						For the socket to become readable or writable.
 *			- CURL_POLL_REMOVE	The specified socket/file descriptor is no
 * 						longer used by libcurl.
 * @param[in] ctx	The rlm_rest_thread_t specific to this thread.
 * @param[in] fd_ctx	Private data associated with the socket.
 */
static int _rest_io_event_modify(UNUSED CURL *easy, curl_socket_t fd, int what, void *ctx, UNUSED void *fd_ctx)
{
	rlm_rest_thread_t	*thread = talloc_get_type_abort(ctx, rlm_rest_thread_t);

	switch (what) {
	case CURL_POLL_IN:
		if (fr_event_fd_insert(thread, thread->el, fd,
				       _rest_io_service_readable,
				       NULL,
				       _rest_io_service_errored,
				       thread) < 0) {
			PERROR("multi-handle %p registration failed for read+error events on FD %i",
			       thread->mandle, fd);
			return -1;
		}
		DEBUG4("multi-handle %p registered for read+error events on FD %i", thread->mandle, fd);
		break;

	case CURL_POLL_OUT:
		if (fr_event_fd_insert(thread, thread->el, fd,
				       NULL,
				       _rest_io_service_writable,
				       _rest_io_service_errored,
				       thread) < 0) {
			PERROR("multi-handle %p registration failed for write+error events on FD %i",
			       thread->mandle, fd);
			return -1;
		}
		DEBUG4("multi-handle %p registered for write+error events on FD %i", thread->mandle, fd);
		break;

	case CURL_POLL_INOUT:
		if (fr_event_fd_insert(thread, thread->el, fd,
				       _rest_io_service_readable,
				       _rest_io_service_writable,
				       _rest_io_service_errored,
				       thread) < 0) {
			PERROR("multi-handle %p registration failed for read+write+error events on FD %i",
			       thread->mandle, fd);
			return -1;
		}
		DEBUG4("multi-handle %p registered for read+write+error events on FD %i", thread->mandle, fd);
		break;

	case CURL_POLL_REMOVE:
		if (fr_event_fd_delete(thread->el, fd, FR_EVENT_FILTER_IO) < 0) {
			PERROR("multi-handle %p de-registration failed for FD %i", thread->mandle, fd);
			return -1;
		}
		DEBUG4("multi-handle %p unregistered events for FD %i", thread->mandle, fd);
		break;

	default:
		rad_assert(0);
		return -1;
	}

	return CURLM_OK;
}
예제 #6
0
/** Frees an unlang event, removing it from the request's event loop
 *
 * @param[in] ev	The event to free.
 *
 * @return 0
 */
static int _unlang_event_free(unlang_module_event_t *ev)
{
	if (ev->ev) {
		(void) fr_event_timer_delete(ev->request->el, &(ev->ev));
		return 0;
	}

	if (ev->fd >= 0) {
		(void) fr_event_fd_delete(ev->request->el, ev->fd, FR_EVENT_FILTER_IO);
	}

	return 0;
}
예제 #7
0
static int _network_socket_free(fr_network_socket_t *s)
{
	fr_network_t *nr = s->nr;
	fr_channel_data_t *cd;

	if (!s->dead) {
		if (fr_event_fd_delete(nr->el, s->fd, s->filter) < 0) {
			PERROR("Failed deleting socket from event loop in _network_socket_free");
			rad_assert("Failed removing socket FD from event loop in _network_socket_free" == NULL);
		}
	}

	rbtree_deletebydata(nr->sockets, s);
	rbtree_deletebydata(nr->sockets_by_num, s);

	if (s->listen->app_io->close) {
		s->listen->app_io->close(s->listen->app_io_instance);
	} else {
		close(s->fd);
	}

	if (s->pending) {
		fr_message_done(&s->pending->m);
		s->pending = NULL;
	}

	/*
	 *	Clean up any queued entries.
	 */
	while ((cd = fr_heap_pop(s->waiting)) != NULL) {
		fr_message_done(&cd->m);
	}

	talloc_free(s->waiting);

	return 0;
}
예제 #8
0
/*
 *	Mark it as dead, but DON'T free it until all of the replies
 *	have come in.
 */
static void fr_network_socket_dead(fr_network_t *nr, fr_network_socket_t *s)
{
	if (s->dead) return;

	s->dead = true;

	fr_event_fd_delete(nr->el, s->fd, s->filter);

	/*
	 *	If there are no outstanding packets, then we can free
	 *	it now.
	 */
	if (!s->outstanding) {
		talloc_free(s);
		return;
	}

	/*
	 *	There are still outstanding packets.  Leave it in the
	 *	socket tree, so that replies from the worker can find
	 *	it.  When we've received all of the replies, then
	 *	fr_network_post_event() will clean up this socket.
	 */
}
/*
 *	The "detail.work" file exists, and is open in the 'fd'.
 */
static int work_exists(proto_detail_file_thread_t *thread, int fd)
{
	proto_detail_file_t const *inst = thread->inst;
	bool			opened = false;
	proto_detail_work_thread_t     *work;
	fr_listen_t		*li = NULL;
	struct stat		st;

	fr_event_vnode_func_t	funcs = { .delete = mod_vnode_delete };

	DEBUG3("proto_detail (%s): Trying to lock %s", thread->name, inst->filename_work);

	/*
	 *	"detail.work" exists, try to lock it.
	 */
	if (rad_lockfd_nonblock(fd, 0) < 0) {
		struct timeval when, now;

		DEBUG3("proto_detail (%s): Failed locking %s: %s",
		       thread->name, inst->filename_work, fr_syserror(errno));

		close(fd);

		when.tv_usec = thread->lock_interval % USEC;
		when.tv_sec = thread->lock_interval / USEC;

		/*
		 *	Ensure that we don't do massive busy-polling.
		 */
		thread->lock_interval += thread->lock_interval / 2;
		if (thread->lock_interval > (30 * USEC)) thread->lock_interval = 30 * USEC;

		DEBUG3("proto_detail (%s): Waiting %d.%06ds for lock on file %s",
		       thread->name, (int) when.tv_sec, (int) when.tv_usec, inst->filename_work);

		gettimeofday(&now, NULL);
		fr_timeval_add(&when, &when, &now);

		if (fr_event_timer_insert(thread, thread->el, &thread->ev,
					  &when, work_retry_timer, thread) < 0) {
			ERROR("Failed inserting retry timer for %s", inst->filename_work);
		}
		return 0;
	}

	DEBUG3("proto_detail (%s): Obtained lock and starting to process file %s",
	       thread->name, inst->filename_work);

	/*
	 *	Ignore empty files.
	 */
	if (fstat(fd, &st) < 0) {
		ERROR("Failed opening %s: %s", inst->filename_work,
		      fr_syserror(errno));
		unlink(inst->filename_work);
		close(fd);
		return 1;
	}

	if (!st.st_size) {
		DEBUG3("proto_detail (%s): %s file is empty, ignoring it.",
		       thread->name, inst->filename_work);
		unlink(inst->filename_work);
		close(fd);
		return 1;
	}

	/*
	 *	This listener is allocated in a thread-specific
	 *	context, so it doesn't need a destructor,
	 */
	MEM(li = talloc_zero(NULL, fr_listen_t));

	/*
	 *	Create a new listener, and insert it into the
	 *	scheduler.  Shamelessly copied from proto_detail.c
	 *	mod_open(), with changes.
	 *
	 *	This listener is parented from the worker.  So that
	 *	when the worker goes away, so does the listener.
	 */
	li->app_io = inst->parent->work_io;

	li->app = inst->parent->self;
	li->app_instance = inst->parent;
	li->server_cs = inst->parent->server_cs;

	/*
	 *	The worker may be in a different thread, so avoid
	 *	talloc threading issues by using a NULL TALLOC_CTX.
	 */
	MEM(li->thread_instance = work = talloc_zero(li, proto_detail_work_thread_t));

	li->app_io_instance = inst->parent->work_io_instance;
	work->inst = li->app_io_instance;
	work->file_parent = thread;
	work->ev = NULL;

	li->fd = work->fd = dup(fd);
	if (work->fd < 0) {
		DEBUG("proto_detail (%s): Failed opening %s: %s",
		      thread->name, inst->filename_work, fr_syserror(errno));

		close(fd);
		talloc_free(li);
		return -1;
	}

	/*
	 *	Don't do anything until the file has been deleted.
	 *
	 *	@todo - ensure that proto_detail_work is done the file...
	 *	maybe by creating a new instance?
	 */
	if (fr_event_filter_insert(thread, thread->el, fd, FR_EVENT_FILTER_VNODE,
				   &funcs, NULL, thread) < 0) {
		PERROR("Failed adding work socket to event loop");
		close(fd);
		talloc_free(li);
		return -1;
	}

	/*
	 *	Remember this for later.
	 */
	thread->vnode_fd = fd;

	/*
	 *	For us, this is the worker listener.
	 *	For the worker, this is it's own parent
	 */
	thread->listen = li;

	work->filename_work = talloc_strdup(work, inst->filename_work);

	/*
	 *	Set configurable parameters for message ring buffer.
	 */
	li->default_message_size = inst->parent->max_packet_size;
	li->num_messages = inst->parent->num_messages;

	pthread_mutex_lock(&thread->worker_mutex);
	thread->num_workers++;
	pthread_mutex_unlock(&thread->worker_mutex);

	/*
	 *	Open the detail.work file.
	 */
	if (li->app_io->open(li) < 0) {
		ERROR("Failed opening %s", li->app_io->name);
		goto error;
	}
	opened = true;

	rad_assert(li->app_io->get_name);
	li->name = li->app_io->get_name(li);

	if (!fr_schedule_listen_add(inst->parent->sc, li)) {
	error:
		if (fr_event_fd_delete(thread->el, thread->vnode_fd, FR_EVENT_FILTER_VNODE) < 0) {
			PERROR("Failed removing DELETE callback when opening work file");
		}
		close(thread->vnode_fd);
		thread->vnode_fd = -1;

		if (opened) {
			(void) li->app_io->close(li);
			thread->listen = NULL;
			li = NULL;
		}

		talloc_free(li);
		return -1;
	}

	/*
	 *	Tell the worker to clean itself up.
	 */
	work->listen = li;

	return 0;
}