Rename a bunch of structures.
Use the standard module instantiation framework for fr_io_t
#endif
#include <freeradius-devel/dl.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
/*
* We'll use this below.
typedef struct rad_protocol_t {
RAD_MODULE_COMMON; //!< Common fields to all loadable modules.
- uint32_t transports; //!< What can transport this protocol.
- bool tls; //!< Whether protocol can be wrapped in TLS.
+ uint32_t transports; //!< What can transport this protocol.
+ bool tls; //!< Whether protocol can be wrapped in TLS.
- rad_listen_unlang_t bootstrap; //!< Phase1 - Basic validation checks of virtual server.
- rad_listen_unlang_t compile; //!< Phase2 - Compile unlang sections in the virtual
+ rad_listen_unlang_t bootstrap; //!< Phase1 - Basic validation checks of virtual server.
+ rad_listen_unlang_t compile; //!< Phase2 - Compile unlang sections in the virtual
//!< server that map to packet types used by the protocol.
- rad_listen_parse_t parse; //!< Perform extra processing of the configuration data
+ rad_listen_parse_t parse; //!< Perform extra processing of the configuration data
//!< specified by config.
- rad_listen_parse_t open; //!< Open a descriptor.
+ rad_listen_parse_t open; //!< Open a descriptor.
- rad_listen_recv_t recv; //!< Read an incoming packet from the descriptor.
- rad_listen_send_t send; //!< Write an outgoing packet to the descriptor.
- rad_listen_error_t error; //!< Handle error/eol on the descriptor.
+ rad_listen_recv_t recv; //!< Read an incoming packet from the descriptor.
+ rad_listen_send_t send; //!< Write an outgoing packet to the descriptor.
+ rad_listen_error_t error; //!< Handle error/eol on the descriptor.
- rad_listen_print_t print; //!< Print a line describing the packet being sent or the
+ rad_listen_print_t print; //!< Print a line describing the packet being sent or the
//!< packet that was received.
- rad_listen_debug_t debug; //!< Print an attribute list for debugging.
+ rad_listen_debug_t debug; //!< Print an attribute list for debugging.
- rad_listen_encode_t encode; //!< Encode an outgoing packet.
- rad_listen_decode_t decode; //!< Decode an incoming packet.
+ rad_listen_encode_t encode; //!< Encode an outgoing packet.
+ rad_listen_decode_t decode; //!< Decode an incoming packet.
} rad_protocol_t;
#define TRANSPORT_NONE 0
int common_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize);
void common_packet_debug(REQUEST *request, RADIUS_PACKET *packet, bool received);
-
typedef int (*fr_app_bootstrap_t)(CONF_SECTION *);
/*
- * src/lib/io/transport.h
+ * src/lib/io/io.h
*/
-typedef struct fr_transport_t fr_transport_t;
+typedef struct fr_io_op_t fr_io_op_t;
-/*
- * src/lib/io/schedule.h
+/** Validate configurable elements of an fr_ctx_t
+ *
+ * @param[in] io_cs Configuration describing the I/O mechanism.
+ * @param[in] instance data. Pre-populated by parsing io_cs.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
*/
-typedef struct fr_schedule_t fr_schedule_t;
-
-typedef int (*fr_app_parse_t)(fr_schedule_t *sc, CONF_SECTION *, bool);
+typedef int (*fr_app_io_instantiate_t)(CONF_SECTION *io_cs, void *instance);
-/*
- * Functions for new virtual servers and listeners
+/** Public structure describing an I/O path for a protocol
+ *
+ * This structure is exported by I/O modules e.g. proto_radius_udp.
*/
-typedef struct fr_app_t {
+typedef struct fr_app_io_t {
RAD_MODULE_COMMON; //!< Common fields to all loadable modules.
- fr_app_bootstrap_t bootstrap;
- fr_app_parse_t parse;
-} fr_app_t;
-
-typedef int (*fr_app_io_open_t)(TALLOC_CTX *ctx, int *, void **, fr_transport_t **, CONF_SECTION *, bool);
+ fr_app_io_instantiate_t instantiate; //!< Perform any config validation, and per-instance work.
+ fr_io_op_t op; //!< Open/close/read/write functions for sending/receiving
+ //!< protocol data.
+} fr_app_io_t;
/*
- * Functions for new virtual servers and listeners
+ * src/lib/io/schedule.h
*/
-typedef struct fr_app_io_t {
+typedef struct fr_schedule_t fr_schedule_t;
+typedef int (*fr_app_instantiate_t)(fr_schedule_t *sc, CONF_SECTION *cs, bool validate_config);
+
+/** Describes a new application (protocol)
+ *
+ */
+typedef struct fr_app_t {
RAD_MODULE_COMMON; //!< Common fields to all loadable modules.
- fr_app_io_open_t open;
-} fr_app_io_t;
+ fr_app_bootstrap_t bootstrap;
+ fr_app_instantiate_t instantiate;
+} fr_app_t;
-typedef int (*fr_app_subtype_compile_t)(CONF_SECTION *cs);
+typedef int (*fr_app_subtype_instantiate_t)(CONF_SECTION *cs);
-/*
- * Functions for new virtual servers and listeners
+/** Public structure describing an application (protocol) specialisation
+ *
+ * Some protocols perform multiple distinct functions, and use
+ * different state machines to perform those functions.
*/
typedef struct fr_app_subtype_t {
RAD_MODULE_COMMON; //!< Common fields to all loadable modules.
- fr_app_subtype_compile_t compile;
- fr_transport_process_t process;
+ fr_app_subtype_instantiate_t instantiate; //!< Perform any config validation, and per-instance work.
+ fr_io_process_t process; //!< Entry point into the protocol subtype's state machine.
} fr_app_subtype_t;
#ifdef __cplusplus
#include <freeradius-devel/io/message.h>
#include <freeradius-devel/io/control.h>
+#include <freeradius-devel/io/io.h>
#include <sys/types.h>
#include <sys/event.h>
* Forward declaration until such time as we fix the code so that
* the network threads can push transports to worker threads.
*/
-typedef struct fr_transport_t fr_transport_t;
-
-typedef struct fr_packet_io_t {
- int fd; //!< the file descriptor
- uint32_t priority; //!< 0 is higher priority than 1
-
- void *ctx; //!< for the transport
- fr_transport_t *transport; //!< the transport structure
-} fr_packet_io_t;
-
+typedef struct fr_io fr_io_t;
typedef enum fr_channel_event_t {
FR_CHANNEL_ERROR = 0,
} channel;
};
- fr_packet_io_t io; //!< for tracking packet transport, etc.
-
union {
struct {
fr_time_t *start_time; //!< time original request started (network -> worker)
} reply;
};
+ uint32_t priority; //!< Priority of this packet.
+
+ fr_io_t *io; //!< for tracking packet transport, etc.
} fr_channel_data_t;
fr_channel_t *fr_channel_create(TALLOC_CTX *ctx, fr_control_t *master, fr_control_t *worker) CC_HINT(nonnull);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#ifndef _FR_TRANSPORT_H
-#define _FR_TRANSPORT_H
+#ifndef _FR_IO_H
+#define _FR_IO_H
/**
* $Id$
*
- * @file io/transport.h
+ * @file io/io.h
* @brief Transport-specific functions.
*
* @copyright 2016 Alan DeKok <aland@freeradius.org>
/**
* Tell an async process function if it should run or exit.
*/
-typedef enum fr_transport_action_t {
- FR_TRANSPORT_ACTION_RUN,
- FR_TRANSPORT_ACTION_DONE,
-} fr_transport_action_t;
+typedef enum fr_io_action_t {
+ FR_IO_ACTION_RUN,
+ FR_IO_ACTION_DONE,
+} fr_io_action_t;
/**
* Answer from an async process function if the worker should yield,
* reply, or drop the request.
*/
-typedef enum fr_transport_final_t {
- FR_TRANSPORT_YIELD, //!< yielded, request can continue processing
- FR_TRANSPORT_REPLY, //!< please send a reply
- FR_TRANSPORT_FAIL, //!< processing failed somehow, cannot send a reply
- FR_TRANSPORT_DONE, //!< succeeded without a reply
-} fr_transport_final_t;
+typedef enum fr_io_final_t {
+ FR_IO_YIELD, //!< yielded, request can continue processing
+ FR_IO_REPLY, //!< please send a reply
+ FR_IO_FAIL, //!< processing failed somehow, cannot send a reply
+ FR_IO_DONE, //!< succeeded without a reply
+} fr_io_final_t;
-typedef struct fr_transport_t fr_transport_t;
+typedef struct fr_channel_t fr_channel_t;
+
+/** Open an I/O path
+ *
+ * Open a socket, file, or anything else that can be referenced
+ * by a file descriptor.
+ *
+ * The file descriptor should be made available to the event loop
+ * via the selectable_fd callback. It will only be used to determine if the
+ * socket is readable/writable/has errored.
+ *
+ * No data will be read from or written to the fd, except by the io_data callbacks here.
+ *
+ * @param[in] io_ctx the context for this function
+ * @return
+ * - 0 on success
+ * - <0 on error
+ */
+typedef int (*fr_io_open_t)(void *io_ctx);
+
+/** Return a selectable file descriptor for this I/O path
+ *
+ * Return the file descriptor associated with this I/O path.
+ *
+ * @param[in] io_ctx containing the file descriptor (amongst other things).
+ */
+typedef int (*fr_io_get_fd_t)(void *io_ctx);
/** Decode a raw packet and convert it into a request.
*
- * This function is the opposite of fr_transport_encode_t.
+ * This function is the opposite of fr_io_encode_t.
*
* The "decode" function is ONLY for decoding data. It should be
* aware of the protocol (e.g. RADIUS), but it MUST NOT know anything
* know anything about how the data will be used (e.g. authorize,
* authenticate, etc. for Access-Request)
*
- * @param[in] transport_ctx the context for this function.
- * @param[in] data the raw packet data
- * @param[in] data_len the length of the raw data
- * @param[in,out] request where the decoded VPs should be placed.
+ * @param[in] io_ctx the context for this function.
+ * @param[in] data the raw packet data
+ * @param[in] data_len the length of the raw data
+ * @param[in,out] request where the decoded VPs should be placed.
* @return
* - <0 on error
* - 0 on success
*/
-typedef int (*fr_transport_decode_t)(void *transport_ctx, uint8_t *const data, size_t data_len, REQUEST *request);
+typedef int (*fr_io_decode_t)(void *io_ctx, uint8_t *const data, size_t data_len, REQUEST *request);
/** Encode data from a REQUEST into a raw packet.
*
- * This function is the opposite of fr_transport_decode_t.
+ * This function is the opposite of fr_io_decode_t.
*
* The "encode" function is ONLY for encoding data. It should be
* aware of the protocol (e.g. RADIUS), but it MUST NOT know anything
* know anything about how the data will be used (e.g. reject delay
* on Access-Reject)
*
- * @param[in] transport_ctx the context for this function.
- * @param[in,out] request where the VPs to be encoded are located
- * @param[in] buffer the buffer where the raw packet will be written
- * @param[in] buffer_len the length of the buffer
+ * @param[in] io_ctx the context for this function.
+ * @param[in,out] request where the VPs to be encoded are located
+ * @param[in] buffer the buffer where the raw packet will be written
+ * @param[in] buffer_len the length of the buffer
* @return
* - <0 on error
* - >=0 length of the encoded data in the buffer, will be <=buffer_len
*/
-typedef ssize_t (*fr_transport_encode_t)(void *transport_ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len);
+typedef ssize_t (*fr_io_encode_t)(void *io_ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len);
/** NAK a packet.
*
* take the appropriate action. e.g. for RADIUS, mark a request as
* "do not respond", even if duplicates come in.
*
- * @param[in] transport_ctx the context for this function.
- * @param[in] packet the packet to NAK
- * @param[in] packet_len length of the packet to NAK
- * @param[in] reply the NAK reply
- * @param[in] reply_len length of the buffer where the reply should be placed.
+ * @param[in] io_ctx the context for this function.
+ * @param[in] packet the packet to NAK
+ * @param[in] packet_len length of the packet to NAK
+ * @param[in] reply the NAK reply
+ * @param[in] reply_len length of the buffer where the reply should be placed.
* @return length of the data in the reply buffer.
*/
-typedef size_t (*fr_transport_nak_t)(void const *transport_ctx, uint8_t *const packet, size_t packet_len,
- uint8_t *reply, size_t reply_len);
+typedef size_t (*fr_io_nak_t)(void const *io_ctx, uint8_t *const packet, size_t packet_len,
+ uint8_t *reply, size_t reply_len);
/** Read/write from a socket.
*
* A stream writer MUST be prepared for the caller to delete the data
* immediately after calling the write routine. This means that if
* the socket is not ready, the writer MUST copy the data to an
- * internal buffer, usually in transport_ctx. It MUST then have a
+ * internal buffer, usually in io_ctx. It MUST then have a
* write callback on the socket, which is called when the socket is
* ready for writing. That callback can then write the internal
* buffer to the socket.
* saying "I took saved the data, but the socket wasn't ready, so you
* need to call me again at a later point".
*
- * @param[in] sockfd the file descriptor to use
- * @param[in] transport_ctx the context for this function
- * @param[in,out] buffer the buffer where the raw packet will be written to (or read from)
- * @param[in] buffer_len the length of the buffer
+ * @param[in] sockfd the file descriptor to use
+ * @param[in] io_ctx the context for this function
+ * @param[in,out] buffer the buffer where the raw packet will be written to (or read from)
+ * @param[in] buffer_len the length of the buffer
* @return
* - <0 on error
* - >=0 length of the data read or written.
*/
-typedef ssize_t (*fr_transport_io_t)(int sockfd, void *transport_ctx, uint8_t *buffer, size_t buffer_len);
+typedef ssize_t (*fr_io_data_t)(int sockfd, void *io_ctx, uint8_t *buffer, size_t buffer_len);
/** Handle a close or error on the socket.
*
* before "close". On normal finish, the "close" function will be
* called.
*
- * @param[in] sockfd the file descriptor to use
- * @param[in] transport_ctx the context for this function
+ * @param[in] sockfd the file descriptor to use
+ * @param[in] io_ctx the context for this function
* @return
* - 0 on success
* - <0 on error
*/
-typedef int (*fr_transport_signal_t)(int sockfd, void *transport_ctx);
+typedef int (*fr_io_signal_t)(int sockfd, void *io_ctx);
-/**
- * Process a request through the transport async state machine.
+/** Process a request through the transport async state machine.
+ *
*/
-typedef fr_transport_final_t (*fr_transport_process_t)(REQUEST *, fr_transport_action_t);
+typedef fr_io_final_t (*fr_io_process_t)(REQUEST *request, fr_io_action_t action);
-/**
- * Data structure describing the transport.
+/** Data structure containing functions for performing I/O
*
* @todo add conf parser, open socket, send_request, recv_reply, send_nak, etc.
*/
-typedef struct fr_transport_t {
- char const *name; //!< name of this transport
- size_t default_message_size; // usually minimum message size
- fr_transport_decode_t decode; //!< function to decode packet to request (worker)
- fr_transport_encode_t encode; //!< function to encode request to packet (worker)
-
- fr_transport_io_t read; //!< read from a socket to a data buffer
- fr_transport_io_t write; //!< write from a data buffer to a socket
- fr_transport_signal_t flush; //!< flush the data when the socket is ready for writing
- fr_transport_signal_t error; //!< there was an error on the socket
- fr_transport_signal_t close; //!< close the transport
- fr_transport_nak_t nak; //!< function to send a NAK
-} fr_transport_t;
-
-typedef enum fr_transport_status_t {
- FR_TRANSPORT_STATUS_INIT = 0,
- FR_TRANSPORT_STATUS_ACTIVE,
- FR_TRANSPORT_STATUS_ZOMBIE,
- FR_TRANSPORT_STATUS_DEAD
-} fr_transport_status_t;
-
-typedef struct fr_transport_socket_t {
- int fd; //!< file descriptor
- fr_transport_status_t status; //!< status of this socket
- void *ctx; //!< transport-specific context
- fr_transport_t *transport; //!< all transport callbacks
- struct fr_transport_socket_t *parent; //!< parent (if applicable)
-} fr_transport_socket_t;
+typedef struct fr_io_op_t {
+ char const *name; //!< Name of this transport
+ size_t default_message_size; // Usually minimum message size
+
+ fr_io_decode_t decode; //!< Function to decode packet to request (worker)
+ fr_io_encode_t encode; //!< Function to encode request to packet (worker)
+
+ fr_io_open_t open; //!< Open a new socket for listening, or accept/connect a new
+ //!< connection.
+ fr_io_get_fd_t fd; //!< Return the file descriptor from the io_ctx.
+ fr_io_data_t read; //!< Read from a socket to a data buffer
+ fr_io_data_t write; //!< Write from a data buffer to a socket
+ fr_io_signal_t flush; //!< Flush the data when the socket is ready for writing.
+ fr_io_signal_t error; //!< There was an error on the socket.
+ fr_io_signal_t close; //!< Close the transport.
+ fr_io_nak_t nak; //!< Function to send a NAK.
+} fr_io_op_t;
+
+typedef enum fr_io_status_t {
+ FR_IO_STATUS_INIT = 0, //!< Initialing I/O path.
+ FR_IO_STATUS_ESTABLISHED,
+ FR_IO_STATUS_FAILED
+} fr_io_status_t;
+
+typedef struct fr_io fr_io_t;
+struct fr_io {
+ fr_io_status_t status; //!< Status of I/O path.
+
+ int fd;
+ void *ctx; //!< I/O path specific context.
+ fr_io_op_t const *op; //!< I/O path functions.
+ fr_io_t *parent; //!< Parent (if applicable)
+};
#ifndef _FR_RADIUSD_H
/**
uint64_t number;
int heap_id;
- fr_dlist_t time_order; //!< tracking requests by time order
- fr_heap_t *runnable; //!< heap of runnable requests
+ fr_dlist_t time_order; //!< tracking requests by time order
+ fr_heap_t *runnable; //!< heap of runnable requests
fr_time_t recv_time;
fr_time_t *original_recv_time;
fr_event_list_t *el;
- fr_transport_process_t process_async;
+ fr_io_process_t process_async;
fr_time_tracking_t tracking;
fr_channel_t *channel;
- fr_packet_io_t io;
+ uint32_t priority;
+ fr_io_t *io; //!< How we received this request,
+ //!< and how we'll send the reply.
};
#endif
}
#endif
-#endif /* _FR_TRANSPORT_H */
+#endif /* _FR_IO_H */
int fd; //!< the file descriptor
void *ctx; //!< transport context
- fr_transport_t *transport; //!< the transport
+ fr_io_op_t *transport; //!< the transport
fr_message_set_t *ms; //!< message buffers for this socket.
fr_channel_data_t *cd; //!< cached in case of allocation & read error
fr_channel_data_t const *a = one;
fr_channel_data_t const *b = two;
- if (a->io.priority < b->io.priority) return -1;
- if (a->io.priority > b->io.priority) return +1;
+ if (a->priority < b->priority) return -1;
+ if (a->priority > b->priority) return +1;
if (a->m.when < b->m.when) return -1;
if (a->m.when > b->m.when) return +1;
* to the stream socket for subsequent reads.
*
* Since we have a message set for each
- * fr_transport_socket_t, no "head of line"
+ * fr_io_socket_t, no "head of line"
* blocking issues can happen for stream sockets.
*/
s->cd = cd;
/*
* Error: close the connection, and remove the
- * fr_transport_t.
+ * fr_io_op_t.
*/
if (data_size < 0) {
fr_log(nr->log, L_DBG_ERR, "error from transport read on socket %d", s->fd);
* Initialize the rest of the fields of the channel data.
*/
cd->m.when = fr_time();
- cd->io.fd = sockfd;
- cd->io.priority = 0;
- cd->io.ctx = s->ctx;
- cd->io.transport = s->transport;
+ cd->io->fd = sockfd;
+ cd->priority = 0;
+ cd->io->ctx = s->ctx;
+ cd->io->op = s->transport;
cd->request.start_time = &start_time; /* @todo - set by transport */
start_time = cd->m.when;
// fr_time_t now;
ssize_t rcode;
fr_channel_data_t *cd;
- fr_packet_io_t *io;
+ fr_io_t *io;
/*
* There are runnable requests. We still service
cd = fr_heap_pop(nr->replies);
if (!cd) continue;
- io = &cd->io;
+ io = cd->io;
/*
* @todo - call transport "recv reply". And if
* the reply is a NAK, don't write it to the
* network.
*/
- rcode = io->transport->write(io->fd, io->ctx, cd->m.data, cd->m.data_size);
+ rcode = io->op->write(io->fd, io->ctx, cd->m.data, cd->m.data_size);
if (rcode < 0) {
fr_dlist_t *entry;
* Don't call close, as that will be done
* in the destructor.
*/
- if (io->transport->error) io->transport->error(io->fd, io->ctx);
+ if (io->op->error) io->op->error(io->fd, io->ctx);
/*
* Find the socket which matches this
break;
}
}
-
+
continue;
}
// call write function again at some later date.
}
- fr_log(nr->log, L_DBG, "Sending reply to socket %d", cd->io.fd);
+ fr_log(nr->log, L_DBG, "Sending reply to socket %d", cd->io->fd);
fr_message_done(&cd->m);
}
}
* @param ctx the context for the transport
* @param transport the transport
*/
-int fr_network_socket_add(fr_network_t *nr, int fd, void *ctx, fr_transport_t *transport)
+int fr_network_socket_add(fr_network_t *nr, int fd, void *ctx, fr_io_op_t *transport)
{
fr_network_socket_t m;
int fr_network_destroy(fr_network_t *nr) CC_HINT(nonnull);
void fr_network(fr_network_t *nr) CC_HINT(nonnull);
-int fr_network_socket_add(fr_network_t *nr, int fd, void *ctx, fr_transport_t *transport) CC_HINT(nonnull);
+int fr_network_socket_add(fr_network_t *nr, int fd, void *ctx, fr_io_op_t *transport) CC_HINT(nonnull);
int fr_network_worker_add(fr_network_t *nr, fr_worker_t *worker) CC_HINT(nonnull);
#ifdef __cplusplus
*/
int fr_schedule_destroy(fr_schedule_t *sc)
{
- int i, num;
+ int i, num;
fr_schedule_worker_t *sw;
sc->running = false;
* @param ctx the context for the transport
* @param transport the transport
*/
-int fr_schedule_socket_add(fr_schedule_t *sc, int fd, void *ctx, fr_transport_t *transport)
+int fr_schedule_socket_add(fr_schedule_t *sc, int fd, void *ctx, fr_io_op_t *transport)
{
return fr_network_socket_add(sc->sn->rc, fd, ctx, transport);
}
int fr_schedule_destroy(fr_schedule_t *sc);
int fr_schedule_get_worker_kq(fr_schedule_t *sc);
-int fr_schedule_socket_add(fr_schedule_t *sc, int fd, void *ctx, fr_transport_t *transport) CC_HINT(nonnull);
+int fr_schedule_socket_add(fr_schedule_t *sc, int fd, void *ctx, fr_io_op_t *transport) CC_HINT(nonnull);
#ifdef __cplusplus
}
* the "time_order" list, and ages out requests which have been
* running for "too long".
*
- * A request may return one of FR_TRANSPORT_YIELD,
- * FR_TRANSPORT_REPLY, or FR_TRANSPORT_DONE. If a request is
+ * A request may return one of FR_IO_YIELD,
+ * FR_IO_REPLY, or FR_IO_DONE. If a request is
* yeilded, it is placed onto the yielded list in the worker
* "tracking" data structure.
*
*/
static void fr_worker_nak(fr_worker_t *worker, fr_channel_data_t *cd, fr_time_t now)
{
- size_t size;
- fr_channel_data_t *reply;
- fr_channel_t *ch;
- fr_message_set_t *ms;
- fr_packet_io_t *io;
+ size_t size;
+ fr_channel_data_t *reply;
+ fr_channel_t *ch;
+ fr_message_set_t *ms;
+ fr_io_t *io;
worker->num_timeouts++;
* Cache the outbound channel. We'll need it later.
*/
ch = cd->channel.ch;
- io = &cd->io;
+ io = cd->io;
ms = fr_channel_worker_ctx_get(ch);
rad_assert(ms != NULL);
/*
* Allocate a default message size.
*/
- reply = (fr_channel_data_t *) fr_message_reserve(ms, io->transport->default_message_size);
+ reply = (fr_channel_data_t *) fr_message_reserve(ms, io->op->default_message_size);
rad_assert(reply != NULL);
/*
* Encode a NAK
*/
- size = io->transport->nak(io->ctx, cd->m.data, cd->m.data_size, reply->m.data, reply->m.rb_size);
+ size = io->op->nak(io->ctx, cd->m.data, cd->m.data_size, reply->m.data, reply->m.rb_size);
(void) fr_message_alloc(ms, &reply->m, size);
if (size) {
ssize_t encoded;
- encoded = request->io.transport->encode(request->io.ctx, request, reply->m.data, reply->m.rb_size);
+ encoded = request->io->op->encode(request->io->ctx, request, reply->m.data, reply->m.rb_size);
if (encoded < 0) {
fr_log(worker->log, L_DBG, "\t%sfails encode", worker->name);
encoded = 0;
talloc_free(request);
}
-
/** Check timeouts on the various queues
*
* This function checks and enforces timeouts on the multiple worker
*/
while ((entry = FR_DLIST_TAIL(worker->time_order)) != NULL) {
REQUEST *request;
- fr_transport_final_t final;
+ fr_io_final_t final;
request = fr_ptr_to_type(REQUEST, time_order, entry);
waiting = now - request->recv_time;
fr_dlist_remove(&request->time_order);
(void) fr_heap_extract(worker->runnable, request);
- final = request->process_async(request, FR_TRANSPORT_ACTION_DONE);
+ final = request->process_async(request, FR_IO_ACTION_DONE);
- if (final != FR_TRANSPORT_DONE) {
+ if (final != FR_IO_DONE) {
fr_dlist_insert_tail(&worker->waiting_to_die, &request->time_order);
continue;
}
entry != NULL;
entry = FR_DLIST_NEXT(worker->waiting_to_die, entry)) {
REQUEST *request;
- fr_transport_final_t final;
+ fr_io_final_t final;
request = fr_ptr_to_type(REQUEST, time_order, entry);
- final = request->process_async(request, FR_TRANSPORT_ACTION_DONE);
+ final = request->process_async(request, FR_IO_ACTION_DONE);
- if (final == FR_TRANSPORT_DONE) {
+ if (final == FR_IO_DONE) {
fr_dlist_remove(&request->time_order);
fr_log(worker->log, L_DBG, "(%"PRIu64") finally finished", request->number);
*/
static REQUEST *fr_worker_get_request(fr_worker_t *worker, fr_time_t now)
{
- int rcode;
- fr_channel_data_t *cd;
- REQUEST *request;
- fr_dlist_t *entry;
- fr_packet_io_t *io;
+ int rcode;
+ fr_channel_data_t *cd;
+ REQUEST *request;
+ fr_dlist_t *entry;
+ fr_io_t *io;
#ifndef HAVE_TALLOC_POOLED_OBJECT
- TALLOC_CTX *ctx;
+ TALLOC_CTX *ctx;
#endif
/*
* Receive a message to the worker queue, and decode it
* to a request.
*/
- rad_assert(cd->io.transport != NULL);
+ rad_assert(cd->io->op != NULL);
/*
* Update the transport-specific fields.
request->number = 0; /* @todo - assigned by someone intelligent... */
request->io = cd->io;
- io = &request->io;
+ io = request->io;
/*
* Now that the "request" structure has been initialized, go decode the packet.
*
* Note that this also sets the "process_async" function.
*/
- rcode = io->transport->decode(io->ctx, cd->m.data, cd->m.data_size, request);
+ rcode = io->op->decode(io->ctx, cd->m.data, cd->m.data_size, request);
if (rcode < 0) {
fr_log(worker->log, L_DBG, "\t%sFAILED decode of request %"PRIu64, worker->name, request->number);
talloc_free(ctx);
static void fr_worker_run_request(fr_worker_t *worker, REQUEST *request)
{
ssize_t size = 0;
- fr_transport_final_t final;
+ fr_io_final_t final;
fr_log(worker->log, L_DBG, "\t%s running request (%"PRIu64")", worker->name, request->number);
*/
if ((*request->original_recv_time == request->recv_time) &&
fr_channel_active(request->channel)) {
- final = request->process_async(request, FR_TRANSPORT_ACTION_RUN);
+ final = request->process_async(request, FR_IO_ACTION_RUN);
} else {
- final = request->process_async(request, FR_TRANSPORT_ACTION_DONE);
+ final = request->process_async(request, FR_IO_ACTION_DONE);
/*
* If the request isn't done, put it into the
* async cleanup queue.
*/
- if (final != FR_TRANSPORT_DONE) {
+ if (final != FR_IO_DONE) {
fr_dlist_remove(&request->time_order);
fr_dlist_insert_tail(&worker->waiting_to_die, &request->time_order);
return;
* Figure out what to do next.
*/
switch (final) {
- case FR_TRANSPORT_DONE:
+ case FR_IO_DONE:
/*
* Done: don't send a reply.
*/
break;
- case FR_TRANSPORT_FAIL:
+ case FR_IO_FAIL:
/*
* Something went wrong. It's done, but we don't send a reply.
*/
break;
- case FR_TRANSPORT_YIELD:
+ case FR_IO_YIELD:
fr_time_tracking_yield(&request->tracking, fr_time(), &worker->tracking);
return;
- case FR_TRANSPORT_REPLY:
- size = request->io.transport->default_message_size;
+ case FR_IO_REPLY:
+ size = request->io->op->default_message_size;
break;
}
fr_channel_data_t const *a = one;
fr_channel_data_t const *b = two;
- if (a->io.priority < b->io.priority) return -1;
- if (a->io.priority > b->io.priority) return +1;
+ if (a->priority < b->priority) return -1;
+ if (a->priority > b->priority) return +1;
if (a->m.when < b->m.when) return -1;
if (a->m.when > b->m.when) return +1;
REQUEST const *a = one;
REQUEST const *b = two;
- if (a->io.priority < b->io.priority) return -1;
- if (a->io.priority > b->io.priority) return +1;
+ if (a->priority < b->priority) return -1;
+ if (a->priority > b->priority) return +1;
if (a->recv_time < b->recv_time) return -1;
if (a->recv_time > b->recv_time) return +1;
if (!request) continue;
rad_assert(request->process_async != NULL);
- rad_assert(request->io.transport != NULL);
+ rad_assert(request->io->op != NULL);
/*
* Run the request, and either track it as
#include <freeradius-devel/event.h>
#include <freeradius-devel/fr_log.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#ifdef __cplusplus
extern "C" {
* Function name is a bit of a misnomer as it can also be used to create client sockets too,
* such is the nature of UDP.
*
- * @param[in] src_ipaddr The IP address to listen on
+ * @param[in] src_ipaddr The IP address to listen on
* @param[in,out] src_port the port to listen on. If *port == 0, the resolved
* service port will be written here.
* @param[in] port_name if *port == 0, the name of the port
*/
sockfd = socket(src_ipaddr->af, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
- fr_strerror_printf("Failed creating UNIX socket: %s", fr_syserror(errno));
+ fr_strerror_printf("Failed creating UDP socket: %s", fr_syserror(errno));
return -1;
}
return -1;
}
- if (!app->parse) {
+ if (!app->instantiate) {
cf_log_err_cs(cs, "Failed to find initialization function for 'transport = %s'",
value);
return -1;
name2, cf_section_filename(cs));
cf_log_info(cs, " namespace = %s", app->name);
- if (app->parse(NULL, cs, check_config) < 0) {
+ if (app->instantiate(NULL, cs, check_config) < 0) {
cf_log_err_cs(cs, "Failed loading virtual server %s", name2);
return -1;
}
/** Decode the packet, and set the request->process function
*
*/
-static int mod_decode(void *transport_ctx, uint8_t *const data, UNUSED size_t data_len, REQUEST *request)
+static int mod_decode(void *io_ctx, uint8_t *const data, UNUSED size_t data_len, REQUEST *request)
{
- proto_radius_ctx_t *ctx = transport_ctx;
+ proto_radius_ctx_t *ctx = io_ctx;
if (fr_radius_verify(data, NULL, (uint8_t const *) ctx->secret, ctx->secret_len) < 0) {
return -1;
return 0;
}
-static ssize_t mod_encode(UNUSED void *transport_ctx, UNUSED REQUEST *request, UNUSED uint8_t *buffer, UNUSED size_t buffer_len)
+static ssize_t mod_encode(UNUSED void *io_ctx, UNUSED REQUEST *request, UNUSED uint8_t *buffer, UNUSED size_t buffer_len)
{
return -1;
}
}
-static int open_transport(proto_radius_ctx_t *ctx, UNUSED fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION *cs, char const *value,
+static int open_transport(proto_radius_ctx_t *ctx, UNUSED fr_schedule_t *handle,
+ CONF_SECTION *server, CONF_SECTION *cs, char const *value,
bool verify_config)
{
- fr_transport_t *transport;
- dl_t const *module;
- fr_app_io_t const *io;
+ dl_t const *module;
+ fr_app_io_t const *app_io;
+ CONF_SECTION *io_cs;
+ void *io_ctx;
char buffer[256];
if (!value || !*value) {
return -1;
}
- io = (fr_app_io_t const *) module->common;
- if (io->open(ctx, &ctx->sockfd, &ctx->io_ctx, &transport, cs, verify_config) < 0) {
+ /*
+ * Lookup io section.
+ */
+ io_cs = cf_subsection_find(cs, value);
+ if (!io_cs) {
+ cf_log_err_cs(cs, "Must contain a '%s' section", value);
+ return -1;
+ }
+
+ if (dl_instance_data_alloc(&io_ctx, NULL, module, io_cs) < 0) {
+ PERROR("Failed io_ctx data");
+ return -1;
+ }
+
+ app_io = (fr_app_io_t const *) module->common;
+ if (app_io->instantiate(io_cs, io_ctx) < 0) {
+ cf_log_err_cs(cs, "Failed instantiating 'transport = %s'", value);
+ talloc_free(io_ctx);
+ return -1;
+ }
+
+ if (!verify_config) return 0;
+
+ if (app_io->op.open(io_ctx) < 0) {
cf_log_err_cs(cs, "Failed compiling unlang for 'transport = %s'", value);
return -1;
}
*
* @note - could also do this in the recv_request function?
*/
- ctx->transport = *transport;
+ ctx->transport = app_io->op;
ctx->transport.decode = mod_decode;
ctx->transport.encode = mod_encode;
if (cf_data_find(cs, char const *, value)) continue;
app = (fr_app_subtype_t const *) module->common;
- if (app->compile(cs) < 0) {
+ if (app->instantiate(cs) < 0) {
cf_log_err_cs(cs, "Failed compiling unlang for 'type = %s'", value);
return -1;
}
.name = "radius",
.load = mod_load,
.bootstrap = mod_bootstrap,
- .parse = mod_parse,
+ .instantiate = mod_parse,
};
typedef struct proto_radius_ctx_t {
int sockfd; //!< sanity checks
- void *io_ctx; //!< for the underlying IO layer
+ void *ctx; //!< for the underlying IO layer
char const *secret; //!< shared secret
size_t secret_len; //!< length of the shared secret
- fr_transport_t transport;
- fr_transport_process_t process[FR_MAX_PACKET_CODE];
+ fr_io_op_t transport;
+ fr_io_process_t process[FR_MAX_PACKET_CODE];
} proto_radius_ctx_t;
#endif /* _PROTO_RADIUS_H */
#include <freeradius-devel/process.h>
#include <freeradius-devel/udp.h>
#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/rad_assert.h>
-static fr_transport_final_t acct_process(REQUEST *request)
+static fr_io_final_t acct_process(REQUEST *request)
{
VALUE_PAIR *vp;
rlm_rcode_t rcode;
if (request->packet->data_len != 0) {
if (fr_radius_packet_decode(request->packet, NULL, request->client->secret) < 0) {
RDEBUG("Failed decoding RADIUS packet: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (RDEBUG_ENABLED) common_packet_debug(request, request->packet, true);
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->packet->code));
if (!dv) {
REDEBUG("Failed to find value for &request:Packet-Type");
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
case REQUEST_RECV:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
case RLM_MODULE_REJECT:
case RLM_MODULE_USERLOCK:
default:
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
/*
case REQUEST_SEND:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
*/
if (!request->reply->code) {
RDEBUG("Not sending reply to client.");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
/*
radlog_request(L_DBG, L_DBG_LVL_1, request, "Sent %s ID %i",
fr_packet_codes[request->reply->code], request->reply->id);
rdebug_proto_pair_list(L_DBG_LVL_1, request, request->reply->vps, "");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
#ifdef WITH_UDPFROMTO
if (fr_radius_packet_encode(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed encoding RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (fr_radius_packet_sign(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed signing RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
break;
default:
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static void acct_running(REQUEST *request, fr_state_action_t action)
{
- fr_transport_final_t rcode;
+ fr_io_final_t rcode;
TRACE_STATE_MACHINE;
case REQUEST_RECV:
case REQUEST_SEND:
rcode = acct_process(request);
- if (rcode == FR_TRANSPORT_YIELD) return;
+ if (rcode == FR_IO_YIELD) return;
- if (rcode == FR_TRANSPORT_REPLY) {
+ if (rcode == FR_IO_REPLY) {
if (fr_radius_packet_send(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed sending RADIUS reply: %s", fr_strerror());
}
#include <freeradius-devel/state.h>
#include <freeradius-devel/udp.h>
#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/rad_assert.h>
#ifndef USEC
}
-static fr_transport_final_t auth_process(REQUEST *request)
+static fr_io_final_t auth_process(REQUEST *request)
{
VALUE_PAIR *vp, *auth_type;
rlm_rcode_t rcode;
if (request->packet->data_len != 0) {
if (fr_radius_packet_decode(request->packet, NULL, request->client->secret) < 0) {
RDEBUG("Failed decoding RADIUS packet: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (RDEBUG_ENABLED) common_packet_debug(request, request->packet, true);
case REQUEST_RECV:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
case REQUEST_PROCESS:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
case REQUEST_SEND:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
*/
if (!request->reply->code) {
RDEBUG("Not sending reply to client.");
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
/*
radlog_request(L_DBG, L_DBG_LVL_1, request, "Sent %s ID %i",
fr_packet_codes[request->reply->code], request->reply->id);
rdebug_proto_pair_list(L_DBG_LVL_1, request, request->reply->vps, "");
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
#ifdef WITH_UDPFROMTO
if (fr_radius_packet_encode(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed encoding RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (fr_radius_packet_sign(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed signing RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
break;
default:
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static void auth_running(REQUEST *request, fr_state_action_t action)
{
- fr_transport_final_t rcode;
+ fr_io_final_t rcode;
TRACE_STATE_MACHINE;
case REQUEST_RECV:
case REQUEST_SEND:
rcode = auth_process(request);
- if (rcode == FR_TRANSPORT_YIELD) return;
+ if (rcode == FR_IO_YIELD) return;
/*
* We can't do anything with the packet.
* state we have, and clean up the packet
* immediately.
*/
- if (rcode == FR_TRANSPORT_FAIL) {
+ if (rcode == FR_IO_FAIL) {
request->reply->code = 0;
fr_state_discard(global_state, request, request->packet);
goto done;
/*
* Forcibly done, don't do anything else.
*/
- if (rcode == FR_TRANSPORT_DONE) {
+ if (rcode == FR_IO_DONE) {
request->reply->code = 0;
fr_state_discard(global_state, request, request->packet);
goto done;
}
- rad_assert(rcode == FR_TRANSPORT_REPLY);
+ rad_assert(rcode == FR_IO_REPLY);
/*
* Internally generated request: clean it
#include <freeradius-devel/process.h>
#include <freeradius-devel/udp.h>
#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/rad_assert.h>
-static fr_transport_final_t coa_process(REQUEST *request)
+static fr_io_final_t coa_process(REQUEST *request)
{
VALUE_PAIR *vp;
rlm_rcode_t rcode;
if (request->packet->data_len != 0) {
if (fr_radius_packet_decode(request->packet, NULL, request->client->secret) < 0) {
RDEBUG("Failed decoding RADIUS packet: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (RDEBUG_ENABLED) common_packet_debug(request, request->packet, true);
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->packet->code));
if (!dv) {
REDEBUG("Failed to find value for &request:Packet-Type");
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
case REQUEST_RECV:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
case REQUEST_SEND:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
*/
if (!request->reply->code) {
RDEBUG("Not sending reply to client.");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
/*
radlog_request(L_DBG, L_DBG_LVL_1, request, "Sent %s ID %i",
fr_packet_codes[request->reply->code], request->reply->id);
rdebug_proto_pair_list(L_DBG_LVL_1, request, request->reply->vps, "");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
#ifdef WITH_UDPFROMTO
if (fr_radius_packet_encode(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed encoding RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
if (fr_radius_packet_sign(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed signing RADIUS reply: %s", fr_strerror());
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
break;
default:
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static void coa_running(REQUEST *request, fr_state_action_t action)
{
- fr_transport_final_t rcode;
+ fr_io_final_t rcode;
TRACE_STATE_MACHINE;
case REQUEST_RECV:
case REQUEST_SEND:
rcode = coa_process(request);
- if (rcode == FR_TRANSPORT_YIELD) return;
+ if (rcode == FR_IO_YIELD) return;
- if (rcode == FR_TRANSPORT_REPLY) {
+ if (rcode == FR_IO_REPLY) {
if (fr_radius_packet_send(request->reply, request->packet, request->client->secret) < 0) {
RDEBUG("Failed sending RADIUS reply: %s", fr_strerror());
}
#include <freeradius-devel/process.h>
#include <freeradius-devel/udp.h>
#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/rad_assert.h>
-static fr_transport_final_t mod_process(REQUEST *request, UNUSED fr_transport_action_t action)
+static fr_io_final_t mod_process(REQUEST *request, UNUSED fr_io_action_t action)
{
rlm_rcode_t rcode;
CONF_SECTION *unlang;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->packet->code));
if (!dv) {
REDEBUG("Failed to find value for &request:Packet-Type");
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
case REQUEST_RECV:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
case REQUEST_SEND:
rcode = unlang_interpret_continue(request);
- if (request->master_state == REQUEST_STOP_PROCESSING) return FR_TRANSPORT_DONE;
+ if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE;
- if (rcode == RLM_MODULE_YIELD) return FR_TRANSPORT_YIELD;
+ if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD;
request->log.unlang_indent = 0;
*/
if (!request->reply->code) {
RDEBUG("Not sending reply to client.");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
/*
radlog_request(L_DBG, L_DBG_LVL_1, request, "Sent %s ID %i",
fr_packet_codes[request->reply->code], request->reply->id);
rdebug_proto_pair_list(L_DBG_LVL_1, request, request->reply->vps, "");
- return FR_TRANSPORT_DONE;
+ return FR_IO_DONE;
}
#ifdef WITH_UDPFROMTO
break;
default:
- return FR_TRANSPORT_FAIL;
+ return FR_IO_FAIL;
}
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
fr_app_subtype_t proto_radius_status = {
.magic = RLM_MODULE_INIT,
.name = "radius_status",
- .compile = mod_compile,
+ .instantiate = mod_compile,
.process = mod_process,
};
#include <freeradius-devel/protocol.h>
#include <freeradius-devel/udp.h>
#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/rad_assert.h>
#include "proto_radius.h"
typedef struct {
- int sockfd; //!< Socket the packet was received on.
+ int sockfd; //!< Socket the packet was received on.
- uint8_t const *secret;
- size_t secret_len;
+ uint8_t const *secret;
+ size_t secret_len;
- uint8_t original[20];
- uint8_t id;
+ uint8_t original[20];
+ uint8_t id;
- struct sockaddr_storage src;
- socklen_t salen;
+ struct sockaddr_storage src;
+ socklen_t salen;
} fr_packet_ctx_t;
-/** Basic config for a UDP listen socket
- *
- */
typedef struct {
- fr_ipaddr_t ipaddr; //!< Ipaddr to listen on.
+ int sockfd;
+
+ fr_ipaddr_t ipaddr; //!< Ipaddr to listen on.
- bool ipaddr_is_set; //!< ipaddr config item is set.
- bool ipv4addr_is_set; //!< ipv4addr config item is set.
- bool ipv6addr_is_set; //!< ipv6addr config item is set.
+ bool ipaddr_is_set; //!< ipaddr config item is set.
+ bool ipv4addr_is_set; //!< ipv4addr config item is set.
+ bool ipv6addr_is_set; //!< ipv6addr config item is set.
- char const *interface; //!< Interface to bind to.
+ char const *interface; //!< Interface to bind to.
- uint16_t port; //!< Port to listen on.
- uint32_t recv_buff; //!< How big the kernel's receive buffer should be.
- bool recv_buff_is_set; //!< Whether we were provided with a receive buffer value.
-} fr_proto_radius_udp_conf_t;
+ uint16_t port; //!< Port to listen on.
+ uint32_t recv_buff; //!< How big the kernel's receive buffer should be.
+ bool recv_buff_is_set; //!< Whether we were provided with a receive
+ //!< buffer value.
+} fr_proto_radius_udp_ctx_t;
static const CONF_PARSER udp_listen_conf[] = {
- { FR_CONF_IS_SET_OFFSET("ipaddr", FR_TYPE_COMBO_IP_ADDR, fr_proto_radius_udp_conf_t, ipaddr) },
- { FR_CONF_IS_SET_OFFSET("ipv4addr", FR_TYPE_IPV4_ADDR, fr_proto_radius_udp_conf_t, ipaddr) },
- { FR_CONF_IS_SET_OFFSET("ipv6addr", FR_TYPE_IPV6_ADDR, fr_proto_radius_udp_conf_t, ipaddr) },
+ { FR_CONF_IS_SET_OFFSET("ipaddr", FR_TYPE_COMBO_IP_ADDR, fr_proto_radius_udp_ctx_t, ipaddr) },
+ { FR_CONF_IS_SET_OFFSET("ipv4addr", FR_TYPE_IPV4_ADDR, fr_proto_radius_udp_ctx_t, ipaddr) },
+ { FR_CONF_IS_SET_OFFSET("ipv6addr", FR_TYPE_IPV6_ADDR, fr_proto_radius_udp_ctx_t, ipaddr) },
- { FR_CONF_OFFSET("interface", FR_TYPE_STRING, fr_proto_radius_udp_conf_t, interface) },
+ { FR_CONF_OFFSET("interface", FR_TYPE_STRING, fr_proto_radius_udp_ctx_t, interface) },
- { FR_CONF_OFFSET("port", FR_TYPE_UINT16, fr_proto_radius_udp_conf_t, port) },
- { FR_CONF_IS_SET_OFFSET("recv_buff", FR_TYPE_UINT32, fr_proto_radius_udp_conf_t, recv_buff) },
+ { FR_CONF_OFFSET("port", FR_TYPE_UINT16, fr_proto_radius_udp_ctx_t, port) },
+ { FR_CONF_IS_SET_OFFSET("recv_buff", FR_TYPE_UINT32, fr_proto_radius_udp_ctx_t, recv_buff) },
CONF_PARSER_TERMINATOR
};
return data_size;
}
-/*
- * We'll figure out how to fix this later...
- */
-static fr_transport_t proto_radius_udp_transport = {
- .name = "radius_udp",
- .default_message_size = 4096,
- .read = mod_read,
- .write = mod_write,
-};
-
-
-/** Open a UDP listener for RADIUS
- *
- */
-static int mod_open(TALLOC_CTX *ctx, int *sockfd_p, void **transport_ctx,
- fr_transport_t **transport_p, CONF_SECTION *listen, bool verify_config)
+static int mod_instantiate(UNUSED CONF_SECTION *cs, void *instance)
{
- CONF_SECTION *cs;
- fr_proto_radius_udp_conf_t *config;
-
- /*
- * We know our name, so we don't need to re-parse the
- * "transport" config item
- */
- cs = cf_subsection_find_next(listen, NULL, "udp");
-
- /*
- * Be gentle...
- */
- if (!cs) {
- cs = listen;
- } else {
- cf_log_info(cs, " udp {");
- }
-
- config = talloc_zero(ctx, fr_proto_radius_udp_conf_t);
- if (cf_section_parse(config, config, cs, udp_listen_conf) < 0) return -1;
+ fr_proto_radius_udp_ctx_t *inst = instance;
/*
* Default to all IPv6 interfaces (it's the future)
*/
- if (!config->ipaddr_is_set && !config->ipv4addr_is_set && !config->ipv6addr_is_set) {
- config->ipaddr.af = AF_INET6;
- config->ipaddr.prefix = 128;
- config->ipaddr.addr.v6 = in6addr_any; /* in6addr_any binds to all addresses */
+ if (!inst->ipaddr_is_set && !inst->ipv4addr_is_set && !inst->ipv6addr_is_set) {
+ inst->ipaddr.af = AF_INET6;
+ inst->ipaddr.prefix = 128;
+ inst->ipaddr.addr.v6 = in6addr_any; /* in6addr_any binds to all addresses */
}
- if (config->recv_buff_is_set) {
- FR_INTEGER_BOUND_CHECK("recv_buff", config->recv_buff, >=, 32);
- FR_INTEGER_BOUND_CHECK("recv_buff", config->recv_buff, <=, INT_MAX);
+ if (inst->recv_buff_is_set) {
+ FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, >=, 32);
+ FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, <=, INT_MAX);
}
- if (cs != listen) cf_log_info(cs, " }");
+ return 0;
+}
- /*
- * If we're only checking the configuration, don't open
- * sockets.
- */
- if (verify_config) return 0;
-
- *transport_p = &proto_radius_udp_transport;
- *sockfd_p = -1;
- *transport_ctx = talloc_strdup(ctx, "testing");
- if (!*transport_ctx) {
- cf_log_err_cs(cs, "Failed allocating memory");
- talloc_free(config);
+/** Open a UDP listener for RADIUS
+ *
+ * @param[in] instance of the RADIUS UDP I/O path.
+ */
+static int mod_open(void *instance)
+{
+ fr_proto_radius_udp_ctx_t *inst = instance;
+
+ int sockfd = 0;
+
+ sockfd = fr_socket_server_udp(&inst->ipaddr, &inst->port, NULL, true);
+ if (sockfd < 0) {
+ ERROR("%s", fr_strerror());
+ error:
return -1;
}
- /*
- * Allocate fr_app_t
- * open sockets
- * create transport structure.
- */
+ if (fr_socket_bind(sockfd, &inst->ipaddr, &inst->port, inst->interface) < 0) {
+ ERROR("Failed binding socket: %s", fr_strerror());
+ goto error;
+ }
+
+ inst->sockfd = sockfd;
return 0;
}
extern fr_app_io_t proto_radius_udp;
fr_app_io_t proto_radius_udp = {
- .magic = RLM_MODULE_INIT,
- .name = "radius_udp",
- .open = mod_open,
+ .magic = RLM_MODULE_INIT,
+ .name = "radius_udp",
+ .config = udp_listen_conf,
+ .inst_size = sizeof(fr_proto_radius_udp_ctx_t),
+ .instantiate = mod_instantiate,
+ .op = {
+ .name = "radius_udp",
+ .default_message_size = 4096,
+ .open = mod_open,
+ .read = mod_read,
+ .write = mod_write,
+ }
};
*/
RCSID("$Id$")
-#include <freeradius-devel/io/transport.h>
+#include <freeradius-devel/io/io.h>
#include <freeradius-devel/md5.h>
#include <freeradius-devel/radius.h>
#include <freeradius-devel/token.h>
-static fr_transport_final_t mod_process(REQUEST *request, fr_transport_action_t action)
+static fr_io_final_t mod_process(REQUEST *request, fr_io_action_t action)
{
RDEBUG("\t\tPROCESS --- request %zd action %d\n", request->number, action);
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static int mod_decode(void const *ctx, uint8_t *const data, size_t data_len, REQUEST *request)
return data_size;
}
-extern fr_transport_t fr_radius_server_udp;
-fr_transport_t fr_radius_server_udp = {
+extern fr_io_op_t fr_radius_server_udp;
+fr_io_op_t fr_radius_server_udp = {
.name = "radius_server_udp",
.default_message_size = 4096,
.read = mod_read,
exit(1);
}
-static fr_transport_final_t test_process(REQUEST *request, fr_transport_action_t action)
+static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
{
MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
return 10;
}
-static fr_transport_t transport = {
+static fr_io_op_t transport = {
.name = "worker-test",
.default_message_size = 4096,
.decode = test_decode,
static void send_reply(int sockfd, fr_channel_data_t *reply)
{
- fr_packet_ctx_t *pc = reply->io.ctx;
+ fr_packet_ctx_t *pc = reply->io->ctx;
MPRINT1("Master got reply %d size %zd\n", pc->id, reply->m.data_size);
rad_assert(pc != NULL);
pc->salen = sizeof(pc->src);
- cd->io.fd = -1;
- cd->io.priority = 0;
- cd->io.ctx = pc;
- cd->io.transport = &transport;
+ cd->io->fd = -1;
+ cd->priority = 0;
+ cd->io->ctx = pc;
+ cd->io->op = &transport;
data_size = recvfrom(sockfd, cd->m.data, cd->m.rb_size, 0,
(struct sockaddr *) &pc->src, &pc->salen);
extern int fr_socket_bind(int sockfd, fr_ipaddr_t *ipaddr, int *port, char const *interface);
extern int fr_fault_setup(char const *cmd, char const *program);
-static fr_transport_final_t test_process(REQUEST *request, fr_transport_action_t action)
+static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
{
MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static int test_decode(void *ctx, uint8_t *const data, size_t data_len, REQUEST *request)
}
-static fr_transport_t transport = {
+static fr_io_op_t transport = {
.name = "schedule-test",
.default_message_size = 4096,
.read = test_read,
exit(1);
}
-static fr_transport_final_t test_process(REQUEST *request, fr_transport_action_t action)
+static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
{
MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
- return FR_TRANSPORT_REPLY;
+ return FR_IO_REPLY;
}
static int test_decode(void *packet_ctx, uint8_t *const data, size_t data_len, REQUEST *request)
return 10;
}
-static fr_transport_t transport = {
+static fr_io_op_t transport = {
.name = "worker-test",
.default_message_size = 4096,
.decode = test_decode,
cd->m.when = fr_time();
- cd->io.fd = -1;
- cd->io.priority = 0;
- cd->io.ctx = NULL;
- cd->io.transport = &transport;
+ cd->io->fd = -1;
+ cd->priority = 0;
+ cd->io->ctx = NULL;
+ cd->io->op = &transport;
if (touch_memory) {
size_t j, k;