]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Make the 'timeout' callback, a generic failure callback
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 7 Jul 2017 16:27:31 +0000 (12:27 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 7 Jul 2017 16:27:31 +0000 (12:27 -0400)
The issue is the connection attempt might explicitly fail, not just timeout.

src/include/connection.h
src/main/connection.c

index 1cd5e550f1c94c4d5dd209376df068681fa1298a..25e5618f30b20160a2dd6d59f9012c804dc48c1d 100644 (file)
@@ -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);
index a1e5c974bc9ba54ba5781b9ceec8ef3ac9669431..b95d45b4cf044833cea0414a893b12d103c89a42 100644 (file)
@@ -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