add ser2net from hazimin fauzi, thx
[openwrt.git] / package / asterisk / patches / asterisk-1.2.0-cdr_mysql.patch
1 diff -ruN asterisk-1.2.0-old/configs/cdr_mysql.conf.sample asterisk-1.2.0-new/configs/cdr_mysql.conf.sample
2 --- asterisk-1.2.0-old/configs/cdr_mysql.conf.sample 1970-01-01 01:00:00.000000000 +0100
3 +++ asterisk-1.2.0-new/configs/cdr_mysql.conf.sample 2005-01-21 02:43:20.000000000 +0100
4 @@ -0,0 +1,21 @@
5 +;
6 +; Note - if the database server is hosted on the same machine as the
7 +; asterisk server, you can achieve a local Unix socket connection by
8 +; setting hostname=localhost
9 +;
10 +; port and sock are both optional parameters. If hostname is specified
11 +; and is not "localhost", then cdr_mysql will attempt to connect to the
12 +; port specified or use the default port. If hostname is not specified
13 +; or if hostname is "localhost", then cdr_mysql will attempt to connect
14 +; to the socket file specified by sock or otherwise use the default socket
15 +; file.
16 +;
17 +;[global]
18 +;hostname=database.host.name
19 +;dbname=asteriskcdrdb
20 +;table=cdr
21 +;password=password
22 +;user=asteriskcdruser
23 +;port=3306
24 +;sock=/tmp/mysql.sock
25 +;userfield=1
26 diff -ruN asterisk-1.2.0-old/cdr/cdr_mysql.c asterisk-1.2.0-new/cdr/cdr_mysql.c
27 --- asterisk-1.2.0-old/cdr/cdr_mysql.c 1970-01-01 01:00:00.000000000 +0100
28 +++ asterisk-1.2.0-new/cdr/cdr_mysql.c 2005-12-04 20:10:59.000000000 +0100
29 @@ -0,0 +1,493 @@
30 +/*
31 + * Asterisk -- A telephony toolkit for Linux.
32 + *
33 + * MySQL CDR logger
34 + *
35 + * James Sharp <jsharp@psychoses.org>
36 + *
37 + * Modified August 2003
38 + * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308@the-tilghman.com>
39 + *
40 + * Modified August 6, 2005
41 + * Joseph Benden <joe@thrallingpenguin.com>
42 + * Added mysql connection timeout parameter
43 + * Added an automatic reconnect as to not lose a cdr record
44 + * Cleaned up the original code to match the coding guidelines
45 + *
46 + * This program is free software, distributed under the terms of
47 + * the GNU General Public License.
48 + *
49 + */
50 +
51 +#include <sys/types.h>
52 +
53 +#include <stdio.h>
54 +#include <string.h>
55 +
56 +#include <stdlib.h>
57 +#include <unistd.h>
58 +#include <time.h>
59 +
60 +#include <mysql.h>
61 +#include <errmsg.h>
62 +
63 +#include <sys/stat.h>
64 +#include <sys/types.h>
65 +#include <errno.h>
66 +
67 +#include <asterisk/config.h>
68 +#include <asterisk/options.h>
69 +#include <asterisk/channel.h>
70 +#include <asterisk/cdr.h>
71 +#include <asterisk/module.h>
72 +#include <asterisk/logger.h>
73 +#include <asterisk/cli.h>
74 +
75 +#define DATE_FORMAT "%Y-%m-%d %T"
76 +
77 +static char *desc = "MySQL CDR Backend";
78 +static char *name = "mysql";
79 +static char *config = "cdr_mysql.conf";
80 +static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL;
81 +static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0;
82 +static int dbport = 0;
83 +static int connected = 0;
84 +static time_t connect_time = 0;
85 +static int records = 0;
86 +static int totalrecords = 0;
87 +static int userfield = 0;
88 +static unsigned int timeout = 0;
89 +
90 +AST_MUTEX_DEFINE_STATIC(mysql_lock);
91 +
92 +static MYSQL mysql;
93 +
94 +static char cdr_mysql_status_help[] =
95 +"Usage: cdr mysql status\n"
96 +" Shows current connection status for cdr_mysql\n";
97 +
98 +static int handle_cdr_mysql_status(int fd, int argc, char *argv[])
99 +{
100 + if (connected) {
101 + char status[256], status2[100] = "";
102 + int ctime = time(NULL) - connect_time;
103 + if (dbport)
104 + snprintf(status, 255, "Connected to %s@%s, port %d", dbname, hostname, dbport);
105 + else if (dbsock)
106 + snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
107 + else
108 + snprintf(status, 255, "Connected to %s@%s", dbname, hostname);
109 +
110 + if (dbuser && *dbuser)
111 + snprintf(status2, 99, " with username %s", dbuser);
112 + if (dbtable && *dbtable)
113 + snprintf(status2, 99, " using table %s", dbtable);
114 + if (ctime > 31536000) {
115 + ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
116 + } else if (ctime > 86400) {
117 + ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
118 + } else if (ctime > 3600) {
119 + ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
120 + } else if (ctime > 60) {
121 + ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
122 + } else {
123 + ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
124 + }
125 + if (records == totalrecords)
126 + ast_cli(fd, " Wrote %d records since last restart.\n", totalrecords);
127 + else
128 + ast_cli(fd, " Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
129 + return RESULT_SUCCESS;
130 + } else {
131 + ast_cli(fd, "Not currently connected to a MySQL server.\n");
132 + return RESULT_FAILURE;
133 + }
134 +}
135 +
136 +static struct ast_cli_entry cdr_mysql_status_cli =
137 + { { "cdr", "mysql", "status", NULL },
138 + handle_cdr_mysql_status, "Show connection status of cdr_mysql",
139 + cdr_mysql_status_help, NULL };
140 +
141 +static int mysql_log(struct ast_cdr *cdr)
142 +{
143 + struct tm tm;
144 + struct timeval tv;
145 + struct localuser *u;
146 + char *userfielddata = NULL;
147 + char sqlcmd[2048], timestr[128];
148 + char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
149 + int retries = 5;
150 +#ifdef MYSQL_LOGUNIQUEID
151 + char *uniqueid = NULL;
152 +#endif
153 +
154 + ast_mutex_lock(&mysql_lock);
155 +
156 + memset(sqlcmd, 0, 2048);
157 +
158 + localtime_r(&cdr->start.tv_sec, &tm);
159 + strftime(timestr, 128, DATE_FORMAT, &tm);
160 +
161 +db_reconnect:
162 + if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
163 + /* Attempt to connect */
164 + mysql_init(&mysql);
165 + /* Add option to quickly timeout the connection */
166 + if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) {
167 + ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
168 + }
169 + if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
170 + connected = 1;
171 + connect_time = time(NULL);
172 + records = 0;
173 + } else {
174 + ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.\n", hostname);
175 + connected = 0;
176 + }
177 + } else {
178 + /* Long connection - ping the server */
179 + int error;
180 + if ((error = mysql_ping(&mysql))) {
181 + connected = 0;
182 + records = 0;
183 + switch (error) {
184 + case CR_SERVER_GONE_ERROR:
185 + case CR_SERVER_LOST:
186 + ast_log(LOG_ERROR, "cdr_mysql: Server has gone away. Attempting to reconnect.\n");
187 + break;
188 + default:
189 + ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
190 + }
191 + retries--;
192 + if (retries)
193 + goto db_reconnect;
194 + else
195 + ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n");
196 + }
197 + }
198 +
199 + /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
200 + /* WARNING: This code previously used mysql_real_escape_string, but the use of said function
201 + requires an active connection to a database. If we are not connected, then this function
202 + cannot be used. This is a problem since we need to store off the SQL statement into our
203 + spool file for later restoration.
204 + So the question is, what's the best way to handle this? This works for now.
205 + */
206 + if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL)
207 + mysql_escape_string(clid, cdr->clid, strlen(cdr->clid));
208 + if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL)
209 + mysql_escape_string(dcontext, cdr->dcontext, strlen(cdr->dcontext));
210 + if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL)
211 + mysql_escape_string(channel, cdr->channel, strlen(cdr->channel));
212 + if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL)
213 + mysql_escape_string(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel));
214 + if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL)
215 + mysql_escape_string(lastapp, cdr->lastapp, strlen(cdr->lastapp));
216 + if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL)
217 + mysql_escape_string(lastdata, cdr->lastdata, strlen(cdr->lastdata));
218 +#ifdef MYSQL_LOGUNIQUEID
219 + if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL)
220 + mysql_escape_string(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid));
221 +#endif
222 + if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL))
223 + mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield));
224 +
225 + /* Check for all alloca failures above at once */
226 +#ifdef MYSQL_LOGUNIQUEID
227 + if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) {
228 +#else
229 + if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) {
230 +#endif
231 + ast_log(LOG_ERROR, "cdr_mysql: Out of memory error (insert fails)\n");
232 + ast_mutex_unlock(&mysql_lock);
233 + return -1;
234 + }
235 +
236 + ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n");
237 +
238 + if (userfield && userfielddata) {
239 +#ifdef MYSQL_LOGUNIQUEID
240 + sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid, userfielddata);
241 +#else
242 + sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, userfielddata);
243 +#endif
244 + } else {
245 +#ifdef MYSQL_LOGUNIQUEID
246 + sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid);
247 +#else
248 + sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode);
249 +#endif
250 + }
251 +
252 + ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd);
253 +
254 + if (connected) {
255 + if (mysql_real_query(&mysql, sqlcmd, strlen(sqlcmd))) {
256 + ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql));
257 + connected = 0;
258 + } else {
259 + records++;
260 + totalrecords++;
261 + }
262 + }
263 + ast_mutex_unlock(&mysql_lock);
264 + return 0;
265 +}
266 +
267 +char *description(void)
268 +{
269 + return desc;
270 +}
271 +
272 +static int my_unload_module(void)
273 +{
274 + ast_cli_unregister(&cdr_mysql_status_cli);
275 + if (connected) {
276 + mysql_close(&mysql);
277 + connected = 0;
278 + records = 0;
279 + }
280 + if (hostname && hostname_alloc) {
281 + free(hostname);
282 + hostname = NULL;
283 + hostname_alloc = 0;
284 + }
285 + if (dbname && dbname_alloc) {
286 + free(dbname);
287 + dbname = NULL;
288 + dbname_alloc = 0;
289 + }
290 + if (dbuser && dbuser_alloc) {
291 + free(dbuser);
292 + dbuser = NULL;
293 + dbuser_alloc = 0;
294 + }
295 + if (dbsock && dbsock_alloc) {
296 + free(dbsock);
297 + dbsock = NULL;
298 + dbsock_alloc = 0;
299 + }
300 + if (dbtable && dbtable_alloc) {
301 + free(dbtable);
302 + dbtable = NULL;
303 + dbtable_alloc = 0;
304 + }
305 + if (password && password_alloc) {
306 + free(password);
307 + password = NULL;
308 + password_alloc = 0;
309 + }
310 + dbport = 0;
311 + ast_cdr_unregister(name);
312 + return 0;
313 +}
314 +
315 +static int my_load_module(void)
316 +{
317 + int res;
318 + struct ast_config *cfg;
319 + struct ast_variable *var;
320 + char *tmp;
321 +
322 + cfg = ast_config_load(config);
323 + if (!cfg) {
324 + ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
325 + return 0;
326 + }
327 +
328 + var = ast_variable_browse(cfg, "global");
329 + if (!var) {
330 + /* nothing configured */
331 + return 0;
332 + }
333 +
334 + tmp = ast_variable_retrieve(cfg, "global", "hostname");
335 + if (tmp) {
336 + hostname = malloc(strlen(tmp) + 1);
337 + if (hostname != NULL) {
338 + hostname_alloc = 1;
339 + strcpy(hostname, tmp);
340 + } else {
341 + ast_log(LOG_ERROR, "Out of memory error.\n");
342 + return -1;
343 + }
344 + } else {
345 + ast_log(LOG_WARNING, "MySQL server hostname not specified. Assuming localhost\n");
346 + hostname = "localhost";
347 + }
348 +
349 + tmp = ast_variable_retrieve(cfg, "global", "dbname");
350 + if (tmp) {
351 + dbname = malloc(strlen(tmp) + 1);
352 + if (dbname != NULL) {
353 + dbname_alloc = 1;
354 + strcpy(dbname, tmp);
355 + } else {
356 + ast_log(LOG_ERROR, "Out of memory error.\n");
357 + return -1;
358 + }
359 + } else {
360 + ast_log(LOG_WARNING, "MySQL database not specified. Assuming asteriskcdrdb\n");
361 + dbname = "asteriskcdrdb";
362 + }
363 +
364 + tmp = ast_variable_retrieve(cfg, "global", "user");
365 + if (tmp) {
366 + dbuser = malloc(strlen(tmp) + 1);
367 + if (dbuser != NULL) {
368 + dbuser_alloc = 1;
369 + strcpy(dbuser, tmp);
370 + } else {
371 + ast_log(LOG_ERROR, "Out of memory error.\n");
372 + return -1;
373 + }
374 + } else {
375 + ast_log(LOG_WARNING, "MySQL database user not specified. Assuming root\n");
376 + dbuser = "root";
377 + }
378 +
379 + tmp = ast_variable_retrieve(cfg, "global", "sock");
380 + if (tmp) {
381 + dbsock = malloc(strlen(tmp) + 1);
382 + if (dbsock != NULL) {
383 + dbsock_alloc = 1;
384 + strcpy(dbsock, tmp);
385 + } else {
386 + ast_log(LOG_ERROR, "Out of memory error.\n");
387 + return -1;
388 + }
389 + } else {
390 + ast_log(LOG_WARNING, "MySQL database sock file not specified. Using default\n");
391 + dbsock = NULL;
392 + }
393 +
394 + tmp = ast_variable_retrieve(cfg, "global", "table");
395 + if (tmp) {
396 + dbtable = malloc(strlen(tmp) + 1);
397 + if (dbtable != NULL) {
398 + dbtable_alloc = 1;
399 + strcpy(dbtable, tmp);
400 + } else {
401 + ast_log(LOG_ERROR, "Out of memory error.\n");
402 + return -1;
403 + }
404 + } else {
405 + ast_log(LOG_NOTICE, "MySQL database table not specified. Assuming \"cdr\"\n");
406 + dbtable = "cdr";
407 + }
408 +
409 + tmp = ast_variable_retrieve(cfg, "global", "password");
410 + if (tmp) {
411 + password = malloc(strlen(tmp) + 1);
412 + if (password != NULL) {
413 + password_alloc = 1;
414 + strcpy(password, tmp);
415 + } else {
416 + ast_log(LOG_ERROR, "Out of memory error.\n");
417 + return -1;
418 + }
419 + } else {
420 + ast_log(LOG_WARNING, "MySQL database password not specified. Assuming blank\n");
421 + password = "";
422 + }
423 +
424 + tmp = ast_variable_retrieve(cfg, "global", "port");
425 + if (tmp) {
426 + if (sscanf(tmp, "%d", &dbport) < 1) {
427 + ast_log(LOG_WARNING, "Invalid MySQL port number. Using default\n");
428 + dbport = 0;
429 + }
430 + }
431 +
432 + tmp = ast_variable_retrieve(cfg, "global", "timeout");
433 + if (tmp) {
434 + if (sscanf(tmp,"%d", &timeout) < 1) {
435 + ast_log(LOG_WARNING, "Invalid MySQL timeout number. Using default\n");
436 + timeout = 0;
437 + }
438 + }
439 +
440 + tmp = ast_variable_retrieve(cfg, "global", "userfield");
441 + if (tmp) {
442 + if (sscanf(tmp, "%d", &userfield) < 1) {
443 + ast_log(LOG_WARNING, "Invalid MySQL configurtation file\n");
444 + userfield = 0;
445 + }
446 + }
447 +
448 + ast_config_destroy(cfg);
449 +
450 + ast_log(LOG_DEBUG, "cdr_mysql: got hostname of %s\n", hostname);
451 + ast_log(LOG_DEBUG, "cdr_mysql: got port of %d\n", dbport);
452 + ast_log(LOG_DEBUG, "cdr_mysql: got a timeout of %d\n", timeout);
453 + if (dbsock)
454 + ast_log(LOG_DEBUG, "cdr_mysql: got sock file of %s\n", dbsock);
455 + ast_log(LOG_DEBUG, "cdr_mysql: got user of %s\n", dbuser);
456 + ast_log(LOG_DEBUG, "cdr_mysql: got dbname of %s\n", dbname);
457 + ast_log(LOG_DEBUG, "cdr_mysql: got password of %s\n", password);
458 +
459 + mysql_init(&mysql);
460 +
461 + if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) {
462 + ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
463 + }
464 +
465 + if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
466 + ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname);
467 + connected = 0;
468 + records = 0;
469 + } else {
470 + ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n");
471 + connected = 1;
472 + records = 0;
473 + connect_time = time(NULL);
474 + }
475 +
476 + res = ast_cdr_register(name, desc, mysql_log);
477 + if (res) {
478 + ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
479 + } else {
480 + res = ast_cli_register(&cdr_mysql_status_cli);
481 + }
482 +
483 + return res;
484 +}
485 +
486 +int load_module(void)
487 +{
488 + return my_load_module();
489 +}
490 +
491 +int unload_module(void)
492 +{
493 + return my_unload_module();
494 +}
495 +
496 +int reload(void)
497 +{
498 + int ret;
499 +
500 + ast_mutex_lock(&mysql_lock);
501 + my_unload_module();
502 + ret = my_load_module();
503 + ast_mutex_unlock(&mysql_lock);
504 +
505 + return ret;
506 +}
507 +
508 +int usecount(void)
509 +{
510 + /* Simplistic use count */
511 + if (ast_mutex_trylock(&mysql_lock)) {
512 + return 1;
513 + } else {
514 + ast_mutex_unlock(&mysql_lock);
515 + return 0;
516 + }
517 +}
518 +
519 +char *key()
520 +{
521 + return ASTERISK_GPL_KEY;
522 +}
This page took 0.062192 seconds and 5 git commands to generate.