]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Commit 95% of the new module framework changes
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 14 Jun 2017 22:20:28 +0000 (18:20 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 14 Jun 2017 22:20:35 +0000 (18:20 -0400)
It doesn't work yet, but the old tests pass and i'm tired.

28 files changed:
src/include/cf_parse.h
src/include/dl.h
src/include/modules.h
src/include/protocol.h
src/lib/io/application.h
src/lib/io/io.h
src/lib/io/listen.h
src/lib/io/network.c
src/lib/io/schedule.h
src/lib/io/worker.c
src/main/cf_parse.c
src/main/dl.c
src/main/mainconfig.c
src/main/modules.c
src/main/radiusd.c
src/main/unit_test_module.c
src/main/virtual_servers.c
src/modules/proto_radius/proto_radius.c
src/modules/proto_radius/proto_radius.h
src/modules/proto_radius/proto_radius_status.c
src/modules/proto_radius/proto_radius_udp.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_pap/rlm_pap.c
src/modules/rlm_sql/rlm_sql.c
src/tests/util/radius1_test.c
src/tests/util/radius_schedule_test.c
src/tests/util/worker_test.c

index 9dbc045dd84fe9145cd6e956d210d481d2c4e149..688f1815786e7f76269f26ac821b44d1f3131cf1 100644 (file)
@@ -75,6 +75,8 @@ typedef void _mismatch_size;          //!< Dummy type used to indicate FR_TYPE_*/C type
 typedef void _mismatch_size_m;         //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
 typedef void _mismatch_timeval;                //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
 typedef void _mismatch_timeval_m;      //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
+typedef void _mismatch_void;           //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
+typedef void _mismatch_void_m;         //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
 typedef void _mismatch_default;                //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
 
 typedef void conf_type_mismatch;       //!< Dummy type used to indicate FR_TYPE_*/C type mismatch.
@@ -178,6 +180,10 @@ _Generic((_ct), \
                        _p, (_mismatch_timeval) 0), \
        _timeval_t **   : __builtin_choose_expr((FR_BASE_TYPE(_t) == FR_TYPE_TIMEVAL) && ((_t) & FR_TYPE_MULTI), \
                        _p, (_mismatch_timeval_m) 0), \
+       void *          : __builtin_choose_expr((FR_BASE_TYPE(_t) == FR_TYPE_VOID) && !((_t) & FR_TYPE_MULTI), \
+                       _p, (_mismatch_void) 0), \
+       void **         : __builtin_choose_expr((FR_BASE_TYPE(_t) == FR_TYPE_VOID) && ((_t) & FR_TYPE_MULTI), \
+                       _p, (_mismatch_void_m) 0), \
        default: (conf_type_mismatch)0))))))
 
 #  define FR_CONF_OFFSET(_n, _t, _s, _f) \
@@ -267,6 +273,7 @@ _Generic((_ct), \
  *  user-supplied variables.
  */
 #define FR_TYPE_SUBSECTION     102
+#define FR_TYPE_VOID           103
 
 /** @name #CONF_PARSER type flags
  *
index 77f98753c2f3827fce43ff263d851c16322e37fb..b6d6818e83bb05b50b80817ff629c34cb7f486f4 100644 (file)
@@ -142,12 +142,23 @@ struct dl_module {
        dl_common_t const       *common;        //!< Symbol exported by the module, containing its public
                                                //!< functions, name and behaviour control flags.
 
-       CONF_SECTION            *conf;          //!< The module's configuration (as opposed to the instance,
+       CONF_SECTION            *conf;          //!< The module's global configuration (as opposed to the instance,
                                                //!< configuration).  May be NULL.
 
        void                    *handle;        //!< Handle returned by dlopen.
 };
 
+/** A module/inst tuple
+ *
+ * Used to pass data back from dl_submodule_parse_func
+ */
+typedef struct {
+       dl_t const              *module;
+       void                    *inst;
+       CONF_SECTION            *conf;          //!< Module's instance configuration.
+} dl_submodule_t;
+
+
 int            dl_symbol_init_cb_register(char const *symbol, dl_init_t func, void *ctx);
 
 void           dl_symbol_init_cb_unregister(char const *symbol, dl_init_t func);
@@ -156,12 +167,15 @@ int               dl_symbol_free_cb_register(char const *symbol, dl_free_t func, void *ctx);
 
 void           dl_symbol_free_cb_unregister(char const *symbol, dl_free_t func);
 
-int            dl_instance_data_alloc(void **out, TALLOC_CTX *ctx, dl_t const *module, CONF_SECTION *cs);
+int            dl_instance_data_alloc(TALLOC_CTX *ctx, void **out, dl_t const *module, CONF_SECTION *cs);
 
 dl_t const     *dl_by_symbol(void *sym);
 
 dl_t const     *dl_module(CONF_SECTION *conf, dl_t const *parent, char const *name, dl_type_t type);
 
+int            dl_submodule(TALLOC_CTX *ctx, dl_submodule_t **out,
+                            CONF_SECTION *conf, dl_t const *parent, char const *name);
+
 #ifdef __cplusplus
 }
 #endif
index a241fe1d487eab4887628b1a8a366932603ae76e..1867b72f642fb0c3a5f9534c3ac15a0fe1e686d4 100644 (file)
@@ -204,9 +204,11 @@ rlm_rcode_t        process_send_coa(int type, REQUEST *request);
 #else
 #  define MODULE_NULL_COA_FUNCS
 #endif
+extern const CONF_PARSER virtual_servers_config[];
 
+int virtual_servers_open(fr_schedule_t *sc);
+int virtual_servers_instantiate(CONF_SECTION *config);
 int virtual_servers_bootstrap(CONF_SECTION *config);
-int virtual_servers_init(fr_schedule_t *sc, CONF_SECTION *config);
 
 /*
  *     In unlang_interpret.c, but here for public consumption.
index e4b41f60502e0cba0b8ef020d4caaac8ae7b77f5..1da22c693f7f9886032c7bee770a9a5d69ccf878 100644 (file)
@@ -39,6 +39,14 @@ typedef int (*rad_listen_parse_t)(CONF_SECTION *, rad_listen_t *);
 typedef int (*rad_listen_unlang_t)(CONF_SECTION *, CONF_SECTION *);
 typedef void (*rad_listen_free_t)(rad_listen_t *);
 
+/*
+ *     @todo: fix for later
+ */
+int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this);
+int common_socket_open(CONF_SECTION *cs, rad_listen_t *this);
+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);
+
 /** Struct exported by a proto_* module
  *
  * Used to pass information common to proto_* modules to the server core,
@@ -77,73 +85,6 @@ typedef struct rad_protocol_t {
 #define TRANSPORT_UDP (1 << IPPROTO_UDP)
 #define TRANSPORT_DUAL (TRANSPORT_UDP | TRANSPORT_TCP)
 
-/*
- *     @todo: fix for later
- */
-int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this);
-int common_socket_open(CONF_SECTION *cs, rad_listen_t *this);
-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/io.h
- */
-typedef struct fr_io_op_t fr_io_op_t;
-
-/** 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 int (*fr_app_io_instantiate_t)(CONF_SECTION *io_cs, void *instance);
-
-/** 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_io_t {
-       RAD_MODULE_COMMON;                              //!< Common fields to all loadable modules.
-
-       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;
-
-/*
- *     src/lib/io/schedule.h
- */
-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_bootstrap_t              bootstrap;
-       fr_app_instantiate_t            instantiate;
-} fr_app_t;
-
-typedef int (*fr_app_subtype_instantiate_t)(CONF_SECTION *cs);
-
-/** 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_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
 }
 #endif
index 939e23669720bf03ebb65aba95c590d86d5becd9..1d6c6664e2f7d9720d133ff2cb8d362a031a5025 100644 (file)
@@ -39,21 +39,21 @@ typedef struct fr_schedule_t fr_schedule_t;
  */
 typedef struct fr_io_op_t fr_io_op_t;
 
+typedef int (*fr_app_open_t)(void *instance, fr_schedule_t *sc, CONF_SECTION *cs);
+typedef int (*fr_app_instantiate_t)(void *instance, CONF_SECTION *cs);
+typedef int (*fr_app_bootstrap_t)( void *instance, CONF_SECTION *cs);
 /** Set the next state executed by the request to be one of the application subtype's entry points
  *
  * @param[in] request  To set the next state function for.
  */
-typedef void (*fr_app_op_set_process_t)(REQUEST *request);
+typedef void (*fr_app_set_process_t)(REQUEST *request, void const *uctx);
 
-/** Public functions exported by the application
+/** Allows submodules to receive uctx data (a structure provided by their parent)
  *
+ * @param[in] instance of #fr_app_subtype_t or #fr_app_io_t.
+ * @param[in] uctx     provided by caller.
  */
- typedef struct {
-       fr_app_op_set_process_t         set_process;
- } fr_app_op_t;
-
-typedef int (*fr_app_instantiate_t)(fr_schedule_t *sc, fr_conf_section_t *cs, bool validate_config);
-typedef int (*fr_app_bootstrap_t)(fr_conf_section_t *cs);
+typedef void (*fr_app_set_uctx_t)(void *instance, void *uctx);
 
 /** Describes a new application (protocol)
  *
@@ -63,12 +63,10 @@ typedef struct {
 
        fr_app_bootstrap_t              bootstrap;
        fr_app_instantiate_t            instantiate;
-
-       fr_app_op_t                     op;             //!< Public functions for apps.
+       fr_app_open_t                   open;           //!< Open listen sockets.
+       fr_app_set_process_t            set_process;
 } fr_app_t;
 
-typedef int (*fr_app_subtype_instantiate_t)(fr_conf_section_t *cs);
-
 /** Public structure describing an application (protocol) specialisation
  *
  * Some protocols perform multiple distinct functions, and use
@@ -77,20 +75,12 @@ typedef int (*fr_app_subtype_instantiate_t)(fr_conf_section_t *cs);
 typedef struct fr_app_subtype_t {
        RAD_MODULE_COMMON;                              //!< Common fields to all loadable modules.
 
-       fr_app_subtype_instantiate_t    instantiate;    //!< Perform any config validation, and per-instance work.
+       fr_app_bootstrap_t              bootstrap;
+       fr_app_instantiate_t            instantiate;
+       fr_app_set_uctx_t               set_uctx;       //!< Allow the submodule to receive data from the main module.
        fr_io_process_t                 process;        //!< Entry point into the protocol subtype's state machine.
 } fr_app_subtype_t;
 
-/** 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 int (*fr_app_io_instantiate_t)(fr_conf_section_t *io_cs, void *instance);
-
 /** Public structure describing an I/O path for a protocol
  *
  * This structure is exported by I/O modules e.g. proto_radius_udp.
@@ -98,7 +88,9 @@ typedef int (*fr_app_io_instantiate_t)(fr_conf_section_t *io_cs, void *instance)
 typedef struct fr_app_io_t {
        RAD_MODULE_COMMON;                              //!< Common fields to all loadable modules.
 
-       fr_app_io_instantiate_t         instantiate;    //!< Perform any config validation, and per-instance work.
+       fr_app_bootstrap_t              bootstrap;
+       fr_app_instantiate_t            instantiate;
+       fr_app_set_uctx_t               set_uctx;       //!< Allow the submodule to receive data from the main module.
        fr_io_op_t                      op;             //!< Open/close/read/write functions for sending/receiving
                                                        //!< protocol data.
 } fr_app_io_t;
index eaf929ce9e8dec220d884c4acfdb20dfb3cb1b48..58282ff9d01dc577660f03bd566fc1b72fdb71d2 100644 (file)
@@ -31,7 +31,6 @@ RCSIDH(transport_h, "$Id$")
 #include <freeradius-devel/event.h>
 #include <freeradius-devel/io/time.h>
 #include <freeradius-devel/io/channel.h>
-//#include <freeradius-devel/io/io.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -78,20 +77,20 @@ typedef struct fr_channel_t fr_channel_t;
  *
  * 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
+ * @param[in] instance the context for this function
  * @return
  *     - 0 on success
  *     - <0 on error
  */
