source: freewrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch@ 428f140

freewrt_1_0 freewrt_2_0
Last change on this file since 428f140 was 475ad56, checked in by Waldemar Brodkorb <wbx@…>, 20 years ago

add OpenWrt trunk revision 3830.

git-svn-id: svn://www.freewrt.org/trunk/freewrt@1 afb5a338-a214-0410-bd46-81f09a774fd1

  • Property mode set to 100644
File size: 16.9 KB
  • configs/cdr_mysql.conf.sample

    diff -ruN asterisk-1.2.0-old/configs/cdr_mysql.conf.sample asterisk-1.2.0-new/configs/cdr_mysql.conf.sample
    old new  
     1;
     2; Note - if the database server is hosted on the same machine as the
     3; asterisk server, you can achieve a local Unix socket connection by
     4; setting hostname=localhost
     5;
     6; port and sock are both optional parameters.  If hostname is specified
     7; and is not "localhost", then cdr_mysql will attempt to connect to the
     8; port specified or use the default port.  If hostname is not specified
     9; or if hostname is "localhost", then cdr_mysql will attempt to connect
     10; to the socket file specified by sock or otherwise use the default socket
     11; file.
     12;
     13;[global]
     14;hostname=database.host.name
     15;dbname=asteriskcdrdb
     16;table=cdr
     17;password=password
     18;user=asteriskcdruser
     19;port=3306
     20;sock=/tmp/mysql.sock
     21;userfield=1
  • cdr/cdr_mysql.c

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