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
+
#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
/* 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;
}
* 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;
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 */
retval[i][0] = '\0';
}
- return retval;
+ sqlsocket->row = retval;
+ return 0;
}
/*************************************************************************
/* 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;
* 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 */
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++)
(char *)freetds_sock->row[column],
columns[column]->column_size);
}
- return freetds_sock->row;
+ sqlsocket->row = freetds_sock->row;
+ return 0;
}
* 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;
}
#include <stdlib.h>
#include <string.h>
+#include <mysql/errmsg.h>
+
#include "radiusd.h"
#include "sql_mysql.h"
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))) {
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));
}
*************************************************************************/
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;
}
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;
-
}
#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;
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;
}
* 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;
+ }
}
MYSQL conn;
MYSQL *sock;
MYSQL_RES *result;
+ SQL_ROW row;
} rlm_sql_mysql_sock;
int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config);
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...
* 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,
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;
}
* 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);
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;
}
}
* 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);
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;
}
* 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;
}
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;
}
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
/* 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;
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);
}
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);
}
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));
/*
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);
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 {
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);
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) {
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;
}
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;
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]);
/*
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);
}
enum { sockconnected, sockunconnected } state;
void *conn;
+ SQL_ROW row;
} SQLSOCK;
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);
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
* 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;
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) {
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);
}
radlog(L_DBG, "rlm_sql: Released sql socket id: %d", sqlsocket->id);
- return 1;
+ return 0;
}
/*************************************************************************
*
+ * 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
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);
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)
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++;
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);
+ }
}
}
}