diff options
Diffstat (limited to 'openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch')
-rw-r--r-- | openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch new file mode 100644 index 000000000..f4dc29fd7 --- /dev/null +++ b/openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch @@ -0,0 +1,522 @@ +diff -ruN asterisk-1.2.0-old/configs/cdr_mysql.conf.sample asterisk-1.2.0-new/configs/cdr_mysql.conf.sample +--- asterisk-1.2.0-old/configs/cdr_mysql.conf.sample 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.0-new/configs/cdr_mysql.conf.sample 2005-01-21 02:43:20.000000000 +0100 +@@ -0,0 +1,21 @@ ++; ++; Note - if the database server is hosted on the same machine as the ++; asterisk server, you can achieve a local Unix socket connection by ++; setting hostname=localhost ++; ++; port and sock are both optional parameters. If hostname is specified ++; and is not "localhost", then cdr_mysql will attempt to connect to the ++; port specified or use the default port. If hostname is not specified ++; or if hostname is "localhost", then cdr_mysql will attempt to connect ++; to the socket file specified by sock or otherwise use the default socket ++; file. ++; ++;[global] ++;hostname=database.host.name ++;dbname=asteriskcdrdb ++;table=cdr ++;password=password ++;user=asteriskcdruser ++;port=3306 ++;sock=/tmp/mysql.sock ++;userfield=1 +diff -ruN asterisk-1.2.0-old/cdr/cdr_mysql.c asterisk-1.2.0-new/cdr/cdr_mysql.c +--- asterisk-1.2.0-old/cdr/cdr_mysql.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.0-new/cdr/cdr_mysql.c 2005-12-04 20:10:59.000000000 +0100 +@@ -0,0 +1,493 @@ ++/* ++ * Asterisk -- A telephony toolkit for Linux. ++ * ++ * MySQL CDR logger ++ * ++ * James Sharp <jsharp@psychoses.org> ++ * ++ * Modified August 2003 ++ * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308@the-tilghman.com> ++ * ++ * Modified August 6, 2005 ++ * Joseph Benden <joe@thrallingpenguin.com> ++ * Added mysql connection timeout parameter ++ * Added an automatic reconnect as to not lose a cdr record ++ * Cleaned up the original code to match the coding guidelines ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License. ++ * ++ */ ++ ++#include <sys/types.h> ++ ++#include <stdio.h> ++#include <string.h> ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <time.h> ++ ++#include <mysql.h> ++#include <errmsg.h> ++ ++#include <sys/stat.h> ++#include <sys/types.h> ++#include <errno.h> ++ ++#include <asterisk/config.h> ++#include <asterisk/options.h> ++#include <asterisk/channel.h> ++#include <asterisk/cdr.h> ++#include <asterisk/module.h> ++#include <asterisk/logger.h> ++#include <asterisk/cli.h> ++ ++#define DATE_FORMAT "%Y-%m-%d %T" ++ ++static char *desc = "MySQL CDR Backend"; ++static char *name = "mysql"; ++static char *config = "cdr_mysql.conf"; ++static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL; ++static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0; ++static int dbport = 0; ++static int connected = 0; ++static time_t connect_time = 0; ++static int records = 0; ++static int totalrecords = 0; ++static int userfield = 0; ++static unsigned int timeout = 0; ++ ++AST_MUTEX_DEFINE_STATIC(mysql_lock); ++ ++static MYSQL mysql; ++ ++static char cdr_mysql_status_help[] = ++"Usage: cdr mysql status\n" ++" Shows current connection status for cdr_mysql\n"; ++ ++static int handle_cdr_mysql_status(int fd, int argc, char *argv[]) ++{ ++ if (connected) { ++ char status[256], status2[100] = ""; ++ int ctime = time(NULL) - connect_time; ++ if (dbport) ++ snprintf(status, 255, "Connected to %s@%s, port %d", dbname, hostname, dbport); ++ else if (dbsock) ++ snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock); ++ else ++ snprintf(status, 255, "Connected to %s@%s", dbname, hostname); ++ ++ if (dbuser && *dbuser) ++ snprintf(status2, 99, " with username %s", dbuser); ++ if (dbtable && *dbtable) ++ snprintf(status2, 99, " using table %s", dbtable); ++ if (ctime > 31536000) { ++ 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); ++ } else if (ctime > 86400) { ++ 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); ++ } else if (ctime > 3600) { ++ ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60); ++ } else if (ctime > 60) { ++ ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60); ++ } else { ++ ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime); ++ } ++ if (records == totalrecords) ++ ast_cli(fd, " Wrote %d records since last restart.\n", totalrecords); ++ else ++ ast_cli(fd, " Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records); ++ return RESULT_SUCCESS; ++ } else { ++ ast_cli(fd, "Not currently connected to a MySQL server.\n"); ++ return RESULT_FAILURE; ++ } ++} ++ ++static struct ast_cli_entry cdr_mysql_status_cli = ++ { { "cdr", "mysql", "status", NULL }, ++ handle_cdr_mysql_status, "Show connection status of cdr_mysql", ++ cdr_mysql_status_help, NULL }; ++ ++static int mysql_log(struct ast_cdr *cdr) ++{ ++ struct tm tm; ++ struct timeval tv; ++ struct localuser *u; ++ char *userfielddata = NULL; ++ char sqlcmd[2048], timestr[128]; ++ char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; ++ int retries = 5; ++#ifdef MYSQL_LOGUNIQUEID ++ char *uniqueid = NULL; ++#endif ++ ++ ast_mutex_lock(&mysql_lock); ++ ++ memset(sqlcmd, 0, 2048); ++ ++ localtime_r(&cdr->start.tv_sec, &tm); ++ strftime(timestr, 128, DATE_FORMAT, &tm); ++ ++db_reconnect: ++ if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) { ++ /* Attempt to connect */ ++ mysql_init(&mysql); ++ /* Add option to quickly timeout the connection */ ++ if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { ++ ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); ++ } ++ if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) { ++ connected = 1; ++ connect_time = time(NULL); ++ records = 0; ++ } else { ++ ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.\n", hostname); ++ connected = 0; ++ } ++ } else { ++ /* Long connection - ping the server */ ++ int error; ++ if ((error = mysql_ping(&mysql))) { ++ connected = 0; ++ records = 0; ++ switch (error) { ++ case CR_SERVER_GONE_ERROR: ++ case CR_SERVER_LOST: ++ ast_log(LOG_ERROR, "cdr_mysql: Server has gone away. Attempting to reconnect.\n"); ++ break; ++ default: ++ ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); ++ } ++ retries--; ++ if (retries) ++ goto db_reconnect; ++ else ++ ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n"); ++ } ++ } ++ ++ /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ ++ /* WARNING: This code previously used mysql_real_escape_string, but the use of said function ++ requires an active connection to a database. If we are not connected, then this function ++ cannot be used. This is a problem since we need to store off the SQL statement into our ++ spool file for later restoration. ++ So the question is, what's the best way to handle this? This works for now. ++ */ ++ if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) ++ mysql_escape_string(clid, cdr->clid, strlen(cdr->clid)); ++ if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) ++ mysql_escape_string(dcontext, cdr->dcontext, strlen(cdr->dcontext)); ++ if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) ++ mysql_escape_string(channel, cdr->channel, strlen(cdr->channel)); ++ if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) ++ mysql_escape_string(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); ++ if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) ++ mysql_escape_string(lastapp, cdr->lastapp, strlen(cdr->lastapp)); ++ if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) ++ mysql_escape_string(lastdata, cdr->lastdata, strlen(cdr->lastdata)); ++#ifdef MYSQL_LOGUNIQUEID ++ if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) ++ mysql_escape_string(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); ++#endif ++ if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)) ++ mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield)); ++ ++ /* Check for all alloca failures above at once */ ++#ifdef MYSQL_LOGUNIQUEID ++ if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) { ++#else ++ if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) { ++#endif ++ ast_log(LOG_ERROR, "cdr_mysql: Out of memory error (insert fails)\n"); ++ ast_mutex_unlock(&mysql_lock); ++ return -1; ++ } ++ ++ ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n"); ++ ++ if (userfield && userfielddata) { ++#ifdef MYSQL_LOGUNIQUEID ++ 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); ++#else ++ 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); ++#endif ++ } else { ++#ifdef MYSQL_LOGUNIQUEID ++ 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); ++#else ++ 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); ++#endif ++ } ++ ++ ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd); ++ ++ if (connected) { ++ if (mysql_real_query(&mysql, sqlcmd, strlen(sqlcmd))) { ++ ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql)); ++ connected = 0; ++ } else { ++ records++; ++ totalrecords++; ++ } ++ } ++ ast_mutex_unlock(&mysql_lock); ++ return 0; ++} ++ ++char *description(void) ++{ ++ return desc; ++} ++ ++static int my_unload_module(void) ++{ ++ ast_cli_unregister(&cdr_mysql_status_cli); ++ if (connected) { ++ mysql_close(&mysql); ++ connected = 0; ++ records = 0; ++ } ++ if (hostname && hostname_alloc) { ++ free(hostname); ++ hostname = NULL; ++ hostname_alloc = 0; ++ } ++ if (dbname && dbname_alloc) { ++ free(dbname); ++ dbname = NULL; ++ dbname_alloc = 0; ++ } ++ if (dbuser && dbuser_alloc) { ++ free(dbuser); ++ dbuser = NULL; ++ dbuser_alloc = 0; ++ } ++ if (dbsock && dbsock_alloc) { ++ free(dbsock); ++ dbsock = NULL; ++ dbsock_alloc = 0; ++ } ++ if (dbtable && dbtable_alloc) { ++ free(dbtable); ++ dbtable = NULL; ++ dbtable_alloc = 0; ++ } ++ if (password && password_alloc) { ++ free(password); ++ password = NULL; ++ password_alloc = 0; ++ } ++ dbport = 0; ++ ast_cdr_unregister(name); ++ return 0; ++} ++ ++static int my_load_module(void) ++{ ++ int res; ++ struct ast_config *cfg; ++ struct ast_variable *var; ++ char *tmp; ++ ++ cfg = ast_config_load(config); ++ if (!cfg) { ++ ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config); ++ return 0; ++ } ++ ++ var = ast_variable_browse(cfg, "global"); ++ if (!var) { ++ /* nothing configured */ ++ return 0; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "hostname"); ++ if (tmp) { ++ hostname = malloc(strlen(tmp) + 1); ++ if (hostname != NULL) { ++ hostname_alloc = 1; ++ strcpy(hostname, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_WARNING, "MySQL server hostname not specified. Assuming localhost\n"); ++ hostname = "localhost"; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "dbname"); ++ if (tmp) { ++ dbname = malloc(strlen(tmp) + 1); ++ if (dbname != NULL) { ++ dbname_alloc = 1; ++ strcpy(dbname, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_WARNING, "MySQL database not specified. Assuming asteriskcdrdb\n"); ++ dbname = "asteriskcdrdb"; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "user"); ++ if (tmp) { ++ dbuser = malloc(strlen(tmp) + 1); ++ if (dbuser != NULL) { ++ dbuser_alloc = 1; ++ strcpy(dbuser, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_WARNING, "MySQL database user not specified. Assuming root\n"); ++ dbuser = "root"; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "sock"); ++ if (tmp) { ++ dbsock = malloc(strlen(tmp) + 1); ++ if (dbsock != NULL) { ++ dbsock_alloc = 1; ++ strcpy(dbsock, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_WARNING, "MySQL database sock file not specified. Using default\n"); ++ dbsock = NULL; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "table"); ++ if (tmp) { ++ dbtable = malloc(strlen(tmp) + 1); ++ if (dbtable != NULL) { ++ dbtable_alloc = 1; ++ strcpy(dbtable, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_NOTICE, "MySQL database table not specified. Assuming \"cdr\"\n"); ++ dbtable = "cdr"; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "password"); ++ if (tmp) { ++ password = malloc(strlen(tmp) + 1); ++ if (password != NULL) { ++ password_alloc = 1; ++ strcpy(password, tmp); ++ } else { ++ ast_log(LOG_ERROR, "Out of memory error.\n"); ++ return -1; ++ } ++ } else { ++ ast_log(LOG_WARNING, "MySQL database password not specified. Assuming blank\n"); ++ password = ""; ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "port"); ++ if (tmp) { ++ if (sscanf(tmp, "%d", &dbport) < 1) { ++ ast_log(LOG_WARNING, "Invalid MySQL port number. Using default\n"); ++ dbport = 0; ++ } ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "timeout"); ++ if (tmp) { ++ if (sscanf(tmp,"%d", &timeout) < 1) { ++ ast_log(LOG_WARNING, "Invalid MySQL timeout number. Using default\n"); ++ timeout = 0; ++ } ++ } ++ ++ tmp = ast_variable_retrieve(cfg, "global", "userfield"); ++ if (tmp) { ++ if (sscanf(tmp, "%d", &userfield) < 1) { ++ ast_log(LOG_WARNING, "Invalid MySQL configurtation file\n"); ++ userfield = 0; ++ } ++ } ++ ++ ast_config_destroy(cfg); ++ ++ ast_log(LOG_DEBUG, "cdr_mysql: got hostname of %s\n", hostname); ++ ast_log(LOG_DEBUG, "cdr_mysql: got port of %d\n", dbport); ++ ast_log(LOG_DEBUG, "cdr_mysql: got a timeout of %d\n", timeout); ++ if (dbsock) ++ ast_log(LOG_DEBUG, "cdr_mysql: got sock file of %s\n", dbsock); ++ ast_log(LOG_DEBUG, "cdr_mysql: got user of %s\n", dbuser); ++ ast_log(LOG_DEBUG, "cdr_mysql: got dbname of %s\n", dbname); ++ ast_log(LOG_DEBUG, "cdr_mysql: got password of %s\n", password); ++ ++ mysql_init(&mysql); ++ ++ if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) { ++ ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql)); ++ } ++ ++ if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) { ++ ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname); ++ connected = 0; ++ records = 0; ++ } else { ++ ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n"); ++ connected = 1; ++ records = 0; ++ connect_time = time(NULL); ++ } ++ ++ res = ast_cdr_register(name, desc, mysql_log); ++ if (res) { ++ ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n"); ++ } else { ++ res = ast_cli_register(&cdr_mysql_status_cli); ++ } ++ ++ return res; ++} ++ ++int load_module(void) ++{ ++ return my_load_module(); ++} ++ ++int unload_module(void) ++{ ++ return my_unload_module(); ++} ++ ++int reload(void) ++{ ++ int ret; ++ ++ ast_mutex_lock(&mysql_lock); ++ my_unload_module(); ++ ret = my_load_module(); ++ ast_mutex_unlock(&mysql_lock); ++ ++ return ret; ++} ++ ++int usecount(void) ++{ ++ /* Simplistic use count */ ++ if (ast_mutex_trylock(&mysql_lock)) { ++ return 1; ++ } else { ++ ast_mutex_unlock(&mysql_lock); ++ return 0; ++ } ++} ++ ++char *key() ++{ ++ return ASTERISK_GPL_KEY; ++} |