]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
use the new udp_queue API
authorAlan T. DeKok <aland@freeradius.org>
Fri, 10 Sep 2021 12:30:34 +0000 (08:30 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 10 Sep 2021 12:30:34 +0000 (08:30 -0400)
the code is a little smaller

src/modules/rlm_dhcpv4/rlm_dhcpv4.c

index 6d593402d5ad84b0c203bdc05304154c83cb2129..ad351fd55b3e02f1611bcc53c9f2f2e49bfdb58c 100644 (file)
@@ -28,8 +28,11 @@ RCSID("$Id$")
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module.h>
 #include <freeradius-devel/io/pair.h>
+#include <freeradius-devel/util/udp_queue.h>
 #include <freeradius-devel/dhcpv4/dhcpv4.h>
 
+#include <freeradius-devel/unlang/module.h>
+
 #include <ctype.h>
 
 static fr_dict_t const *dict_dhcpv4;
@@ -72,39 +75,32 @@ typedef struct {
        char const              *name;
        char const              *xlat_name;
 
-       int                     fd;                     //!< only relay, no proxying for now
-
-       fr_ipaddr_t             ipaddr;                 //!< socket IP address
-       uint16_t                port;                   //!< socket port
-
-       char const              *interface;             //!< Interface to bind to.
-
-       uint32_t                recv_buff;              //!< How big the kernel's receive buffer should be.
-       uint32_t                send_buff;              //!< How big the kernel's send buffer should be.
+       fr_udp_queue_config_t   config;         //!< UDP queue config
 
        uint32_t                max_packet_size;        //!< Maximum packet size.
-
-       bool                    recv_buff_is_set;       //!< Whether we were provided with a recv_buf
-       bool                    send_buff_is_set;       //!< Whether we were provided with a send_buf
 } rlm_dhcpv4_t;
 
 typedef struct {
+       fr_udp_queue_t          *uq;                    //!< udp queue handler
        uint8_t                 *buffer;                //!< for encoding packets
        uint32_t                buffer_size;            //!< Maximum packet size.
+       uint32_t                xid;                    //!< XID
 } rlm_dhcpv4_thread_t;
 
 static const CONF_PARSER module_config[] = {
-       { FR_CONF_OFFSET("ipaddr", FR_TYPE_IPV4_ADDR, rlm_dhcpv4_t, ipaddr), },
-       { FR_CONF_OFFSET("ipv4addr", FR_TYPE_IPV4_ADDR, rlm_dhcpv4_t, ipaddr) },
+       { FR_CONF_OFFSET("ipaddr", FR_TYPE_IPV4_ADDR, rlm_dhcpv4_t, config.ipaddr), },
+       { FR_CONF_OFFSET("ipv4addr", FR_TYPE_IPV4_ADDR, rlm_dhcpv4_t, config.ipaddr) },
 
-       { FR_CONF_OFFSET("port", FR_TYPE_UINT16, rlm_dhcpv4_t, port), .dflt = "68" },
+       { FR_CONF_OFFSET("port", FR_TYPE_UINT16, rlm_dhcpv4_t, config.port), .dflt = "68" },
 
-       { FR_CONF_OFFSET("interface", FR_TYPE_STRING, rlm_dhcpv4_t, interface) },
+       { FR_CONF_OFFSET("interface", FR_TYPE_STRING, rlm_dhcpv4_t, config.interface) },
 
-       { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, rlm_dhcpv4_t, recv_buff) },
-       { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, rlm_dhcpv4_t, send_buff) },
+       { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, rlm_dhcpv4_t, config.send_buff) },
 
        { FR_CONF_OFFSET("max_packet_size", FR_TYPE_UINT32, rlm_dhcpv4_t, max_packet_size), .dflt = "576" },
+       { FR_CONF_OFFSET("max_queued_packets", FR_TYPE_UINT32, rlm_dhcpv4_t, config.max_queued_packets), .dflt = "65536" },
+
+       { FR_CONF_OFFSET("timeout", FR_TYPE_TIME_DELTA, rlm_dhcpv4_t, config.max_queued_time), .dflt = "0" },
 
        CONF_PARSER_TERMINATOR
 };
