Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_mysql / sql_mysql.c
index bd692b6..8da0503 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000  The FreeRADIUS server project
+ * Copyright 2000,2006  The FreeRADIUS server project
  * Copyright 2000  Mike Machado <mike@innercite.com>
  * Copyright 2000  Alan DeKok <aland@ox.org>
  */
 
-#include <stdio.h>
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
 #include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
 
-#include       "radiusd.h"
-#include       "sql_mysql.h"
+#include "config.h"
+
+#ifdef HAVE_MYSQL_MYSQL_H
+#include <mysql/mysql_version.h>
+#include <mysql/errmsg.h>
+#include <mysql/mysql.h>
+#else
+#ifdef HAVE_MYSQL_H
+#include <mysql_version.h>
+#include <errmsg.h>
+#include <mysql.h>
+#endif
+#endif
+
+#include       "rlm_sql.h"
 
+typedef struct rlm_sql_mysql_sock {
+       MYSQL conn;
+       MYSQL *sock;
+       MYSQL_RES *result;
+       SQL_ROW row;
+} rlm_sql_mysql_sock;
 
 /*************************************************************************
  *
  *     Purpose: Establish connection to the db
  *
  *************************************************************************/
-int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
+static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock;
 
-       sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
-
+       if (!sqlsocket->conn) {
+               sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
+               if (!sqlsocket->conn) {
+                       return -1;
+               }
+       }
        mysql_sock = sqlsocket->conn;
+       memset(mysql_sock, 0, sizeof(*mysql_sock));
+
+       radlog(L_INFO, "rlm_sql_mysql: 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_ERR, "rlm_sql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
-               radlog(L_ERR, "rlm_sql:  Mysql error '%s'", mysql_error(&mysql_sock->conn));
+       mysql_options(&(mysql_sock->conn), MYSQL_READ_DEFAULT_GROUP, "freeradius");
+       if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn),
+                                                   config->sql_server,
+                                                   config->sql_login,
+                                                   config->sql_password,
+                                                   config->sql_db,
+                                                   atoi(config->sql_port),
+                                                   NULL,
+                                                   CLIENT_FOUND_ROWS))) {
+               radlog(L_ERR, "rlm_sql_mysql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
+               radlog(L_ERR, "rlm_sql_mysql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
                mysql_sock->sock = NULL;
                return -1;
        }
@@ -67,12 +103,10 @@ int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
  *     Purpose: Free socket and any private connection data
  *
  *************************************************************************/
-int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
-       rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
-
-       free(mysql_sock);
-       free(sqlsocket);
+static int sql_destroy_socket(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config)
+{
+       free(sqlsocket->conn);
+       sqlsocket->conn = NULL;
 
        return 0;
 }
@@ -80,51 +114,54 @@ int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
 
 /*************************************************************************
  *
- *     Function: sql_query
+ *     Function: sql_check_error
  *
- *     Purpose: Issue a query to the database
+ *     Purpose: check the error to see if the server is down
  *
  *************************************************************************/
-int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) {
-
-       rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
-
-       if (config->sqltrace)
-               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) {
+static int sql_check_error(int error)
+{
+       switch(error) {
+       case CR_SERVER_GONE_ERROR:
+       case CR_SERVER_LOST:
+       case -1:
+               radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d, returning SQL_DOWN", error);
+               return SQL_DOWN;
+               break;
+       case 0:
                return 0;
-       } else {
+               break;
+       case CR_OUT_OF_MEMORY:
+       case CR_COMMANDS_OUT_OF_SYNC:
+       case CR_UNKNOWN_ERROR:
+       default:
+               radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d received", error);
                return -1;
+               break;
        }
 }
 
 
 /*************************************************************************
  *
- *     Function: sql_select_query
+ *     Function: sql_query
  *
- *     Purpose: Issue a select query to the database
+ *     Purpose: Issue a query to the database
  *
  *************************************************************************/
-int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
-
+static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
        if (config->sqltrace)
-               radlog(L_DBG,querystr);
+               radlog(L_DBG,"rlm_sql_mysql: query:  %s", querystr);
        if (mysql_sock->sock == NULL) {
-               radlog(L_ERR, "Socket not connected");
-               return -1;
+               radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
+               return SQL_DOWN;
        }
+
        mysql_query(mysql_sock->sock, querystr);
-       if (sql_store_result(sqlsocket, config) < 0 || sql_num_fields(sqlsocket, config) < 0)
-               return -1;
-       else
-               return 0;
+       return sql_check_error(mysql_errno(mysql_sock->sock));
 }
 
 
@@ -136,21 +173,21 @@ int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
  *               set for the query.
  *
  *************************************************************************/
-int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_store_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
        if (mysql_sock->sock == NULL) {
-               radlog(L_ERR, "Socket not connected");
-               return -1;
+               radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
+               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;
+               radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: Cannot get result");
+               radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: %s",
+                      mysql_error(mysql_sock->sock));
+               return sql_check_error(mysql_errno(mysql_sock->sock));
        }
        return 0;