-typedef int (*fr_io_open_t)(void *io_ctx);
+typedef int (*fr_io_open_t)(void *instance);
 
 /** 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).
+ * @param[in] instance containing the file descriptor (amongst other things).
  */
-typedef int (*fr_io_get_fd_t)(void *io_ctx);
+typedef int (*fr_io_get_fd_t)(void const *instance);
 
 /** Decode a raw packet and convert it into a request.
  *
@@ -103,15 +102,16 @@ typedef int (*fr_io_get_fd_t)(void *io_ctx);
  *  know anything about how the data will be used (e.g. authorize,
  *  authenticate, etc. for Access-Request)
  *
- * @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.
+ * @param[in] instance         the context for this function.
  * @return
  *     - <0 on error
  *     - 0 on success
  */
-typedef int (*fr_io_decode_t)(void *io_ctx, uint8_t *const data, size_t data_len, REQUEST *request);
+typedef int (*fr_io_decode_t)(void const *instance, REQUEST *request, uint8_t *const data, size_t data_len);
 
 /** Encode data from a REQUEST into a raw packet.
  *
@@ -123,15 +123,16 @@ typedef int (*fr_io_decode_t)(void *io_ctx, uint8_t *const data, size_t data_len
  *  know anything about how the data will be used (e.g. reject delay
  *  on Access-Reject)
  *
- * @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
+ * @param[in] instance         the context for this function.
  * @return
  *     - <0 on error
  *     - >=0 length of the encoded data in the buffer, will be <=buffer_len
  */
-typedef ssize_t (*fr_io_encode_t)(void *io_ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len);
+typedef ssize_t (*fr_io_encode_t)(void const *instance, REQUEST *request, uint8_t *buffer, size_t buffer_len);
 
 /** NAK a packet.
  *
@@ -148,17 +149,52 @@ typedef ssize_t (*fr_io_encode_t)(void *io_ctx, REQUEST *request, uint8_t *buffe
  *  take the appropriate action.  e.g. for RADIUS, mark a request as
  *  "do not respond", even if duplicates come in.
  *
- * @param[in] io_ctx           the context for this function.
+ * @param[in] instance         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_io_nak_t)(void const *io_ctx, uint8_t *const packet, size_t packet_len,
+typedef size_t (*fr_io_nak_t)(void const *instance, uint8_t *const packet, size_t packet_len,
                              uint8_t *reply, size_t reply_len);
 
-/** Read/write from a socket.
+/** Read from a socket.
+ *
+ *  If the socket is a datagram socket, then the function can read or
+ *  write directly into the buffer.  Stream sockets are a bit more complicated.
+ *
+ *  A stream reader can read data into the buffer, and be guaranteed
+ *  that the data will not change in between subsequent calls to the
+ *  read routine.
+ *
+ *  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 instance.  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.
+ *
+ *  i.e. this write() function is a way for the network thread to
+ *  write packets to the transport context.  The data may or may not
+ *  go out to the network right away.
+ *
+ *  If the writer returns LESS THAN buffer_len, that's a special case
+ *  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] instance         the context for this function
+ * @param[out] packet_ctx      Where to write a newly allocated packet_ctx struct containing request specific data.
+ * @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_io_data_read_t)(void const *instance, void **packet_ctx, uint8_t *buffer, size_t buffer_len);
+
+/** Write a socket.
  *
  *  If the socket is a datagram socket, then the function can read or
  *  write directly into the buffer.  Stream sockets are a bit more complicated.
@@ -170,7 +206,7 @@ typedef size_t (*fr_io_nak_t)(void const *io_ctx, uint8_t *const packet, size_t
  *  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 io_ctx.  It MUST then have a
+ *  internal buffer, usually in instance.  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.
@@ -183,14 +219,15 @@ typedef size_t (*fr_io_nak_t)(void const *io_ctx, uint8_t *const packet, size_t
  *  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] 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
+ * @param[in] instance         the context for this function
+ * @param[in] packet_ctx       Request specific data.
  * @return
  *     - <0 on error
  *     - >=0 length of the data read or written.
  */
-typedef ssize_t (*fr_io_data_t)(void *io_ctx, uint8_t *buffer, size_t buffer_len);
+typedef ssize_t (*fr_io_data_write_t)(void const *instance, void *packet_ctx, uint8_t *buffer, size_t buffer_len);
 
 /**  Handle a close or error on the socket.
  *
@@ -199,12 +236,12 @@ typedef ssize_t (*fr_io_data_t)(void *io_ctx, uint8_t *buffer, size_t buffer_len
  *  before "close".  On normal finish, the "close" function will be
  *  called.
  *
- * @param[in] io_ctx           the context for this function
+ * @param[in] instance         the context for this function
  * @return
  *     - 0 on success
  *     - <0 on error
  */
-typedef int (*fr_io_signal_t)(void *io_ctx);
+typedef int (*fr_io_signal_t)(void const *instance);
 
 /** Process a request through the transport async state machine.
  *
@@ -219,51 +256,17 @@ 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_get_fd_t          fd;             //!< Return the file descriptor from the instance.
+       fr_io_data_read_t       read;           //!< Read from a socket to a data buffer
+       fr_io_data_write_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 struct fr_io fr_io_t;
-struct fr_io {
-       void                    *ctx;           //!< I/O path specific context.
-       fr_io_op_t const        *op;            //!< I/O path functions.
-       void                    *parent;        //!< Parent usually the proto_* ctx.
-};
-
-#ifndef _FR_RADIUSD_H
-/**
- *     Minimal data structure to use the new code.
- */
-struct rad_request {
-       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_time_t               recv_time;
-       fr_time_t               *original_recv_time;
-       fr_event_list_t         *el;
-       fr_io_process_t         process_async;
-       fr_time_tracking_t      tracking;
-       fr_channel_t            *channel;
-
-       uint32_t                priority;
-       fr_io_t const           *io;            //!< How we received this request,
-                                               //!< and how we'll send the reply.
-};
-#endif
-
 #ifdef __cplusplus
 }
 #endif
index abca1ecfac9b4477f954859e3d57267836ba8986..0b09ca50a37a4d805c54c89207262c433acd2475 100644 (file)
@@ -13,8 +13,8 @@
  *  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_LISTEN_H
-#define _FR_LISTEN_H
+#ifndef _FR_IO_LISTEN_H
+#define _FR_IO_LISTEN_H
 #include <freeradius-devel/io/io.h>
 #include <freeradius-devel/io/application.h>
 
 typedef struct fr_io fr_io_t;
 struct fr_io {
        fr_io_op_t const        *op;            //!< I/O path functions.
-       void const              *ctx;           //!< I/O path specific context.
-
-       fr_app_op_t const       *app_op;        //!< Application functions.
-       void const              *app_ctx;       //!< Application context.
+       void                    *ctx;           //!< I/O path specific context.
 
        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_app_set_process_t    set_process;    //!< Set the state machine entry point for a request.
+       void const              *app_ctx;
 };
 
 #ifndef _FR_RADIUSD_H
index 4d946b38885004933c5a9b50bf83fec3bb1faf67..b60e4e7c8305590028a04a2c24bdb182d6dd6579 100644 (file)
@@ -33,6 +33,7 @@ RCSID("$Id$")
 #include <freeradius-devel/io/control.h>
 #include <freeradius-devel/io/worker.h>
 #include <freeradius-devel/io/network.h>
