From: Alan T. DeKok Date: Wed, 12 Jun 2024 18:50:33 +0000 (-0400) Subject: add connection_timeout to RADIUS client BIO X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26e91b067fb2d8826e17aff29386952329dcaefb;p=thirdparty%2Ffreeradius-server.git add connection_timeout to RADIUS client BIO --- diff --git a/src/bin/radclient-ng.c b/src/bin/radclient-ng.c index 7da8f4c08e8..4f48d5d9dfd 100644 --- a/src/bin/radclient-ng.c +++ b/src/bin/radclient-ng.c @@ -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, diff --git a/src/lib/bio/base.h b/src/lib/bio/base.h index 0f00397e956..0f9db535834 100644 --- a/src/lib/bio/base.h +++ b/src/lib/bio/base.h @@ -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; diff --git a/src/lib/bio/packet.h b/src/lib/bio/packet.h index b9f64b8679a..7dc90ec82be 100644 --- a/src/lib/bio/packet.h +++ b/src/lib/bio/packet.h @@ -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; diff --git a/src/protocols/radius/client.c b/src/protocols/radius/client.c index 0c90587617c..97dcd694d0b 100644 --- a/src/protocols/radius/client.c +++ b/src/protocols/radius/client.c @@ -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); } diff --git a/src/protocols/radius/client.h b/src/protocols/radius/client.h index 98518514793..48dee240ce5 100644 --- a/src/protocols/radius/client.h +++ b/src/protocols/radius/client.h @@ -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; diff --git a/src/protocols/radius/client_priv.h b/src/protocols/radius/client_priv.h index c164b6c137e..fca93f3208e 100644 --- a/src/protocols/radius/client_priv.h +++ b/src/protocols/radius/client_priv.h @@ -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