-
 }
 
 
@@ -162,9 +199,8 @@ int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *               of columns from query
  *
  *************************************************************************/
-int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
-
+static int sql_num_fields(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        int     num = 0;
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
@@ -173,8 +209,9 @@ 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: %s", mysql_error(mysql_sock->sock));
+               radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields");
+               radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s",
+                      mysql_error(mysql_sock->sock));
        }
        return num;
 }
@@ -182,17 +219,50 @@ int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
 
 /*************************************************************************
  *
+ *     Function: sql_select_query
+ *
+ *     Purpose: Issue a select query to the database
+ *
+ *************************************************************************/
+static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config,
+                           char *querystr)
+{
+       int ret;
+
+       ret = sql_query(sqlsocket, config, querystr);
+       if(ret)
+               return ret;
+       ret = sql_store_result(sqlsocket, config);
+       if (ret) {
+               return ret;
+       }
+
+       /* 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;
+}
+
+
+/*************************************************************************
+ *
  *     Function: sql_num_rows
  *
  *     Purpose: database specific num_rows. Returns number of rows in
  *               query
  *
  *************************************************************************/
-int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_num_rows(SQLSOCK * sqlsocket, UNUSED 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,16 +271,28 @@ 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) {
-
+static int sql_fetch_row(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
-       return mysql_fetch_row(mysql_sock->result);
-}
+       /*
+        *  Check pointer before de-referencing it.
+        */
+       if (!mysql_sock->result) {
+               return SQL_DOWN;
+       }
+
+       sqlsocket->row = mysql_fetch_row(mysql_sock->result);
 
+       if (sqlsocket->row == NULL) {
+               return sql_check_error(mysql_errno(mysql_sock->sock));
+       }
+       return 0;
+}
 
 
 /*************************************************************************
@@ -221,12 +303,13 @@ SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *               for a result set
  *
  *************************************************************************/
-int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_free_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
        if (mysql_sock->result) {
                mysql_free_result(mysql_sock->result);
+               mysql_sock->result = NULL;
        }
 
        return 0;
@@ -242,10 +325,13 @@ int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *               connection
  *
  *************************************************************************/
-char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static char *sql_error(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
+       if (mysql_sock == NULL || mysql_sock->sock == NULL) {
+               return "rlm_sql_mysql: no connection to db";
+       }
        return mysql_error(mysql_sock->sock);
 }
 
@@ -258,12 +344,14 @@ char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *               connection
  *
  *************************************************************************/
-int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_close(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
-       mysql_close(mysql_sock->sock);
-       mysql_sock->sock = NULL;
+       if (mysql_sock && mysql_sock->sock){
+               mysql_close(mysql_sock->sock);
+               mysql_sock->sock = NULL;
+       }
 
        return 0;
 }
@@ -276,8 +364,8 @@ int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *     Purpose: End the query, such as freeing memory
  *
  *************************************************************************/
-int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_finish_query(UNUSED SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        return 0;
 }
 
@@ -290,8 +378,8 @@ int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *     Purpose: End the select query, such as freeing memory or result
  *
  *************************************************************************/
-int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
+{
        sql_free_result(sqlsocket, config);
 
        return 0;
@@ -305,32 +393,14 @@ int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
  *     Purpose: End the select query, such as freeing memory or result
  *
  *************************************************************************/
-int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_affected_rows(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
        rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
 
        return mysql_affected_rows(mysql_sock->sock);
 }
 
 
-/*************************************************************************
- *
- *      Function: sql_escape_string
- *
- *      Purpose: Esacpe "'" and any other wierd charactors
- *
- *************************************************************************
- * Unused.  Now provided in rlm_sql main module.
- * But left in here just in case...
- *
-int sql_escape_string(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *to, char *from, int length) {
-
-       mysql_escape_string(to, from, length);
-       return 0;
-}
-*/
-
-
 /* Exported to rlm_sql */
 rlm_sql_module_t rlm_sql_mysql = {
        "rlm_sql_mysql",