summaryrefslogtreecommitdiffstats
path: root/mod_log_sql_mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_log_sql_mysql.c')
-rw-r--r--mod_log_sql_mysql.c241
1 files changed, 241 insertions, 0 deletions
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}