]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add connection_timeout to RADIUS client BIO
authorAlan T. DeKok <aland@freeradius.org>
Wed, 12 Jun 2024 18:50:33 +0000 (14:50 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 19 Jun 2024 12:44:33 +0000 (08:44 -0400)
src/bin/radclient-ng.c
src/lib/bio/base.h
src/lib/bio/packet.h
src/protocols/radius/client.c
src/protocols/radius/client.h
src/protocols/radius/client_priv.h

index 7da8f4c08e8bf598962e27c9087a67046b89a7a8..4f48d5d9dfd2acf8c54f23f651c5333ff4a6224f 100644 (file)
@@ -1098,6 +1098,20 @@ static int client_bio_write_resume(fr_bio_packet_t *bio)
 }
 
 
+static NEVER_RETURNS void client_bio_failed(fr_bio_packet_t *bio)
+{
+       ERROR("Failed connecting to server");
+
+       /*
+        *      Cleanly close the BIO, so that we exercise the shutdown path.
+        */
+       fr_assert(bio == client_bio);
+       TALLOC_FREE(client_bio);
+
+       fr_exit_now(1);
+}
+
+
 static NEVER_RETURNS void client_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags,
                                       int fd_errno, void *uctx)
 {
@@ -1734,6 +1748,7 @@ int main(int argc, char **argv)
         */
        client_config.packet_cb_cfg = (fr_bio_packet_cb_funcs_t) {
                .activate       = client_bio_activate,
+               .failed         = client_bio_failed,
 
                .write_blocked  = client_bio_write_pause,
                .write_resume   = client_bio_write_resume,
index 0f00397e956faa2eb4faa0262fb5654dae7fc3a3..0f9db535834cf760c02d8a6a23d00f4e7896ad31 100644 (file)
@@ -85,8 +85,9 @@ typedef void (*fr_bio_callback_t)(fr_bio_t *bio); /* activate / shutdown callbac
 
 typedef struct {
        fr_bio_callback_t       activate;               //!< called when the BIO is ready to be used
-       fr_bio_callback_t       eof;                    //!< called when the BIO is at EOF
        fr_bio_callback_t       shutdown;               //!< called when the BIO is being shut down
+       fr_bio_callback_t       eof;                    //!< called when the BIO is at EOF
+       fr_bio_callback_t       failed;                 //!< called when the BIO fails
 
        fr_bio_io_t             read_blocked;
        fr_bio_io_t             write_blocked;
index b9f64b8679af578e565c667b532f93f3cfa91498..7dc90ec82bede1ae6b3f14d90c07602b52473f85 100644 (file)
@@ -69,8 +69,9 @@ typedef void (*fr_bio_packet_callback_t)(fr_bio_packet_t *bio);
 
 typedef struct {
        fr_bio_packet_callback_t        activate;
-       fr_bio_packet_callback_t        eof;
        fr_bio_packet_callback_t        shutdown;
+       fr_bio_packet_callback_t        eof;
+       fr_bio_packet_callback_t        failed;
 
        fr_bio_packet_io_t      read_blocked;
        fr_bio_packet_io_t      write_blocked;
index 0c90587617c428fe49555fb4c3c21dd9099eb208..97dcd694d0b224adf1bc15773c6b24210414a8cb 100644 (file)
@@ -45,6 +45,8 @@ static bool radius_client_retry_response(fr_bio_t *bio, fr_bio_retry_entry_t **r
 static void radius_client_retry_release(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED fr_bio_retry_release_reason_t reason);
 static ssize_t radius_client_retry(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED const void *buffer, NDEBUG_UNUSED size_t size);
 
+static void fr_radius_client_bio_connect_timer(fr_event_list_t *el, fr_time_t now, void *uctx);
+
 fr_bio_packet_t *fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
 {
        fr_assert(fd_cfg->type == FR_BIO_FD_CONNECTED);
@@ -139,12 +141,24 @@ fr_radius_client_fd_bio_t *fr_radius_client_fd_bio_alloc(TALLOC_CTX *ctx, size_t
         */
        fr_radius_client_bio_cb_set(&my->common, &cfg->packet_cb_cfg);
 
+       talloc_set_destructor(my, _radius_client_fd_bio_free);
+
        /*
         *      Set up the connected status.
         */
        my->info.connected = (my->info.fd_info->type == FR_BIO_FD_CONNECTED) && (my->info.fd_info->state == FR_BIO_FD_STATE_OPEN);
 
-       talloc_set_destructor(my, _radius_client_fd_bio_free);
+       /*
+        *      If we're supposed to be connected (but aren't), then ensure that we don't keep trying to
+        *      connect forever.
+        */
+       if ((my->info.fd_info->type == FR_BIO_FD_CONNECTED) && !my->info.connected &&
+           fr_time_delta_ispos(cfg->connection_timeout) && cfg->retry_cfg.el) {
+               if (fr_event_timer_in(my, cfg->retry_cfg.el, &my->ev, cfg->connection_timeout, fr_radius_client_bio_connect_timer, my) < 0) {
+                       talloc_free(my);
+                       return -1;
+               }
+       }
 
        return my;
 }
@@ -640,8 +654,25 @@ static void fr_radius_client_bio_activate(fr_bio_t *bio)
        fr_assert(!my->info.connected);
 
        my->info.connected = true;
+
+       talloc_const_free(&my->ev);
 }
 
+/** We failed to connect in the given timeout, the connection is dead.
+ *
+ */
+static void fr_radius_client_bio_connect_timer(NDEBUG_UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
+{
+       fr_radius_client_fd_bio_t *my = talloc_get_type_abort(uctx, fr_radius_client_fd_bio_t);
+
+       fr_assert(my->info.retry_info->el == el);
+
+       talloc_const_free(&my->ev);
+
+       if (my->common.cb.failed) my->common.cb.failed(&my->common);
+}
+
+
 void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx)
 {
        fr_radius_client_fd_bio_t *my = talloc_get_type_abort(uctx, fr_radius_client_fd_bio_t);
@@ -670,7 +701,12 @@ void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUS
        my->info.connected = true;
 
 activate:
-       (void) my->common.cb.activate(&my->common);
+       /*
+        *      Stop any connection timeout.
+        */
+       talloc_const_free(&my->ev);
+
+       my->common.cb.activate(&my->common);
 }
 
 
index 985185147938b9b277fe310af71589b243ed3787..48dee240ce5038772fa9a74b76a93c2241a0a069 100644 (file)
@@ -40,6 +40,8 @@ typedef struct {
 
        fr_bio_packet_cb_funcs_t packet_cb_cfg;
 
+       fr_time_delta_t         connection_timeout;
+
        bool                    add_proxy_state;
        uint32_t                proxy_state;
 
index c164b6c137eed1b7105fd568cbbc6fc6dc87b7ad..fca93f3208edc4633596d0e258072e74c69a26b5 100644 (file)
@@ -44,6 +44,8 @@ typedef struct {
        fr_bio_t                *mem;
        fr_bio_t                *fd;
 
+       fr_event_timer_t const  *ev;
+
        /*
         *      @todo - this blocks on _any_ ID space being full.  So if we send auth+acct and auth blocks,
         *      then acct is also blocked.  Perhaps we want to track these individually, which means having