Example #1
0
/** Handle a network control message callback for a new "watch directory"
 *
 * @param[in] ctx the network
 * @param[in] data the message
 * @param[in] data_size size of the data
 * @param[in] now the current time
 */
static void fr_network_directory_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now)
{
	int			num_messages;
	fr_network_t		*nr = ctx;
	fr_network_socket_t	*s;
	fr_app_io_t const	*app_io;
	fr_event_vnode_func_t	funcs = { .extend = fr_network_vnode_extend };

	rad_assert(data_size == sizeof(s->listen));

	if (data_size != sizeof(s->listen)) return;

	s = talloc_zero(nr, fr_network_socket_t);
	rad_assert(s != NULL);

	s->nr = nr;
	memcpy(&s->listen, data, sizeof(s->listen));
	s->number = nr->num_sockets++;

	MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id));

	talloc_set_destructor(s, _network_socket_free);

	/*
	 *	Allocate the ring buffer for messages and packets.
	 */
	num_messages = s->listen->num_messages;
	if (num_messages < 8) num_messages = 8;

	s->ms = fr_message_set_create(s, num_messages,
				      sizeof(fr_channel_data_t),
				      s->listen->default_message_size * s->listen->num_messages);
	if (!s->ms) {
		fr_log(nr->log, L_ERR, "Failed creating message buffers for directory IO: %s", fr_strerror());
		talloc_free(s);
		return;
	}

	app_io = s->listen->app_io;

	if (app_io->event_list_set) app_io->event_list_set(s->listen->app_io_instance, nr->el, nr);

	rad_assert(app_io->fd);
	s->fd = app_io->fd(s->listen->app_io_instance);
	s->filter = FR_EVENT_FILTER_VNODE;

	if (fr_event_filter_insert(nr, nr->el, s->fd, s->filter,
				   &funcs,
				   app_io->error ? fr_network_error : NULL,
				   s) < 0) {
		PERROR("Failed adding new socket to event loop");
		talloc_free(s);
		return;
	}

	(void) rbtree_insert(nr->sockets, s);
	(void) rbtree_insert(nr->sockets_by_num, s);

	DEBUG3("Using new socket with FD %d", s->fd);
}
Example #2
0
void log_hex(fr_log_t const *log, fr_log_type_t type, fr_log_lvl_t lvl, uint8_t const *data, size_t data_len)
{
	size_t i, j, len;
	char *p;
	char buffer[(0x10 * 3) + 1];

	if (!debug_enabled(L_DBG, lvl)) return;

	for (i = 0; i < data_len; i += 0x10) {
		len = 0x10;
		if ((i + len) > data_len) len = data_len - i;

		for (p = buffer, j = 0; j < len; j++, p += 3) sprintf(p, "%02x ", data[i + j]);
		fr_log(log, type, "%04x: %s", (int)i, buffer);
	}
}
Example #3
0
/*
 *	This is wrapper for fr_log
 *	Now users can call radiusd::log(level,msg) wich is the same
 *	as calling fr_log from C code.
 */
static XS(XS_radiusd_log)
{
	dXSARGS;
	if (items !=2)
		croak("Usage: radiusd::log(level, message)");
	{
		int     level;
		char    *msg;

		level = (int) SvIV(ST(0));
		msg   = (char *) SvPV(ST(1), PL_na);

		/*
		 *	Because 'msg' is a 'char *', we don't want '%s', etc.
		 *	in it to give us printf-style vulnerabilities.
		 */
		fr_log(&default_log, level, "rlm_perl: %s", msg);
	}
	XSRETURN_NO;
}
Example #4
0
/** Handle a network control message callback for a new socket
 *
 * @param[in] ctx the network
 * @param[in] data the message
 * @param[in] data_size size of the data
 * @param[in] now the current time
 */
static void fr_network_socket_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now)
{
	fr_network_t		*nr = ctx;
	fr_network_socket_t	*s;
	fr_app_io_t const	*app_io;
	size_t			size;
	int			num_messages;

	rad_assert(data_size == sizeof(s->listen));

	if (data_size != sizeof(s->listen)) return;

	s = talloc_zero(nr, fr_network_socket_t);
	rad_assert(s != NULL);

	s->nr = nr;
	memcpy(&s->listen, data, sizeof(s->listen));
	s->number = nr->num_sockets++;

	MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id));

	talloc_set_destructor(s, _network_socket_free);

	/*
	 *	Put reasonable limits on the ring buffer size.  Then
	 *	round it up to the nearest power of 2, which is
	 *	required by the ring buffer code.
	 */
	num_messages = s->listen->num_messages;
	if (num_messages < 8) num_messages = 8;

	size = s->listen->default_message_size * num_messages;
	if (!size) size = (1 << 17);

	/*
	 *	Allocate the ring buffer for messages and packets.
	 */
	s->ms = fr_message_set_create(s, num_messages,
				      sizeof(fr_channel_data_t),
				      size);
	if (!s->ms) {
		fr_log(nr->log, L_ERR, "Failed creating message buffers for network IO: %s", fr_strerror());
		talloc_free(s);
		return;
	}

	app_io = s->listen->app_io;

	rad_assert(app_io->fd);
	s->fd = app_io->fd(s->listen->app_io_instance);
	s->filter = FR_EVENT_FILTER_IO;

	if (fr_event_fd_insert(nr, nr->el, s->fd,
			       fr_network_read,
			       NULL,
			       fr_network_error,
			       s) < 0) {
		PERROR("Failed adding new socket to network event loop");
		talloc_free(s);
		return;
	}

	if (app_io->event_list_set) app_io->event_list_set(s->listen->app_io_instance, nr->el, nr);

	(void) rbtree_insert(nr->sockets, s);
	(void) rbtree_insert(nr->sockets_by_num, s);

	DEBUG3("Using new socket with FD %d", s->fd);
}
Example #5
0
/** Read a packet from the network.
 *
 * @param[in] el	the event list.
 * @param[in] sockfd	the socket which is ready to read.
 * @param[in] flags	from kevent.
 * @param[in] ctx	the network socket context.
 */