+#include <freeradius-devel/io/listen.h>
 
 typedef struct fr_network_worker_t {
        int                     heap_id;                //!< workers are in a heap
@@ -361,7 +362,7 @@ static void fr_network_read(UNUSED fr_event_list_t *el, int sockfd, void *ctx)
         *      network side knows that it needs to close the
         *      connection.
         */
-       data_size = s->io->op->read(s->io->ctx, cd->m.data, cd->m.rb_size);
+       data_size = s->io->op->read(s->io->ctx, &cd->packet_ctx, cd->m.data, cd->m.rb_size);
        if (data_size == 0) {
                fr_log(nr->log, L_DBG_ERR, "got no data from transport read");
 
@@ -776,7 +777,7 @@ void fr_network(fr_network_t *nr)
                 *      the reply is a NAK, don't write it to the
                 *      network.
                 */
-               rcode = io->op->write(io->ctx, cd->m.data, cd->m.data_size);
+               rcode = io->op->write(io->ctx, cd->packet_ctx, cd->m.data, cd->m.data_size);
                if (rcode < 0) {
                        fr_network_socket_t my_socket, *s;
 
index 4e82d760470f367aafe6013cae9ec2d33f76a080..4521e5499cdbe0d9a18f070a2677229048406490 100644 (file)
@@ -36,14 +36,14 @@ extern "C" {
 typedef struct fr_schedule_t fr_schedule_t;
 typedef int (*fr_schedule_thread_instantiate_t)(void *ctx);
 
-fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_log_t *log, int max_inputs, int max_workers,
-                                 fr_schedule_thread_instantiate_t worker_thread_instantiate,
-                                 void *worker_thread_ctx);
+fr_schedule_t          *fr_schedule_create(TALLOC_CTX *ctx, fr_log_t *log, int max_inputs, int max_workers,
+                                           fr_schedule_thread_instantiate_t worker_thread_instantiate,
+                                           void *worker_thread_ctx);
 /* schedulers are async, so there's no fr_schedule_run() */
-int fr_schedule_destroy(fr_schedule_t *sc);
-int fr_schedule_get_worker_kq(fr_schedule_t *sc);
+int                    fr_schedule_destroy(fr_schedule_t *sc);
+int                    fr_schedule_get_worker_kq(fr_schedule_t *sc);
 
-fr_network_t *fr_schedule_socket_add(fr_schedule_t *sc, fr_io_t const *io) CC_HINT(nonnull);
+fr_network_t           *fr_schedule_socket_add(fr_schedule_t *sc, fr_io_t const *io) CC_HINT(nonnull);
 
 #ifdef __cplusplus
 }
index 0ab8d92e8db2a3e507eb8b4201543ce2cf9d2729..30bf73af1536e8beffa44beedaf2c0bb902464cd 100644 (file)
@@ -64,6 +64,7 @@ RCSID("$Id$")
 #include <freeradius-devel/io/worker.h>
 #include <freeradius-devel/io/channel.h>
 #include <freeradius-devel/io/message.h>
+#include <freeradius-devel/io/listen.h>
 
 /**
  *  Track things by priority and time.
@@ -413,7 +414,7 @@ static void fr_worker_send_reply(fr_worker_t *worker, REQUEST *request, size_t s
        if (size) {
                ssize_t encoded;
 
-               encoded = request->io->op->encode(request->io->ctx, request, reply->m.data, reply->m.rb_size);
+               encoded = request->io->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;
@@ -695,7 +696,7 @@ static REQUEST *fr_worker_get_request(fr_worker_t *worker, fr_time_t now)
         *
         *      Note that this also sets the "process_async" function.
         */
-       rcode = io->op->decode(io->ctx, cd->m.data, cd->m.data_size, request);
+       rcode = io->decode(io->ctx, request, cd->m.data, cd->m.data_size);
        if (rcode < 0) {
                fr_log(worker->log, L_DBG, "\t%sFAILED decode of request %"PRIu64, worker->name, request->number);
                talloc_free(ctx);
index f8865315cfa12f3517ac858538cd5fb159eeb71b..dd879116a0a38af04790553c4e5ba9c58af32f97 100644 (file)
@@ -846,22 +846,23 @@ static void cf_section_parse_warn(CONF_SECTION *cs)
  * @param[in] ctx              to allocate any additional structures under.
  * @param[out] out             pointer to a struct/pointer to fill with data.
  * @param[in] cs               to parse.
- * @param[in] name             of subsection to parse.
- * @param[in] type             flags.
- * @param[in] rules            to push for subsections.
- * @param[in] subcs_size       size of subsection structures to allocate.
+ * @param[in] rule             to parse the subcs with.
  * @return
  *     - 0 on success.
  *     - -1 on general error.
  *     - -2 if a deprecated #CONF_ITEM was found.
  */
-static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs,
-                              char const *name, fr_type_t type,
-                              CONF_PARSER const *rules, size_t subcs_size)
+static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs, CONF_PARSER const *rule)
 {
-       CONF_SECTION    *subcs = NULL;
-       int             count = 0, i, ret;
-       uint8_t         **array;
+       CONF_SECTION            *subcs = NULL;
+       int                     count = 0, i, ret;
+
+       char const              *name = rule->name;
+       fr_type_t               type = rule->type;
+       size_t                  subcs_size = rule->subcs_size;
+       CONF_PARSER const       *rules = rule->subcs;
+
+       uint8_t                 **array;
 
        rad_assert(type & FR_TYPE_SUBSECTION);
 
@@ -874,7 +875,12 @@ static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs,
        if (!(type & FR_TYPE_MULTI)) {
                uint8_t *buff;
 
+               /*
+                *      Add any rules, so the func can just call cf_section_parse
+                *      if it wants to continue after doing its stuff.
+                */
                if (cf_section_rules_push(subcs, rules) < 0) return -1;
+               if (rule->func) return rule->func(ctx, out, cf_section_to_item(cs), rule);
 
                /*
                 *      FIXME: We shouldn't allow nested structures like this.
@@ -921,10 +927,22 @@ static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs,
                MEM(buff = talloc_zero_array(array, uint8_t, subcs_size));
                array[i] = buff;
 
+               /*
+                *      Add any rules, so the func can just call cf_section_parse
+                *      if it wants to continue after doing its stuff.
+                */
                if (cf_section_rules_push(subcs, rules) < 0) {
                        talloc_free(array);
                        return -1;
                }
+               if (rule->func) {
+                       ret = rule->func(ctx, buff, cf_section_to_item(cs), rule);
+                       if (ret < 0) {
+                               talloc_free(array);
+                               return ret;
+                       }
+                       continue;
+               }
 
                ret = cf_section_parse(buff, buff, subcs);
                if (ret < 0) {
@@ -972,24 +990,22 @@ int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
                 */
                if (cf_section_parse_init(cs, base, rule) < 0) return -1;
 
+               if (rule->data) {
+                       data = rule->data; /* prefer this. */
+               } else if (base) {
+                       data = ((uint8_t *)base) + rule->offset;
+               } else {
+                       data = NULL;
+               }
+
                /*
                 *      Handle subsections specially
                 */
                if (FR_BASE_TYPE(rule->type) == FR_TYPE_SUBSECTION) {
-                       if (cf_subsection_parse(ctx, (uint8_t *)base + rule->offset, cs,
-                                               rule->name, rule->type,
-                                               rule->subcs, rule->subcs_size) < 0) goto finish;
+                       if (cf_subsection_parse(ctx, data, cs, rule) < 0) goto finish;
                        continue;
                } /* else it's a CONF_PAIR */
 
-               if (rule->data) {
-                       data = rule->data; /* prefer this. */
-               } else if (base) {
-                       data = ((uint8_t *)base) + rule->offset;
-               } else if (!rad_cond_assert(0)) {
-                       ret = -1;
-                       goto finish;
-               }
 
                /*
                 *      Get pointer to where we need to write out
index 603494a60c37f2c2901b2e7326cd0d74a52dbfd4..df97c6c2700e64485cce87fda175b2faf73ad9b7 100644 (file)
@@ -390,15 +390,15 @@ static void *dl_by_name(char const *name)
 
 /** Allocate module instance data, and parse the module's configuration
  *
- * @param[out] data    Module's private data, the result of parsing the config.
  * @param[in] ctx      to allocate this instance data in.
+ * @param[out] data    Module's private data, the result of parsing the config.
  * @param[in] module   to alloc instance data for.
  * @param[in] cs       module's config section.
  * @return
  *     - 0 on success.
  *     - -1 on failure.
  */
-int dl_instance_data_alloc(void **data, TALLOC_CTX *ctx, dl_t const *module, CONF_SECTION *cs)
+int dl_instance_data_alloc(TALLOC_CTX *ctx, void **data, dl_t const *module, CONF_SECTION *cs)
 {
        *data = NULL;
 
@@ -767,6 +767,49 @@ dl_t const *dl_module(CONF_SECTION *conf, dl_t const *parent, char const *name,
        return dl_module;
 }
 
+/** Load a submodule and parse its #CONF_SECTION in one operation
+ *
+ * @note This is here as a convenience function for wrapping by #cf_parse_t callbacks.
+ *
+ * @param[in] ctx      to allocate structures in.
+ * @param[out] out     where to write our #dl_submodule_t containing the module
+ *                     handle and instance.
+ * @param[in] conf     section to parse.
+ * @param[in] parent   module.
+ * @param[in] name     of the submodule to load .e.g. 'udp' for 'proto_radius_udp'
+ *                     if the parent were 'proto_radius'.
+
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int dl_submodule(TALLOC_CTX *ctx, dl_submodule_t **out,
+                CONF_SECTION *conf, dl_t const *parent, char const *name)
+{
+       dl_submodule_t  *submodule = talloc_zero(ctx, dl_submodule_t);
+
+       /*
+        *      Find a section with the same name as the submodule
+        */
+       submodule->module = dl_module(conf, parent, name, DL_TYPE_SUBMODULE);
+       if (!submodule->module) {
+               cf_log_err(conf, "Failed finding submodule library for '%s_%s'", parent->name, name);
+               return -1;
+       }
+
+       /*
+        *      ctx here is the main module's instance data
+        */
+       if (dl_instance_data_alloc(submodule, &submodule->inst, submodule->module, conf) < 0) {
+               cf_log_perr(conf, "Failed allocating instance data for '%s_%s'", parent->name, name);
+               return -1;
+       }
+
+       *out = submodule;
+
+       return 0;
+}
+
 /** Initialise structures needed by the dynamic linker
  *
  */
index 30046b574657c8f57deadaffba8571f13c45c762..4bc030253ca87d2483b2eb023b9ee840677db03e 100644 (file)
@@ -893,6 +893,7 @@ do {\
         *      radiusd.conf, the other configuration files exist.
         */
        if (cf_section_rules_push(cs, server_config) < 0) return -1;
+//     if (cf_section_rules_push(cs, virtual_servers_config) < 0) return -1;
        if (cf_section_parse(NULL, NULL, cs) < 0) return -1;
 
        /*
index 20415a81b07ae6e346be8757e58d717ab2f3ccc7..29dd86bfbc0f692bc883daf745f0f5362e6f11ef 100644 (file)
@@ -891,7 +891,7 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION *
        /*
         *      Parse the modules configuration.
         */
-       if (dl_instance_data_alloc(&instance->data, instance, instance->handle, cs) < 0) {
+       if (dl_instance_data_alloc(instance, &instance->data, instance->handle, cs) < 0) {
                talloc_free(instance);
                return NULL;
        }
index 2478b87d57c8f4622d19b528332512ba33b4bd1c..b1077618ded71f8416f8e2dde2c099f1a0f31568 100644 (file)
@@ -560,7 +560,12 @@ int main(int argc, char *argv[])
        /*
         *      And then load the virtual servers.
         */
-       if (virtual_servers_init(sc, main_config.config) < 0) exit(EXIT_FAILURE);
+       if (virtual_servers_instantiate(main_config.config) < 0) exit(EXIT_FAILURE);
+
+       /*
+        *      If this isn't just a config check, open the sockets
+        */
+       if (!check_config && virtual_servers_open(sc) < 0) exit(EXIT_FAILURE);
 
        /*
         *      Initialise the SNMP stats structures
index 5bd98d7f44ade8b926de6e64372526607e74fce6..afd2995add2fe97bc52ace65f26c40fe044fc35b 100644 (file)
@@ -896,7 +896,7 @@ int main(int argc, char *argv[])
        /*
         *      And then load the virtual servers.
         */
-       if (virtual_servers_init(NULL, main_config.config) < 0) goto exit_failure;
+       if (virtual_servers_instantiate(main_config.config) < 0) goto exit_failure;
 
        state = fr_state_tree_init(NULL, main_config.max_requests * 2, 10);
 
index fda4a27b11dffa089f5253eb99edd2402cb0c71d..223e26a0b06367181901d10b11d36327a505b65e 100644 (file)
@@ -32,6 +32,8 @@ RCSID("$Id$")
 #include <freeradius-devel/interpreter.h>
 #include <freeradius-devel/parser.h>
 #include <freeradius-devel/protocol.h>
+#include <freeradius-devel/dl.h>
+#include <freeradius-devel/io/application.h>
 
 static int default_component_results[MOD_COUNT] = {
        RLM_MODULE_REJECT,      /* AUTH */
@@ -49,6 +51,87 @@ static int default_component_results[MOD_COUNT] = {
 #endif
 };
 
+typedef struct {
+       dl_submodule_t          *proto_module;  //!< The proto_* module for a listen section.
+       fr_app_t const          *app;           //!< Easy access to the exported struct.
+} fr_virtual_listen_t;
+
+typedef struct {
+       char const              *namespace;     //!< Protocol namespace
+       fr_virtual_listen_t     **listener;     //!< Listeners in this virtual server.
+} fr_virtual_server_t;
+
+typedef struct {
+       fr_virtual_server_t     **server;       //!< All the servers in the server.
+} fr_virtual_t;
+
+/** Top level structure holding all virtual servers
+ *
+ * Blame LLDB for forcing the stupid name
+ */
+static fr_virtual_t *virtual_root;
+static int listen_parse(TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, CONF_PARSER const *rule);
+
+static const CONF_PARSER server_config[] = {
+       { FR_CONF_OFFSET("namespace", FR_TYPE_STRING, fr_virtual_server_t, namespace) },
+       { FR_CONF_OFFSET("listen", FR_TYPE_SUBSECTION | FR_TYPE_MULTI, fr_virtual_server_t, listener), \
+                        .subcs_size = sizeof(fr_virtual_listen_t), .func = listen_parse},
+
+       CONF_PARSER_TERMINATOR
+};
+
+const CONF_PARSER virtual_servers_config[] = {
+       { FR_CONF_POINTER("server", FR_TYPE_SUBSECTION | FR_TYPE_MULTI, &virtual_root), \
+                         .subcs_size = sizeof(virtual_root), .subcs = (void const *) server_config},
+
+       CONF_PARSER_TERMINATOR
+};
+
+/** dl_open a proto_* module
+ *
+ * @param[in] ctx      to allocate data in (instance of proto_radius).
+ * @param[out] out     Where to our listen configuration.  Is a #fr_virtual_listen_t structure.
+ * @param[in] ci       #CONF_PAIR specifying the name of the type module.
+ * @param[in] rule     unused.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+static int listen_parse(UNUSED TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
+{
+       fr_virtual_listen_t     *listen = out;  /* Pre-allocated for us */
+       CONF_SECTION            *listen_cs = cf_item_to_section(ci);
+       CONF_SECTION            *server = cf_item_to_section(cf_parent(ci));
+       CONF_PAIR               *namespace;
+       dl_t const              *module;
+
+       talloc_set_type(listen, fr_virtual_listen_t);
+
+       namespace = cf_pair_find(server, "namespace");
+       if (!namespace) return 0;       /* Old style server, skip */
+
+       module = dl_module(listen_cs, NULL, cf_pair_value(namespace), DL_TYPE_PROTO);
+       if (!module) {
+               cf_log_perr(listen_cs, "Failed loading proto module");
+               return -1;
+       }
+
+       MEM(listen->proto_module = talloc_zero(listen, dl_submodule_t));
+
+       if (dl_instance_data_alloc(listen, &listen->proto_module->inst, module, listen_cs) < 0) {
+               cf_log_perr(listen_cs, "Failed parsing config");
+               talloc_free(listen);
+               return -1;
+       }
+
+       listen->proto_module->module = module;
+       listen->proto_module->conf = listen_cs;
+
+       *(void **)out = listen;
+
+       return 0;
+}
+
 /**
  */
 static rlm_rcode_t module_method_call(rlm_components_t comp, int idx, REQUEST *request)
@@ -236,44 +319,6 @@ rlm_rcode_t process_send_coa(int send_coa_type, REQUEST *request)
 }
 #endif
 
-static int define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *name)
-{
-       fr_value_box_t  value = { .type = FR_TYPE_UINT32 };
-       fr_dict_enum_t  *dval;
-
-       /*
-        *      If the value already exists, don't
-        *      create it again.
-        */
-       dval = fr_dict_enum_by_alias(NULL, da, name);
-       if (dval) {
-               if (dval->value == 0) {
-                       ERROR("The dictionaries must not define VALUE %s %s 0", da->name, name);
-                       return -1;
-               }
-               return 0;
-       }
-
-       /*
-        *      Create a new unique value with a
-        *      meaningless number.  You can't look at
-        *      it from outside of this code, so it
-        *      doesn't matter.  The only requirement
-        *      is that it's unique.
-        */
-       do {
-               value.vb_uint32 = (fr_rand() & 0x00ffffff) + 1;
-       } while (fr_dict_enum_by_value(NULL, da, &value));
-
-       cf_log_debug(cs, "Creating %s = %s", da->name, name);
-       if (fr_dict_enum_add_alias(da, name, &value, true, false) < 0) {
-               ERROR("%s", fr_strerror());
-               return -1;
-       }
-
-       return 0;
-}
-
 /*
  *     Load a sub-module list, as found inside an Auth-Type foo {}
  *     block
@@ -358,8 +403,7 @@ static int virtual_servers_compile(CONF_SECTION *cs)
        char const *name = cf_section_name2(cs);
        CONF_PAIR *cp;
 
-       cf_log_info(cs, "server %s { # from file %s",
-                   name, cf_filename(cs));
+       cf_log_info(cs, "server %s { # from file %s", name, cf_filename(cs));
 
        cp = cf_pair_find(cs, "namespace");
        if (cp) {
@@ -443,6 +487,44 @@ static int virtual_servers_compile(CONF_SECTION *cs)
        return 0;
 }
 
+static int define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *name)
+{
+       fr_value_box_t  value = { .type = FR_TYPE_UINT32 };
+       fr_dict_enum_t  *dval;
+
+       /*
+        *      If the value already exists, don't
+        *      create it again.
+        */
+       dval = fr_dict_enum_by_alias(NULL, da, name);
+       if (dval) {
+               if (dval->value == 0) {
+                       ERROR("The dictionaries must not define VALUE %s %s 0", da->name, name);
+                       return -1;
+               }
+               return 0;
+       }
+
+       /*
+        *      Create a new unique value with a
+        *      meaningless number.  You can't look at
+        *      it from outside of this code, so it
+        *      doesn't matter.  The only requirement
+        *      is that it's unique.
+        */
+       do {
+               value.vb_uint32 = (fr_rand() & 0x00ffffff) + 1;
+       } while (fr_dict_enum_by_value(NULL, da, &value));
+
+       cf_log_debug(cs, "Creating %s = %s", da->name, name);
+       if (fr_dict_enum_add_alias(da, name, &value, true, false) < 0) {
+               ERROR("%s", fr_strerror());
+               return -1;
+       }
+
+       return 0;
+}
+
 static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
 {
        fr_dict_attr_t const *da;
@@ -503,189 +585,166 @@ static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
        return true;
 }
 
-
-/*
- *     Bootstrap Auth-Type, etc.
+/** Open all the listen sockets
+ *
+ * @param[in] sc       Scheduler to add I/O paths to.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
  */
-int virtual_servers_bootstrap(CONF_SECTION *config)
+int virtual_servers_open(fr_schedule_t *sc)
 {
-       CONF_SECTION *cs = NULL;
-       char const *server_name;
-
-       if (!cf_section_find(config, "server", CF_IDENT_ANY)) {
-               ERROR("No virtual servers found");
-               return -1;
-       }
-
-       /*
-        *      Bootstrap global listeners.
-        */
-       while ((cs = cf_section_find_next(config, cs, "listen", NULL))) {
-               if (cf_pair_find(cs, "namespace") != NULL) {
-                       main_config.namespace = true;
-                       continue;
-               }
+       size_t i, server_cnt = virtual_root ? talloc_array_length(virtual_root->server) : 0;
 
-               if (listen_bootstrap(config, cs, NULL) < 0) return -1;
-       }
+       DEBUG2("%s: #### Opening listener interfaces ####", main_config.name);
 
-       cs = NULL;
-       while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) {
-               CONF_ITEM *ci;
-               CONF_SECTION *subcs;
-               CONF_PAIR *cp;
+       for (i = 0; i < server_cnt; i++) {
+               fr_virtual_listen_t     **listener;
+               size_t                  j, listen_cnt;
 
-               server_name = cf_section_name2(cs);
-               if (!server_name) {
-                       cf_log_err(cs, "server sections must have a name");
-                       return -1;
-               }
+               if (!virtual_root->server[i]) continue; /* Skip old style */
 
-               /*
-                *      Check for duplicates.
-                */
-               subcs = cf_section_find(config, "server", server_name);
-               if (subcs && (subcs != cs)) {
-                       ERROR("Duplicate virtual server \"%s\", in file %s:%d and file %s:%d",
-                             server_name,
-                             cf_filename(cs),
-                             cf_lineno(cs),
-                             cf_filename(subcs),
-                             cf_lineno(subcs));
-                       return -1;
-               }
+               listener = virtual_root->server[i]->listener;
+               listen_cnt = talloc_array_length(listener);
 
-               /*
-                *      New-style virtual servers are special.
-                */
-               cp = cf_pair_find(cs, "namespace");
-               if (cp) {
-                       char const *value;
-                       dl_t const *module;
-                       fr_app_t const *app;
+               for (j = 0; j < listen_cnt; j++) {
+                       fr_virtual_listen_t *listen = listener[j];
 
-                       value = cf_pair_value(cp);
-                       if (!value) {
-                               cf_log_err(cs, "Cannot have empty namespace");
+                       if (listen->app->open &&
+                           listen->app->open(listen->proto_module->inst, sc, listen->proto_module->conf) < 0) {
+                               cf_log_err(listen->proto_module->conf, "Opening I/O interface failed");
                                return -1;
                        }
+               }
 
-                       if (strcmp(value, "radius") != 0) {
-                               cf_log_err(cs, "Unknown namespace '%s'", value);
-                               return -1;
-                       }
+       }
 
-                       module = dl_module(cs, NULL, value, DL_TYPE_PROTO);
-                       if (!module) {
-                               cf_log_err(cs, "Failed to find library for 'namespace = %s'", value);
-                               return -1;
-                       }
+       return 0;
+}
 
-                       app = (fr_app_t const *) module->common;
+/** Instantiate all the virtual servers
+ *
+ * @param[in] config   section containing all the virtual servers.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int virtual_servers_instantiate(CONF_SECTION *config)
+{
+       size_t i, server_cnt = virtual_root ? talloc_array_length(virtual_root->server) : 0;
 
-                       if (app->bootstrap && (app->bootstrap(cs) < 0)) {
-                               cf_log_err(cs, "Failed to bootstrap library for 'namespace = %s'", value);
-                               return -1;
-                       }
+       CONF_SECTION *cs = NULL;
 
-                       if (!app->instantiate) {
-                               cf_log_err(cs, "Failed to find initialization function for 'transport = %s'",
-                                             value);
-                               return -1;
-                       }
+       DEBUG2("%s: #### Instantiating listeners ####", main_config.name);
 
-                       cf_data_add(cs, module, "app", false);
-                       continue;
-               }
+       /*
+        *      Load all of the virtual servers.
+        */
+       while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) {
+               /*
+                *      Skip old-style virtual servers.
+                */
+               if (cf_pair_find(cs, "namespace")) continue;
 
-               for (ci = cf_item_next(cs, NULL);
-                    ci != NULL;
-                    ci = cf_item_next(cs, ci)) {
-                       rlm_components_t comp;
-                       char const *name1;
+               if (virtual_servers_compile(cs) < 0) return -1;
+       }
 
-                       if (cf_item_is_pair(ci)) {
-                               cf_log_err(ci, "Cannot set variables inside of a virtual server.");
-                               return -1;
-                       }
+       for (i = 0; i < server_cnt; i++) {
+               fr_virtual_listen_t     **listener;
+               size_t                  j, listen_cnt;
 
-                       if (!cf_item_is_section(ci)) continue;
+               if (!virtual_root->server[i]) continue; /* Skip old style */
 
-                       subcs = cf_item_to_section(ci);
-                       name1 = cf_section_name1(subcs);
+               listener = virtual_root->server[i]->listener;
+               listen_cnt = talloc_array_length(listener);
 
-                       if (strcmp(name1, "listen") == 0) {
-                               if (listen_bootstrap(cs, subcs, server_name) < 0) return -1;
-                               continue;
-                       }
+               for (j = 0; j < listen_cnt; j++) {
+                       fr_virtual_listen_t *listen = listener[j];
 
-                       /*
-                        *      See if it's a RADIUS section.
-                        */
-                       for (comp = 0; comp < MOD_COUNT; ++comp) {
-                               if (strcmp(name1, section_type_value[comp].section) == 0) {
-                                       if (!virtual_server_define_types(subcs, comp)) return -1;
-                               }
+                       if (listen->app->instantiate &&
+                           listen->app->instantiate(listen->proto_module->inst, listen->proto_module->conf) < 0) {
+                               cf_log_err(listen->proto_module->conf, "Instantiate failed");
+                               return -1;
                        }
-               } /* loop over things inside of a virtual server */
-       } /* loop over virtual servers */
+               }
+
+       }
 
        return 0;
 }
 
-/*
- *     Load all of the virtual servers.
+/** Load protocol modules and call their bootstrap methods
+ *
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
  */
-int virtual_servers_init(fr_schedule_t *sc, CONF_SECTION *config)
+int virtual_servers_bootstrap(CONF_SECTION *config)
 {
+       size_t i, server_cnt = virtual_root ? talloc_array_length(virtual_root->server) : 0;
+
        CONF_SECTION *cs = NULL;
 
-       DEBUG2("%s: #### Loading Virtual Servers ####", main_config.name);
+       DEBUG2("%s: #### Bootstrapping listeners ####", main_config.name);
 
        /*
         *      Load all of the virtual servers.
         */
        while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) {
-               char const *name2;
+               CONF_SECTION *subcs = NULL;
+               char const *server_name;
 
-               name2 = cf_section_name2(cs);
+               server_name = cf_section_name2(cs);
+               if (!server_name) {
+                       cf_log_err(cs, "server sections must have a name");
+                       return -1;
+               }
 
                /*
-                *      Skip new-style virtual servers.
+                *      Skip old-style virtual servers.
                 */
-               if (cf_pair_find(cs, "namespace")) {
-                       dl_t const *module;
-                       fr_app_t const *app;
-
-                       if (!sc) continue;
+               if (cf_pair_find(cs, "namespace")) continue;
 
-                       module = cf_data_value(cf_data_find(cs, dl_t, "app"));
-                       if (!module) continue;
+               while ((subcs = cf_section_next(cs, subcs))) {
+                       rlm_components_t comp;
 
-                       app = (fr_app_t const *) module->common;
+                       if (strcmp(cf_section_name1(subcs), "listen") == 0) {
+                               if (listen_bootstrap(cs, subcs, server_name) < 0) return -1;
+                               continue;
+                       }
 
                        /*
-                        *      @todo - create a scheduler
+                        *      See if it's a RADIUS section.
                         */
+                       for (comp = 0; comp < MOD_COUNT; ++comp) {
+                               if (strcmp(cf_section_name1(subcs), section_type_value[comp].section) == 0) {
+                                       if (!virtual_server_define_types(subcs, comp)) return -1;
+                               }
+                       }
+               }
+       }
 
-                       cf_log_info(cs, "server %s { # from file %s",
-                                   name2, cf_filename(cs));
-                       cf_log_info(cs, "  namespace = %s", app->name);
+       for (i = 0; i < server_cnt; i++) {
+               fr_virtual_listen_t     **listener;
+               size_t                  j, listen_cnt;
 
-                       if (app->instantiate(sc, cs, check_config) < 0) {
-                               cf_log_err(cs, "Failed loading virtual server %s", name2);
-                               return -1;
-                       }
+               if (!virtual_root->server[i]) continue; /* Skip old style */
 
-                       DEBUG("  Loaded Protocol %s", module->name);
+               listener = virtual_root->server[i]->listener;
+               listen_cnt = talloc_array_length(listener);
 
-                       cf_log_info(cs, "} # server %s", name2);
-                       continue;
-               }
+               for (j = 0; j < listen_cnt; j++) {
+                       fr_virtual_listen_t *listen = listener[j];
 
-               if (virtual_servers_compile(cs) < 0) {
-                       return -1;
+                       listen->app = (fr_app_t const *)listen->proto_module->module->common;   /* For laziness */
+
+                       if (listen->app->bootstrap &&
+                           listen->app->bootstrap(listen->proto_module->inst, listen->proto_module->conf) < 0) {
+                               cf_log_err(listen->proto_module->conf, "Bootstrap failed");
+                               return -1;
+                       }
                }
+
        }
 
        return 0;
index 76ceb551c7c52c0eb0f32b47cd208819d6865692..8c6750e89f958748eeac0bf0d8f2d002e09ff15d 100644 (file)
@@ -1,8 +1,4 @@
 /*
- * proto_radius.c      RADIUS master protocol handler
- *
- * Version:    $Id$
- *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  *   the Free Software Foundation; either version 2 of the License, or
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2016 The FreeRADIUS server project
- * Copyright 2016 Alan DeKok <aland@deployingradius.com>
  */
 
+/**
+ * $Id$
+ * @file proto_radius.c
+ * @brief RAIDUS master protocol handler.
+ *
+ * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2016 Alan DeKok (aland@freeradius.org)
+ */
 #include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/protocol.h>
 #include <freeradius-devel/radius/radius.h>
+#include <freeradius-devel/io/listen.h>
 #include <freeradius-devel/io/schedule.h>
+#include <freeradius-devel/io/application.h>
 #include <freeradius-devel/rad_assert.h>
 #include "proto_radius.h"
 
-/** Decode the packet, and set the request->process function
+/** An instance of a proto_radius listen section
  *
  */
-static int mod_decode(UNUSED void *io_ctx, uint8_t *const data, UNUSED size_t data_len, REQUEST *request)
-{
-//     proto_radius_ctx_t *ctx = io_ctx;
-
-       if (fr_radius_verify(data, NULL, (uint8_t const *) "testing123", 10) < 0) {
-               return -1;
-       }
+typedef struct {
+       dl_submodule_t          *io_submodule;          //!< I/O module's instance.
+       dl_submodule_t          **type_submodule;       //!< Instance of the various types
+                                                       //!< only one instance per type allowed.
 
-       rad_assert(data[0] < FR_MAX_PACKET_CODE);
+       fr_io_t const           *io;
 
-       if (fr_radius_packet_decode(request->packet, NULL, "testing123") < 0) {
-               return -1;
-       }
-
-//     request->async_process = ctx->process[data[0]];
+       fr_app_io_t const       *app_io;                //!< Easy access to the app_io handle.
+       fr_app_subtype_t const  *app_by_code[FR_CODE_MAX];      //!< Lookup submodule by code.
+} proto_radius_ctx_t;
 
-       return 0;
-}
+extern fr_app_t proto_radius;
+static int subtype_parse(TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, CONF_PARSER const *rule);
+static int transport_parse(TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, CONF_PARSER const *rule);
 
-static ssize_t mod_encode(UNUSED void *io_ctx, UNUSED REQUEST *request, UNUSED uint8_t *buffer, UNUSED size_t buffer_len)
-{
-       return -1;
-}
+/** How to parse a RADIUS listen section
+ *
+ */
+static CONF_PARSER const proto_radius_config[] = {
+       { FR_CONF_OFFSET("type", FR_TYPE_VOID | FR_TYPE_MULTI | FR_TYPE_NOT_EMPTY, proto_radius_ctx_t, type_submodule),
+                        .dflt = "Status-Server", .func = subtype_parse },
+       { FR_CONF_OFFSET("transport", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY, proto_radius_ctx_t, io_submodule),
+                        .dflt = "udp", .func = transport_parse },
 
+       CONF_PARSER_TERMINATOR
+};
 
-/** Load the RADIUS protocol
+/** Wrapper around dl_submodule which translates the packet-type into a submodule name
  *
- * Typically loads dictionaries, etc.
+ * @param[in] ctx      to allocate data in (instance of proto_radius).
+ * @param[out] out     Where to write a dl_submodule_t containing the module handle and instance.
+ * @param[in] ci       #CONF_PAIR specifying the name of the type module.
+ * @param[in] rule     unused.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
  */
-static int mod_load(void)
+static int subtype_parse(TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
 {
+       static char const *type_lib_table[] = {
+               [FR_CODE_ACCESS_REQUEST]        = "auth",
+               [FR_CODE_ACCOUNTING_REQUEST]    = "acct",
+               [FR_CODE_COA_REQUEST]           = "coa",
+               [FR_CODE_DISCONNECT_REQUEST]    = "coa",
+               [FR_CODE_STATUS_SERVER]         = "status",
+               [FR_CODE_MAX]                   = NULL
+       };
+
+       char const              *type_str = cf_pair_value(cf_item_to_pair(ci));
+       CONF_SECTION            *parent_cs = cf_item_to_section(cf_parent(ci));
+       char const              *name;
+       fr_dict_attr_t const    *da;
+       fr_dict_enum_t const    *type_enum;
+       uint32_t                code;
+
+       da = fr_dict_attr_by_name(NULL, "Packet-Type");
+       if (!da) {
+               ERROR("Missing definiton for Packet-Type");
+               return -1;
+       }
+
        /*
-        *      @todo - load the RADIUS dictionaries
+        *      Look the type up using the Packet-Type enumv
         */
+       type_enum = fr_dict_enum_by_alias(NULL, da, type_str);
+       if (!type_enum) {
+       invalid_type:
+               cf_log_err(ci, "Invalid type \"%s\"", type_str);
+               return -1;
+       }
 
-       return 0;
+       code = type_enum->value->vb_uint32;
+       if (code >= FR_CODE_MAX) goto invalid_type;
+
+       name = type_lib_table[code];
+
+       return dl_submodule(ctx, out, cf_section_find(parent_cs, name, NULL), dl_by_symbol(&proto_radius), name);
 }
 
-/** Bootstrap the RADIUS protocol in a particular virtual server.
+/** Wrapper around dl_submodule
  *
+ * @param[in] ctx      to allocate data in (instance of proto_radius).
+ * @param[out] out     Where to write a dl_submodule_t containing the module handle and instance.
+ * @param[in] ci       #CONF_PAIR specifying the name of the type module.
+ * @param[in] rule     unused.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
  */
-static int mod_bootstrap(UNUSED CONF_SECTION *cs)
+static int transport_parse(TALLOC_CTX *ctx, void *out, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
 {
-       return 0;
-}
-
-typedef struct type2lib_t {
-       char const *type;
-       char const *lib;
-       char const *port_name;
-} type2lib_t;
-
-static const type2lib_t type2lib[] = {
-       { "Access-Request", "radius_auth", "radius" },
-       { "Accounting-Request", "radius_acct", "radius-acct" },
-       { "CoA-Request", "coa", "radius-dynauth" },
-       { "Disconnect-Request", "radius_coa", "radius-dynauth" },
-       { "Status-Server", "radius_status", NULL },
-       { NULL, NULL }
-};
-
-typedef struct pr_config_t {
-       char const      **types;
-       char const      *transport;
-} pr_config_t;
-
-
-static const CONF_PARSER mod_config[] = {
-       { FR_CONF_OFFSET("type", FR_TYPE_STRING | FR_TYPE_MULTI, pr_config_t, types), .dflt = "Status-Server" },
-       { FR_CONF_OFFSET("transport", FR_TYPE_STRING, pr_config_t, transport), .dflt = "udp" },
-
-       CONF_PARSER_PARTIAL_TERMINATOR
-};
+       char const              *name = cf_pair_value(cf_item_to_pair(ci));
+       CONF_SECTION            *parent_cs = cf_item_to_section(cf_parent(ci));
 
+       return dl_submodule(ctx, out, cf_section_find(parent_cs, name, NULL), dl_by_symbol(&proto_radius), name);
+}
 
-static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECTION *cs, char const *value)
+/** Decode the packet, and set the request->process function
+ *
+ */
+static int mod_decode(UNUSED void const *io_ctx, REQUEST *request,
+                     UNUSED uint8_t *const data, UNUSED size_t data_len)
 {
-       int i, code;
-       char const *lib, *port_name;
-       dl_t const *module;
-       fr_app_subtype_t const *app;
-
-       if (!value || !*value) {
-               cf_log_err(cs, "Must specify a value for 'type'");
-               return -1;
-       }
-
-       code = 0;
-       for (i = 1; i < FR_MAX_PACKET_CODE; i++) {
-               if (strcmp(value, fr_packet_codes[i]) == 0) {
-                       code = i;
-                       break;
-               }
-       }
-
-       if (!code) {
-               cf_log_err(cs, "Unknown 'type = %s'", value);
-               return -1;
-       }
+//     proto_radius_ctx_t *ctx = io_ctx;
 
-       if (ctx->process[i]) {
-               cf_log_err(cs, "Duplicate 'type = %s'", value);
+       if (fr_radius_verify(data, NULL, (uint8_t const *) "testing123", 10) < 0) {
                return -1;
        }
 
-       /*
-        *      Already loaded the module in this virtual
-        *      server, don't do anything more.
-        */
-       if (cf_data_find(server, dl_t, value)) return 0;
-
-       /*
-        *      Convert "Access-Request" -> "auth"
-        */
-       port_name = lib = NULL;
-       for (i = 0; type2lib[i].type != NULL; i++) {
-               if (strcmp(type2lib[i].type, value) == 0) {
-                       lib = type2lib[i].lib;
-                       port_name = type2lib[i].port_name;
-                       break;
-               }
-       }
+       rad_assert(data[0] < FR_MAX_PACKET_CODE);
 
-       if (!lib) {
-               cf_log_err(cs, "Unknown 'type = %s'", value);
+       if (fr_radius_packet_decode(request->packet, NULL, "testing123") < 0) {
                return -1;
        }
 
-       /*
-        *      Add the default port name, if it exists.
-        */
-       if (port_name) {
-               CONF_PAIR *cp;
-
-               cp = cf_pair_find(cs, "port_name");
-               if (!cp) {
-                       cp = cf_pair_alloc(cs, "port_name", port_name,
-                                          T_OP_SET, T_BARE_WORD, T_BARE_WORD);
-                       if (!cp) {
-                               cf_log_err(cs, "Out of memory");
-                               return -1;
-                       }
-
-                       (void) cf_pair_add(cs, cp);
-               }
-       }
+//     request->async_process = ctx->process[data[0]];
 
+       return 0;
+}
 
-       /*
-        *      Load the module.
-        */
-       module = dl_module(server, NULL, lib, DL_TYPE_PROTO);
-       if (!module) {
-               cf_log_err(cs, "Failed finding submodule library for 'type = %s'", value);
-               return -1;
-       }
+static ssize_t mod_encode(UNUSED void const *io_ctx, UNUSED REQUEST *request,
+                         UNUSED uint8_t *buffer, UNUSED size_t buffer_len)
+{
+       return -1;
+}
 
-       app = (fr_app_subtype_t const *) module->common;
-       ctx->process[i] = app->process;
+static void mod_set_process(UNUSED REQUEST *request, UNUSED void const *uctx)
+{
+//     proto_radius_ctx_t const *inst = talloc_get_type_abort(uctx, proto_radius_ctx_t);
 
        /*
-        *      Remember that we loaded the module in the server.
+        *      - Figure out the request code
+        *      - Look it up in the app_by_code array
+        *      - Set the state machine entry point to the one provided by the subtype
         */
-       cf_data_add(server, module, value, false);
-
-       return 0;
 }
 
-
-static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
-                         CONF_SECTION *server, CONF_SECTION *cs, char const *value,
-                         bool verify_config)
+/** Open listen sockets/connect to external event source
+ *
+ * @param[in] instance Ctx data for this application.
+ * @param[in] sc       to add our file descriptor to.
+ * @param[in] conf     Listen section parsed to give us isntance.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+static int mod_open(void *instance, fr_schedule_t *sc, CONF_SECTION *conf)
 {
-       dl_t const              *module;
-       fr_app_io_t const       *app_io;
-       CONF_SECTION            *io_cs;
-       void                    *io_ctx;
-       CONF_PAIR               *cp;
-       char                    buffer[256];
-
-       if (!value || !*value) {
-               cf_log_err(cs, "Must specify a value for 'transport'");
-               return -1;
-       }
-
-       snprintf(buffer, sizeof(buffer), "radius_%s", value);
-
-       module = dl_module(server, NULL, buffer, DL_TYPE_PROTO);
-       if (!module) {
-               cf_log_err(cs, "Failed finding submodule library for 'transport = %s'", value);
-               return -1;
-       }
+       int                     fd;
+       fr_io_t                 *io;
+       proto_radius_ctx_t      *inst = talloc_get_type_abort(instance, proto_radius_ctx_t);
 
        /*
-        *      Lookup io section.
+        *      Open the listen socket
         */
-       io_cs = cf_section_find(cs, value, NULL);
-       if (!io_cs) {
-               cf_log_err(cs, "Must contain a '%s' section", value);
-               return -1;
-       }
-
-       if (dl_instance_data_alloc(&io_ctx, NULL, module, io_cs) < 0) {
-               cf_log_perr(cs, "Failed io_ctx data");
-               return -1;
-       }
-
-       cp = cf_pair_find(cs, "port_name");
-       if (cp) {
-               cp = cf_pair_alloc(io_cs, "port_name", cf_pair_value(cp),
-                                  T_OP_SET, T_BARE_WORD, T_BARE_WORD);
-               if (!cp) {
-                       cf_log_err(cs, "Out of memory");
-                       return -1;
-               }
-
-               (void) cf_pair_add(io_cs, cp);
-       }
-
-       app_io = (fr_app_io_t const *) module->common;
-       if (app_io->instantiate(io_cs, io_ctx) < 0) {
-               cf_log_err(cs, "Failed instantiating 'transport = %s'", value);
-               talloc_free(io_ctx);
+       if (inst->app_io->op.open(inst->io_submodule->inst) < 0) {
+               cf_log_err(conf, "Failed opening I/O interface");
                return -1;
        }
 
-       if (verify_config) return 0;
-
-       if (app_io->op.open(io_ctx) < 0) {
-               cf_log_err(cs, "Failed opening I/O interface '%s'", value);
-               return -1;
-       }
+       fd = inst->app_io->op.fd(inst->io_submodule->inst);
+       rad_assert(fd >= 0);
 
        /*
-        *      Set to the function which will decode the packet and
-        *      set request->process to the correct entry.
-        *
-        *      @note - could also do this in the recv_request function?
+        *      Build the fr_io_t from the op array of the transport and its
+        *      instance data.
         */
-       ctx->transport = app_io->op;
-       ctx->transport.decode = mod_decode;
-       ctx->transport.encode = mod_encode;
+       io = talloc_zero(inst, fr_io_t);
 
+       io->ctx = inst->io_submodule->inst;
+       io->op = &inst->app_io->op;
+
+       io->set_process = mod_set_process;
+       io->app_ctx = instance;
+       io->encode = mod_encode;
+       io->decode = mod_decode;
 
        /*
         *      Add it to the scheduler.  Note that we add our context
         *      instead of the transport one, as we need to swap out
         *      the process function.
-        *
-        *      @todo - more cleanup on error.
         */
-       if (!fr_schedule_socket_add(handle, io_ctx)) {
-               talloc_free(ctx);
+       if (!fr_schedule_socket_add(sc, io)) {
+               talloc_free(io);
                return -1;
        }
 
-       /*
-        *      Remember that we loaded the transport library in the server.
-        */
-       cf_data_add(server, module, value, false);
+       inst->io = io;  /* Probably won't need it, but doesn't hurt */
 
        return 0;
 }
 
-static int open_listen(fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION *cs, bool verify_config)
+/** Instantiate the application
+ *
+ * Instantiate I/O and type submodules.
+ *
+ * @param[in] instance Ctx data for this application.
+ * @param[in] conf     Listen section parsed to give us isntance.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+static int mod_instantiate(void *instance, CONF_SECTION *conf)
 {
-       size_t i;
-       pr_config_t config;
-       proto_radius_ctx_t *ctx;
+       proto_radius_ctx_t      *inst = talloc_get_type_abort(instance, proto_radius_ctx_t);
+       size_t                  i = 0;
 
-       if (cf_section_rules_push(cs, mod_config) < 0) return -1;
+       fr_dict_attr_t const    *da;
+       CONF_PAIR               *cp = NULL;
 
-       if ((cf_section_parse(cs, &config, cs) < 0) || (cf_section_parse_pass2(&config, cs) < 0)) {
-               cf_log_err(cs, "Failed parsing listen { ...}");
-               return -1;
-       }
-
-       if (!config.types) {
-               cf_log_err(cs, "type MUST be specified");
-               return -1;
-       }
-
-       if (!config.transport) {
-               cf_log_err(cs, "transport MUST be specified");
+       /*
+        *      Instantiate the IO module
+        */
+       if (inst->app_io->instantiate && (inst->app_io->instantiate(inst->io_submodule->conf,
+                                                                   inst->io_submodule->inst) < 0)) {
+               cf_log_err(conf, "I/O instantiation failed");
                return -1;
        }
 
-       ctx = talloc_zero(NULL, proto_radius_ctx_t);
-       if (!ctx) {
-               cf_log_err(cs, "Failed allocating memory");
+       /*
+        *      Needed to populate the code array
+        */
+       da = fr_dict_attr_by_name(NULL, "Packet-Type");
+       if (!da) {
+               ERROR("Missing definiton for Packet-Type");
                return -1;
        }
 
        /*
-        *      Compile one or more types.
+        *      Instantiate the subtypes
         */
-       for (i = 0; i < talloc_array_length(config.types); i++) {
-               if (compile_type(ctx, server, cs, config.types[i]) < 0) {
-                       cf_log_err(server, "Failed compiling unlang for 'type = %s'",
-                                     config.types[i]);
+       while ((cp = cf_pair_find_next(conf, cp, "type"))) {
+               fr_app_subtype_t const *subtype = (fr_app_subtype_t const *)inst->type_submodule[i]->module->common;
+
+               if (subtype->instantiate && (subtype->instantiate(inst->type_submodule[i]->conf,
+                                                                 inst->type_submodule[i]->inst) < 0)) {
+                       cf_log_err(conf, "Subtype instantiation failed");
                        return -1;
                }
-       }
 
-       /*
-        *      Call transport-specific library to open the socket.
-        */
-       if (open_transport(ctx, handle, server, cs, config.transport, verify_config) < 0) {
-               cf_log_err(server, "Failed opening connection for 'transport = %s'",
-                                     config.transport);
-               return -1;
+               /*
+                *      We've already done bounds checking in the subtype_parse function
+                */
+               inst->app_by_code[fr_dict_enum_by_alias(NULL, da, cf_pair_value(cp))->value->vb_uint32] = subtype;
+
+               i++;
        }
 
        return 0;
 }
 
-
-/** Open a RADIUS application in a virtual server,
+/** Bootstrap the application
+ *
+ * Bootstrap I/O and type submodules.
  *
+ * @param[in] instance Ctx data for this application.
+ * @param[in] conf     Listen section parsed to give us isntance.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
  */
-static int mod_parse(fr_schedule_t *handle, CONF_SECTION *cs, bool verify_config)
+static int mod_bootstrap(void *instance, CONF_SECTION *conf)
 {
-       CONF_SECTION *subcs = NULL;
+       proto_radius_ctx_t      *inst = talloc_get_type_abort(instance, proto_radius_ctx_t);
+       size_t                  i = 0;
+       CONF_PAIR               *cp = NULL;
 
        /*
-        *      Load all of the listen sections.  They do all of the
-        *      dirty work.
+        *      Bootstrap the IO module
         */
-       while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL))) {
-               if (open_listen(handle, cs, subcs, verify_config) < 0) {
-                       return -1;
-               }
+       inst->app_io = (fr_app_io_t const *) inst->io_submodule->module->common;
+       if (inst->app_io->bootstrap && (inst->app_io->bootstrap(inst->io_submodule->conf,
+                                       inst->io_submodule->inst) < 0)) {
+               cf_log_err(inst->io_submodule->conf, "I/O bootstrap failed");
+               return -1;
        }
 
-       subcs = NULL;
-
        /*
-        *      Compile the sub-sections AFTER parsing all of the
-        *      listen sections.  This is mainly for nice debugging
-        *      output.  It's inefficient as heck, but it's pretty.
+        *      Bootstrap the subtypes
         */
-       while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL))) {
-               CONF_PAIR *cp;
-
-               for (cp = cf_pair_find(subcs, "type");
-                    cp != NULL;
-                    cp = cf_pair_find_next(subcs, cp, "type")) {
-                       char const              *value;
-                       dl_t const              *module;
-                       fr_app_subtype_t        const *app;
-
-                       value = cf_pair_value(cp);
-
-                       module = cf_data_value(cf_data_find(cs, dl_t, value));
-                       if (!module) {
-                               cf_log_err(cs, "Section missing module data");
-                               return -1;
-                       }
-                       if (cf_data_find(cs, char const *, value)) continue;
-
-                       app = (fr_app_subtype_t const *) module->common;
-                       if (app->instantiate(cs) < 0) {
-                               cf_log_err(cs, "Failed compiling unlang for 'type = %s'", value);
-                               return -1;
-                       }
-
-                       cf_data_add(cs, value, value, false);
+       while ((cp = cf_pair_find_next(conf, cp, "type"))) {
+               fr_app_subtype_t const *subtype = (fr_app_subtype_t const *)inst->type_submodule[i]->module->common;
+
+               if (subtype->bootstrap && (subtype->bootstrap(inst->type_submodule[i]->conf,
+                                                             inst->type_submodule[i]->inst) < 0)) {
+                       cf_log_err(inst->type_submodule[i]->conf, "Subtype bootstrap failed");
+                       return -1;
                }
+               i++;
        }
 
        return 0;
 }
 
-extern fr_app_t proto_radius;
 fr_app_t proto_radius = {
        .magic          = RLM_MODULE_INIT,
        .name           = "radius",
-       .load           = mod_load,
+       .config         = proto_radius_config,
+       .inst_size      = sizeof(proto_radius_ctx_t),
+       .inst_type      = "proto_radius_ctx_t",
+
        .bootstrap      = mod_bootstrap,
-       .instantiate    = mod_parse,
+       .instantiate    = mod_instantiate,
+       .open           = mod_open,
+       .set_process    = mod_set_process
 };
index b156e6b0648620b796b0a5654f869133ca94899c..4d9449a315b3d84b76c9378758dd870b044b48e3 100644 (file)
  * @copyright 2017 Alan DeKok <aland@freeradius.org>
  */
 
-typedef struct proto_radius_ctx_t {
-       int                     sockfd;                         //!< sanity checks
-       void                    *ctx;                   //!< for the underlying IO layer
-
-       char const              *secret;                        //!< shared secret
-       size_t                  secret_len;                     //!< length of the shared secret
-
-       fr_io_op_t              transport;
-       fr_io_process_t         process[FR_MAX_PACKET_CODE];
-} proto_radius_ctx_t;
-
 #endif /* _PROTO_RADIUS_H */
index eef289bee6ba3928daf21587604a4be04f626617..f3908b4afd88eb06b57dbf620fb19b77218bba72 100644 (file)
@@ -28,6 +28,7 @@
 #include <freeradius-devel/udp.h>
 #include <freeradius-devel/radius/radius.h>
 #include <freeradius-devel/io/io.h>
+#include <freeradius-devel/io/application.h>
 #include <freeradius-devel/rad_assert.h>
 
 static fr_io_final_t mod_process(REQUEST *request, UNUSED fr_io_action_t action)
@@ -227,7 +228,7 @@ static int mod_compile_section(CONF_SECTION *server_cs, char const *name1, char
 /*
  *     Ensure that the "radius" section is compiled.
  */
-static int mod_compile(CONF_SECTION *server_cs)
+static int mod_compile(UNUSED void *instance, CONF_SECTION *server_cs)
 {
        int rcode;
 
index 7794dc37659da68fa4cb5ac369330fa69e1c606d..55cfdca3c2239b264f2843f234f4956061d5a154 100644 (file)
 #include <freeradius-devel/udp.h>
 #include <freeradius-devel/radius/radius.h>
 #include <freeradius-devel/io/io.h>
+#include <freeradius-devel/io/application.h>
 #include <freeradius-devel/rad_assert.h>
 #include "proto_radius.h"
 
+typedef struct {
+       uint8_t                 header[20];
+       uint8_t                 id;
+
+       fr_ipaddr_t             src_ipaddr;
+       fr_ipaddr_t             dst_ipaddr;
+       uint16_t                src_port;
+       uint16_t                dst_port;
+
+       RADCLIENT               *client;
+} fr_proto_radius_packet_ctx_t;
+
 typedef struct {
        int                             sockfd;
 
@@ -46,20 +59,11 @@ typedef struct {
        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.
-       /*
-        *      SHIT
-        */
-       uint8_t const                   *secret;
-       size_t                          secret_len;
-
-       uint8_t                         original[20];
-       uint8_t                         id;
 
-       struct sockaddr_storage         src;
-       socklen_t                       salen;
+       RADCLIENT                       *dummy_client;
 } fr_proto_radius_udp_ctx_t;
 
-static const CONF_PARSER udp_listen_conf[] = {
+static const CONF_PARSER udp_listen_config[] = {
        { 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) },
@@ -72,16 +76,22 @@ static const CONF_PARSER udp_listen_conf[] = {
        CONF_PARSER_TERMINATOR
 };
 
-static ssize_t mod_read(void *ctx, uint8_t *buffer, size_t buffer_len)
+static ssize_t mod_read(void const *instance, void **packet_ctx, uint8_t *buffer, size_t buffer_len)
 {
+       fr_proto_radius_udp_ctx_t const *inst = talloc_get_type_abort(instance, fr_proto_radius_udp_ctx_t);
+       fr_proto_radius_packet_ctx_t    *pctx;
+
        ssize_t                         data_size;
        size_t                          packet_len;
-       fr_proto_radius_udp_ctx_t       *pc = ctx;
        decode_fail_t                   reason;
 
-       pc->salen = sizeof(pc->src);
+       struct sockaddr_storage         sockaddr;
+       socklen_t                       salen = sizeof(sockaddr);
+
 
-       data_size = recvfrom(pc->sockfd, buffer, buffer_len, 0, (struct sockaddr *) &pc->src, &pc->salen);
+       memset(&sockaddr, 0, sizeof(sockaddr));
+
+       data_size = recvfrom(inst->sockfd, buffer, buffer_len, 0, (struct sockaddr *)&sockaddr, &salen);
        if (data_size <= 0) return data_size;
 
        packet_len = data_size;
@@ -89,47 +99,97 @@ static ssize_t mod_read(void *ctx, uint8_t *buffer, size_t buffer_len)
        /*
         *      If it's not a RADIUS packet, ignore it.
         */
-       if (!fr_radius_ok(buffer, &packet_len, false, &reason)) {
-               return 0;
-       }
+       if (!fr_radius_ok(buffer, &packet_len, false, &reason)) return -1;
 
        /*
         *      If the signature fails validation, ignore it.
         */
-       if (fr_radius_verify(buffer, NULL, pc->secret, pc->secret_len) < 0) {
-               return 0;
+       if (fr_radius_verify(buffer, NULL,
+                            (uint8_t const *)inst->dummy_client->secret,
+                            talloc_array_length(inst->dummy_client->secret)) < 0) return -1;
+
+       /*
+        *      Populate the packet context
+        */
+       pctx = talloc_zero(NULL, fr_proto_radius_packet_ctx_t);
+       pctx->client = inst->dummy_client;
+       if (fr_ipaddr_from_sockaddr(&sockaddr, salen, &pctx->src_ipaddr, &pctx->src_port) < 0) {
+               PERROR("Read failed");
+               talloc_free(pctx);
+               return -1;
        }
+       pctx->id = buffer[1];
+       memcpy(pctx->header, buffer, sizeof(pctx->header));
 
-       pc->id = buffer[1];
-       memcpy(pc->original, buffer, sizeof(pc->original));
+       *packet_ctx = pctx;
 
        return packet_len;
 }
 
 
-static ssize_t mod_write(void *ctx, uint8_t *buffer, size_t buffer_len)
+static ssize_t mod_write(void const *instance, void *packet_ctx, uint8_t *buffer, size_t buffer_len)
 {
-       ssize_t data_size;
-       fr_proto_radius_udp_ctx_t *pc = ctx;
+       fr_proto_radius_udp_ctx_t const *inst = talloc_get_type_abort(instance, fr_proto_radius_udp_ctx_t);
+       fr_proto_radius_packet_ctx_t    *pctx = talloc_get_type_abort(packet_ctx, fr_proto_radius_packet_ctx_t);
 
-       pc->salen = sizeof(pc->src);
+       ssize_t                         data_size;
+       struct sockaddr_storage         sockaddr;
+       socklen_t                       salen;
+
+       if (fr_ipaddr_to_sockaddr(&pctx->src_ipaddr, pctx->src_port, &sockaddr, &salen) < 0) {
+               PERROR("Write failed");
+               talloc_free(packet_ctx);
+               return -1;
+       }
 
        /*
         *      @todo - do more stuff
         */
-       data_size = sendto(pc->sockfd, buffer, buffer_len, 0, (struct sockaddr *) &pc->src, pc->salen);
+       data_size = sendto(inst->sockfd, buffer, buffer_len, 0, (struct sockaddr *) &sockaddr, salen);
        if (data_size <= 0) return data_size;
 
+       talloc_free(packet_ctx);        /* Probably a bad idea */
+
        /*
         *      @todo - post-write cleanups
         */
-
        return data_size;
 }
 
-static int mod_instantiate(CONF_SECTION *cs, void *instance)
+/** Open a UDP listener for RADIUS
+ *
+ * @param[in] instance of the RADIUS UDP I/O path.
+ * @return
+ *     - <0 on error
+ *     - 0 on success
+ */
+static int mod_open(void *instance)
 {
-       fr_proto_radius_udp_ctx_t       *inst = instance;
+       fr_proto_radius_udp_ctx_t *inst = instance;
+
+       int                             sockfd = 0;
+       uint16_t                        port = inst->port;
+
+       sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
+       if (sockfd < 0) {
+               ERROR("%s", fr_strerror());
+       error:
+               return -1;
+       }
+
+       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+               ERROR("Failed binding socket: %s", fr_strerror());
+               goto error;
+       }
+
+       inst->sockfd = sockfd;
+
+       return 0;
+}
+
+static int mod_instantiate(void *instance, CONF_SECTION *cs)
+{
+       fr_proto_radius_udp_ctx_t *inst = instance;
 
        /*
         *      Default to all IPv6 interfaces (it's the future)
@@ -162,38 +222,7 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
                inst->port = ntohl(s->s_port);
        }
 
-       inst->secret = (uint8_t const *) "testing123";
-       inst->secret_len = 10;
-
-       return 0;
-}
-
-/** Open a UDP listener for RADIUS
- *
- * @param[in] instance of the RADIUS UDP I/O path.
- * @return
- *     - <0 on error
- *     - 0 on success
- */
-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, inst->port_name, true);
-       if (sockfd < 0) {
-               ERROR("%s", fr_strerror());
-       error:
-               return -1;
-       }
-
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &inst->port, inst->interface) < 0) {
-               ERROR("Failed binding socket: %s", fr_strerror());
-               goto error;
-       }
-
-       inst->sockfd = sockfd;
+       inst->dummy_client = client_afrom_query(inst, "127.0.0.1", "testing123", "test", "test", NULL, false);
 
        return 0;
 }
@@ -203,9 +232,9 @@ static int mod_open(void *instance)
  * @param[in] instance of the RADIUS UDP I/O path.
  * @return the file descriptor
  */
-static int mod_fd(void *instance)
+static int mod_fd(void const *instance)
 {
-       fr_proto_radius_udp_ctx_t       *inst = instance;
+       fr_proto_radius_udp_ctx_t const *inst = instance;
 
        return inst->sockfd;
 }
@@ -214,7 +243,7 @@ extern fr_app_io_t proto_radius_udp;
 fr_app_io_t proto_radius_udp = {
        .magic                  = RLM_MODULE_INIT,
        .name                   = "radius_udp",
-       .config                 = udp_listen_conf,
+       .config                 = udp_listen_config,
        .inst_size              = sizeof(fr_proto_radius_udp_ctx_t),
        .inst_type              = "fr_proto_radius_udp_ctx_t",
        .instantiate            = mod_instantiate,
index 6b1b9003c95d40d514154cfa51603c782550f29c..e048afb36c2c49afa4bf7ac669699f7bf6650ea5 100644 (file)
@@ -954,7 +954,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        rad_assert(inst->driver->insert);
        rad_assert(inst->driver->expire);
 
-       if (dl_instance_data_alloc(&inst->driver_inst, inst, inst->driver_handle, driver_cs) < 0) return -1;
+       if (dl_instance_data_alloc(inst, &inst->driver_inst, inst->driver_handle, driver_cs) < 0) return -1;
 
        if (inst->driver->instantiate &&
            (inst->driver->instantiate(&inst->config, inst->driver_inst, driver_cs) < 0)) return -1;
index cdc6a3158f08d406183e1dc3144b377d8a293c0f..0d4243c101cff2efecc4899453ca48c5d060630c 100644 (file)
@@ -105,7 +105,7 @@ int eap_method_instantiate(rlm_eap_method_t **out, rlm_eap_t *inst, eap_type_t n
         *      Allocate submodule instance data and parse the method's
         *      configuration.
         */
-       if (dl_instance_data_alloc(&method->submodule_inst, method, method->submodule_handle, cs) < 0) {
+       if (dl_instance_data_alloc(method, &method->submodule_inst, method->submodule_handle, cs) < 0) {
                talloc_free(method);
                return -1;
        }
index e489a433a1b18416f5c34bed271bc5437aaf77ec..52964d2acacd662fe434e1c04f5a9a014fc5bbc1 100644 (file)
@@ -506,8 +506,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, UNUSED void *t
        }
 
        if (inst->auth_type) {
-               vp = radius_pair_create(request, &request->control,
-                                      FR_AUTH_TYPE, 0);
+               vp = radius_pair_create(request, &request->control, FR_AUTH_TYPE, 0);
                vp->vp_uint32 = inst->auth_type;
        }
 
index b16b87e4e29e154977bc3886b98be27358e91a50..6b5b0709af380a56f5b0bbfd4f3735125a2b023b 100644 (file)
@@ -1091,7 +1091,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
         *      Pre-allocate the driver's instance data,
         *      and parse the driver's configuration.
         */
-       if (dl_instance_data_alloc(&inst->driver_inst, inst, inst->driver_handle, driver_cs) < 0) {
+       if (dl_instance_data_alloc(inst, &inst->driver_inst, inst->driver_handle, driver_cs) < 0) {
        error:
                talloc_decrease_ref_count(inst->driver_handle);
                return -1;
index a61562f7f0f10b11f860afb37f968ab6307386af..fe15c5d51afe68c40f6846a994daafafa651ba6c 100644 (file)
@@ -24,6 +24,7 @@ RCSID("$Id$")
 
 #include <freeradius-devel/io/control.h>
 #include <freeradius-devel/io/worker.h>
+#include <freeradius-devel/io/listen.h>
 #include <freeradius-devel/inet.h>
 #include <freeradius-devel/fr_log.h>
 #include <freeradius-devel/radius.h>
@@ -102,9 +103,9 @@ static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
 }
 
 
-static int test_decode(void *packet_ctx, uint8_t *const data, size_t data_len, REQUEST *request)
+static int test_decode(void const *instance, REQUEST *request, uint8_t *const data, size_t data_len)
 {
-       fr_radius_packet_ctx_t const *pc = talloc_get_type_abort(packet_ctx, fr_radius_packet_ctx_t);
+       fr_radius_packet_ctx_t const *pc = talloc_get_type_abort(instance, fr_radius_packet_ctx_t);
 
        request->number = pc->id;
        request->process_async = test_process;
@@ -116,10 +117,10 @@ static int test_decode(void *packet_ctx, uint8_t *const data, size_t data_len, R
        return 0;
 }
 
-static ssize_t test_encode(void *packet_ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len)
+static ssize_t test_encode(void const *instance, REQUEST *request, uint8_t *buffer, size_t buffer_len)
 {
        FR_MD5_CTX context;
-       fr_radius_packet_ctx_t const *pc = talloc_get_type_abort(packet_ctx, fr_radius_packet_ctx_t);
+       fr_radius_packet_ctx_t const *pc = talloc_get_type_abort(instance, fr_radius_packet_ctx_t);
 
        MPRINT1("\t\tENCODE >>> request %"PRIu64" - data %p %p room %zd\n",
                request->number, pc, buffer, buffer_len);
@@ -139,9 +140,9 @@ static ssize_t test_encode(void *packet_ctx, REQUEST *request, uint8_t *buffer,
        return 20;
 }
 
-static size_t test_nak(void const *packet_ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
+static size_t test_nak(void const *instance, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
 {
-       MPRINT1("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], packet_ctx, packet, packet_len);
+       MPRINT1("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], instance, packet, packet_len);
 
        return 10;
 }
@@ -149,8 +150,6 @@ static size_t test_nak(void const *packet_ctx, uint8_t *const packet, size_t pac
 static fr_io_op_t op = {
        .name = "worker-test",
        .default_message_size = 4096,
-       .decode = test_decode,
-       .encode = test_encode,
        .nak = test_nak,
 };
 
@@ -215,7 +214,7 @@ static void master_process(TALLOC_CTX *ctx)
        int                     kq_master;
        fr_atomic_queue_t       *aq_master;
        fr_control_t            *control_master;
-       fr_io_t                 io = { .ctx = NULL, .op = &op };
+       fr_io_t                 io = { .ctx = NULL, .op = &op, .encode = test_encode, .decode = test_decode };
        int                     sockfd;
 
        MPRINT1("Master started.\n");
index 48600c69d3645360069cbfd1b912903bf2cb8428..68cd8b2a18ab6a7c4f6bb782c1ed82f9522db884 100644 (file)
@@ -23,6 +23,7 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/io/schedule.h>
+#include <freeradius-devel/io/listen.h>
 #include <freeradius-devel/inet.h>
 #include <freeradius-devel/radius.h>
 #include <freeradius-devel/md5.h>
@@ -76,9 +77,9 @@ static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
        return FR_IO_REPLY;
 }
 
-static int test_decode(void *ctx, uint8_t *const data, size_t data_len, REQUEST *request)
+static int test_decode(void const *instance, REQUEST *request, uint8_t *const data, size_t data_len)
 {
-       fr_io_test_ctx_t const *pc = ctx;
+       fr_io_test_ctx_t const *pc = instance;
 
        request->process_async = test_process;
 
@@ -89,10 +90,10 @@ static int test_decode(void *ctx, uint8_t *const data, size_t data_len, REQUEST
        return 0;
 }
 
-static ssize_t test_encode(void *ctx, REQUEST *request, uint8_t *buffer, size_t buffer_len)
+static ssize_t test_encode(void const *instance, REQUEST *request, uint8_t *buffer, size_t buffer_len)
 {
        FR_MD5_CTX context;
-       fr_io_test_ctx_t const *pc = ctx;
+       fr_io_test_ctx_t const *pc = instance;
 
        MPRINT1("\t\tENCODE >>> request %"PRIu64"- data %p %p room %zd\n", request->number, pc, buffer, buffer_len);
 
@@ -136,7 +137,7 @@ static int test_open(void *ctx)
        return 0;
 }
 
-static ssize_t test_read(void *ctx, uint8_t *buffer, size_t buffer_len)
+static ssize_t test_read(void const *ctx, UNUSED void **packet_ctx, uint8_t *buffer, size_t buffer_len)
 {
        ssize_t                 data_size;
        fr_io_test_ctx_t        *io_ctx = talloc_get_type_abort(ctx, fr_io_test_ctx_t);
@@ -156,7 +157,7 @@ static ssize_t test_read(void *ctx, uint8_t *buffer, size_t buffer_len)
 }
 
 
-static ssize_t test_write(void *ctx, uint8_t *buffer, size_t buffer_len)
+static ssize_t test_write(void const *ctx, UNUSED void *packet_ctx, uint8_t *buffer, size_t buffer_len)
 {
        ssize_t                 data_size;
        fr_io_test_ctx_t        *io_ctx = talloc_get_type_abort(ctx, fr_io_test_ctx_t);
@@ -173,7 +174,7 @@ static ssize_t test_write(void *ctx, uint8_t *buffer, size_t buffer_len)
        return data_size;
 }
 
-static int test_fd(void *ctx)
+static int test_fd(void const *ctx)
 {
        fr_io_test_ctx_t        *io_ctx = talloc_get_type_abort(ctx, fr_io_test_ctx_t);
 
@@ -186,8 +187,6 @@ static fr_io_op_t op = {
        .open = test_open,
        .read = test_read,
        .write = test_write,
-       .decode = test_decode,
-       .encode = test_encode,
        .fd = test_fd,
        .nak = test_nak
 };
@@ -211,7 +210,7 @@ int main(int argc, char *argv[])
        uint16_t                port16 = 0;
        TALLOC_CTX              *autofree = talloc_init("main");
        fr_schedule_t           *sched;
-       fr_io_t                 io = { .op = &op };
+       fr_io_t                 io = { .op = &op, .decode = test_decode, .encode = test_encode };
        fr_io_test_ctx_t        *io_ctx;
 
        io.ctx = io_ctx = talloc_zero(autofree, fr_io_test_ctx_t);
index 21a7a805529a73c50d47036cf4b7546fb10d564f..53ed5da7abb854ed4f33a205bde4458eabe4444f 100644 (file)
@@ -24,6 +24,7 @@ RCSID("$Id$")
 
 #include <freeradius-devel/io/control.h>
 #include <freeradius-devel/io/worker.h>
+#include <freeradius-devel/io/listen.h>
 #include <freeradius-devel/rad_assert.h>
 
 #ifdef HAVE_GETOPT_H
@@ -82,7 +83,7 @@ static fr_io_final_t test_process(REQUEST *request, fr_io_action_t action)
        return FR_IO_REPLY;
 }
 
-static int test_decode(void *packet_ctx, uint8_t *const data, size_t data_len, REQUEST *request)
+static int test_decode(UNUSED void const *packet_ctx, REQUEST *request, uint8_t *const data, size_t data_len)
 {
        uint32_t number;
 
@@ -98,9 +99,9 @@ static int test_decode(void *packet_ctx, uint8_t *const data, size_t data_len, R
        return 0;
 }
 
-static ssize_t test_encode(void *packet_ctx, REQUEST *request, uint8_t *const data, size_t data_len)
+static ssize_t test_encode(void const *instance, REQUEST *request, uint8_t *const data, size_t data_len)
 {
-       MPRINT1("\t\tENCODE >>> request %"PRIu64" - data %p %p size %zd\n", request->number, packet_ctx, data, data_len);
+       MPRINT1("\t\tENCODE >>> request %"PRIu64" - data %p %p size %zd\n", request->number, instance, data, data_len);
 
        return data_len;
 }
@@ -123,8 +124,6 @@ static size_t test_nak(void const *packet_ctx, uint8_t *const packet, size_t pac
 static fr_io_op_t transport = {
        .name = "worker-test",
        .default_message_size = 4096,
-       .decode = test_decode,
-       .encode = test_encode,
        .nak = test_nak,
 };
 
@@ -170,7 +169,7 @@ static void master_process(void)
        fr_channel_event_t      ce;
        pthread_attr_t          attr;
        fr_schedule_worker_t    *sw;
-       fr_io_t                 io = { .ctx = NULL, .op = &transport };
+       fr_io_t                 io = { .ctx = NULL, .op = &transport, .encode = test_encode, .decode = test_decode };
        struct kevent           events[MAX_KEVENTS];
 
        ctx = talloc_init("master");