@@ -130,100 +126,48 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        /*
         *      Ensure that we have a destination address.
         */
-       if (inst->ipaddr.af == AF_UNSPEC) {
+       if (inst->config.ipaddr.af == AF_UNSPEC) {
                cf_log_err(conf, "A value must be given for 'ipaddr'");
                return -1;
        }
 
-       if (inst->ipaddr.af != AF_INET) {
+       if (inst->config.ipaddr.af != AF_INET) {
                cf_log_err(conf, "DHCPv4 can only use IPv4 addresses in 'ipaddr'");
                return -1;
        }
 
-       if (!inst->port) {
+       if (!inst->config.port) {
                cf_log_err(conf, "A value must be given for 'port'");
                return -1;
        }
 
        /*
-        *      Clamp max_packet_size first before checking recv_buff and send_buff
+        *      Clamp max_packet_size
         */
        FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, >=, DEFAULT_PACKET_SIZE);
        FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, <=, MAX_PACKET_SIZE);
 
-       if (inst->send_buff_is_set) {
-               FR_INTEGER_BOUND_CHECK("send_buff", inst->send_buff, >=, inst->max_packet_size);
-               FR_INTEGER_BOUND_CHECK("send_buff", inst->send_buff, <=, (1 << 30));
-       }
-
        return 0;
 }
 
-/** Instantiate the module
- *
- * Instantiate I/O and type submodules.
- *
- * @param[in] instance data for this module
- * @param[in] conf     our configuration section parsed to give us instance.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int mod_instantiate(void *instance, CONF_SECTION *conf)
-{
-       rlm_dhcpv4_t    *inst = talloc_get_type_abort(instance, rlm_dhcpv4_t);
-
-       /*
-        *      Open the outgoing socket.
-        */
-       inst->fd = fr_socket_server_udp(&inst->ipaddr, &inst->port, NULL, true);
-       if (inst->fd < 0) {
-               cf_log_err(conf, "Failed opening socket: %s", fr_strerror());
-               return -1;
-       }
-
-       /*
-        *      Bind to the interface, if required.
-        */
-       if (inst->interface) {
-               if (fr_socket_bind(inst->fd, &inst->ipaddr, &inst->port, inst->interface) < 0) {
-                       cf_log_err(conf, "Failed binding to interface %s: %s", inst->interface, fr_strerror());
-                       return -1;
-               }
-       }
-
-       fr_nonblock(inst->fd);
-
-#ifdef SO_RCVBUF
-       if (inst->recv_buff_is_set) {
-               int opt;
-
-               opt = inst->recv_buff;
-               if (setsockopt(inst->fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(int)) < 0) {
-                       cf_log_warn(conf, "Failed setting 'SO_RCVBUF': %s", fr_syserror(errno));
-               }
-       }
-#endif
+typedef struct {
+       request_t               *request;
+       bool                    sent;
+} rlm_dhcpv4_delay_t;
 
-#ifdef SO_SNDBUF
-       if (inst->send_buff_is_set) {
-               int opt;
+static void dhcpv4_queue_resume(bool sent, void *rctx)
+{
+       rlm_dhcpv4_delay_t *d = talloc_get_type_abort(rctx, rlm_dhcpv4_delay_t);
 
-               opt = inst->send_buff;
-               if (setsockopt(inst->fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(int)) < 0) {
-                       cf_log_warn(conf, "Failed setting 'SO_SNDBUF', write performance may be sub-optimal: %s",
-                                   fr_syserror(errno));
-               }
-       }
-#endif
+       d->sent = sent;
 
-       return 0;
+       unlang_interpret_mark_runnable(d->request);
 }
 
 /** Instantiate thread data for the submodule.
  *
  */
