SQL Socket Reconnect patch from Todd T. Fries.
authorcparker <cparker>
Thu, 11 Jul 2002 16:28:58 +0000 (16:28 +0000)
committercparker <cparker>
Thu, 11 Jul 2002 16:28:58 +0000 (16:28 +0000)
MySQL is completed.  Other drivers need to be updated to return
SQL_DOWN in the appropriate spots to trigger the reconnect
functionality.

Sybase driver is partially updated to use reconnect when the
DB closes the socket.

Info on what needs to be updated on other drivers can be found
in the rlm_sql/README file.

14 files changed:
src/modules/rlm_sql/README
src/modules/rlm_sql/conf.h
src/modules/rlm_sql/drivers/rlm_sql_db2/sql_db2.c
src/modules/rlm_sql/drivers/rlm_sql_freetds/sql_freetds.c
src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.c
src/modules/rlm_sql/drivers/rlm_sql_mysql/sql_mysql.c
src/modules/rlm_sql/drivers/rlm_sql_mysql/sql_mysql.h
src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.c
src/modules/rlm_sql/drivers/rlm_sql_postgresql/sql_postgresql.c
src/modules/rlm_sql/drivers/rlm_sql_sybase/sql_sybase.c
src/modules/rlm_sql/drivers/rlm_sql_unixodbc/sql_unixodbc.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sql/rlm_sql.h
src/modules/rlm_sql/sql.c

index 0cfcc16..a643249 100644 (file)
@@ -7,3 +7,23 @@ Mike Machado
 mike@innercite.com
 InnerCite Inc.
 Engineering Director / CTO
+
+Returning 'SQL_DOWN' allows sql.c to reconnect and try again, in most cases
+
+sql_select_query: returns -1 on failure, SQL_DOWN on 'socket not connected'
+sql_query: returns -1 on failure, SQL_DOWN on 'socket not connected'
+sql_store_result: returns -1 on failure, SQL_DOWN on 'socket not connected'
+sql_num_fields: cannot return an error, complains if zero fields
+sql_finish_select_query: returns 0 always
+sql_finish_query: does nothing, returns 0
+sql_free_result: returns 0 always, mysql_free_result has no return value
+sql_release_socket: returns 1 always
+sql_fetch_row: returns 0 if ok, SQL_DOWN on 'socket not connected', row is
+               in sqlsocket->row now
+
+TODO:
+
+db2/freetds/iodbc/oracle/postgresql/sybase/unixodbc:
+     for the above functions, where it can return SQL_DOWN, determine if an
+     error with the database exists, if it is down, and return SQL_DOWN
+
index a4e2d4c..954e244 100644 (file)
@@ -81,6 +81,9 @@ typedef struct sql_config {
 #define SQL_LOCK_LEN                   MAX_QUERY_LEN
 #define        SQLTRACEFILE                    RADLOG_DIR "/sqltrace.sql"
 
+/* SQL Errors */
+#define SQL_DOWN                       1 /* for re-connect */
+
 #define MAX_COMMUNITY_LEN              50
 #define MAX_SQL_SOCKS                  256
 #define MAX_TABLE_LEN                  20
index 0563684..7e4c4ab 100644 (file)
@@ -97,6 +97,7 @@ int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
        /* execute query */
        retval = SQLExecDirect(sock->stmt, querystr, SQL_NTS);
        if(retval != SQL_SUCCESS) {
+               /* XXX Check if retval means we should return SQL_DOWN */
                radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
                return -1;
        }
@@ -156,10 +157,11 @@ int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config)
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) 
+int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) 
 {
        int c, i;
        SQLINTEGER len, slen;
@@ -171,8 +173,10 @@ SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
        c = sql_num_fields(sqlsocket, config);
        retval = (SQL_ROW)rad_malloc(c*sizeof(char*)+1);
        /* advance cursor */
-       if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND)
-               return NULL;
+       if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) {
+               sqlsocket->row = NULL;
+               return 0;
+       }
 
        for(i = 0; i < c; i++) {
                /* get column length */
@@ -187,7 +191,8 @@ SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
                        retval[i][0] = '\0';
        }
 
