From: Arran Cudbard-Bell Date: Fri, 7 Jul 2017 16:27:31 +0000 (-0400) Subject: Make the 'timeout' callback, a generic failure callback X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcbb8cc104fe7beb61dba821f513ed84e89c9e13;p=thirdparty%2Ffreeradius-server.git Make the 'timeout' callback, a generic failure callback The issue is the connection attempt might explicitly fail, not just timeout. --- diff --git a/src/include/connection.h b/src/include/connection.h index 1cd5e550f1c..25e5618f30b 100644 --- a/src/include/connection.h +++ b/src/include/connection.h @@ -66,21 +66,23 @@ typedef fr_connection_state_t (*fr_connection_init_t)(int *fd_out, void *uctx); */ typedef fr_connection_state_t (*fr_connection_open_t)(int fd, fr_event_list_t *el, void *uctx); -/** Notification that a connection attempt has timed out +/** Notification that a connection attempt has failed * * @note If the callback frees the connection, it must return #FR_CONNECTION_STATE_HALTED. * * @param[in] fd That was successfully opened. - * @param[in] el to use for inserting I/O events. + * @param[in] state the connection was in when it failed. Usually one of: + * - #FR_CONNECTION_STATE_CONNECTING the connection attempt explicitly failed. + * - #FR_CONNECTION_STATE_CONNECTED something called #fr_connection_reconnect. + * - #FR_CONNECTION_STATE_TIMEOUT the connection attempt timed out. * @param[in] uctx User context. * @return - * - #FR_CONNECTION_STATE_FAILED to reattempt the connection after - * the configured delay period. + * - #FR_CONNECTION_STATE_INIT to transition to the init state. * - #FR_CONNECTION_STATE_HALTED To prevent further reconnection * attempts Can be restarted with * #fr_connection_start(). */ -typedef fr_connection_state_t (*fr_connection_timeout_t)(int fd, void *uctx); +typedef fr_connection_state_t (*fr_connection_failed_t)(int fd, fr_connection_state_t state, void *uctx); /** Notification that the connection has errored and must be closed * @@ -102,7 +104,7 @@ fr_connection_t *fr_connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, fr_connection_close_t close, char const *log_prefix, void *uctx); -void fr_connection_timeout_func(fr_connection_t *conn, fr_connection_timeout_t func); +void fr_connection_failed_func(fr_connection_t *conn, fr_connection_failed_t func); void fr_connection_start(fr_connection_t *conn); int fr_connection_get_fd(fr_connection_t const *conn); void fr_connection_reconnect(fr_connection_t *conn); diff --git a/src/main/connection.c b/src/main/connection.c index a1e5c974bc9..b95d45b4cf0 100644 --- a/src/main/connection.c +++ b/src/main/connection.c @@ -56,7 +56,7 @@ struct fr_conn { fr_connection_init_t init; //!< Callback for initialising a connection. fr_connection_open_t open; //!< Callback for 'open' notification. fr_connection_close_t close; //!< Callback to close a connection. - fr_connection_timeout_t timeout; //!< Callback for 'timeout' notification. + fr_connection_failed_t failed; //!< Callback for 'failed' notification. int fd; //!< File descriptor. fr_event_list_t *el; //!< Event list for timers and I/O events. @@ -122,6 +122,36 @@ static void connection_state_failed(fr_connection_t *conn, struct timeval *now) prev = conn->state; STATE_TRANSITION(FR_CONNECTION_STATE_FAILED); + /* + * If there's a failed callback, give it the + * opportunity to suspend/destroy the + * connection. + */ + if (conn->failed) { + fr_connection_state_t ret; + + /* + * Callback may free the connection, so we + * set this before calling the callback, so + * if the connection isn't freed it's in the + * correct state, without us needing to check. + */ + conn->state = FR_CONNECTION_STATE_HALTED; + ret = conn->failed(conn->fd, prev, conn->uctx); + switch (ret) { + case FR_CONNECTION_STATE_INIT: + connection_state_init(conn, now); + break; + + case FR_CONNECTION_STATE_HALTED: /* Do nothing */ + STATE_TRANSITION(FR_CONNECTION_STATE_HALTED); + return; + + default: + rad_assert(0); + } + } + switch (prev) { case FR_CONNECTION_STATE_INIT: /* Failed during initialisation */ case FR_CONNECTION_STATE_CONNECTED: /* Failed after connecting */ @@ -136,29 +166,7 @@ static void connection_state_failed(fr_connection_t *conn, struct timeval *now) break; case FR_CONNECTION_STATE_TIMEOUT: /* Failed during connecting */ - if (conn->timeout) { - fr_connection_state_t ret; - - /* - * Callback may free the connection, so we - * set this before calling the callback, so - * if the connection isn't freed it's in the - * correct state, without us needing to check. - */ - STATE_TRANSITION(FR_CONNECTION_STATE_HALTED); - ret = conn->timeout(conn->fd, conn->uctx); - switch (ret) { - case FR_CONNECTION_STATE_FAILED: - connection_state_init(conn, now); - break; - - case FR_CONNECTION_STATE_HALTED: /* Do nothing */ - break; - - default: - rad_assert(0); - } - } + connection_state_init(conn, now); break; default: @@ -390,12 +398,12 @@ fr_connection_t *fr_connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, return conn; } -/** Set an (optional) callback to be called on connection timeout +/** Set an (optional) callback to be called on connection timeout/failure * */ -void fr_connection_timeout_func(fr_connection_t *conn, fr_connection_timeout_t func) +void fr_connection_failed_func(fr_connection_t *conn, fr_connection_failed_t func) { - conn->timeout = func; + conn->failed = func; } /** Start a new or halted connection