static void fr_network_read(UNUSED fr_event_list_t *el, int sockfd, UNUSED int flags, void *ctx)
{
	int num_messages = 0;
	fr_network_socket_t *s = ctx;
	fr_network_t *nr = s->nr;
	ssize_t data_size;
	fr_channel_data_t *cd, *next;
	fr_time_t *recv_time;

	if (!fr_cond_assert(s->fd == sockfd)) return;

	DEBUG3("network read");

	if (!s->cd) {
		cd = (fr_channel_data_t *) fr_message_reserve(s->ms, s->listen->default_message_size);
		if (!cd) {
			fr_log(nr->log, L_ERR, "Failed allocating message size %zd! - Closing socket", s->listen->default_message_size);
			fr_network_socket_dead(nr, s);
			return;
		}
	} else {
		cd = s->cd;
	}

	rad_assert(cd->m.data != NULL);
	rad_assert(cd->m.rb_size >= 256);

next_message:
	/*
	 *	Poll this socket, but not too often.  We have to go
	 *	service other sockets, too.
	 */
	if (num_messages > 16) {
		s->cd = cd;
		return;
	}

	cd->request.is_dup = false;
	cd->priority = PRIORITY_NORMAL;

	/*
	 *	Read data from the network.
	 *
	 *	Return of 0 means "no data", which is fine for UDP.
	 *	For TCP, if an underlying read() on the TCP socket
	 *	returns 0, (which signals that the FD is no longer
	 *	usable) this function should return -1, so that the
	 *	network side knows that it needs to close the
	 *	connection.
	 */
	data_size = s->listen->app_io->read(s->listen->app_io_instance, &cd->packet_ctx, &recv_time,
					    cd->m.data, cd->m.rb_size, &s->leftover, &cd->priority, &cd->request.is_dup);
	if (data_size == 0) {
		/*
		 *	Cache the message for later.  This is
		 *	important for stream sockets, which can do
		 *	partial reads into the current buffer.  We
		 *	need to be able to give the same buffer back
		 *	to the stream socket for subsequent reads.
		 *
		 *	Since we have a message set for each
		 *	fr_io_socket_t, no "head of line"
		 *	blocking issues can happen for stream sockets.
		 */
		s->cd = cd;
		return;
	}

	/*
	 *	Error: close the connection, and remove the fr_listen_t
	 */
	if (data_size < 0) {
//		fr_log(nr->log, L_DBG_ERR, "error from transport read on socket %d", sockfd);
		fr_network_socket_dead(nr, s);
		return;
	}
	s->cd = NULL;

	DEBUG("Network received packet size %zd", data_size);
	nr->stats.in++;
	s->stats.in++;

	/*
	 *	Initialize the rest of the fields of the channel data.
	 *
	 *	We always use "now" as the time of the message, as the
	 *	packet MAY be a duplicate packet magically resurrected
	 *	from the past.
	 */
	cd->m.when = fr_time();
	cd->listen = s->listen;
	cd->request.recv_time = recv_time;

	/*
	 *	Nothing in the buffer yet.  Allocate room for one
	 *	packet.
	 */
	if ((cd->m.data_size == 0) && (!s->leftover)) {

		(void) fr_message_alloc(s->ms, &cd->m, data_size);
		next = NULL;

	} else {
		/*
		 *	There are leftover bytes in the buffer, feed
		 *	them to the next round of reading.
		 */
		next = (fr_channel_data_t *) fr_message_alloc_reserve(s->ms, &cd->m, data_size, s->leftover,
								      s->listen->default_message_size);
		if (!next) {
			fr_log(nr->log, L_ERR, "Failed reserving partial packet.");
			// @todo - probably close the socket...
			rad_assert(0 == 1);
		}
	}

	if (!fr_network_send_request(nr, cd)) {
		fr_log(nr->log, L_ERR, "Failed sending packet to worker");
		fr_message_done(&cd->m);
		nr->stats.dropped++;
		s->stats.dropped++;
	} else {
		/*
		 *	One more packet sent to a worker.
		 */
		s->outstanding++;
	}

	/*
	 *	If there is a next message, go read it from the buffer.
	 *
	 *	@todo - note that this calls read(), even if the
	 *	app_io has paused the reader.  We likely want to be
	 *	able to check that, too.  We might just remove this
	 *	"goto"...
	 */
	if (next) {
		cd = next;
		num_messages++;
		goto next_message;
	}
}