-       return retval;
+       sqlsocket->row = retval;
+       return 0;
 }
 
 /*************************************************************************
index 289ca21..d9a614f 100644 (file)
@@ -137,6 +137,7 @@ int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
     /* Executing query */
     if (tds_submit_query(freetds_sock->tds_socket, querystr) != TDS_SUCCEED)
     {
+       /* XXX determine if return above suggests returning SQL_DOWN or not */
        radlog(L_ERR, "rlm_sql_freetds: Can't execute the query");
        radlog(L_ERR, "rlm_sql_freetds: %s", freetds_sock->tds_socket->msg_info->message);
        return -1;
@@ -264,34 +265,39 @@ int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
     rlm_sql_freetds_sock *freetds_sock = sqlsocket->conn;
     TDSRESULTINFO *result_info;    
     TDSCOLINFO **columns;
     int numfields, column, retcode;
 
+    sqlsocket->row = NULL;
+
     retcode = tds_process_row_tokens(freetds_sock->tds_socket);
+    /* XXX Check if retcode is something we should return SQL_DOWN for */
     if (retcode == TDS_NO_MORE_ROWS)
     {
-       return NULL;
+       return 0;
     } else if (retcode != TDS_SUCCEED) {
        radlog(L_ERR, "rlm_sql_freetds: A error occured during fetching the row");
-       return NULL;
+       return -1;
     }
     
     /* Getting amount of result fields */
     numfields = sql_num_fields(sqlsocket, config);
-    if (numfields < 0) return NULL;
+    if (numfields < 0)
+       return 0;
 
     /* Get information about the resulting set */
     result_info = freetds_sock->tds_socket->res_info;
     if (result_info == NULL)
     {
        radlog(L_ERR, "rlm_sql_freetds: Can't get information about the resulting set");
-       return NULL;
+       return -1;
     }
     
     /* Get information about the column set */
@@ -299,11 +305,11 @@ SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
     if (columns == NULL)
     {
        radlog(L_ERR, "rlm_sql_freetds: Can't get information about the column set");
-       return NULL;
+       return -1;
     }
 
     /* Alocating the memory */
-    if (sql_store_result(sqlsocket, config) < 0) return NULL;
+    if (sql_store_result(sqlsocket, config) < 0) return 0;
 
     /* Converting the fields to a CHAR data type */
     for (column = 0; column < numfields; column++)
@@ -319,7 +325,8 @@ SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
            (char *)freetds_sock->row[column],
            columns[column]->column_size);
     }
-    return freetds_sock->row;
+    sqlsocket->row = freetds_sock->row;
+    return 0;
 }
 
 
index 633bfe0..e2aa845 100644 (file)
@@ -207,18 +207,24 @@ int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
 
        SQLRETURN rc;
        rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
 
+       sqlsocket->row = NULL;
+
        if((rc = SQLFetch(iodbc_sock->stmt_handle)) == SQL_NO_DATA_FOUND) {
-               return NULL;
+               return 0;
        }
-       return iodbc_sock->row;
+       /* XXX Check rc for database down, if so, return SQL_DOWN */
+       
+       sqlsocket->row = iodbc_sock->row;
+       return 0;
 }
 
 
index 7c9cc84..6e55071 100644 (file)
@@ -27,6 +27,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <mysql/errmsg.h>
+
 #include       "radiusd.h"
 #include       "sql_mysql.h"
 
@@ -46,6 +48,9 @@ int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
 
        mysql_sock = sqlsocket->conn;
 
+       radlog(L_INFO, "rlm_sql: Starting connect to MySQL server for #%d",
+                       sqlsocket->id);
+
        mysql_init(&(mysql_sock->conn));
        if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn), config->sql_server, config->sql_login, config->sql_password,
                                                                                                        config->sql_db, 0, NULL, CLIENT_FOUND_ROWS))) {
@@ -93,13 +98,10 @@ int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) {
                radlog(L_DBG,"query:  %s", querystr);
        if (mysql_sock->sock == NULL) {
                radlog(L_ERR, "Socket not connected");
-               return -1;
-       }
-       if (mysql_query(mysql_sock->sock, querystr) == 0) {
-               return 0;
-       } else {
-               return -1;
+               return SQL_DOWN;
        }
+
+       return sql_check_error(mysql_query(mysql_sock->sock, querystr));
 }
 
 
