summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Edward Rudd 2004-03-02 05:34:50 +0000
committerGravatar Edward Rudd 2004-03-02 05:34:50 +0000
commit1caf9013120e8df2d65a97c7216cefa58536f058 (patch)
treedf9201a0d86396bae32a1a4cb366761859dcce72
parent53acb181ef04ae70a7dcfed849f7c02850781c20 (diff)
mysql code separation complete..
-rw-r--r--mod_log_sql.c266
-rw-r--r--mod_log_sql.h34
-rw-r--r--mod_log_sql_mysql.c219
3 files changed, 278 insertions, 241 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 50c7964..faac51e 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,4 +1,4 @@
1/* $Id $ */ 1/* $Id: mod_log_sql.c,v 1.17 2004/03/02 05:34:50 urkle Exp $ */
2/* --------* 2/* --------*
3 * DEFINES * 3 * DEFINES *
4 * --------*/ 4 * --------*/
@@ -61,7 +61,6 @@ typedef struct {
61 int createtables; 61 int createtables;
62 int forcepreserve; 62 int forcepreserve;
63 char *machid; 63 char *machid;
64 apr_table_t *dbparams;
65 logsql_dbconnection db; 64 logsql_dbconnection db;
66} global_config_t; 65} global_config_t;
67 66
@@ -147,56 +146,28 @@ LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
147# include "functions20.h" 146# include "functions20.h"
148#endif 147#endif
149 148
150/* Routine to escape the 'dangerous' characters that would otherwise 149static logsql_opendb_ret log_sql_opendb_link(server_rec* s)
151 * corrupt the INSERT string: ', \, and "
152 */
153static const char *escape_query(const char *from_str, apr_pool_t *p)
154{
155 if (!from_str)
156 return NULL;
157 else {
158 char *to_str;
159 unsigned long length = strlen(from_str);
160 unsigned long retval;
161
162 /* Pre-allocate a new string that could hold twice the original, which would only
163 * happen if the whole original string was 'dangerous' characters.
164 */
165 to_str = (char *) apr_palloc(p, length * 2 + 1);
166 if (!to_str) {
167 return from_str;
168 }
169
170 if (!global_config.db.connected) {
171 /* Well, I would have liked to use the current database charset. mysql is
172 * unavailable, however, so I fall back to the slightly less respectful
173 * mysql_escape_string() function that uses the default charset.
174 */
175 retval = mysql_escape_string(to_str, from_str, length);
176 } else {
177 /* MySQL is available, so I'll go ahead and respect the current charset when
178 * I perform the escape.
179 */
180 retval = mysql_real_escape_string(global_config.db.handle, to_str, from_str, length);
181 }
182
183 if (retval)
184 return to_str;
185 else
186 return from_str;
187 }
188}
189
190static logsql_opendb open_logdb_link(server_rec* s)
191{ 150{
151 logsql_opendb_ret result;
192 if (global_config.forcepreserve) 152 if (global_config.forcepreserve)
153 global_config.db.connected = 1;
193 return LOGSQL_OPENDB_PRESERVE; 154 return LOGSQL_OPENDB_PRESERVE;
194 155
195 if (global_config.db.connected) 156 if (global_config.db.connected)
196 return LOGSQL_OPENDB_ALREADY; 157 return LOGSQL_OPENDB_ALREADY;
197 158 /* database
198 if ((global_config.dbname) && (global_config.dbhost) && (global_config.dbuser) && (global_config.dbpwd)) { 159 host
199 log_sql_mysql_connect(); 160 user
161 passwd
162 */
163 if (global_config.db.parms) {
164 result = log_sql_mysql_connect(s, &global_config.db);
165 if (result==LOGSQL_OPENDB_FAIL) {
166 global_config.db.connected = 0;
167 } else {
168 global_config.db.connected = 1;
169 }
170 return result;
200 } else { 171 } else {
201 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link"); 172 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link");
202 return LOGSQL_OPENDB_FAIL; 173 return LOGSQL_OPENDB_FAIL;
@@ -323,21 +294,24 @@ static const char *set_server_nmv_string_slot(cmd_parms *parms,
323} 294}
324 295
325/* Set a DB connection parameter */ 296/* Set a DB connection parameter */
326static void set_dbparam(apr_pool_t *p, const char *key, 297static const char *set_dbparam(cmd_parms *cmd,
327 const char *val); 298 void *struct_ptr,
299 const char *key,
300 const char *val)
328{ 301{
329 if (!global_config.dbparams) { 302 if (!global_config.db.parms) {
330 global_config.dbparams = apr_table_make(p,5); 303 global_config.db.parms = apr_table_make(cmd->pool,5);
331 } 304 }
332 apr_table_set(global_config.dbparams,key,val); 305 apr_table_set(global_config.db.parms,key,val);
306 return NULL;
333} 307}
334 308
335static const char *set_dbparam_slot(cmd_params *cmd, 309static const char *set_dbparam_slot(cmd_parms *cmd,
336 void *struct_ptr, 310 void *struct_ptr,
337 const char *arg) 311 const char *arg)
338{ 312{
339 const char *param = (char *)cmd->info; 313 const char *param = (char *)cmd->info;
340 set_dbparam(cmd->pool,param,arg); 314 set_dbparam(cmd,NULL,param,arg);
341 return NULL; 315 return NULL;
342} 316}
343 317
@@ -346,14 +320,13 @@ static const char *set_log_sql_info(cmd_parms *cmd, void *dummy,
346 const char *host, const char *user, const char *pwd) 320 const char *host, const char *user, const char *pwd)
347{ 321{
348 if (*host != '.') { 322 if (*host != '.') {
349 set_db_param_slot(cmd->pool, "host", host); 323 set_dbparam(cmd, NULL, "host", host);
350 } 324 }
351 if (*user != '.') { 325 if (*user != '.') {
352 set_db_param_slot(cmd->pool, "user", user); 326 set_dbparam(cmd, NULL, "user", user);
353 global_config.dbuser = apr_pstrdup(cmd->pool,user);
354 } 327 }
355 if (*pwd != '.') { 328 if (*pwd != '.') {
356 set_db_param_slot(cmd->pool, "passwd", pwd); 329 set_dbparam(cmd, NULL, "passwd", pwd);
357 } 330 }
358 return NULL; 331 return NULL;
359} 332}
@@ -373,13 +346,6 @@ static const char *add_server_string_slot(cmd_parms *cmd,
373 return NULL; 346 return NULL;
374} 347}
375 348
376static const char *set_log_sql_tcp_port(cmd_parms *parms, void *dummy, const char *arg)
377{
378 global_config.tcpport = (unsigned int)atoi(arg);
379
380 return NULL;
381}
382
383/*------------------------------------------------------------* 349/*------------------------------------------------------------*
384 * Apache-specific hooks into the module code * 350 * Apache-specific hooks into the module code *
385 * that are defined in the array 'mysql_lgog_module' (at EOF) * 351 * that are defined in the array 'mysql_lgog_module' (at EOF) *
@@ -388,13 +354,13 @@ static const char *set_log_sql_tcp_port(cmd_parms *parms, void *dummy, const cha
388#if defined(WITH_APACHE20) 354#if defined(WITH_APACHE20)
389static apr_status_t log_sql_close_link(void *data) 355static apr_status_t log_sql_close_link(void *data)
390{ 356{
391 mysql_close(global_config.server_p); 357 log_sql_mysql_close(&global_config.db);
392 return APR_SUCCESS; 358 return APR_SUCCESS;
393} 359}
394#elif defined(WITH_APACHE13) 360#elif defined(WITH_APACHE13)
395static void log_sql_child_exit(server_rec *s, apr_pool_t *p) 361static void log_sql_child_exit(server_rec *s, apr_pool_t *p)
396{ 362{
397 mysql_close(global_config.server_p); 363 log_sql_mysql_close(&global_config.db);
398} 364}
399#endif 365#endif
400 366
@@ -410,9 +376,9 @@ static int log_sql_open(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_re
410static void log_sql_child_init(server_rec *s, apr_pool_t *p) 376static void log_sql_child_init(server_rec *s, apr_pool_t *p)
411#endif 377#endif
412{ 378{
413 logsql_opendb retval; 379 logsql_opendb_ret retval;
414 /* Open a link to the database */ 380 /* Open a link to the database */
415 retval = open_logdb_link(s); 381 retval = log_sql_opendb_link(s);
416 switch (retval) { 382 switch (retval) {
417 case LOGSQL_OPENDB_FAIL: 383 case LOGSQL_OPENDB_FAIL:
418 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link"); 384 log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link");
@@ -438,10 +404,10 @@ static void log_sql_module_init(server_rec *s, apr_pool_t *p)
438#endif 404#endif
439{ 405{
440 /* Initialize Global configuration */ 406 /* Initialize Global configuration */
441 if (!global_config.socketfile) 407 if (!apr_table_get(global_config.db.parms,"socketfile"))
442 global_config.socketfile = "/tmp/mysql.sock"; 408 apr_table_setn(global_config.db.parms,"socketfile","/tmp/mysql.sock");
443 if (!global_config.tcpport) 409 if (!apr_table_get(global_config.db.parms,"tcpport"))
444 global_config.tcpport = 3306; 410 apr_table_setn(global_config.db.parms,"tcpport","3306");
445 411
446 /* TODO: Add local_address, remote_address, server_name, connection_status */ 412 /* TODO: Add local_address, remote_address, server_name, connection_status */
447 /* Register handlers */ 413 /* Register handlers */
@@ -481,11 +447,88 @@ static void log_sql_module_init(server_rec *s, apr_pool_t *p)
481 * Parms: request record, table type, table name, and the full SQL command 447 * Parms: request record, table type, table name, and the full SQL command
482 */ 448 */
483 449
484static void safe_sql_insert(request_rec *r, logsql_tabletype table_type, 450static logsql_query_ret safe_sql_insert(request_rec *r, logsql_tabletype table_type,
485 const char *table_name, const char *sql) { 451 const char *table_name, const char *query) {
486 int result; 452
487 if (!global_config.connected) { 453 logsql_query_ret result;
454 logsql_state *cls = ap_get_module_config(r->server->module_config,
455 &log_sql_module);
456
457 if (!global_config.db.connected) {
458 /* preserve query */
459 return LOGSQL_QUERY_NOLINK;
460 }
461
462 result = log_sql_mysql_query(r,&global_config.db,query);
463
464 /* If we ran the query and it returned an error, try to be robust.
465 * (After all, the module thought it had a valid mysql_log connection but the query
466 * could have failed for a number of reasons, so we have to be extra-safe and check.) */
467 switch (result) {
468 case LOGSQL_QUERY_SUCCESS:
469 return LOGSQL_QUERY_SUCCESS;
470 case LOGSQL_QUERY_NOLINK:
471 return LOGSQL_QUERY_FAIL;
472 /* TODO: What do we do here */
473 case LOGSQL_QUERY_FAIL:
474 log_sql_mysql_close(&global_config.db);
475 global_config.db.connected = 0;
476 /* re-open the connection and try again */
477 if (log_sql_opendb_link(r->server) != LOGSQL_OPENDB_FAIL) {
478 log_error(APLOG_MARK,APLOG_ERR,r->server,"db reconnect successful");
479 result = log_sql_mysql_query(r,&global_config.db,query);
480 if (result == LOGSQL_QUERY_SUCCESS) {
481 return LOGSQL_QUERY_SUCCESS;
482 } else {
483 log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt failed");
484 preserve_entry(r, query);
485 return LOGSQL_QUERY_PRESERVED;
486 }
487 } else {
488 log_error(APLOG_MARK,APLOG_ERR,r->server,"reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
489 log_error(APLOG_MARK,APLOG_ERR,r->server,"log entries are being preserved in %s",cls->preserve_file);
490 preserve_entry(r, query);
491 return LOGSQL_QUERY_PRESERVED;
492 }
493 break;
494 case LOGSQL_QUERY_NOTABLE:
495 if (global_config.createtables) {
496 log_error(APLOG_MARK,APLOG_ERR,r->server,
497 "table doesn't exist...creating now");
498 if ((result = log_sql_mysql_create(r, &global_config.db, table_type,
499 table_name))!=LOGSQL_TABLE_SUCCESS) {
500 log_error(APLOG_MARK,APLOG_ERR,r->server,
501 "child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r));
502 preserve_entry(r, query);
503 return LOGSQL_QUERY_PRESERVED;
504 } else {
505 log_error(APLOG_MARK,APLOG_ERR,r->server,
506 "tables successfully created - retrying query");
507 if ((result = log_sql_mysql_query(r,&global_config.db,query))!=LOGSQL_QUERY_SUCCESS) {
508 log_error(APLOG_MARK,APLOG_ERR,r->server,
509 "giving up, preserving query");
510 preserve_entry(r, query);
511 return LOGSQL_QUERY_PRESERVED;
512 } else {
513 log_error(APLOG_MARK,APLOG_ERR,r->server,
514 "query successful after table creation");
515 return LOGSQL_QUERY_SUCCESS;
516 }
517 }
518 } else {
519 log_error(APLOG_MARK,APLOG_ERR,r->server,
520 "table doesn't exist, creation denied by configuration, preserving query");
521 preserve_entry(r, query);
522 return LOGSQL_QUERY_PRESERVED;
523 }
524 break;
525 default:
526 log_error(APLOG_MARK,APLOG_ERR,r->server,
527 "Invalid return code from mog_log_query");
528 return LOGSQL_QUERY_FAIL;
529 break;
488 } 530 }
531 return LOGSQL_QUERY_FAIL;
489} 532}
490 533
491/* This function gets called to create a per-server configuration 534/* This function gets called to create a per-server configuration
@@ -726,7 +769,7 @@ static int log_sql_transaction(request_rec *orig)
726 item->sql_field_name, NULL); 769 item->sql_field_name, NULL);
727 values = apr_pstrcat(r->pool, values, (i ? "," : ""), 770 values = apr_pstrcat(r->pool, values, (i ? "," : ""),
728 (item->string_contents ? "'" : ""), 771 (item->string_contents ? "'" : ""),
729 escape_query(formatted_item, r->pool), 772 log_sql_mysql_escape(formatted_item, r->pool,&global_config.db),
730 (item->string_contents ? "'" : ""), NULL); 773 (item->string_contents ? "'" : ""), NULL);
731 } 774 }
732 775
@@ -743,9 +786,9 @@ static int log_sql_transaction(request_rec *orig)
743 "('", 786 "('",
744 unique_id, 787 unique_id,
745 "','", 788 "','",
746 escape_query(*ptrptr, r->pool), 789 log_sql_mysql_escape(*ptrptr, r->pool,&global_config.db),
747 "','", 790 "','",
748 escape_query(theitem, r->pool), 791 log_sql_mysql_escape(theitem, r->pool,&global_config.db),
749 "')", 792 "')",
750 NULL); 793 NULL);
751 i++; 794 i++;
@@ -753,7 +796,7 @@ static int log_sql_transaction(request_rec *orig)
753 } 796 }
754 if ( itemsets != "" ) { 797 if ( itemsets != "" ) {
755 note_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s", 798 note_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s",
756 global_config.insertdelayed?"delayed":"", notes_tablename, itemsets); 799 /*global_config.insertdelayed?"delayed":*/"", notes_tablename, itemsets);
757 800
758 #ifdef DEBUG 801 #ifdef DEBUG
759 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: note string: %s", note_query); 802 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: note string: %s", note_query);
@@ -773,9 +816,9 @@ static int log_sql_transaction(request_rec *orig)
773 "('", 816 "('",
774 unique_id, 817 unique_id,
775 "','", 818 "','",
776 escape_query(*ptrptr, r->pool), 819 log_sql_mysql_escape(*ptrptr, r->pool,&global_config.db),
777 "','", 820 "','",
778 escape_query(theitem, r->pool), 821 log_sql_mysql_escape(theitem, r->pool,&global_config.db),
779 "')", 822 "')",
780 NULL); 823 NULL);
781 i++; 824 i++;
@@ -783,11 +826,9 @@ static int log_sql_transaction(request_rec *orig)
783 } 826 }
784 if ( itemsets != "" ) { 827 if ( itemsets != "" ) {
785 hout_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s", 828 hout_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s",
786 global_config.insertdelayed?"delayed":"", hout_tablename, itemsets); 829 /*global_config.insertdelayed?"delayed":*/"", hout_tablename, itemsets);
787 830
788 #ifdef DEBUG 831 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: header_out string: %s", hout_query);
789 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: header_out string: %s", hout_query);
790 #endif
791 } 832 }
792 833
793 834
@@ -804,9 +845,9 @@ static int log_sql_transaction(request_rec *orig)
804 "('", 845 "('",
805 unique_id, 846 unique_id,
806 "','", 847 "','",
807 escape_query(*ptrptr, r->pool), 848 log_sql_mysql_escape(*ptrptr, r->pool,&global_config.db),
808 "','", 849 "','",
809 escape_query(theitem, r->pool), 850 log_sql_mysql_escape(theitem, r->pool,&global_config.db),
810 "')", 851 "')",
811 NULL); 852 NULL);
812 i++; 853 i++;
@@ -814,11 +855,9 @@ static int log_sql_transaction(request_rec *orig)
814 } 855 }
815 if ( itemsets != "" ) { 856 if ( itemsets != "" ) {
816 hin_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s", 857 hin_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s",
817 global_config.insertdelayed?"delayed":"", hin_tablename, itemsets); 858 /*global_config.insertdelayed?"delayed":*/"", hin_tablename, itemsets);
818 859
819 #ifdef DEBUG 860 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: header_in string: %s", hin_query);
820 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: header_in string: %s", hin_query);
821 #endif
822 } 861 }
823 862
824 863
@@ -835,9 +874,9 @@ static int log_sql_transaction(request_rec *orig)
835 "('", 874 "('",
836 unique_id, 875 unique_id,
837 "','", 876 "','",
838 escape_query(*ptrptr, r->pool), 877 log_sql_mysql_escape(*ptrptr, r->pool,&global_config.db),
839 "','", 878 "','",
840 escape_query(theitem, r->pool), 879 log_sql_mysql_escape(theitem, r->pool,&global_config.db),
841 "')", 880 "')",
842 NULL); 881 NULL);
843 i++; 882 i++;
@@ -846,29 +885,23 @@ static int log_sql_transaction(request_rec *orig)
846 } 885 }
847 if ( itemsets != "" ) { 886 if ( itemsets != "" ) {
848 cookie_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s", 887 cookie_query = apr_psprintf(r->pool, "insert %s into `%s` (id, item, val) values %s",
849 global_config.insertdelayed?"delayed":"", cookie_tablename, itemsets); 888 /*global_config.insertdelayed?"delayed":*/"", cookie_tablename, itemsets);
850 889
851 #ifdef DEBUG 890 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: cookie string: %s", cookie_query);
852 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: cookie string: %s", cookie_query);
853 #endif
854 } 891 }
855 892
856 893
857 /* Set up the actual INSERT statement */ 894 /* Set up the actual INSERT statement */
858 access_query = apr_psprintf(r->pool, "insert %s into `%s` (%s) values (%s)", 895 access_query = apr_psprintf(r->pool, "insert %s into `%s` (%s) values (%s)",
859 global_config.insertdelayed?"delayed":"", transfer_tablename, fields, values); 896 /*global_config.insertdelayed?"delayed":*/"", transfer_tablename, fields, values);
860 897
861 #ifdef DEBUG 898 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: access string: %s", access_query);
862 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: access string: %s", access_query);
863 #endif
864 899
865 /* If the person activated force-preserve, go ahead and push all the entries 900 /* If the person activated force-preserve, go ahead and push all the entries
866 * into the preserve file, then return. 901 * into the preserve file, then return.
867 */ 902 */
868 if (global_config.forcepreserve) { 903 if (global_config.forcepreserve) {
869 #ifdef DEBUG 904 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: preservation forced");
870 log_error(APLOG_MARK,APLOG_DEBUG,orig->server,"mod_log_sql: preservation forced");
871 #endif
872 preserve_entry(orig, access_query); 905 preserve_entry(orig, access_query);
873 if ( note_query != NULL ) 906 if ( note_query != NULL )
874 preserve_entry(orig, note_query); 907 preserve_entry(orig, note_query);
@@ -882,12 +915,12 @@ static int log_sql_transaction(request_rec *orig)
882 } 915 }
883 916
884 /* How's our mysql link integrity? */ 917 /* How's our mysql link integrity? */
885 if (global_config.server_p == NULL) { 918 if (!global_config.db.connected) {
886 919
887 /* Make a try to establish the link */ 920 /* Make a try to establish the link */
888 open_logdb_link(r->server); 921 log_sql_opendb_link(r->server);
889 922
890 if (global_config.server_p == NULL) { 923 if (!global_config.db.connected) {
891 /* Unable to re-establish a DB link, so assume that it's really 924 /* Unable to re-establish a DB link, so assume that it's really
892 * gone and send the entry to the preserve file instead. 925 * gone and send the entry to the preserve file instead.
893 * This short-circuits safe_sql_query() during a db outage and therefore 926 * This short-circuits safe_sql_query() during a db outage and therefore
@@ -915,24 +948,20 @@ static int log_sql_transaction(request_rec *orig)
915 /* ---> i.e. we have a good MySQL connection. <--- */ 948 /* ---> i.e. we have a good MySQL connection. <--- */
916 949
917 /* Make the access-table insert */ 950 /* Make the access-table insert */
918 if (safe_create_tables(orig, LOGSQL_TABLE_ACCESS, transfer_tablename)==APR_SUCCESS) { 951 safe_sql_insert(orig,LOGSQL_TABLE_ACCESS,transfer_tablename,access_query);
919 safe_sql_query(orig, access_query);
920 } else {
921 preserve_entry(orig, access_query);
922 }
923 952
924 /* Log the optional notes, headers, etc. */ 953 /* Log the optional notes, headers, etc. */
925 if (note_query) 954 if (note_query)
926 safe_sql_query(orig, note_query); 955 safe_sql_insert(orig, LOGSQL_TABLE_NOTES,notes_tablename,note_query);
927 956
928 if (hout_query) 957 if (hout_query)
929 safe_sql_query(orig, hout_query); 958 safe_sql_insert(orig, LOGSQL_TABLE_HEADERSOUT,hout_tablename,hout_query);
930 959
931 if (hin_query) 960 if (hin_query)
932 safe_sql_query(orig, hin_query); 961 safe_sql_insert(orig, LOGSQL_TABLE_HEADERSIN,hin_tablename,hin_query);
933 962
934 if (cookie_query) 963 if (cookie_query)
935 safe_sql_query(orig, cookie_query); 964 safe_sql_insert(orig, LOGSQL_TABLE_COOKIES,cookie_tablename,cookie_query);
936 965
937 return OK; 966 return OK;
938 } 967 }
@@ -1027,6 +1056,9 @@ static const command_rec log_sql_cmds[] = {
1027 AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF, 1056 AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF,
1028 "The database host, user-id and password for logging") 1057 "The database host, user-id and password for logging")
1029 , 1058 ,
1059 AP_INIT_TAKE2("LogSQLDBParam", set_dbparam, NULL, RSRC_CONF,
1060 "First argument is the DB parameter, second is the value to assign")
1061 ,
1030 AP_INIT_TAKE1("LogSQLDatabase", set_dbparam_slot, 1062 AP_INIT_TAKE1("LogSQLDatabase", set_dbparam_slot,
1031 (void *)"database", RSRC_CONF, 1063 (void *)"database", RSRC_CONF,
1032 "The name of the database database for logging") 1064 "The name of the database database for logging")
diff --git a/mod_log_sql.h b/mod_log_sql.h
index 0c59cb7..1eed9b4 100644
--- a/mod_log_sql.h
+++ b/mod_log_sql.h
@@ -1,4 +1,4 @@
1/* $Id: mod_log_sql.h,v 1.4 2004/02/29 23:36:18 urkle Exp $ */ 1/* $Id: mod_log_sql.h,v 1.5 2004/03/02 05:34:50 urkle Exp $ */
2 2
3#ifndef MOD_LOG_SQL_H 3#ifndef MOD_LOG_SQL_H
4#define MOD_LOG_SQL_H 4#define MOD_LOG_SQL_H
@@ -31,12 +31,11 @@ LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
31 char key, logsql_item_func *func, const char *sql_field_name, 31 char key, logsql_item_func *func, const char *sql_field_name,
32 int want_orig_default, int string_contents); 32 int want_orig_default, int string_contents);
33 33
34/* DB Connection structure holds connection status information 34/* DB Connection structure holds connection handle */
35 * and connection handle
36 */
37typedef struct { 35typedef struct {
38 int connected; /* Are we connected to the DB */ 36 int connected; /* Are we connected to the DB */
39 void *handle; /* DB specific connection pointer */ 37 void *handle; /* DB specific connection pointer */
38 apr_table_t *parms; /* DB connection parameters */
40} logsql_dbconnection; 39} logsql_dbconnection;
41 40
42/* open db handle return values*/ 41/* open db handle return values*/
@@ -45,9 +44,22 @@ typedef enum {
45 LOGSQL_OPENDB_SUCCESS, 44 LOGSQL_OPENDB_SUCCESS,
46 LOGSQL_OPENDB_ALREADY, 45 LOGSQL_OPENDB_ALREADY,
47 LOGSQL_OPENDB_PRESERVE 46 LOGSQL_OPENDB_PRESERVE
48} logsql_opendb; 47} logsql_opendb_ret;
48
49typedef enum {
50 LOGSQL_QUERY_SUCCESS = 0,
51 LOGSQL_QUERY_FAIL,
52 LOGSQL_QUERY_NOLINK,
53 LOGSQL_QUERY_NOTABLE,
54 LOGSQL_QUERY_PRESERVED,
55} logsql_query_ret;
49 56
50/* For passing to create_tables handler */ 57typedef enum {
58 LOGSQL_TABLE_SUCCESS = 0,
59 LOGSQL_TABLE_FAIL,
60} logsql_table_ret;
61
62/* Table type to create/log to */
51typedef enum { 63typedef enum {
52 LOGSQL_TABLE_ACCESS = 0, 64 LOGSQL_TABLE_ACCESS = 0,
53 LOGSQL_TABLE_NOTES, 65 LOGSQL_TABLE_NOTES,
@@ -60,5 +72,15 @@ typedef enum {
60#define LOGSQL_TABLE_ALL LOGSQL_TABLE_ACCESS | LOGSQL_TABLE_NOTES | \ 72#define LOGSQL_TABLE_ALL LOGSQL_TABLE_ACCESS | LOGSQL_TABLE_NOTES | \
61 LOGSQL_TABLE_HEADERSIN | LOGSQL_TABLE_HEADERSOUT | LOGSQL_TABLE_COOKIES 73 LOGSQL_TABLE_HEADERSIN | LOGSQL_TABLE_HEADERSOUT | LOGSQL_TABLE_COOKIES
62 74
75/* MySQL module calls */
76logsql_opendb_ret log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db);
77void log_sql_mysql_close(logsql_dbconnection *db);
78const char *log_sql_mysql_escape(const char *from_str, apr_pool_t *p,
79 logsql_dbconnection *db);
80logsql_query_ret log_sql_mysql_query(request_rec *r,logsql_dbconnection *db,
81 const char *query);
82logsql_table_ret log_sql_mysql_create(request_rec *r, logsql_dbconnection *db,
83 logsql_tabletype table_type, const char *table_name);
84
63 85
64#endif /* MOD_LOG_SQL_H */ 86#endif /* MOD_LOG_SQL_H */
diff --git a/mod_log_sql_mysql.c b/mod_log_sql_mysql.c
index 3f05935..d0666fe 100644
--- a/mod_log_sql_mysql.c
+++ b/mod_log_sql_mysql.c
@@ -1,4 +1,4 @@
1/* $Id: mod_log_sql_mysql.c,v 1.1 2004/02/29 23:36:18 urkle Exp $ */ 1/* $Id: mod_log_sql_mysql.c,v 1.2 2004/03/02 05:34:50 urkle Exp $ */
2#include "mysql.h" 2#include "mysql.h"
3#include "mysqld_error.h" 3#include "mysqld_error.h"
4 4
@@ -28,160 +28,133 @@
28/* The enduser won't modify these */ 28/* The enduser won't modify these */
29#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") 29#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
30 30
31logsql_opendb log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db, 31/* Connect to the MYSQL database */
32 apr_table_t *dbparms) 32logsql_opendb_ret log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db)
33{ 33{
34 MYSQL *dblink; 34 const char *host = apr_table_get(db->parms,"host");
35 char *host = apr_table_get(dbparms,"host"); 35 const char *user = apr_table_get(db->parms,"user");
36 char *user = apr_table_get(dbparms,"user"); 36 const char *passwd = apr_table_get(db->parms,"passwd");
37 char *passwd = apr_table_get(dbparms,"passwd"); 37 const char *database = apr_table_get(db->parms,"database");
38 char *database = apr_table_get(dbparms,"database"); 38 unsigned int tcpport = atoi(apr_table_get(db->parms,"tcpport"));
39 char *tcpport = apr_table_get(dbparms,"tcpport"); 39 const char *socketfile = apr_table_get(db->parms,"socketfile");
40 char *socketfile = apr_table_get(dbparms,"socketfile"); 40 MYSQL *dblink = db->handle;
41 mysql_init(&dblink); 41
42 if (mysql_real_connect(&dblink, host, user, passwd, database, tcpport, 42 dblink = mysql_init(dblink);
43 socketfile, 0) { 43 db->handle = (void *)dblink;
44
45 if (mysql_real_connect(dblink, host, user, passwd, database, tcpport,
46 socketfile, 0)) {
44 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", 47 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
45 host, tcpport, database, user, socketfile); 48 host, tcpport, database, user, socketfile);
46 return LOGSQL_OPENDB_SUCCESS; 49 return LOGSQL_OPENDB_SUCCESS;
47 } else { 50 } else {
48 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s", 51 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s",
49 MYSQL_ERROR(&dblink)); 52 MYSQL_ERROR(dblink));
50 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", 53 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
51 host, tcpport, database, user, socketfile); 54 host, tcpport, database, user, socketfile);
52 return LOGSQL_OPENDB_FAIL; 55 return LOGSQL_OPENDB_FAIL;
53 } 56 }
54} 57}
55 58
56/*-----------------------------------------------------* 59void log_sql_mysql_close(logsql_dbconnection *db)
57 * safe_sql_query: perform a database query with * 60{
58 * a degree of safety and error checking. * 61 mysql_close((MYSQL *)db->handle);
59 * * 62}
60 * Parms: request record, SQL insert statement * 63
61 * Returns: 0 (OK) on success * 64/* Routine to escape the 'dangerous' characters that would otherwise
62 * 1 if have no log handle * 65 * corrupt the INSERT string: ', \, and "
63 * 2 if insert delayed failed (kluge) * 66 */
64 * the actual MySQL return code on error * 67const char *log_sql_mysql_escape(const char *from_str, apr_pool_t *p,
65 *-----------------------------------------------------*/ 68 logsql_dbconnection *db)
66unsigned int log_sql_mysql_query(request_rec *r, const char *query) 69{
70 if (!from_str)
71 return NULL;
72 else {
73 char *to_str;
74 unsigned long length = strlen(from_str);
75 unsigned long retval;
76
77 /* Pre-allocate a new string that could hold twice the original, which would only
78 * happen if the whole original string was 'dangerous' characters.
79 */
80 to_str = (char *) apr_palloc(p, length * 2 + 1);
81 if (!to_str) {
82 return from_str;
83 }
84
85 if (!db->connected) {
86 /* Well, I would have liked to use the current database charset. mysql is
87 * unavailable, however, so I fall back to the slightly less respectful
88 * mysql_escape_string() function that uses the default charset.
89 */
90 retval = mysql_escape_string(to_str, from_str, length);
91 } else {
92 /* MySQL is available, so I'll go ahead and respect the current charset when
93 * I perform the escape.
94 */
95 retval = mysql_real_escape_string((MYSQL *)db->handle, to_str, from_str, length);
96 }
97
98 if (retval)
99 return to_str;
100 else
101 return from_str;
102 }
103}
104
105logsql_query_ret log_sql_mysql_query(request_rec *r,logsql_dbconnection *db,
106 const char *query)
67{ 107{
68 int retval; 108 int retval;
69 struct timespec delay, remainder;
70 int ret;
71 void (*handler) (int); 109 void (*handler) (int);
72 logsql_state *cls;
73 unsigned int real_error = 0; 110 unsigned int real_error = 0;
74 const char *real_error_str = NULL; 111 /*const char *real_error_str = NULL;*/
112
113 MYSQL *dblink = (MYSQL *)db->handle;
75 114
115 if (!dblink) {
116 return LOGSQL_QUERY_NOLINK;
117 }
76 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ 118 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
77 handler = signal(SIGPIPE, SIG_IGN); 119 handler = signal(SIGPIPE, SIG_IGN);
78 120
79 /* First attempt for the query */ 121 /* Run the query */
80 if (!global_config.server_p) { 122 if (!(retval = mysql_query(dblink, query))) {
81 signal(SIGPIPE, handler);
82 return 1;
83 } else if (!(retval = mysql_query(global_config.server_p, query))) {
84 signal(SIGPIPE, handler); 123 signal(SIGPIPE, handler);
85 return 0; 124 return LOGSQL_QUERY_SUCCESS;
86 } 125 }
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" */ 126 /* Check to see if the error is "nonexistent table" */
93 if (global_config.insertdelayed) { 127 real_error = mysql_errno(dblink);
94 real_error_str = MYSQL_ERROR(global_config.server_p); 128
95 retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist")); 129 if (real_error == ER_NO_SUCH_TABLE) {
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"); 130 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 */ 131 /* Restore SIGPIPE to its original handler function */
104 signal(SIGPIPE, handler); 132 signal(SIGPIPE, handler);
105 return ER_NO_SUCH_TABLE; 133 return LOGSQL_QUERY_NOTABLE;
106 } 134 }
107 135
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 */ 136 /* Restore SIGPIPE to its original handler function */
158 signal(SIGPIPE, handler); 137 signal(SIGPIPE, handler);
159 return retval; 138 return LOGSQL_QUERY_FAIL;
160} 139}
161 140
162/*-----------------------------------------------------* 141logsql_table_ret log_sql_mysql_create(request_rec *r, logsql_dbconnection *db,
163 * safe_create_tables: create SQL table set for the * 142 logsql_tabletype table_type, const char *table_name)
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{ 143{
174 int retval; 144 int retval;
175 145 const char *tabletype = apr_table_get(db->parms,"tabletype");
146 void (*handler) (int);
176 char *type_suffix = NULL; 147 char *type_suffix = NULL;
177 148
178 char *create_prefix = "create table if not exists `"; 149 char *create_prefix = "create table if not exists `";
179 char *create_suffix = NULL; 150 char *create_suffix = NULL;
180 char *create_sql; 151 char *create_sql;
181 152
182 if (!global_config.createtables) { 153 MYSQL *dblink = (MYSQL *)db->handle;
154
155/* if (!global_config.createtables) {
183 return APR_SUCCESS; 156 return APR_SUCCESS;
184 } 157 }*/
185 158
186 switch (table_type) { 159 switch (table_type) {
187 case LOGSQL_TABLE_ACCESS: 160 case LOGSQL_TABLE_ACCESS:
@@ -223,9 +196,9 @@ int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
223 break; 196 break;
224 } 197 }
225 198
226 if (global_config.tabletype) { 199 if (tabletype) {
227 type_suffix = apr_pstrcat(r->pool, " TYPE=", 200 type_suffix = apr_pstrcat(r->pool, " TYPE=",
228 global_config.tabletype, NULL); 201 tabletype, NULL);
229 } 202 }
230 /* Find memory long enough to hold the whole CREATE string + \0 */ 203 /* Find memory long enough to hold the whole CREATE string + \0 */
231 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix, 204 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix,
@@ -233,9 +206,19 @@ int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
233 206
234 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql); 207 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql);
235 208
236 if ((retval = safe_sql_query(r, create_sql))) { 209 if (!dblink) {
210 return LOGSQL_QUERY_NOLINK;
211 }
212 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
213 handler = signal(SIGPIPE, SIG_IGN);
214
215 /* Run the create query */
216 if ((retval = mysql_query(dblink, create_sql))) {
237 log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s", 217 log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s",
238 table_name); 218 table_name);
219 signal(SIGPIPE, handler);
220 return LOGSQL_TABLE_FAIL;
239 } 221 }
240 return retval; 222 signal(SIGPIPE, handler);
223 return LOGSQL_TABLE_SUCCESS;
241} 224}