summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorEdward Rudd <urkle@outoforder.cc>2004-02-29 23:36:18 (GMT)
committer Edward Rudd <urkle@outoforder.cc>2004-02-29 23:36:18 (GMT)
commit53acb181ef04ae70a7dcfed849f7c02850781c20 (patch)
tree3df5086ba326284771f9cb6492e975f1713b3e40
parentb16bc88ccee527a7a9ea107c93f36264dbf82ed5 (diff)
separated out most mysql specific code to mod_log_sql_mysql.c
beginnings of separation of core SQL logging logic moved DB connection paramters to a table (for cutoms params for DB drivers) added new configuration directive to handle any DB parameter renamed all log_sql_* vars and type to logsql_* Added enums for opendb return codes. organized config directives and commented for easier reading of source
-rw-r--r--CHANGELOG5
-rw-r--r--Documentation/manual.xml1
-rw-r--r--Makefile.in6
-rw-r--r--apache13.h4
-rw-r--r--mod_log_sql.c488
-rw-r--r--mod_log_sql.h38
-rw-r--r--mod_log_sql.prj3
-rw-r--r--mod_log_sql_mysql.c241
-rw-r--r--mod_log_sql_ssl.c2
9 files changed, 409 insertions, 379 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 7c4b38b..d16549b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
1$Id: CHANGELOG,v 1.13 2004/02/12 03:21:35 urkle Exp $ 1$Id: CHANGELOG,v 1.14 2004/02/29 23:36:17 urkle Exp $
21.96: ? 21.96: ?
3* fixed LogSQLPreserveFile config parameter 3* fixed LogSQLPreserveFile config parameter
4* reworked safe_create_tables
5* renamed log_sql_* variables and typedefs to logsql_*
6* beginnings of abstraction layer
4 7
51.95: 2004-02-05 81.95: 2004-02-05
6* audit and update of extract_* functions to acheive same output as 9* audit and update of extract_* functions to acheive same output as
diff --git a/Documentation/manual.xml b/Documentation/manual.xml
index 3495047..fe13daa 100644
--- a/Documentation/manual.xml
+++ b/Documentation/manual.xml
@@ -16,6 +16,7 @@
16 <author> 16 <author>
17 <firstname>Christopher</firstname> 17 <firstname>Christopher</firstname>
18 <othername>B.</othername> 18 <othername>B.</othername>
19 <surname>Powell</surname>
19 <contrib>Original documentation author.</contrib> 20 <contrib>Original documentation author.</contrib>
20 <affiliation> 21 <affiliation>
21 <address format="linespecific"><email>chris &lt;at&gt; grubbybaby &lt;dot&gt; com</email></address> 22 <address format="linespecific"><email>chris &lt;at&gt; grubbybaby &lt;dot&gt; com</email></address>
diff --git a/Makefile.in b/Makefile.in
index 1ad7562..139a715 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -2,8 +2,8 @@
2 2
3# Modify these top variables. 3# Modify these top variables.
4SUBDIRS = Documentation contrib 4SUBDIRS = Documentation contrib
5SOURCES = \ 5SOURCES = @PACKAGE_NAME@.c \
6 @PACKAGE_NAME@.c 6 @PACKAGE_NAME@_mysql.c
7 7
8HEADERS = mod_log_sql.h \ 8HEADERS = mod_log_sql.h \
9 functions.h \ 9 functions.h \
@@ -22,7 +22,7 @@ EXTRA_DIST = AUTHORS INSTALL TODO LICENSE CHANGELOG make_combined_log.pl
22 22
23TARGET = @PACKAGE_NAME@@APXS_EXTENSION@ 23TARGET = @PACKAGE_NAME@@APXS_EXTENSION@
24 24
25sslSOURCES = mod_log_sql_ssl.c 25sslSOURCES = @PACKAGE_NAME@_ssl.c
26 26
27sslTARGET = @PACKAGE_NAME@_ssl@APXS_EXTENSION@ 27sslTARGET = @PACKAGE_NAME@_ssl@APXS_EXTENSION@
28 28
diff --git a/apache13.h b/apache13.h
index 8181c43..11e8dcb 100644
--- a/apache13.h
+++ b/apache13.h
@@ -1,4 +1,4 @@
1/* $Header: /home/cvs/mod_log_sql/apache13.h,v 1.4 2004/02/05 21:59:46 urkle Exp $ */ 1/* $Header: /home/cvs/mod_log_sql/apache13.h,v 1.5 2004/02/29 23:36:17 urkle Exp $ */
2#ifndef APACHE13_H 2#ifndef APACHE13_H
3#define APACHE13_H 3#define APACHE13_H
4 4
@@ -51,7 +51,9 @@
51#define apr_psprintf ap_psprintf 51#define apr_psprintf ap_psprintf
52#define apr_snprintf ap_snprintf 52#define apr_snprintf ap_snprintf
53 53
54#define apr_table_set ap_table_set
54#define apr_table_get ap_table_get 55#define apr_table_get ap_table_get
56#define apr_table_make ap_make_table
55 57
56#define apr_array_push ap_push_array 58#define apr_array_push ap_push_array
57#define apr_array_make ap_make_array 59#define apr_array_make ap_make_array
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 564f3fc..50c7964 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,4 +1,4 @@
1/* $Header: /home/cvs/mod_log_sql/mod_log_sql.c,v 1.15 2004/02/12 03:18:18 urkle Exp $ */ 1/* $Id $ */
2/* --------* 2/* --------*
3 * DEFINES * 3 * DEFINES *
4 * --------*/ 4 * --------*/
@@ -6,15 +6,6 @@
6/* The enduser may wish to modify this */ 6/* The enduser may wish to modify this */
7#define DEBUG 7#define DEBUG
8 8
9/* The enduser won't modify these */
10#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
11
12/* ---------*
13 * INCLUDES *
14 * ---------*/
15#include "mysql.h"
16#include "mysqld_error.h"
17
18#if defined(WITH_APACHE20) 9#if defined(WITH_APACHE20)
19# include "apache20.h" 10# include "apache20.h"
20#elif defined(WITH_APACHE13) 11#elif defined(WITH_APACHE13)
@@ -69,17 +60,9 @@ typedef struct {
69 int massvirtual; 60 int massvirtual;
70 int createtables; 61 int createtables;
71 int forcepreserve; 62 int forcepreserve;
72 char *tabletype;
73 char *dbname;
74 char *dbhost;
75 char *dbuser;
76 char *dbpwd;
77 char *machid; 63 char *machid;
78 char *socketfile; 64 apr_table_t *dbparams;
79 unsigned int tcpport; 65 logsql_dbconnection db;
80 int insertdelayed;
81 MYSQL server;
82 MYSQL *server_p;
83} global_config_t; 66} global_config_t;
84 67
85static global_config_t global_config; 68static global_config_t global_config;
@@ -87,11 +70,11 @@ static global_config_t global_config;
87/* structure to hold helper function info */ 70/* structure to hold helper function info */
88typedef struct { 71typedef struct {
89 char key; /* item letter character */ 72 char key; /* item letter character */
90 log_sql_item_func *func; /* its extraction function */ 73 logsql_item_func *func; /* its extraction function */
91 const char *sql_field_name; /* its column in SQL */ 74 const char *sql_field_name; /* its column in SQL */
92 int want_orig_default; /* if it requires the original request prior to internal redirection */ 75 int want_orig_default; /* if it requires the original request prior to internal redirection */
93 int string_contents; /* if it returns a string */ 76 int string_contents; /* if it returns a string */
94} log_sql_item; 77} logsql_item;
95 78
96/* But the contents of this structure will vary by virtual server. 79/* But the contents of this structure will vary by virtual server.
97 * This permits each virtual server to vary its configuration slightly 80 * This permits each virtual server to vary its configuration slightly
@@ -114,33 +97,28 @@ typedef struct {
114 const char *transfer_table_name; 97 const char *transfer_table_name;
115 const char *transfer_log_format; 98 const char *transfer_log_format;
116 apr_pool_t *parsed_pool; 99 apr_pool_t *parsed_pool;
117 log_sql_item **parsed_log_format; 100 logsql_item **parsed_log_format;
118 const char *preserve_file; 101 const char *preserve_file;
119 const char *cookie_name; 102 const char *cookie_name;
120} logsql_state; 103} logsql_state;
121 104
122 105
123/* -----------------* 106/* list of "handlers" for log types */
124 * HELPER FUNCTIONS * 107static apr_array_header_t *logsql_item_list;
125 * -----------------*/
126
127static int safe_create_tables(logsql_state *cls, request_rec *r);
128
129static apr_array_header_t *log_sql_item_list;
130 108
131/* Registration Function for extract functions * 109/* Registration Function for extract functions *
132 * and update parse cache for transfer_log_format * 110 * and update parse cache for transfer_log_format *
133 * this is exported from the module */ 111 * this is exported from the module */
134LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, 112LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
135 char key, log_sql_item_func *func, const char *sql_field_name, 113 char key, logsql_item_func *func, const char *sql_field_name,
136 int want_orig_default, int string_contents) 114 int want_orig_default, int string_contents)
137{ 115{
138 server_rec *ts; 116 server_rec *ts;
139 log_sql_item *item; 117 logsql_item *item;
140 if (!log_sql_item_list) 118 if (!logsql_item_list)
141 log_sql_item_list = apr_array_make(p,10, sizeof(log_sql_item)); 119 logsql_item_list = apr_array_make(p,10, sizeof(logsql_item));
142 120
143 item= apr_array_push(log_sql_item_list); 121 item= apr_array_push(logsql_item_list);
144 item->key = key; 122 item->key = key;
145 item->func = func; 123 item->func = func;
146 item->sql_field_name = sql_field_name; 124 item->sql_field_name = sql_field_name;
@@ -189,7 +167,7 @@ static const char *escape_query(const char *from_str, apr_pool_t *p)
189 return from_str; 167 return from_str;
190 } 168 }
191 169
192 if (!global_config.server_p) { 170 if (!global_config.db.connected) {
193 /* Well, I would have liked to use the current database charset. mysql is 171 /* Well, I would have liked to use the current database charset. mysql is
194 * unavailable, however, so I fall back to the slightly less respectful 172 * unavailable, however, so I fall back to the slightly less respectful
195 * mysql_escape_string() function that uses the default charset. 173 * mysql_escape_string() function that uses the default charset.
@@ -199,7 +177,7 @@ static const char *escape_query(const char *from_str, apr_pool_t *p)
199 /* MySQL is available, so I'll go ahead and respect the current charset when 177 /* MySQL is available, so I'll go ahead and respect the current charset when
200 * I perform the escape. 178 * I perform the escape.
201 */ 179 */
202 retval = mysql_real_escape_string(global_config.server_p, to_str, from_str, length); 180 retval = mysql_real_escape_string(global_config.db.handle, to_str, from_str, length);
203 } 181 }
204 182
205 if (retval) 183 if (retval)
@@ -209,42 +187,19 @@ static const char *escape_query(const char *from_str, apr_pool_t *p)
209 } 187 }
210} 188}
211 189
212static int open_logdb_link(server_rec* s) 190static logsql_opendb open_logdb_link(server_rec* s)
213{ 191{
214 /* Returns:
215 3 if preserve forced
216 2 if already connected
217 1 if successful
218 0 if unsuccessful
219 */
220
221 if (global_config.forcepreserve) 192 if (global_config.forcepreserve)
222 return 3; 193 return LOGSQL_OPENDB_PRESERVE;
223 194
224 if (global_config.server_p) 195 if (global_config.db.connected)
225 return 2; 196 return LOGSQL_OPENDB_ALREADY;
226 197
227 if ((global_config.dbname) && (global_config.dbhost) && (global_config.dbuser) && (global_config.dbpwd)) { 198 if ((global_config.dbname) && (global_config.dbhost) && (global_config.dbuser) && (global_config.dbpwd)) {
228 mysql_init(&global_config.server); 199 log_sql_mysql_connect();
229 global_config.server_p = mysql_real_connect(&global_config.server, global_config.dbhost, global_config.dbuser, global_config.dbpwd, global_config.dbname, global_config.tcpport, global_config.socketfile, 0);
230
231 if (global_config.server_p) {
232 #ifdef DEBUG
233 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
234 global_config.dbhost, global_config.tcpport, global_config.dbname, global_config.dbuser, global_config.socketfile);
235 #endif
236 return 1;
237 } else {
238 #ifdef DEBUG
239 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s",MYSQL_ERROR(&global_config.server));
240 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
241 global_config.dbhost, global_config.tcpport, global_config.dbname, global_config.dbuser, global_config.socketfile);
242 #endif
243 return 0;
244 }
245 } else { 200 } else {
246 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link"); 201 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link");
247 return 0; 202 return LOGSQL_OPENDB_FAIL;
248 } 203 }
249} 204}
250 205
@@ -286,245 +241,6 @@ static void preserve_entry(request_rec *r, const char *query)
286} 241}
287 242
288 243
289/*-----------------------------------------------------*
290 * safe_sql_query: perform a database query with *
291 * a degree of safety and error checking. *
292 * *
293 * Parms: request record, SQL insert statement *
294 * Returns: 0 (OK) on success *
295 * 1 if have no log handle *
296 * 2 if insert delayed failed (kluge) *
297 * the actual MySQL return code on error *
298 *-----------------------------------------------------*/
299static unsigned int safe_sql_query(request_rec *r, const char *query)
300{
301 int retval;
302 struct timespec delay, remainder;
303 int ret;
304 void (*handler) (int);
305 logsql_state *cls;
306 unsigned int real_error = 0;
307 const char *real_error_str = NULL;
308
309 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
310 handler = signal(SIGPIPE, SIG_IGN);
311
312 /* First attempt for the query */
313 if (!global_config.server_p) {
314 signal(SIGPIPE, handler);
315 return 1;
316 } else if (!(retval = mysql_query(global_config.server_p, query))) {
317 signal(SIGPIPE, handler);
318 return 0;
319 }
320
321 /* If we ran the query and it returned an error, try to be robust.
322 * (After all, the module thought it had a valid mysql_log connection but the query
323 * could have failed for a number of reasons, so we have to be extra-safe and check.) */
324 if (global_config.insertdelayed) {
325 real_error_str = MYSQL_ERROR(global_config.server_p);
326 } else {
327 real_error = mysql_errno(global_config.server_p);
328 }
329
330 /* Check to see if the error is "nonexistent table" */
331 if (global_config.insertdelayed) {
332 retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist"));
333 } else {
334 retval = (real_error == ER_NO_SUCH_TABLE);
335 }
336 if (retval) {
337 if (global_config.createtables) {
338 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: table doesn't exist...creating now");
339 cls = ap_get_module_config(r->server->module_config, &log_sql_module);
340 if (safe_create_tables(cls, r)) {
341 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r));
342 preserve_entry(r, query);
343 retval = mysql_errno(global_config.server_p);
344 } else {
345 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: tables successfully created - retrying query");
346 if (mysql_query(global_config.server_p, query)) {
347 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: giving up, preserving query");
348 preserve_entry(r, query);
349 retval = mysql_errno(global_config.server_p);
350 } else
351 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: query successful after table creation");
352 retval = 0;
353 }
354 } else {
355 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql, table doesn't exist, creation denied by configuration, preserving query");
356 preserve_entry(r, query);
357 retval = ER_NO_SUCH_TABLE;
358 }
359 /* Restore SIGPIPE to its original handler function */
360 signal(SIGPIPE, handler);
361 return retval;
362 }
363
364 /* Handle all other types of errors */
365
366 cls = ap_get_module_config(r->server->module_config, &log_sql_module);
367
368 /* Something went wrong, so start by trying to restart the db link. */
369 if (global_config.insertdelayed) {
370 real_error = 2;
371 } else {
372 real_error = mysql_errno(global_config.server_p);
373 }
374
375 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(global_config.server_p));
376 mysql_close(global_config.server_p);
377 global_config.server_p = NULL;
378 open_logdb_link(r->server);
379
380 if (global_config.server_p == NULL) { /* still unable to link */
381 signal(SIGPIPE, handler);
382 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
383 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: log entries are being preserved in %s", cls->preserve_file);
384 return 1;
385 } else
386 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: db reconnect successful");
387
388 /* First sleep for a tiny amount of time. */
389 delay.tv_sec = 0;
390 delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */
391 ret = nanosleep(&delay, &remainder);
392 if (ret && errno != EINTR)
393 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: nanosleep unsuccessful");
394
395 /* Then make our second attempt */
396 retval = mysql_query(global_config.server_p,query);
397
398 /* If this one also failed, log that and append to our local offline file */
399 if (retval) {
400 if (global_config.insertdelayed) {
401 real_error = 2;
402 } else {
403 real_error = mysql_errno(global_config.server_p);
404 }
405
406 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(global_config.server_p));
407 preserve_entry(r, query);
408 retval = real_error;
409 } else
410 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: second attempt successful");
411
412 /* Restore SIGPIPE to its original handler function */
413 signal(SIGPIPE, handler);
414 return retval;
415}
416
417/*-----------------------------------------------------*
418 * safe_create_tables: create SQL table set for the *
419 * virtual server represented by cls. *
420 * *
421 * Parms: virtserver structure, request record *
422 * Returns: 0 on no errors *
423 * mysql error code on failure *
424 *-----------------------------------------------------*/
425static int safe_create_tables(logsql_state *cls, request_rec *r)
426{
427 int retval;
428 unsigned int create_results;
429 char *create_access = NULL;
430 char *create_notes = NULL;
431 char *create_hout = NULL;
432 char *create_hin = NULL;
433 char *create_cookies = NULL;
434
435 char *type_suffix = NULL;
436
437 char *createprefix = "create table if not exists `";
438 char *access_suffix =
439 "` (id char(19),\
440 agent varchar(255),\
441 bytes_sent int unsigned,\
442 child_pid smallint unsigned,\
443 cookie varchar(255),\
444 machine_id varchar(25),\
445 request_file varchar(255),\
446 referer varchar(255),\
447 remote_host varchar(50),\
448 remote_logname varchar(50),\
449 remote_user varchar(50),\
450 request_duration smallint unsigned,\
451 request_line varchar(255),\
452 request_method varchar(10),\
453 request_protocol varchar(10),\
454 request_time char(28),\
455 request_uri varchar(255),\
456 request_args varchar(255),\
457 server_port smallint unsigned,\
458 ssl_cipher varchar(25),\
459 ssl_keysize smallint unsigned,\
460 ssl_maxkeysize smallint unsigned,\
461 status smallint unsigned,\
462 time_stamp int unsigned,\
463 virtual_host varchar(255))";
464
465 char *notes_suffix =
466 "` (id char(19),\
467 item varchar(80),\
468 val varchar(80))";
469
470 char *headers_suffix =
471 "` (id char(19),\
472 item varchar(80),\
473 val varchar(80))";
474
475 char *cookies_suffix =
476 "` (id char(19),\
477 item varchar(80),\
478 val varchar(80))";
479 if (global_config.tabletype) {
480 type_suffix = apr_pstrcat(r->pool, " TYPE=", global_config.tabletype, NULL);
481 }
482 /* Find memory long enough to hold the whole CREATE string + \0 */
483 create_access = apr_pstrcat(r->pool, createprefix, cls->transfer_table_name, access_suffix, type_suffix, NULL);
484 create_notes = apr_pstrcat(r->pool, createprefix, cls->notes_table_name, notes_suffix, type_suffix, NULL);
485 create_hout = apr_pstrcat(r->pool, createprefix, cls->hout_table_name, headers_suffix, type_suffix, NULL);
486 create_hin = apr_pstrcat(r->pool, createprefix, cls->hin_table_name, headers_suffix, type_suffix, NULL);
487 create_cookies= apr_pstrcat(r->pool, createprefix, cls->cookie_table_name, cookies_suffix, type_suffix, NULL);
488
489 #ifdef DEBUG
490 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_access);
491 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_notes);
492 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_hout);
493 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_hin);
494 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_cookies);
495 #endif
496
497 /* Assume that things worked unless told otherwise */
498 retval = 0;
499
500 if ((create_results = safe_sql_query(r, create_access))) {
501 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create access table");
502 retval = create_results;
503 }
504
505 if ((create_results = safe_sql_query(r, create_notes))) {
506 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create notes table");
507 retval = create_results;
508 }
509
510 if ((create_results = safe_sql_query(r, create_hin))) {
511 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create header_in table");
512 retval = create_results;
513 }
514
515 if ((create_results = safe_sql_query(r, create_hout))) {
516 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create header_out table");
517 retval = create_results;
518 }
519
520 if ((create_results = safe_sql_query(r, create_cookies))) {
521 log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create cookies table");
522 retval = create_results;
523 }
524
525 return retval;
526}
527
528/* ------------------------------------------------* 244/* ------------------------------------------------*
529 * Command handlers that are called according * 245 * Command handlers that are called according *
530 * to the directives found at Apache runtime. * 246 * to the directives found at Apache runtime. *
@@ -567,7 +283,6 @@ static const char *set_global_string_slot(cmd_parms *cmd,
567 *(const char **)((char *)ptr + offset) = apr_pstrdup(cmd->pool,arg); 283 *(const char **)((char *)ptr + offset) = apr_pstrdup(cmd->pool,arg);
568 return NULL; 284 return NULL;
569} 285}
570
571static const char *set_server_string_slot(cmd_parms *cmd, 286static const char *set_server_string_slot(cmd_parms *cmd,
572 void *struct_ptr, 287 void *struct_ptr,
573 const char *arg) 288 const char *arg)
@@ -591,7 +306,7 @@ static const char *set_logformat_slot(cmd_parms *cmd,
591 cfg->transfer_log_format = arg; 306 cfg->transfer_log_format = arg;
592/* apr_pool_clear(cfg->parsed_pool);*/ 307/* apr_pool_clear(cfg->parsed_pool);*/
593 cfg->parsed_log_format = apr_pcalloc(cfg->parsed_pool, 308 cfg->parsed_log_format = apr_pcalloc(cfg->parsed_pool,
594 strlen(arg) * sizeof(log_sql_item *)); 309 strlen(arg) * sizeof(logsql_item *));
595 return NULL; 310 return NULL;
596} 311}
597 312
@@ -607,16 +322,38 @@ static const char *set_server_nmv_string_slot(cmd_parms *parms,
607 return set_server_string_slot(parms,struct_ptr,arg); 322 return set_server_string_slot(parms,struct_ptr,arg);
608} 323}
609 324
610static const char *set_log_sql_info(cmd_parms *cmd, void *dummy, const char *host, const char *user, const char *pwd) 325/* Set a DB connection parameter */
326static void set_dbparam(apr_pool_t *p, const char *key,
327 const char *val);
328{
329 if (!global_config.dbparams) {
330 global_config.dbparams = apr_table_make(p,5);
331 }
332 apr_table_set(global_config.dbparams,key,val);
333}
334
335static const char *set_dbparam_slot(cmd_params *cmd,
336 void *struct_ptr,
337 const char *arg)
338{
339 const char *param = (char *)cmd->info;
340 set_dbparam(cmd->pool,param,arg);
341 return NULL;
342}
343
344/* Sets basic connection info */
345static const char *set_log_sql_info(cmd_parms *cmd, void *dummy,
346 const char *host, const char *user, const char *pwd)
611{ 347{
612 if (*host != '.') { 348 if (*host != '.') {
613 global_config.dbhost = apr_pstrdup(cmd->pool,host); 349 set_db_param_slot(cmd->pool, "host", host);
614 } 350 }
615 if (*user != '.') { 351 if (*user != '.') {
352 set_db_param_slot(cmd->pool, "user", user);
616 global_config.dbuser = apr_pstrdup(cmd->pool,user); 353 global_config.dbuser = apr_pstrdup(cmd->pool,user);
617 } 354 }
618 if (*pwd != '.') { 355 if (*pwd != '.') {
619 global_config.dbpwd = apr_pstrdup(cmd->pool,pwd); 356 set_db_param_slot(cmd->pool, "passwd", pwd);
620 } 357 }
621 return NULL; 358 return NULL;
622} 359}
@@ -673,37 +410,26 @@ static int log_sql_open(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_re
673static void log_sql_child_init(server_rec *s, apr_pool_t *p) 410static void log_sql_child_init(server_rec *s, apr_pool_t *p)
674#endif 411#endif
675{ 412{
676 int retval; 413 logsql_opendb retval;
677 /* Open a link to the database */ 414 /* Open a link to the database */
678 retval = open_logdb_link(s); 415 retval = open_logdb_link(s);
679 if (!retval) 416 switch (retval) {
417 case LOGSQL_OPENDB_FAIL:
680 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link"); 418 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link");
681 419 break;
682 #ifdef DEBUG 420 case LOGSQL_OPENDB_SUCCESS:
683 if ( (retval == 1) || (retval == 2) ) 421 case LOGSQL_OPENDB_ALREADY:
684 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link successful"); 422 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link successful");
685 if (retval == 3) 423 break;
424 case LOGSQL_OPENDB_PRESERVE:
686 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link said that preservation is forced"); 425 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link said that preservation is forced");
687 #endif 426 break;
427 }
688#if defined(WITH_APACHE20) 428#if defined(WITH_APACHE20)
689 return OK; 429 return OK;
690#endif 430#endif
691} 431}
692/*
693void *log_sql_initializer(server_rec *main_server, apr_pool_t *p)
694{
695 server_rec *s;
696
697 logsql_state main_conf = ap_get_module_config(main_server->module_config, &log_sql_module);
698 432
699 for (server_rec *s = main_server; s; s = s->next) {
700 conf = ap_get_module_config(s->module_config, &log_sql_module);
701 if (conf->transfer_log_format == NULL && s != main_server) {
702 *conf = *main_conf;
703 }
704
705}
706 */
707/* post_config / module_init */ 433/* post_config / module_init */
708#if defined(WITH_APACHE20) 434#if defined(WITH_APACHE20)
709static int log_sql_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) 435static int log_sql_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
@@ -748,6 +474,20 @@ static void log_sql_module_init(server_rec *s, apr_pool_t *p)
748#endif 474#endif
749} 475}
750 476
477/* This function handles calling the DB module, handling errors
478 * of missing tables and lost DB connections, and falling back to
479 * preserving the DB query.
480 *
481 * Parms: request record, table type, table name, and the full SQL command
482 */
483
484static void safe_sql_insert(request_rec *r, logsql_tabletype table_type,
485 const char *table_name, const char *sql) {
486 int result;
487 if (!global_config.connected) {
488 }
489}
490
751/* This function gets called to create a per-server configuration 491/* This function gets called to create a per-server configuration
752 * record. It will always be called for the main server and 492 * record. It will always be called for the main server and
753 * for each virtual server that is established. Each server maintains 493 * for each virtual server that is established. Each server maintains
@@ -764,7 +504,7 @@ static void *log_sql_make_state(apr_pool_t *p, server_rec *s)
764 cls->transfer_log_format = DEFAULT_TRANSFER_LOG_FMT; 504 cls->transfer_log_format = DEFAULT_TRANSFER_LOG_FMT;
765 apr_pool_create(&cls->parsed_pool, p); 505 apr_pool_create(&cls->parsed_pool, p);
766 cls->parsed_log_format = apr_pcalloc(cls->parsed_pool, 506 cls->parsed_log_format = apr_pcalloc(cls->parsed_pool,
767 strlen(cls->transfer_log_format) * sizeof(log_sql_item *)); 507 strlen(cls->transfer_log_format) * sizeof(logsql_item *));
768 cls->notes_table_name = DEFAULT_NOTES_TABLE_NAME; 508 cls->notes_table_name = DEFAULT_NOTES_TABLE_NAME;
769 cls->hin_table_name = DEFAULT_HIN_TABLE_NAME; 509 cls->hin_table_name = DEFAULT_HIN_TABLE_NAME;
770 cls->hout_table_name = DEFAULT_HOUT_TABLE_NAME; 510 cls->hout_table_name = DEFAULT_HOUT_TABLE_NAME;
@@ -801,7 +541,7 @@ static void *log_sql_merge_state(apr_pool_t *p, void *basev, void *addv)
801 child->transfer_log_format = parent->transfer_log_format; 541 child->transfer_log_format = parent->transfer_log_format;
802 /*apr_pool_clear(child->parsed_pool);*/ 542 /*apr_pool_clear(child->parsed_pool);*/
803 child->parsed_log_format = apr_pcalloc(child->parsed_pool, 543 child->parsed_log_format = apr_pcalloc(child->parsed_pool,
804 strlen(child->transfer_log_format) * sizeof(log_sql_item *)); 544 strlen(child->transfer_log_format) * sizeof(logsql_item *));
805 } 545 }
806 546
807 if (child->preserve_file == DEFAULT_PRESERVE_FILE) 547 if (child->preserve_file == DEFAULT_PRESERVE_FILE)
@@ -961,7 +701,7 @@ static int log_sql_transaction(request_rec *orig)
961 * what the user has configured. */ 701 * what the user has configured. */
962 length = strlen(cls->transfer_log_format); 702 length = strlen(cls->transfer_log_format);
963 for (i = 0; i<length; i++) { 703 for (i = 0; i<length; i++) {
964 log_sql_item *item = cls->parsed_log_format[i]; 704 logsql_item *item = cls->parsed_log_format[i];
965 if (item==NULL) { 705 if (item==NULL) {
966 log_error(APLOG_MARK, APLOG_ERR, orig->server, 706 log_error(APLOG_MARK, APLOG_ERR, orig->server,
967 "Log Format '%c' unknown",cls->transfer_log_format[i]); 707 "Log Format '%c' unknown",cls->transfer_log_format[i]);
@@ -1175,7 +915,11 @@ static int log_sql_transaction(request_rec *orig)
1175 /* ---> i.e. we have a good MySQL connection. <--- */ 915 /* ---> i.e. we have a good MySQL connection. <--- */
1176 916
1177 /* Make the access-table insert */ 917 /* Make the access-table insert */
1178 safe_sql_query(orig, access_query); 918 if (safe_create_tables(orig, LOGSQL_TABLE_ACCESS, transfer_tablename)==APR_SUCCESS) {
919 safe_sql_query(orig, access_query);
920 } else {
921 preserve_entry(orig, access_query);
922 }
1179 923
1180 /* Log the optional notes, headers, etc. */ 924 /* Log the optional notes, headers, etc. */
1181 if (note_query) 925 if (note_query)
@@ -1199,6 +943,7 @@ static int log_sql_transaction(request_rec *orig)
1199 * Structure: command, function called, NULL, where available, how many arguments, verbose description 943 * Structure: command, function called, NULL, where available, how many arguments, verbose description
1200 */ 944 */
1201static const command_rec log_sql_cmds[] = { 945static const command_rec log_sql_cmds[] = {
946 /* Table names */
1202 AP_INIT_TAKE1("LogSQLTransferLogTable", set_server_nmv_string_slot, 947 AP_INIT_TAKE1("LogSQLTransferLogTable", set_server_nmv_string_slot,
1203 (void *)APR_OFFSETOF(logsql_state, transfer_table_name), RSRC_CONF, 948 (void *)APR_OFFSETOF(logsql_state, transfer_table_name), RSRC_CONF,
1204 "The database table that holds the transfer log") 949 "The database table that holds the transfer log")
@@ -1219,14 +964,21 @@ static const command_rec log_sql_cmds[] = {
1219 (void *)APR_OFFSETOF(logsql_state, cookie_table_name), RSRC_CONF, 964 (void *)APR_OFFSETOF(logsql_state, cookie_table_name), RSRC_CONF,
1220 "The database table that holds the cookie info") 965 "The database table that holds the cookie info")
1221 , 966 ,
967 AP_INIT_FLAG("LogSQLMassVirtualHosting", set_global_flag_slot,
968 (void *)APR_OFFSETOF(global_config_t, massvirtual), RSRC_CONF,
969 "Activates option(s) useful for ISPs performing mass virutal hosting")
970 ,
971 /* Log format */
1222 AP_INIT_TAKE1("LogSQLTransferLogFormat", set_logformat_slot, 972 AP_INIT_TAKE1("LogSQLTransferLogFormat", set_logformat_slot,
1223 NULL, RSRC_CONF, 973 NULL, RSRC_CONF,
1224 "Instruct the module what information to log to the database transfer log") 974 "Instruct the module what information to log to the database transfer log")
1225 , 975 ,
976 /* Machine ID */
1226 AP_INIT_TAKE1("LogSQLMachineID", set_global_string_slot, 977 AP_INIT_TAKE1("LogSQLMachineID", set_global_string_slot,
1227 (void *)APR_OFFSETOF(global_config_t, machid), RSRC_CONF, 978 (void *)APR_OFFSETOF(global_config_t, machid), RSRC_CONF,
1228 "Machine ID that the module will log, useful in web clusters to differentiate machines") 979 "Machine ID that the module will log, useful in web clusters to differentiate machines")
1229 , 980 ,
981 /* Limits on logging */
1230 AP_INIT_ITERATE("LogSQLRequestAccept", add_server_string_slot, 982 AP_INIT_ITERATE("LogSQLRequestAccept", add_server_string_slot,
1231 (void *)APR_OFFSETOF(logsql_state, transfer_accept_list), RSRC_CONF, 983 (void *)APR_OFFSETOF(logsql_state, transfer_accept_list), RSRC_CONF,
1232 "List of URIs to accept for logging. Accesses that don't match will not be logged") 984 "List of URIs to accept for logging. Accesses that don't match will not be logged")
@@ -1239,48 +991,14 @@ static const command_rec log_sql_cmds[] = {
1239 (void *)APR_OFFSETOF(logsql_state, remhost_ignore_list), RSRC_CONF, 991 (void *)APR_OFFSETOF(logsql_state, remhost_ignore_list), RSRC_CONF,
1240 "List of remote hosts to ignore. Accesses that match will not be logged to database") 992 "List of remote hosts to ignore. Accesses that match will not be logged to database")
1241 , 993 ,
1242 AP_INIT_TAKE1("LogSQLDatabase", set_global_string_slot,
1243 (void *)APR_OFFSETOF(global_config_t, dbname), RSRC_CONF,
1244 "The name of the database database for logging")
1245 ,
1246 AP_INIT_TAKE1("LogSQLWhichCookie", set_server_string_slot, 994 AP_INIT_TAKE1("LogSQLWhichCookie", set_server_string_slot,
1247 (void *)APR_OFFSETOF(logsql_state, cookie_name), RSRC_CONF, 995 (void *)APR_OFFSETOF(logsql_state, cookie_name), RSRC_CONF,
1248 "The single cookie that you want logged in the access_log when using the 'c' config directive") 996 "The single cookie that you want logged in the access_log when using the 'c' config directive")
1249 , 997 ,
1250 AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF,
1251 "The database host, user-id and password for logging")
1252 ,
1253 AP_INIT_FLAG("LogSQLCreateTables", set_global_nmv_flag_slot,
1254 (void *)APR_OFFSETOF(global_config_t, createtables), RSRC_CONF,
1255 "Turn on module's capability to create its SQL tables on the fly")
1256 ,
1257 AP_INIT_FLAG("LogSQLMassVirtualHosting", set_global_flag_slot,
1258 (void *)APR_OFFSETOF(global_config_t, massvirtual), RSRC_CONF,
1259 "Activates option(s) useful for ISPs performing mass virutal hosting")
1260 ,
1261 AP_INIT_FLAG("LogSQLDelayedInserts", set_global_flag_slot,
1262 (void *)APR_OFFSETOF(global_config_t, insertdelayed), RSRC_CONF,
1263 "Whether to use delayed inserts")
1264 ,
1265 AP_INIT_FLAG("LogSQLForcePreserve", set_global_flag_slot,
1266 (void *)APR_OFFSETOF(global_config_t, forcepreserve), RSRC_CONF,
1267 "Forces logging to preserve file and bypasses database")
1268 ,
1269 AP_INIT_TAKE1("LogSQLPreserveFile", set_server_string_slot, 998 AP_INIT_TAKE1("LogSQLPreserveFile", set_server_string_slot,
1270 (void *)APR_OFFSETOF(logsql_state,preserve_file), RSRC_CONF, 999 (void *)APR_OFFSETOF(logsql_state,preserve_file), RSRC_CONF,
1271 "Name of the file to use for data preservation during database downtime") 1000 "Name of the file to use for data preservation during database downtime")
1272 , 1001 ,
1273 AP_INIT_TAKE1("LogSQLSocketFile", set_global_string_slot,
1274 (void *)APR_OFFSETOF(global_config_t, socketfile), RSRC_CONF,
1275 "Name of the file to employ for socket connections to database")
1276 ,
1277 AP_INIT_TAKE1("LogSQLTableType", set_global_string_slot,
1278 (void *)APR_OFFSETOF(global_config_t, tabletype), RSRC_CONF,
1279 "What kind of table to create (MyISAM, InnoDB,...) when creating tables")
1280 ,
1281 AP_INIT_TAKE1("LogSQLTCPPort", set_log_sql_tcp_port, NULL, RSRC_CONF,
1282 "Port number to use for TCP connections to database, defaults to 3306 if not set")
1283 ,
1284 AP_INIT_ITERATE("LogSQLWhichNotes", add_server_string_slot, 1002 AP_INIT_ITERATE("LogSQLWhichNotes", add_server_string_slot,
1285 (void *)APR_OFFSETOF(logsql_state, notes_list), RSRC_CONF, 1003 (void *)APR_OFFSETOF(logsql_state, notes_list), RSRC_CONF,
1286 "Notes that you would like to log in a separate table") 1004 "Notes that you would like to log in a separate table")
@@ -1297,6 +1015,38 @@ static const command_rec log_sql_cmds[] = {
1297 (void *)APR_OFFSETOF(logsql_state, cookie_list), RSRC_CONF, 1015 (void *)APR_OFFSETOF(logsql_state, cookie_list), RSRC_CONF,
1298 "The cookie(s) that you would like to log in a separate table") 1016 "The cookie(s) that you would like to log in a separate table")
1299 , 1017 ,
1018 /* DB connection parameters */
1019 AP_INIT_FLAG("LogSQLForcePreserve", set_global_flag_slot,
1020 (void *)APR_OFFSETOF(global_config_t, forcepreserve), RSRC_CONF,
1021 "Forces logging to preserve file and bypasses database")
1022 ,
1023 AP_INIT_FLAG("LogSQLCreateTables", set_global_nmv_flag_slot,
1024 (void *)APR_OFFSETOF(global_config_t, createtables), RSRC_CONF,
1025 "Turn on module's capability to create its SQL tables on the fly")
1026 ,
1027 AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF,
1028 "The database host, user-id and password for logging")
1029 ,
1030 AP_INIT_TAKE1("LogSQLDatabase", set_dbparam_slot,
1031 (void *)"database", RSRC_CONF,
1032 "The name of the database database for logging")
1033 ,
1034 AP_INIT_TAKE1("LogSQLDelayedInserts", set_dbparam_slot,
1035 (void *)"insertdelayed", RSRC_CONF,
1036 "Whether to use delayed inserts")
1037 ,
1038 AP_INIT_TAKE1("LogSQLTableType", set_dbparam_slot,
1039 (void *)"tabletype", RSRC_CONF,
1040 "What kind of table to create (MyISAM, InnoDB,...) when creating tables")
1041 ,
1042 AP_INIT_TAKE1("LogSQLSocketFile", set_dbparam_slot,
1043 (void *)"socketfile", RSRC_CONF,
1044 "Name of the file to employ for socket connections to database")
1045 ,
1046 AP_INIT_TAKE1("LogSQLTCPPort", set_dbparam_slot,
1047 (void *)"tcpport", RSRC_CONF,
1048 "Port number to use for TCP connections to database, defaults to 3306 if not set")
1049 ,
1300 {NULL} 1050 {NULL}
1301}; 1051};
1302/* The configuration array that sets up the hooks into the module. */ 1052/* The configuration array that sets up the hooks into the module. */
diff --git a/mod_log_sql.h b/mod_log_sql.h
index f54ab54..0c59cb7 100644
--- a/mod_log_sql.h
+++ b/mod_log_sql.h
@@ -1,4 +1,5 @@
1/* $Header: /home/cvs/mod_log_sql/mod_log_sql.h,v 1.3 2004/01/22 05:26:56 urkle Exp $ */ 1/* $Id: mod_log_sql.h,v 1.4 2004/02/29 23:36:18 urkle Exp $ */
2
2#ifndef MOD_LOG_SQL_H 3#ifndef MOD_LOG_SQL_H
3#define MOD_LOG_SQL_H 4#define MOD_LOG_SQL_H
4 5
@@ -23,10 +24,41 @@
23#define LOGSQL_DECLARE_DATA __declspec(dllimport) 24#define LOGSQL_DECLARE_DATA __declspec(dllimport)
24#endif 25#endif
25 26
26typedef const char *log_sql_item_func(request_rec *r, char *a); 27typedef const char *logsql_item_func(request_rec *r, char *a);
27 28
28/* Registration Function for extract functions */ 29/* Registration Function for extract functions */
29LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, 30LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
30 char key, log_sql_item_func *func, const char *sql_field_name, 31 char key, logsql_item_func *func, const char *sql_field_name,
31 int want_orig_default, int string_contents); 32 int want_orig_default, int string_contents);
33
34/* DB Connection structure holds connection status information
35 * and connection handle
36 */
37typedef struct {
38 int connected; /* Are we connected to the DB */
39 void *handle; /* DB specific connection pointer */
40} logsql_dbconnection;
41
42/* open db handle return values*/
43typedef enum {
44 LOGSQL_OPENDB_FAIL = 0,
45 LOGSQL_OPENDB_SUCCESS,
46 LOGSQL_OPENDB_ALREADY,
47 LOGSQL_OPENDB_PRESERVE
48} logsql_opendb;
49
50/* For passing to create_tables handler */
51typedef enum {
52 LOGSQL_TABLE_ACCESS = 0,
53 LOGSQL_TABLE_NOTES,
54 LOGSQL_TABLE_HEADERSOUT,
55 LOGSQL_TABLE_HEADERSIN,
56 LOGSQL_TABLE_COOKIES,
57} logsql_tabletype;
58
59/* All Tables */
60#define LOGSQL_TABLE_ALL LOGSQL_TABLE_ACCESS | LOGSQL_TABLE_NOTES | \
61 LOGSQL_TABLE_HEADERSIN | LOGSQL_TABLE_HEADERSOUT | LOGSQL_TABLE_COOKIES
62
63
32#endif /* MOD_LOG_SQL_H */ 64#endif /* MOD_LOG_SQL_H */
diff --git a/mod_log_sql.prj b/mod_log_sql.prj
index ad294d5..4c194ce 100644
--- a/mod_log_sql.prj
+++ b/mod_log_sql.prj
@@ -68,7 +68,8 @@ module.source.files=\
68 mod_log_sql.c\ 68 mod_log_sql.c\
69 make_combined_log.pl\ 69 make_combined_log.pl\
70 contrib/mysql_import_combined_log.pl\ 70 contrib/mysql_import_combined_log.pl\
71 mod_log_sql_ssl.c 71 mod_log_sql_ssl.c\
72 mod_log_sql_mysql.c
72 73
73module.pixmap.name=. 74module.pixmap.name=.
74module.pixmap.type= 75module.pixmap.type=
diff --git a/mod_log_sql_mysql.c b/mod_log_sql_mysql.c
new file mode 100644
index 0000000..3f05935
--- /dev/null
+++ b/mod_log_sql_mysql.c
@@ -0,0 +1,241 @@
1/* $Id: mod_log_sql_mysql.c,v 1.1 2004/02/29 23:36:18 urkle Exp $ */
2#include "mysql.h"
3#include "mysqld_error.h"
4
5#if defined(WITH_APACHE20)
6# include "apache20.h"
7#elif defined(WITH_APACHE13)
8# include "apache13.h"
9#else
10# error Unsupported Apache version
11#endif
12
13#ifdef HAVE_CONFIG_H
14/* Undefine these to prevent conflicts between Apache ap_config_auto.h and
15 * my config.h. Only really needed for Apache < 2.0.48, but it can't hurt.
16 */
17#undef PACKAGE_BUGREPORT
18#undef PACKAGE_NAME
19#undef PACKAGE_STRING
20#undef PACKAGE_TARNAME
21#undef PACKAGE_VERSION
22
23#include "config.h"
24#endif
25
26#include "mod_log_sql.h"
27
28/* The enduser won't modify these */
29#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
30
31logsql_opendb log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db,
32 apr_table_t *dbparms)
33{
34 MYSQL *dblink;
35 char *host = apr_table_get(dbparms,"host");
36 char *user = apr_table_get(dbparms,"user");
37 char *passwd = apr_table_get(dbparms,"passwd");
38 char *database = apr_table_get(dbparms,"database");
39 char *tcpport = apr_table_get(dbparms,"tcpport");
40 char *socketfile = apr_table_get(dbparms,"socketfile");
41 mysql_init(&dblink);
42 if (mysql_real_connect(&dblink, host, user, passwd, database, tcpport,
43 socketfile, 0) {
44 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
45 host, tcpport, database, user, socketfile);
46 return LOGSQL_OPENDB_SUCCESS;
47 } else {
48 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s",
49 MYSQL_ERROR(&dblink));
50 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
51 host, tcpport, database, user, socketfile);
52 return LOGSQL_OPENDB_FAIL;
53 }
54}
55
56/*-----------------------------------------------------*
57 * safe_sql_query: perform a database query with *
58 * a degree of safety and error checking. *
59 * *
60 * Parms: request record, SQL insert statement *
61 * Returns: 0 (OK) on success *
62 * 1 if have no log handle *
63 * 2 if insert delayed failed (kluge) *
64 * the actual MySQL return code on error *
65 *-----------------------------------------------------*/
66unsigned int log_sql_mysql_query(request_rec *r, const char *query)
67{
68 int retval;
69 struct timespec delay, remainder;
70 int ret;
71 void (*handler) (int);
72 logsql_state *cls;
73 unsigned int real_error = 0;
74 const char *real_error_str = NULL;
75
76 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
77 handler = signal(SIGPIPE, SIG_IGN);
78
79 /* First attempt for the query */
80 if (!global_config.server_p) {
81 signal(SIGPIPE, handler);
82 return 1;
83 } else if (!(retval = mysql_query(global_config.server_p, query))) {
84 signal(SIGPIPE, handler);
85 return 0;
86 }
87
88 /* If we ran the query and it returned an error, try to be robust.
89 * (After all, the module thought it had a valid mysql_log connection but the query
90 * could have failed for a number of reasons, so we have to be extra-safe and check.) */
91
92 /* Check to see if the error is "nonexistent table" */
93 if (global_config.insertdelayed) {
94 real_error_str = MYSQL_ERROR(global_config.server_p);
95 retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist"));
96 } else {
97 real_error = mysql_errno(global_config.server_p);
98 retval = (real_error == ER_NO_SUCH_TABLE);
99 }
100 if (retval) {
101 log_error(APLOG_MARK,APLOG_ERR,r->server,"table does not exist, preserving query");
102 preserve_entry(r, query);
103 /* Restore SIGPIPE to its original handler function */
104 signal(SIGPIPE, handler);
105 return ER_NO_SUCH_TABLE;
106 }
107
108 /* Handle all other types of errors */
109
110 cls = ap_get_module_config(r->server->module_config, &log_sql_module);
111
112 /* Something went wrong, so start by trying to restart the db link. */
113 if (global_config.insertdelayed) {
114 real_error = 2;
115 } /*else {
116 real_error = mysql_errno(global_config.server_p);
117 }*/
118
119 log_error(APLOG_MARK,APLOG_ERR,r->server,"first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(global_config.server_p));
120 mysql_close(global_config.server_p);
121 global_config.server_p = NULL;
122 open_logdb_link(r->server);
123
124 if (global_config.server_p == NULL) { /* still unable to link */
125 signal(SIGPIPE, handler);
126 log_error(APLOG_MARK,APLOG_ERR,r->server,"reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
127 log_error(APLOG_MARK,APLOG_ERR,r->server,"log entries are being preserved in %s", cls->preserve_file);
128 return 1;
129 } else
130 log_error(APLOG_MARK,APLOG_ERR,r->server,"db reconnect successful");
131
132 /* First sleep for a tiny amount of time. */
133 delay.tv_sec = 0;
134 delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */
135 ret = nanosleep(&delay, &remainder);
136 if (ret && errno != EINTR)
137 log_error(APLOG_MARK,APLOG_ERR,r->server,"nanosleep unsuccessful");
138
139 /* Then make our second attempt */
140 retval = mysql_query(global_config.server_p,query);
141
142 /* If this one also failed, log that and append to our local offline file */
143 if (retval) {
144 if (global_config.insertdelayed) {
145 real_error = 2;
146 } else {
147 real_error = mysql_errno(global_config.server_p);
148 }
149
150 log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(global_config.server_p));
151 preserve_entry(r, query);
152 retval = real_error;
153 } else {
154 log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt successful");
155 retval = 0;
156 }
157 /* Restore SIGPIPE to its original handler function */
158 signal(SIGPIPE, handler);
159 return retval;
160}
161
162/*-----------------------------------------------------*
163 * safe_create_tables: create SQL table set for the *
164 * virtual server represented by cls. *
165 * *
166 * Parms: virtserver structure, request record, *
167 * tables to create *
168 * Returns: 0 on no errors *
169 * mysql error code on failure *
170 *-----------------------------------------------------*/
171int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
172 const char *table_name)
173{
174 int retval;
175
176 char *type_suffix = NULL;
177
178 char *create_prefix = "create table if not exists `";
179 char *create_suffix = NULL;
180 char *create_sql;
181
182 if (!global_config.createtables) {
183 return APR_SUCCESS;
184 }
185
186 switch (table_type) {
187 case LOGSQL_TABLE_ACCESS:
188 create_suffix =
189 "` (id char(19),\
190 agent varchar(255),\
191 bytes_sent int unsigned,\
192 child_pid smallint unsigned,\
193 cookie varchar(255),\
194 machine_id varchar(25),\
195 request_file varchar(255),\
196 referer varchar(255),\
197 remote_host varchar(50),\
198 remote_logname varchar(50),\
199 remote_user varchar(50),\
200 request_duration smallint unsigned,\
201 request_line varchar(255),\
202 request_method varchar(10),\
203 request_protocol varchar(10),\
204 request_time char(28),\
205 request_uri varchar(255),\
206 request_args varchar(255),\
207 server_port smallint unsigned,\
208 ssl_cipher varchar(25),\
209 ssl_keysize smallint unsigned,\
210 ssl_maxkeysize smallint unsigned,\
211 status smallint unsigned,\
212 time_stamp int unsigned,\
213 virtual_host varchar(255))";
214 break;
215 case LOGSQL_TABLE_COOKIES:
216 case LOGSQL_TABLE_HEADERSIN:
217 case LOGSQL_TABLE_HEADERSOUT:
218 case LOGSQL_TABLE_NOTES:
219 create_suffix =
220 "` (id char(19),\
221 item varchar(80),\
222 val varchar(80))";
223 break;
224 }
225
226 if (global_config.tabletype) {
227 type_suffix = apr_pstrcat(r->pool, " TYPE=",
228 global_config.tabletype, NULL);
229 }
230 /* Find memory long enough to hold the whole CREATE string + \0 */
231 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix,
232 type_suffix, NULL);
233
234 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql);
235
236 if ((retval = safe_sql_query(r, create_sql))) {
237 log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s",
238 table_name);
239 }
240 return retval;
241}
diff --git a/mod_log_sql_ssl.c b/mod_log_sql_ssl.c
index c874a2b..2bdb37b 100644
--- a/mod_log_sql_ssl.c
+++ b/mod_log_sql_ssl.c
@@ -1,4 +1,4 @@
1/* $Header: /home/cvs/mod_log_sql/mod_log_sql_ssl.c,v 1.4 2004/01/22 05:26:56 urkle Exp $ */ 1/* $Id: mod_log_sql_ssl.c,v 1.5 2004/02/29 23:36:18 urkle Exp $ */
2/* mod_log_sql_ssl */ 2/* mod_log_sql_ssl */
3 3
4#if defined(WITH_APACHE20) 4#if defined(WITH_APACHE20)