@@ -112,19 +114,23 @@ int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) {
  *************************************************************************/
 int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
 
-       rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
+       int ret;
 
-       if (config->sqltrace)
-               radlog(L_DBG,querystr);
-       if (mysql_sock->sock == NULL) {
-               radlog(L_ERR, "Socket not connected");
-               return -1;
+       ret = sql_query(sqlsocket, config, querystr);
+       if(ret)
+               return ret;
+       ret = sql_store_result(sqlsocket, config);
+       if (ret) {
+               return ret;
        }
-       mysql_query(mysql_sock->sock, querystr);
-       if (sql_store_result(sqlsocket, config) < 0 || sql_num_fields(sqlsocket, config) < 0)
-               return -1;
-       else
-               return 0;
+
+       /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
+        * this cannot return an error.  Perhaps just to complain if no
+        * fields are found?
+        */
+       sql_num_fields(sqlsocket, config);
+
+       return ret;
 }
 
 
@@ -142,15 +148,14 @@ int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 
        if (mysql_sock->sock == NULL) {
                radlog(L_ERR, "Socket not connected");
-               return -1;
+               return SQL_DOWN;
        }
        if (!(mysql_sock->result = mysql_store_result(mysql_sock->sock))) {
                radlog(L_ERR, "MYSQL Error: Cannot get result");
                radlog(L_ERR, "MYSQL Error: %s", mysql_error(mysql_sock->sock));
-               return -1;
+               return sql_check_error(mysql_errno(mysql_sock->sock));
        }
        return 0;
-
 }
 
 
@@ -173,7 +178,7 @@ int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 #else
        if (!(num = mysql_num_fields(mysql_sock->sock))) {
 #endif
-               radlog(L_ERR, "MYSQL Error: Cannot get result");
+               radlog(L_ERR, "MYSQL Error: No Fields");
                radlog(L_ERR, "MYSQL error: %s", mysql_error(mysql_sock->sock));
        }
        return num;
@@ -192,7 +197,10 @@ int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
-       return mysql_num_rows(mysql_sock->result);
+       if(mysql_sock->result)
+               return mysql_num_rows(mysql_sock->result);
+
+       return 0;
 }
 
 
@@ -201,14 +209,49 @@ int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if database is down.
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
-       return mysql_fetch_row(mysql_sock->result);
+       sqlsocket->row = mysql_fetch_row(mysql_sock->result);
+
+       if (sqlsocket->row == NULL) {
+               return sql_check_error(mysql_errno(mysql_sock->sock));
+       }
+       return 0;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_check_error
+ *
+ *     Purpose: check the error to see if the server is down
+ *
+ *************************************************************************/
+int sql_check_error(int error) {
+       switch(error) {
+       case CR_SERVER_GONE_ERROR:
+       case CR_SERVER_LOST:
+       case -1:
+               radlog(L_DBG, "MYSQL check_error: %d, returning SQL_DOWN", error);
+               return SQL_DOWN;
+               break;
+       case 0:
+               return 0;
+               break;
+       case CR_OUT_OF_MEMORY:
+       case CR_COMMANDS_OUT_OF_SYNC:
+       case CR_UNKNOWN_ERROR:
+       default:
+               radlog(L_DBG, "MYSQL check_error: %d received", error);
+               return -1;
+               break;
+       }
 }
 
 
index 1a706bd..c5cb968 100644 (file)
@@ -12,6 +12,7 @@ typedef struct rlm_sql_mysql_sock {
        MYSQL conn;
        MYSQL *sock;
        MYSQL_RES *result;
+       SQL_ROW row;
 } rlm_sql_mysql_sock;
 
 int    sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config);
@@ -21,13 +22,14 @@ int     sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr)
 int     sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config);
 int     sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config);
 int     sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-int    sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-char   *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-int    sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-int    sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config);
-int    sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int     sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int     sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+char    *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int     sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int     sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int     sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config);
 int     sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config);
