Add "lifetime" to SQL sockets.
authorAlan T. DeKok <aland@freeradius.org>
Fri, 28 Nov 2008 10:00:25 +0000 (11:00 +0100)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 5 Jan 2009 15:03:28 +0000 (16:03 +0100)
After "lifetime" seconds, an open connection is closed.  This can help
address issues such as firewalls that time out open connections...

raddb/sql.conf
src/modules/rlm_sql/conf.h
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sql/rlm_sql.h
src/modules/rlm_sql/sql.c

index c83afdf..4cba389 100644 (file)
@@ -80,6 +80,13 @@ sql {
        # connection (per_socket)
        connect_failure_retry_delay = 60
 
+       # lifetime of an SQL socket.  If you are having network issues
+       # such as TCP sessions expiring, you may need to set the socket
+       # lifetime.  If set to non-zero, any open connections will be
+       # closed "lifetime" seconds after they were first opened.
+       lifetime = 0
+
+
        # Set to 'yes' to read radius clients from the database ('nas' table)
        # Clients will ONLY be read on server startup.  For performance
        # and security reasons, finding clients via SQL queries CANNOT
index 3235dab..646468b 100644 (file)
@@ -42,6 +42,7 @@ typedef struct sql_config {
        char   *xlat_name;
        int     deletestalesessions;
        int     num_sql_socks;
+       int     lifetime;
        int     connect_failure_retry_delay;
        char   *postauth_query;
        char   *allowed_chars;
index 8d9956f..bcfddf1 100644 (file)
@@ -62,6 +62,8 @@ static const CONF_PARSER module_config[] = {
         offsetof(SQL_CONFIG,deletestalesessions), NULL, "yes"},
        {"num_sql_socks", PW_TYPE_INTEGER,
         offsetof(SQL_CONFIG,num_sql_socks), NULL, "5"},
+       {"lifetime", PW_TYPE_INTEGER,
+        offsetof(SQL_CONFIG,lifetime), NULL, "0"},
        {"sql_user_name", PW_TYPE_STRING_PTR,
         offsetof(SQL_CONFIG,query_user), NULL, ""},
        {"default_user_profile", PW_TYPE_STRING_PTR,
index 236078b..4847c46 100644 (file)
@@ -37,6 +37,7 @@ typedef struct sql_socket {
 
        void    *conn;
        SQL_ROW row;
+       time_t  connected;
 } SQLSOCK;
 
 typedef struct rlm_sql_module_t {
index ce00d83..f369985 100644 (file)
@@ -53,12 +53,12 @@ static int connect_single_socket(SQLSOCK *sqlsocket, SQL_INST *inst)
        int rcode;
        radlog(L_DBG, "rlm_sql (%s): Attempting to connect %s #%d",
               inst->config->xlat_name, inst->module->name, sqlsocket->id);
-
        rcode = (inst->module->sql_init_socket)(sqlsocket, inst->config);
        if (rcode == 0) {
                radlog(L_DBG, "rlm_sql (%s): Connected new DB handle, #%d",
                       inst->config->xlat_name, sqlsocket->id);
                sqlsocket->state = sockconnected;
+               if (inst->config->lifetime) time(&sqlsocket->connected);
                return(0);
        }
 
@@ -195,7 +195,7 @@ SQLSOCK * sql_get_socket(SQL_INST * inst)
        SQLSOCK *cur, *start;
        int tried_to_connect = 0;
        int unconnected = 0;
-       time_t now;
+       time_t now = time(NULL);
 
        /*
         *      Start at the last place we left off.
@@ -219,12 +219,25 @@ SQLSOCK * sql_get_socket(SQL_INST * inst)
 #endif
 
                /*
+                *      If the socket has outlived its lifetime, and
+                *      is connected, close it, and mark it as open for
+                *      reconnections.
+                */
+               if (inst->config->lifetime && (cur->state == sockconnected) &&
+                   ((cur->connected + inst->config->lifetime) < now)) {
+                       (inst->module->sql_close)(cur, inst->config);
+                       cur->state = sockunconnected;
+                       goto reconnect;
+               }
+
+               /*
                 *      If we happen upon an unconnected socket, and
                 *      this instance's grace period on
                 *      (re)connecting has expired, then try to
                 *      connect it.  This should be really rare.
                 */
-               if ((cur->state == sockunconnected) && (time(NULL) > inst->connect_after)) {
+               if ((cur->state == sockunconnected) && (now > inst->connect_after)) {
+               reconnect:
                        radlog(L_INFO, "rlm_sql (%s): Trying to (re)connect unconnected handle %d..", inst->config->xlat_name, cur->id);
                        tried_to_connect++;
                        connect_single_socket(cur, inst);
@@ -292,7 +305,6 @@ SQLSOCK * sql_get_socket(SQL_INST * inst)
         *      This code has race conditions when threaded, but the
         *      only result is that a few more messages are logged.
         */
-       now = time(NULL);
        if (now <= last_logged_failure) return NULL;
        last_logged_failure = now;