Implemented sql_destroy_socket
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_mysql / sql_mysql.c
1 /*
2  * sql_mysql.c          SQL Module
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Mike Machado <mike@innercite.com>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <mysql/errmsg.h>
31
32 #include        "radiusd.h"
33
34 #include        <mysql/mysql.h>
35 #include        "rlm_sql.h"
36
37 typedef struct rlm_sql_mysql_sock {
38         MYSQL conn;
39         MYSQL *sock;
40         MYSQL_RES *result;
41         SQL_ROW row;
42 } rlm_sql_mysql_sock;
43
44 /*************************************************************************
45  *
46  *      Function: sql_create_socket
47  *
48  *      Purpose: Establish connection to the db
49  *
50  *************************************************************************/
51 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
52 {
53         rlm_sql_mysql_sock *mysql_sock;
54
55         sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
56
57         mysql_sock = sqlsocket->conn;
58         memset(mysql_sock, 0, sizeof(*mysql_sock));
59
60         radlog(L_INFO, "rlm_sql_mysql: Starting connect to MySQL server for #%d",
61                         sqlsocket->id);
62
63         mysql_init(&(mysql_sock->conn));
64         if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn),
65                                                     config->sql_server,
66                                                     config->sql_login,
67                                                     config->sql_password,
68                                                     config->sql_db,
69                                                     atoi(config->sql_port),
70                                                     NULL,
71                                                     CLIENT_FOUND_ROWS))) {
72                 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);
73                 radlog(L_ERR, "rlm_sql_mysql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
74                 mysql_sock->sock = NULL;
75                 return -1;
76         }
77
78
79         return 0;
80 }
81
82
83 /*************************************************************************
84  *
85  *      Function: sql_destroy_socket
86  *
87  *      Purpose: Free socket and any private connection data
88  *
89  *************************************************************************/
90 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
91 {
92         free(sqlsocket->conn);
93         sqlsocket->conn = NULL;
94
95         return 0;
96 }
97
98
99 /*************************************************************************
100  *
101  *      Function: sql_check_error
102  *
103  *      Purpose: check the error to see if the server is down
104  *
105  *************************************************************************/
106 static int sql_check_error(int error)
107 {
108         switch(error) {
109         case CR_SERVER_GONE_ERROR:
110         case CR_SERVER_LOST:
111         case -1:
112                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d, returning SQL_DOWN", error);
113                 return SQL_DOWN;
114                 break;
115         case 0:
116                 return 0;
117                 break;
118         case CR_OUT_OF_MEMORY:
119         case CR_COMMANDS_OUT_OF_SYNC:
120         case CR_UNKNOWN_ERROR:
121         default:
122                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d received", error);
123                 return -1;
124                 break;
125         }
126 }
127
128
129 /*************************************************************************
130  *
131  *      Function: sql_query
132  *
133  *      Purpose: Issue a query to the database
134  *
135  *************************************************************************/
136 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
137 {
138         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
139
140         if (config->sqltrace)
141                 radlog(L_DBG,"rlm_sql_mysql: query:  %s", querystr);
142         if (mysql_sock->sock == NULL) {
143                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
144                 return SQL_DOWN;
145         }
146
147         mysql_query(mysql_sock->sock, querystr);
148         return sql_check_error(mysql_errno(mysql_sock->sock));
149 }
150
151
152 /*************************************************************************
153  *
154  *      Function: sql_store_result
155  *
156  *      Purpose: database specific store_result function. Returns a result
157  *               set for the query.
158  *
159  *************************************************************************/
160 static int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
161 {
162         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
163
164         if (mysql_sock->sock == NULL) {
165                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
166                 return SQL_DOWN;
167         }
168         if (!(mysql_sock->result = mysql_store_result(mysql_sock->sock))) {
169                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: Cannot get result");
170                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: %s",
171                        mysql_error(mysql_sock->sock));
172                 return sql_check_error(mysql_errno(mysql_sock->sock));
173         }
174         return 0;
175 }
176
177
178 /*************************************************************************
179  *
180  *      Function: sql_num_fields
181  *
182  *      Purpose: database specific num_fields function. Returns number
183  *               of columns from query
184  *
185  *************************************************************************/
186 static int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config)
187 {
188         int     num = 0;
189         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
190
191 #if MYSQL_VERSION_ID >= 32224
192         if (!(num = mysql_field_count(mysql_sock->sock))) {
193 #else
194         if (!(num = mysql_num_fields(mysql_sock->sock))) {
195 #endif
196                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields");
197                 radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s",
198                        mysql_error(mysql_sock->sock));
199         }
200         return num;
201 }
202
203
204 /*************************************************************************
205  *
206  *      Function: sql_select_query
207  *
208  *      Purpose: Issue a select query to the database
209  *
210  *************************************************************************/
211 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config,
212                             char *querystr)
213 {
214         int ret;
215
216         ret = sql_query(sqlsocket, config, querystr);
217         if(ret)
218                 return ret;
219         ret = sql_store_result(sqlsocket, config);
220         if (ret) {
221                 return ret;
222         }
223
224         /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
225          * this cannot return an error.  Perhaps just to complain if no
226          * fields are found?
227          */
228         sql_num_fields(sqlsocket, config);
229
230         return ret;
231 }
232
233
234 /*************************************************************************
235  *
236  *      Function: sql_num_rows
237  *
238  *      Purpose: database specific num_rows. Returns number of rows in
239  *               query
240  *
241  *************************************************************************/
242 static int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config)
243 {
244         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
245
246         if (mysql_sock->result)
247                 return mysql_num_rows(mysql_sock->result);
248
249         return 0;
250 }
251
252
253 /*************************************************************************
254  *
255  *      Function: sql_fetch_row
256  *
257  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
258  *               with all the data for the query in 'sqlsocket->row'. Returns
259  *               0 on success, -1 on failure, SQL_DOWN if database is down.
260  *
261  *************************************************************************/
262 static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
263 {
264         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
265
266         /*
267          *  Check pointer before de-referencing it.
268          */
269         if (!mysql_sock->result) {
270                 return SQL_DOWN;
271         }
272
273         sqlsocket->row = mysql_fetch_row(mysql_sock->result);
274
275         if (sqlsocket->row == NULL) {
276                 return sql_check_error(mysql_errno(mysql_sock->sock));
277         }
278         return 0;
279 }
280
281
282 /*************************************************************************
283  *
284  *      Function: sql_free_result
285  *
286  *      Purpose: database specific free_result. Frees memory allocated
287  *               for a result set
288  *
289  *************************************************************************/
290 static int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
291 {
292         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
293
294         if (mysql_sock->result) {
295                 mysql_free_result(mysql_sock->result);
296                 mysql_sock->result = NULL;
297         }
298
299         return 0;
300 }
301
302
303
304 /*************************************************************************
305  *
306  *      Function: sql_error
307  *
308  *      Purpose: database specific error. Returns error associated with
309  *               connection
310  *
311  *************************************************************************/
312 static char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config)
313 {
314         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
315
316         if (mysql_sock == NULL || mysql_sock->sock == NULL) {
317                 return "rlm_sql_mysql: no connection to db";
318         }
319         return mysql_error(mysql_sock->sock);
320 }
321
322
323 /*************************************************************************
324  *
325  *      Function: sql_close
326  *
327  *      Purpose: database specific close. Closes an open database
328  *               connection
329  *
330  *************************************************************************/
331 static int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config)
332 {
333         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
334
335         if (mysql_sock && mysql_sock->sock){
336                 mysql_close(mysql_sock->sock);
337                 mysql_sock->sock = NULL;
338         }
339
340         return 0;
341 }
342
343
344 /*************************************************************************
345  *
346  *      Function: sql_finish_query
347  *
348  *      Purpose: End the query, such as freeing memory
349  *
350  *************************************************************************/
351 static int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
352 {
353         return 0;
354 }
355
356
357
358 /*************************************************************************
359  *
360  *      Function: sql_finish_select_query
361  *
362  *      Purpose: End the select query, such as freeing memory or result
363  *
364  *************************************************************************/
365 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
366 {
367         sql_free_result(sqlsocket, config);
368
369         return 0;
370 }
371
372
373 /*************************************************************************
374  *
375  *      Function: sql_affected_rows
376  *
377  *      Purpose: End the select query, such as freeing memory or result
378  *
379  *************************************************************************/
380 static int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config)
381 {
382         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
383
384         return mysql_affected_rows(mysql_sock->sock);
385 }
386
387
388 /* Exported to rlm_sql */
389 rlm_sql_module_t rlm_sql_mysql = {
390         "rlm_sql_mysql",
391         sql_init_socket,
392         sql_destroy_socket,
393         sql_query,
394         sql_select_query,
395         sql_store_result,
396         sql_num_fields,
397         sql_num_rows,
398         sql_fetch_row,
399         sql_free_result,
400         sql_error,
401         sql_close,
402         sql_finish_query,
403         sql_finish_select_query,
404         sql_affected_rows
405 };