+int    sql_check_error(int error);
 /*
  * Unused.  Now provided in rlm_sql main module.
  * But left in here just in case...
index 4284b42..806c9a2 100644 (file)
@@ -354,14 +354,17 @@ int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if database is down.
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
 
        int     x;
        rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
 
+       sqlsocket->row = NULL;
+
        x=OCIStmtFetch(oracle_sock->queryHandle,
                        oracle_sock->errHandle,
                        1,
@@ -371,12 +374,14 @@ SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
                return NULL;
        }
        else if (x != OCI_SUCCESS) {
+               /* XXX Check if x suggests we should return SQL_DOWN */
                radlog(L_ERR,"sql_fetch_row: fetch failed: %s",
                                sql_error(sqlsocket, config));
-               return NULL;
+               return -1;
        }
 
-       return oracle_sock->results;
+       sqlsocket->row = oracle_sock->results;
+       return 0;
 }
 
 
index 54b569f..e7b5deb 100644 (file)
@@ -238,16 +238,19 @@ int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'.
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 
        int records, i, len;
        rlm_sql_postgres_sock *pg_sock = sqlsocket->conn;
 
+       sqlsocket->row = NULL;
+
        if (pg_sock->cur_row >= PQntuples(pg_sock->result))
-               return NULL;
+               return 0;
 
        free_result_row(pg_sock);
 
@@ -265,9 +268,10 @@ SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
                        strncpy(pg_sock->row[i], PQgetvalue(pg_sock->result, pg_sock->cur_row,i),len);
                }
                pg_sock->cur_row++;
-               return pg_sock->row;
+               sqlsocket->row = pg_sock->row;
+               return 0;
        } else {
-               return NULL;
+               return 0;
        }
 }
 
index a3ff8ba..1185f7b 100644 (file)
@@ -645,14 +645,17 @@ int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'.
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
 
        rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
        CS_INT          ret, count;
 
+       sqlsocket->row = NULL;
+
 
        ret = ct_fetch(sybase_sock->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
 
@@ -672,28 +675,29 @@ SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
                        ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
                        sql_close(sqlsocket, config);
                }
-               return NULL;
+               return SQL_DOWN;
                break;
 
        case CS_END_DATA:
 
-               return NULL;
+               return 0;
                break;
 
        case CS_SUCCEED:
 
-               return sybase_sock->results;
+               sqlsocket->row = sybase_sock->results;
+               return 0;
                break;
 
        case CS_ROW_FAIL:
        
                radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Recoverable failure fething row data, try again perhaps?");
-               return NULL;
+               return -1;
 
        default:
                
                radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Unexpected returncode from ct_fetch");
-               return NULL;
+               return -1;
                break;
        }
 
index 45a196a..fad9fa1 100644 (file)
@@ -204,16 +204,22 @@ int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Function: sql_fetch_row
  *
  *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
- *               with all the data for the query
+ *               with all the data for the query in 'sqlsocket->row'. Returns
+ *              0 on success, -1 on failure, SQL_DOWN if 'database is down'.
  *
  *************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
     rlm_sql_unixodbc_sock *unixodbc_sock = sqlsocket->conn;
 
+    sqlsocket->row = NULL;
+
     if(SQLFetch(unixodbc_sock->stmt_handle) == SQL_NO_DATA_FOUND)
-       return NULL;
+       return 0;
+
+    /* XXX Check if return suggests we should return error or SQL_DOWN */
 
-    return unixodbc_sock->row;
+    sqlsocket->row = unixodbc_sock->row;
+    return 0;
 }
 
 