-static int mod_thread_instantiate(CONF_SECTION const *cs, void *instance, UNUSED fr_event_list_t *el, void *thread)
+static int mod_thread_instantiate(CONF_SECTION const *cs, void *instance, fr_event_list_t *el, void *thread)
 {
        rlm_dhcpv4_t *inst = talloc_get_type_abort(instance, rlm_dhcpv4_t);
        rlm_dhcpv4_thread_t *t = talloc_get_type_abort(thread, rlm_dhcpv4_thread_t);
@@ -236,35 +180,45 @@ static int mod_thread_instantiate(CONF_SECTION const *cs, void *instance, UNUSED
 
        t->buffer_size = inst->max_packet_size;
 
+       t->uq = fr_udp_queue_alloc(t, &inst->config, el, dhcpv4_queue_resume);
+       if (!t->uq) {
+               cf_log_err(cs, "Failed allocating outbound udp queue - %s", fr_strerror());
+               return -1;
+       }
+
        return 0;
 }
 
+static unlang_action_t dhcpv4_resume(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx,
+                                    UNUSED request_t *request, void *rctx)
+{
+       rlm_dhcpv4_delay_t *d = talloc_get_type_abort(rctx, rlm_dhcpv4_delay_t);
+
+       if (!d->sent) {
+               talloc_free(d);
+               RETURN_MODULE_FAIL;
+       }
+
+       talloc_free(d);
+       RETURN_MODULE_OK;
+}
+
+
 /** Send packets outbound.
  *
  */
 static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
 {
-       rlm_dhcpv4_t            *inst = talloc_get_type_abort(mctx->instance, rlm_dhcpv4_t);
        rlm_dhcpv4_thread_t     *t = talloc_get_type_abort(mctx->thread, rlm_dhcpv4_thread_t);
        ssize_t                 data_len;
        dhcp_packet_t           *original = (dhcp_packet_t *) request->packet->data;
        dhcp_packet_t           *packet;
-       struct sockaddr_storage sockaddr;
-       socklen_t               socklen;
+
        uint32_t                xid;
        fr_pair_t               *vp;
-       int                     code, port;
+       int                     code, port, rcode;
 
-       /*
-        *      Discard any incoming packets, as we don't care about
-        *      them.
-        *
-        *      @todo - maybe set up a thread listener to do this, if
-        *      we care.
-        */
-       while (read(inst->fd, t->buffer, t->buffer_size) > 0) {
-               /* do nothing with the data, we don't care */
-       }
+       rlm_dhcpv4_delay_t      *d;
 
        /*
         *      We can only send relayed packets, which have a gateway IP
@@ -286,7 +240,7 @@ static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, modul
                xid = ntohl(original->xid);
 
        } else {
-               xid = fr_rand(); /* shouldn't happen, as we're relaying packets, not creating them (yet) */
+               xid = t->xid++;
        }
 
        /*
@@ -324,8 +278,6 @@ static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, modul
                RETURN_MODULE_NOOP;
        }
 
-       fr_ipaddr_to_sockaddr(&sockaddr, &socklen, &vp->vp_ip, port);
-
        /*
         *      Encode the packet using the original information.
         */
@@ -350,15 +302,25 @@ static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, modul
 
        FR_PROTO_HEX_DUMP(t->buffer, data_len, "DHCPv4");
 
-       /*
-        *      Send the packet, via "fire and forget".
-        */
-       if (sendto(inst->fd, t->buffer, data_len, 0, (struct sockaddr *) &sockaddr, socklen) < 0) {
-               REDEBUG("Failed sending packet to %pV: %s", &vp->data, fr_syserror(errno));
+       d = talloc_zero(request, rlm_dhcpv4_delay_t);
+       if (!d) RETURN_MODULE_FAIL;
+
+       *d = (rlm_dhcpv4_delay_t) {
+               .request = request,
+               .sent = false,
+       };
+
+       rcode = fr_udp_queue_write(d, t->uq, t->buffer, data_len, &vp->vp_ip, port, d);
+       if (rcode > 0) {
+               talloc_free(d);
+               RETURN_MODULE_OK;
+       }
+       if (rcode < 0) {
+               talloc_free(d);
                RETURN_MODULE_FAIL;
        }
 
-       RETURN_MODULE_OK;
+       return unlang_module_yield(request, dhcpv4_resume, NULL, d);
 }
 
 extern module_t rlm_dhcpv4;
@@ -367,7 +329,6 @@ module_t rlm_dhcpv4 = {
        .name           = "dhcpv4",
        .inst_size      = sizeof(rlm_dhcpv4_t),
        .bootstrap      = mod_bootstrap,
-       .instantiate    = mod_instantiate,
 
        .config                 = module_config,