index e185399..c208cc2 100644 (file)
@@ -128,15 +128,22 @@ static int sql_xlat(void *instance, REQUEST *request, char *fmt, char *out, int
        sqlsocket = sql_get_socket(inst);
        if (sqlsocket == NULL)
                return 0;
-       if ((inst->module->sql_select_query)(sqlsocket,inst->config,querystr) <0){
+       if (_sql_select_query(sqlsocket,inst,querystr)){
                radlog(L_ERR, "rlm_sql: database query error");
                sql_release_socket(inst,sqlsocket);
                return 0;
        }
-       row = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
+
+       ret = _sql_fetch_row(sqlsocket, inst);
+
        (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
        sql_release_socket(inst,sqlsocket);
-       if (row == NULL){
+       if (ret) {
+               DEBUG("rlm_sql: SQL query did not succeed");
+               return 0;
+       }
+       row = sqlsocket->row;
+       if (row == NULL) {
                DEBUG("rlm_sql: SQL query did not return any results");
                return 0;
        }
@@ -325,6 +332,7 @@ static int rlm_sql_authorize(void *instance, REQUEST * request) {
        SQL_INST *inst = instance;
        SQL_ROW row;
        char    querystr[MAX_QUERY_LEN];
+       int     ret;
 
        /* sqlusername holds the sql escaped username. The original
         * username is at most MAX_STRING_LEN chars long and
@@ -454,16 +462,22 @@ static int rlm_sql_authorize(void *instance, REQUEST * request) {
                /* Remove the username we (maybe) added above */
                pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
 
-               if ((inst->module->sql_select_query)(sqlsocket, inst->config, querystr) < 0) {
+               if (_sql_select_query(sqlsocket, inst, querystr)) {
                        radlog(L_ERR, "rlm_sql_authorize: database query error");
                        sql_release_socket(inst, sqlsocket);
                        return RLM_MODULE_FAIL;
                }
+               ret = _sql_fetch_row(sqlsocket, inst);
 
-               row = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
                (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
                sql_release_socket(inst, sqlsocket);
 
+               if (ret) {
+                       radlog(L_ERR, "rlm_sql_authorize: query failed");
+                       return RLM_MODULE_FAIL;
+               }
+
+               row = sqlsocket->row;
                if (row == NULL) {
                        radlog(L_ERR, "rlm_sql_authorize: no rows returned from query (no such user)");
                        return RLM_MODULE_OK;
@@ -531,7 +545,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                        if (sqlsocket == NULL)
                                return(RLM_MODULE_FAIL);
                        if (querystr) {
-                               if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0)
+                               if (_sql_query(sqlsocket, inst, querystr))
                                        radlog(L_ERR, "rlm_sql: Couldn't update SQL accounting for Acct On/Off packet - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
                                (inst->module->sql_finish_query)(sqlsocket, inst->config);
                        }
@@ -555,7 +569,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                        if (sqlsocket == NULL)
                                return(RLM_MODULE_FAIL);
                        if (querystr) {
-                               if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0)
+                               if (_sql_query(sqlsocket, inst, querystr))
                                        radlog(L_ERR, "rlm_sql: Couldn't update SQL accounting for ALIVE packet - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
                                (inst->module->sql_finish_query)(sqlsocket, inst->config);
                        }
@@ -579,7 +593,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                        if (sqlsocket == NULL)
                                return(RLM_MODULE_FAIL);
                        if (querystr) {
-                               if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0) {
+                               if (_sql_query(sqlsocket, inst, querystr)) {
                                        radlog(L_ERR, "rlm_sql: Couldn't update SQL accounting" " for START packet - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
 
                                        /*
@@ -591,7 +605,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                                        query_log(inst, querystr);
 
                                        if (querystr) {
-                                               if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0) {
+                                               if (_sql_query(sqlsocket, inst, querystr)) {
                                                        radlog(L_ERR, "rlm_sql: Couldn't update SQL" "accounting START record - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
                                                }
                                                (inst->module->sql_finish_query)(sqlsocket, inst->config);
@@ -618,7 +632,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                        if (sqlsocket == NULL)
                                return(RLM_MODULE_FAIL);
                        if (querystr) {
-                               if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0) {
+                               if (_sql_query(sqlsocket, inst, querystr)) {
                                        radlog(L_ERR, "rlm_sql: Couldn't update SQL accounting STOP record - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
                                }
                                else {
@@ -652,7 +666,7 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
                                                query_log(inst, querystr);
 
                                                if (querystr) {
-                                                       if ((inst->module->sql_query)(sqlsocket, inst->config, querystr) < 0) {
+                                                       if (_sql_query(sqlsocket, inst, querystr)) {
                                                                radlog(L_ERR, "rlm_sql: Couldn't insert SQL accounting STOP record - %s", (char *)(inst->module->sql_error)(sqlsocket, inst->config));
                                                        }
                                                        (inst->module->sql_finish_query)(sqlsocket, inst->config);
@@ -689,6 +703,7 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
         uint32_t        ipno = 0;
         char            *call_num = NULL;
        VALUE_PAIR      *vp;
+       int             ret;
 
        /* If simul_count_query is not defined, we don't do any checking */
        if (inst->config->simul_count_query[0] == 0) {
@@ -709,16 +724,31 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
                return RLM_MODULE_FAIL;
 
        radius_xlat(querystr, MAX_QUERY_LEN, inst->config->simul_count_query, request, NULL);
-       if((inst->module->sql_select_query)(sqlsocket, inst->config, querystr) < 0) {
+       if(_sql_select_query(sqlsocket, inst, querystr)) {
                radlog(L_ERR, "sql_checksimul: Database query failed");
                sql_release_socket(inst, sqlsocket);
                return RLM_MODULE_FAIL;
        }
 
-       row = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
-       request->simul_count = atoi(row[0]);
+       ret = _sql_fetch_row(sqlsocket, inst);
+
+       if (ret == 0) {
+               row = sqlsocket->row;
+       }
        (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
 
+       if (ret) {
+               sql_release_socket(inst, sqlsocket);
+               return RLM_MODULE_FAIL;
+       }
+
+       if (row == NULL) {
+               sql_release_socket(inst, sqlsocket);
+               return RLM_MODULE_FAIL;
+       }
+
+       request->simul_count = atoi(row[0]);
+
        if(request->simul_count < request->simul_max) {
                sql_release_socket(inst, sqlsocket);
                return RLM_MODULE_OK;
@@ -732,7 +762,7 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
        }
 
        radius_xlat(querystr, MAX_QUERY_LEN, inst->config->simul_verify_query, request, NULL);
-       if((inst->module->sql_select_query)(sqlsocket, inst->config, querystr) < 0) {
+       if(_sql_select_query(sqlsocket, inst, querystr)) {
                radlog(L_ERR, "sql_checksimul: Database query error");
                sql_release_socket(inst, sqlsocket);
                return RLM_MODULE_FAIL;
@@ -749,7 +779,10 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
                 call_num = vp->strvalue;        
 
 
-       while((row=(inst->module->sql_fetch_row)(sqlsocket, inst->config))) {
+       while (_sql_fetch_row(sqlsocket, inst) == 0) {
+               row = sqlsocket->row;
+               if (row == NULL)
+                       break;
                check = rad_check_ts((uint32_t)row[3], (int)row[4], row[2], row[1]);
 
                 /*
@@ -782,7 +815,10 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
                                                                row[1],row[3],row[4]);
                                sqlsocket1 = sql_get_socket(inst);
                                sprintf(querystr, inst->config->simul_zap_query, row[0]);
-                               (inst->module->sql_query)(sqlsocket1, inst->config, querystr);
+                               if (_sql_query(sqlsocket1, inst, querystr)) {
+                                       radlog(L_ERR, "rlm_sql: Deletion of stale session [%s] failed",
+                                                               row[1]);
+                               }
                                (inst->module->sql_finish_select_query)(sqlsocket1, inst->config);
                                sql_release_socket(inst, sqlsocket1);
                        }
index 3465d33..524887a 100644 (file)
@@ -44,6 +44,7 @@ typedef struct sql_socket {
        enum { sockconnected, sockunconnected } state;
 
        void    *conn;
+       SQL_ROW row;
 } SQLSOCK;
 
 typedef struct rlm_sql_module_t {
@@ -55,7 +56,7 @@ typedef struct rlm_sql_module_t {
        int (*sql_store_result)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
        int (*sql_num_fields)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
        int (*sql_num_rows)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
-       SQL_ROW (*sql_fetch_row)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
+       int (*sql_fetch_row)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
        int (*sql_free_result)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
        char *(*sql_error)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
        int (*sql_close)(SQLSOCK *sqlsocket, SQL_CONFIG *config);
@@ -92,4 +93,7 @@ int     sql_read_naslist(SQLSOCK * sqlsocket);
 int     sql_read_clients(SQLSOCK * sqlsocket);
 int     sql_dict_init(SQLSOCK * sqlsocket);
 void    query_log(SQL_INST * inst, char *querystr);
+int    _sql_select_query(SQLSOCK *sqlsocket, SQL_INST *inst, char *query);
+int    _sql_query(SQLSOCK *sqlsocket, SQL_INST *inst, char *query);
+int    _sql_fetch_row(SQLSOCK *sqlsocket, SQL_INST *inst);
 #endif
index b7e39d0..be52b69 100644 (file)
@@ -60,6 +60,7 @@
  * issues).  If successful in connecting, set state to sockconnected.   - chad
  */
 static int connect_single_socket(SQLSOCK *sqlsocket, SQL_INST *inst) {
+       radlog(L_DBG, "rlm_sql:  Attempting to connect #%d", sqlsocket->id);
        if ((inst->module->sql_init_socket)(sqlsocket, inst->config) < 0) {
                radlog(L_CONS | L_ERR, "rlm_sql:  Failed to connect DB handle #%d", sqlsocket->id);
                inst->connect_after = time(NULL) + inst->config->connect_failure_retry_delay;
@@ -91,6 +92,7 @@ int sql_init_socketpool(SQL_INST * inst) {
        inst->socknr = 0;
 
        for (i = 0; i < inst->config->num_sql_socks; i++) {
+               radlog(L_DBG, "rlm_sql: starting %d", i);
 
                sqlsocket = rad_malloc(sizeof(SQLSOCK));
                if (sqlsocket == NULL) {
@@ -112,6 +114,7 @@ int sql_init_socketpool(SQL_INST * inst) {
 
                if (time(NULL) > inst->connect_after) {
                        /* this sets the sqlsocket->state, and possibly sets inst->connect_after */
+                       /* FIXME! check return code */
                        connect_single_socket(sqlsocket, inst);
                }
 
@@ -257,7 +260,7 @@ int sql_release_socket(SQL_INST * inst, SQLSOCK * sqlsocket) {
 
        radlog(L_DBG, "rlm_sql: Released sql socket id: %d", sqlsocket->id);
 
-       return 1;
+       return 0;
 }
 
 
@@ -307,6 +310,94 @@ int sql_userparse(VALUE_PAIR ** first_pair, SQL_ROW row, int querymode) {
 
 /*************************************************************************
  *
+ *     Function: _sql_fetch_row
+ *
+ *     Purpose: call the module's sql_fetch_row and implement re-connect
+ *
+ *************************************************************************/
+int _sql_fetch_row(SQLSOCK *sqlsocket, SQL_INST *inst) {
+       int ret;
+
+       ret = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
+
+       if (ret == SQL_DOWN) {
+               if (connect_single_socket(sqlsocket, inst) < 0) {
+                       radlog(L_ERR, "rlm_sql: reconnect failed, database down?");
+                       return -1;
+               }
+
+               ret = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
+
+               if (ret) {
+                       radlog(L_ERR, "rlm_sql: failed after re-connect");
+                       return -1;
+               }
+       }
+
+       return ret;
+}
+
+/*************************************************************************
+ *
+ *     Function: _sql_query
+ *
+ *     Purpose: call the module's sql_query and implement re-connect
+ *
+ *************************************************************************/
+int _sql_query(SQLSOCK *sqlsocket, SQL_INST *inst, char *query) {
+       int ret;
+
+       ret = (inst->module->sql_query)(sqlsocket, inst->config, query);
+
+       if (ret == SQL_DOWN) {
+               if (connect_single_socket(sqlsocket, inst) < 0) {
+                       radlog(L_ERR, "rlm_sql: reconnect failed, database down?");
+                       return -1;
+               }
+
+               ret = (inst->module->sql_query)(sqlsocket, inst->config, query);
+
+               if (ret) {
+                       radlog(L_ERR, "rlm_sql: failed after re-connect");
+                       return -1;
+               }
+       }
+
+       return ret;
+}
+
+/*************************************************************************
+ *
+ *     Function: _sql_select_query
+ *
+ *     Purpose: call the module's sql_select_query and implement re-connect
+ *
+ *************************************************************************/
+int _sql_select_query(SQLSOCK *sqlsocket, SQL_INST *inst, char *query) {
+       int ret;
+
+       ret = (inst->module->sql_select_query)(sqlsocket, inst->config, query);
+
+       if (ret == SQL_DOWN) {
+               if (connect_single_socket(sqlsocket, inst) < 0) {
+                       radlog(L_ERR, "rlm_sql: reconnect failed, database down?");
+                       return -1;
+               }
+
+               ret = (inst->module->sql_select_query)(sqlsocket, inst->config, query);
+
+               if (ret) {
+                       radlog(L_ERR, "rlm_sql: failed after re-connect");
+                       return -1;
+               }
+       }
+
+       return ret;
+}
+
+
+/*************************************************************************
+ *
  *     Function: sql_getvpdata
  *
  *     Purpose: Get any group check or reply pairs
@@ -317,11 +408,14 @@ int sql_getvpdata(SQL_INST * inst, SQLSOCK * sqlsocket, VALUE_PAIR **pair, char
        SQL_ROW row;
        int     rows = 0;
 
-       if ((inst->module->sql_select_query)(sqlsocket, inst->config, query) < 0) {
+       if (_sql_select_query(sqlsocket, inst, query)) {
                radlog(L_ERR, "rlm_sql_getvpdata: database query error");
                return -1;
        }
-       while ((row = (inst->module->sql_fetch_row)(sqlsocket, inst->config))) {
+       while (_sql_fetch_row(sqlsocket, inst)==0) {
+               row = sqlsocket->row;
+               if (!row)
+                       break;
                if (sql_userparse(pair, row, mode) != 0) {
                        radlog(L_ERR | L_CONS, "rlm_sql:  Error getting data from database");
                        (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
@@ -447,13 +541,24 @@ int sql_check_multi(SQL_INST * inst, SQLSOCK * sqlsocket, char *name, VALUE_PAIR
 
        sprintf(authstr, "UserName = '%s'", name);
        sprintf(querystr, "SELECT COUNT(*) FROM %s WHERE %s AND AcctStopTime = 0", inst->config->sql_acct_table, authstr);
-       if ((inst->module->sql_select_query)(sqlsocket, inst->config, querystr) < 0) {
+       
+
+       if (_sql_select_query(sqlsocket, inst, querystr)) {
                radlog(L_ERR, "sql_check_multi: database query error");
                return -1;
        }
 
-       row = (inst->module->sql_fetch_row)(sqlsocket, inst->config);
-       count = atoi(row[0]);
+       if (_sql_fetch_row(sqlsocket, inst->config)) {
+               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+               return -1;
+       }
+
+       row = sqlsocket->row;
+       if (row != NULL) {
+               count = atoi(row[0]);
+       } else {
+               count = 0;
+       }
        (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
 
        if (count < maxsimul)
@@ -467,12 +572,18 @@ int sql_check_multi(SQL_INST * inst, SQLSOCK * sqlsocket, char *name, VALUE_PAIR
 
        count = 0;
        sprintf(querystr, "SELECT * FROM %s WHERE %s AND AcctStopTime = 0", inst->config->sql_acct_table, authstr);
-       if ((inst->module->sql_select_query)(sqlsocket, inst->config, querystr) < 0) {
+
+       if (_sql_select_query(sqlsocket, inst, querystr)) {
                radlog(L_ERR, "sql_check_multi: database query error");
                return -1;
        }
-       while ((row = (inst->module->sql_fetch_row)(sqlsocket, inst->config))) {
-               int     check = sql_check_ts(row);
+       while (_sql_fetch_row(sqlsocket, inst) == 0) {
+               int     check;
+               row = sqlsocket->row;
+               if (row == NULL) {
+                       break;
+               }
+               check = sql_check_ts(row);
 
                if (check == 1) {
                        count++;
@@ -493,9 +604,12 @@ int sql_check_multi(SQL_INST * inst, SQLSOCK * sqlsocket, char *name, VALUE_PAIR
                                radlog(L_ERR, "rlm_sql:  Deleteing stale session [%s] (from nas %s/%s)", row[2], row[4], row[5]);
                                sqlsocket1 = sql_get_socket(inst);
                                sprintf(querystr, "DELETE FROM %s WHERE RadAcctId = '%s'", inst->config->sql_acct_table, row[0]);
-                               (inst->module->sql_query)(sqlsocket1, inst->config, querystr);
-                               (inst->module->sql_finish_query)(sqlsocket1, inst->config);
-                               sql_release_socket(inst, sqlsocket1);
+                               if(_sql_query(sqlsocket1, inst, querystr)) {
+                                       radlog(L_ERR, "rlm_sql: database query error");
+                               } else {
+                                       (inst->module->sql_finish_query)(sqlsocket1, inst->config);
+                                       sql_release_socket(inst, sqlsocket1);
+                               }
                        }
                }
        }