cdr_mysql.c File Reference

MySQL CDR backend. More...

#include "asterisk.h"
#include <mysql/mysql.h>
#include <mysql/errmsg.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"
#include "asterisk/strings.h"
#include "asterisk/linkedlists.h"
#include "asterisk/threadstorage.h"

Include dependency graph for cdr_mysql.c:

Go to the source code of this file.

Data Structures

struct  column
struct  columns
struct  unload_string
struct  unload_strings

Defines

#define DATE_FORMAT   "%Y-%m-%d %T"

Functions

static void __fini_columns (void)
static void __init_columns (void)
static void __init_escape_buf (void)
static void __init_sql1_buf (void)
static void __init_sql2_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static char * handle_cli_cdr_mysql_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int load_module (void)
static int my_load_config_number (struct ast_config *cfg, const char *category, const char *variable, int *field, int def)
static int my_load_config_string (struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
static int my_load_module (int reload)
static int my_unload_module (int reload)
static int mysql_log (struct ast_cdr *cdr)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MySQL CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static int calldate_compat = 0
static struct ast_cli_entry cdr_mysql_status_cli []
static struct ast_strcdrzone = NULL
static const char config [] = "cdr_mysql.conf"
static time_t connect_time = 0
static int connected = 0
static struct ast_strdbcharset = NULL
static struct ast_strdbname = NULL
static int dbport = 0
static struct ast_strdbsock = NULL
static struct ast_strdbtable = NULL
static struct ast_strdbuser = NULL
static const char desc [] = "MySQL CDR Backend"
static struct ast_threadstorage escape_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escape_buf , .custom_init = NULL , }
static struct ast_strhostname = NULL
static MYSQL mysql = { { NULL }, }
static ast_mutex_t mysql_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static const char name [] = "mysql"
static struct ast_strpassword = NULL
static int records = 0
static struct ast_threadstorage sql1_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql1_buf , .custom_init = NULL , }
static struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , }
static struct ast_strssl_ca = NULL
static struct ast_strssl_cert = NULL
static struct ast_strssl_key = NULL
static int timeout = 0
static int totalrecords = 0


Detailed Description

MySQL CDR backend.

Definition in file cdr_mysql.c.


Define Documentation

#define DATE_FORMAT   "%Y-%m-%d %T"


Function Documentation

static void __fini_columns ( void   )  [static]

Definition at line 101 of file cdr_mysql.c.

00103 { { NULL }, };

static void __init_columns ( void   )  [static]

Definition at line 101 of file cdr_mysql.c.

00103 { { NULL }, };

static void __init_escape_buf ( void   )  [static]

Definition at line 65 of file cdr_mysql.c.

00085 {

static void __init_sql1_buf ( void   )  [static]

Definition at line 63 of file cdr_mysql.c.

00085 {

static void __init_sql2_buf ( void   )  [static]

Definition at line 64 of file cdr_mysql.c.

00085 {

static void __reg_module ( void   )  [static]

Definition at line 705 of file cdr_mysql.c.

static void __unreg_module ( void   )  [static]

Definition at line 705 of file cdr_mysql.c.

static char* handle_cli_cdr_mysql_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 105 of file cdr_mysql.c.

References ast_cli_args::argc, ast_cli(), ast_str_buffer(), ast_str_strlen(), ast_strlen_zero, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, NULL, S_OR, status, and ast_cli_entry::usage.

00106 {
00107    switch (cmd) {
00108    case CLI_INIT:
00109       e->command = "cdr mysql status";
00110       e->usage =
00111          "Usage: cdr mysql status\n"
00112          "       Shows current connection status for cdr_mysql\n";
00113       return NULL;
00114    case CLI_GENERATE:
00115       return NULL;
00116    }
00117 
00118    if (a->argc != 3)
00119       return CLI_SHOWUSAGE;
00120 
00121    if (connected) {
00122       char status[256], status2[100] = "";
00123       int ctime = time(NULL) - connect_time;
00124       if (dbport)
00125          snprintf(status, 255, "Connected to %s@%s, port %d", ast_str_buffer(dbname), ast_str_buffer(hostname), dbport);
00126       else if (dbsock)
00127          snprintf(status, 255, "Connected to %s on socket file %s", ast_str_buffer(dbname), S_OR(ast_str_buffer(dbsock), "default"));
00128       else
00129          snprintf(status, 255, "Connected to %s@%s", ast_str_buffer(dbname), ast_str_buffer(hostname));
00130 
00131       if (!ast_strlen_zero(ast_str_buffer(dbuser)))
00132          snprintf(status2, 99, " with username %s", ast_str_buffer(dbuser));
00133       if (ast_str_strlen(dbtable))
00134          snprintf(status2, 99, " using table %s", ast_str_buffer(dbtable));
00135       if (ctime > 31536000) {
00136          ast_cli(a->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);
00137       } else if (ctime > 86400) {
00138          ast_cli(a->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);
00139       } else if (ctime > 3600) {
00140          ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00141       } else if (ctime > 60) {
00142          ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
00143       } else {
00144          ast_cli(a->fd, "%s%s for %d seconds.\n", status, status2, ctime);
00145       }
00146       if (records == totalrecords)
00147          ast_cli(a->fd, "  Wrote %d records since last restart.\n", totalrecords);
00148       else
00149          ast_cli(a->fd, "  Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
00150    } else {
00151       ast_cli(a->fd, "Not currently connected to a MySQL server.\n");
00152    }
00153 
00154    return CLI_SUCCESS;
00155 }

static int load_module ( void   )  [static]

Definition at line 679 of file cdr_mysql.c.

References my_load_module().

00680 {
00681    return my_load_module(0);
00682 }

static int my_load_config_number ( struct ast_config cfg,
const char *  category,
const char *  variable,
int *  field,
int  def 
) [static]

Definition at line 420 of file cdr_mysql.c.

References ast_variable_retrieve(), and tmp().

Referenced by my_load_module().

00421 {
00422    const char *tmp;
00423 
00424    tmp = ast_variable_retrieve(cfg, category, variable);
00425 
00426    if (!tmp || sscanf(tmp, "%30d", field) < 1)
00427       *field = def;
00428 
00429    return 0;
00430 }

static int my_load_config_string ( struct ast_config cfg,
const char *  category,
const char *  variable,
struct ast_str **  field,
const char *  def 
) [static]

Definition at line 394 of file cdr_mysql.c.

References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_str_create(), ast_str_set(), ast_variable_retrieve(), unload_string::str, and tmp().

Referenced by my_load_module().

00395 {
00396    struct unload_string *us;
00397    const char *tmp;
00398 
00399    if (!(us = ast_calloc(1, sizeof(*us))))
00400       return -1;
00401 
00402    if (!(*field = ast_str_create(16))) {
00403       ast_free(us);
00404       return -1;
00405    }
00406 
00407    tmp = ast_variable_retrieve(cfg, category, variable);
00408 
00409    ast_str_set(field, 0, "%s", tmp ? tmp : def);
00410 
00411    us->str = *field;
00412 
00413    AST_LIST_LOCK(&unload_strings);
00414    AST_LIST_INSERT_HEAD(&unload_strings, us, entry);
00415    AST_LIST_UNLOCK(&unload_strings);
00416 
00417    return 0;
00418 }

static int my_load_module ( int  reload  )  [static]

Definition at line 432 of file cdr_mysql.c.

References ast_calloc, ast_cdr_backend_unsuspend(), ast_cdr_register(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load, ast_debug, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_str_buffer(), ast_str_set(), ast_str_strlen(), ast_strdupa, ast_strip(), ast_strlen_zero, ast_true(), ast_variable_browse(), ast_verb, column::cdrname, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, item, column::list, LOG_ERROR, LOG_WARNING, my_load_config_number(), my_load_config_string(), my_unload_module(), mysql, mysql_log(), column::name, ast_variable::name, ast_variable::next, NULL, result, S_OR, column::staticvalue, column::type, ast_variable::value, and var.

Referenced by load_module(), and reload().

00433 {
00434    int res;
00435    struct ast_config *cfg;
00436    struct ast_variable *var;
00437    /* CONFIG_STATUS_FILEUNCHANGED is impossible when config_flags is always 0,
00438     * and it has to be zero, so a reload can be sent to tell the driver to
00439     * rescan the table layout. */
00440    struct ast_flags config_flags = { 0 };
00441    struct column *entry;
00442    char *temp;
00443    struct ast_str *compat;
00444    MYSQL_ROW row;
00445    MYSQL_RES *result;
00446    char sqldesc[128];
00447 #if MYSQL_VERSION_ID >= 50013
00448    my_bool my_bool_true = 1;
00449 #endif
00450 
00451    /* Cannot use a conditionally different flag, because the table layout may
00452     * have changed, which is not detectable by config file change detection,
00453     * but should still cause the configuration to be re-parsed. */
00454    cfg = ast_config_load(config, config_flags);
00455    if (cfg == CONFIG_STATUS_FILEMISSING) {
00456       ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
00457       return AST_MODULE_LOAD_SUCCESS;
00458    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00459       ast_log(LOG_ERROR, "Unable to load configuration file '%s'\n", config);
00460       return AST_MODULE_LOAD_DECLINE;
00461    }
00462 
00463    if (reload) {
00464       AST_RWLIST_WRLOCK(&columns);
00465       my_unload_module(1);
00466    }
00467 
00468    var = ast_variable_browse(cfg, "global");
00469    if (!var) {
00470       /* nothing configured */
00471       if (reload) {
00472          AST_RWLIST_UNLOCK(&columns);
00473       }
00474       ast_config_destroy(cfg);
00475       return AST_MODULE_LOAD_SUCCESS;
00476    }
00477 
00478    res = 0;
00479 
00480    res |= my_load_config_string(cfg, "global", "hostname", &hostname, "localhost");
00481    res |= my_load_config_string(cfg, "global", "dbname", &dbname, "astriskcdrdb");
00482    res |= my_load_config_string(cfg, "global", "user", &dbuser, "root");
00483    res |= my_load_config_string(cfg, "global", "sock", &dbsock, "");
00484    res |= my_load_config_string(cfg, "global", "table", &dbtable, "cdr");
00485    res |= my_load_config_string(cfg, "global", "password", &password, "");
00486 
00487    res |= my_load_config_string(cfg, "global", "charset", &dbcharset, "");
00488 
00489    res |= my_load_config_string(cfg, "global", "ssl_ca", &ssl_ca, "");
00490    res |= my_load_config_string(cfg, "global", "ssl_cert", &ssl_cert, "");
00491    res |= my_load_config_string(cfg, "global", "ssl_key", &ssl_key, "");
00492 
00493    res |= my_load_config_number(cfg, "global", "port", &dbport, 0);
00494    res |= my_load_config_number(cfg, "global", "timeout", &timeout, 0);
00495    res |= my_load_config_string(cfg, "global", "compat", &compat, "no");
00496    res |= my_load_config_string(cfg, "global", "cdrzone", &cdrzone, "");
00497    if (ast_str_strlen(cdrzone) == 0) {
00498       for (; var; var = var->next) {
00499          if (!strcasecmp(var->name, "usegmtime") && ast_true(var->value)) {
00500             ast_str_set(&cdrzone, 0, "UTC");
00501          }
00502       }
00503    }
00504 
00505    if (ast_true(ast_str_buffer(compat))) {
00506       calldate_compat = 1;
00507    } else {
00508       calldate_compat = 0;
00509    }
00510 
00511    if (res < 0) {
00512       if (reload) {
00513          AST_RWLIST_UNLOCK(&columns);
00514       }
00515       ast_config_destroy(cfg);
00516       return AST_MODULE_LOAD_FAILURE;
00517    }
00518 
00519    /* Check for any aliases */
00520    if (!reload) {
00521       /* Lock, if not already */
00522       AST_RWLIST_WRLOCK(&columns);
00523    }
00524    while ((entry = AST_LIST_REMOVE_HEAD(&columns, list))) {
00525       ast_free(entry);
00526    }
00527 
00528    ast_debug(1, "Got hostname of %s\n", ast_str_buffer(hostname));
00529    ast_debug(1, "Got port of %d\n", dbport);
00530    ast_debug(1, "Got a timeout of %d\n", timeout);
00531    if (dbsock)
00532       ast_debug(1, "Got sock file of %s\n", ast_str_buffer(dbsock));
00533    ast_debug(1, "Got user of %s\n", ast_str_buffer(dbuser));
00534    ast_debug(1, "Got dbname of %s\n", ast_str_buffer(dbname));
00535    ast_debug(1, "Got password of %s\n", ast_str_buffer(password));
00536    ast_debug(1, "%sunning in calldate compatibility mode\n", calldate_compat ? "R" : "Not r");
00537    ast_debug(1, "Dates and times are localized to %s\n", S_OR(ast_str_buffer(cdrzone), "local timezone"));
00538 
00539    if (dbcharset) {
00540       ast_debug(1, "Got DB charset of %s\n", ast_str_buffer(dbcharset));
00541    }
00542 
00543    mysql_init(&mysql);
00544 
00545    if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {
00546       ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00547    }
00548 
00549 #if MYSQL_VERSION_ID >= 50013
00550    /* Add option for automatic reconnection */
00551    if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
00552       ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00553    }
00554 #endif
00555 
00556    if ((ssl_ca && ast_str_strlen(ssl_ca)) || (ssl_cert && ast_str_strlen(ssl_cert)) || (ssl_key && ast_str_strlen(ssl_key))) {
00557       mysql_ssl_set(&mysql,
00558          ssl_key ? ast_str_buffer(ssl_key) : NULL,
00559          ssl_cert ? ast_str_buffer(ssl_cert) : NULL,
00560          ssl_ca ? ast_str_buffer(ssl_ca) : NULL,
00561          NULL, NULL);
00562    }
00563    temp = dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL;
00564    if (!mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, temp, ssl_ca && ast_str_strlen(ssl_ca) ? CLIENT_SSL : 0)) {
00565       ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", ast_str_buffer(dbname), ast_str_buffer(hostname));
00566       connected = 0;
00567       records = 0;
00568    } else {
00569       ast_debug(1, "Successfully connected to MySQL database.\n");
00570       connected = 1;
00571       records = 0;
00572       connect_time = time(NULL);
00573       if (dbcharset) {
00574          snprintf(sqldesc, sizeof(sqldesc), "SET NAMES '%s'", ast_str_buffer(dbcharset));
00575          mysql_real_query(&mysql, sqldesc, strlen(sqldesc));
00576          ast_debug(1, "SQL command as follows: %s\n", sqldesc);
00577       }
00578 
00579       /* Get table description */
00580       snprintf(sqldesc, sizeof(sqldesc), "DESC %s", dbtable ? ast_str_buffer(dbtable) : "cdr");
00581       if (mysql_query(&mysql, sqldesc)) {
00582          ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
00583          mysql_close(&mysql);
00584          connected = 0;
00585          AST_RWLIST_UNLOCK(&columns);
00586          ast_config_destroy(cfg);
00587          return AST_MODULE_LOAD_FAILURE;
00588       }
00589 
00590       if (!(result = mysql_store_result(&mysql))) {
00591          ast_log(LOG_ERROR, "Unable to query table description!!  Logging disabled.\n");
00592          mysql_close(&mysql);
00593          connected = 0;
00594          AST_RWLIST_UNLOCK(&columns);
00595          ast_config_destroy(cfg);
00596          return AST_MODULE_LOAD_FAILURE;
00597       }
00598 
00599       while ((row = mysql_fetch_row(result))) {
00600          struct column *entry;
00601          char *cdrvar = "", *staticvalue = "";
00602 
00603          ast_debug(1, "Got a field '%s' of type '%s'\n", row[0], row[1]);
00604          /* Check for an alias or a static value */
00605          for (var = ast_variable_browse(cfg, "columns"); var; var = var->next) {
00606             if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, row[0]) == 0 ) {
00607                char *alias = ast_strdupa(var->name + 5);
00608                cdrvar = ast_strip(alias);
00609                ast_verb(3, "Found alias %s for column %s\n", cdrvar, row[0]);
00610                break;
00611             } else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, row[0]) == 0) {
00612                char *item = ast_strdupa(var->name + 6);
00613                item = ast_strip(item);
00614                if (item[0] == '"' && item[strlen(item) - 1] == '"') {
00615                   /* Remove surrounding quotes */
00616                   item[strlen(item) - 1] = '\0';
00617                   item++;
00618                }
00619                staticvalue = item;
00620             }
00621          }
00622 
00623          entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(row[0]) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1 + strlen(row[1]) + 1);
00624          if (!entry) {
00625             ast_log(LOG_ERROR, "Out of memory creating entry for column '%s'\n", row[0]);
00626             res = -1;
00627             break;
00628          }
00629 
00630          entry->name = (char *)entry + sizeof(*entry);
00631          strcpy(entry->name, row[0]);
00632 
00633          if (!ast_strlen_zero(cdrvar)) {
00634             entry->cdrname = entry->name + strlen(row[0]) + 1;
00635             strcpy(entry->cdrname, cdrvar);
00636          } else { /* Point to same place as the column name */
00637             entry->cdrname = (char *)entry + sizeof(*entry);
00638          }
00639 
00640          if (!ast_strlen_zero(staticvalue)) {
00641             entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;
00642             strcpy(entry->staticvalue, staticvalue);
00643             ast_debug(1, "staticvalue length: %d\n", (int) strlen(staticvalue) );
00644             entry->type = entry->staticvalue + strlen(entry->staticvalue) + 1;
00645          } else {
00646             entry->type = entry->cdrname + strlen(entry->cdrname) + 1;
00647          }
00648          strcpy(entry->type, row[1]);
00649 
00650          ast_debug(1, "Entry name '%s'\n", entry->name);
00651          ast_debug(1, "   cdrname '%s'\n", entry->cdrname);
00652          ast_debug(1, "    static '%s'\n", entry->staticvalue);
00653          ast_debug(1, "      type '%s'\n", entry->type);
00654 
00655          AST_LIST_INSERT_TAIL(&columns, entry, list);
00656       }
00657       mysql_free_result(result);
00658    }
00659    AST_RWLIST_UNLOCK(&columns);
00660    ast_config_destroy(cfg);
00661    if (res < 0) {
00662       return AST_MODULE_LOAD_FAILURE;
00663    }
00664 
00665    if (!reload) {
00666       res = ast_cdr_register(name, desc, mysql_log);
00667    } else {
00668       res = ast_cdr_backend_unsuspend(name);
00669    }
00670    if (res) {
00671       ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
00672    } else {
00673       res = ast_cli_register_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry));
00674    }
00675 
00676    return res;
00677 }

static int my_unload_module ( int  reload  )  [static]

Definition at line 356 of file cdr_mysql.c.

References ast_cdr_backend_suspend(), ast_cdr_unregister(), ast_cli_unregister_multiple(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, column::list, mysql, and unload_string::str.

Referenced by my_load_module(), and unload_module().

00357 { 
00358    struct unload_string *us;
00359    struct column *entry;
00360 
00361    ast_cli_unregister_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry));
00362 
00363    if (connected) {
00364       mysql_close(&mysql);
00365       connected = 0;
00366       records = 0;
00367    }
00368 
00369    AST_LIST_LOCK(&unload_strings);
00370    while ((us = AST_LIST_REMOVE_HEAD(&unload_strings, entry))) {
00371       ast_free(us->str);
00372       ast_free(us);
00373    }
00374    AST_LIST_UNLOCK(&unload_strings);
00375 
00376    if (!reload) {
00377       AST_RWLIST_WRLOCK(&columns);
00378    }
00379    while ((entry = AST_RWLIST_REMOVE_HEAD(&columns, list))) {
00380       ast_free(entry);
00381    }
00382    if (!reload) {
00383       AST_RWLIST_UNLOCK(&columns);
00384    }
00385 
00386    dbport = 0;
00387    if (reload) {
00388       return ast_cdr_backend_suspend(name);
00389    } else {
00390       return ast_cdr_unregister(name);
00391    }
00392 }

static int mysql_log ( struct ast_cdr cdr  )  [static]

Note:
For some dumb reason, "calldate" used to be formulated using the datetime the record was posted, rather than the start time of the call. If someone really wants the old compatible behavior, it's provided here.

Definition at line 161 of file cdr_mysql.c.

References ast_cdr::answer, AS_OR, ast_cdr_format_var(), ast_copy_string(), ast_debug, ast_localtime(), ast_log, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_str_append(), ast_str_buffer(), ast_str_make_space(), ast_str_set(), ast_str_strlen(), ast_str_thread_get(), ast_strdupa, ast_strftime(), ast_strlen_zero, ast_tvdiff_us(), ast_tvnow(), ast_tvzero(), column::cdrname, ast_cdr::end, error(), escape_buf, LOG_ERROR, mysql, mysql_lock, column::name, NULL, sql1_buf, sql2_buf, ast_cdr::start, column::staticvalue, column::type, and value.

Referenced by my_load_module().

00162 {
00163    struct ast_str *sql1 = ast_str_thread_get(&sql1_buf, 1024), *sql2 = ast_str_thread_get(&sql2_buf, 1024);
00164    int retries = 5;
00165 #if MYSQL_VERSION_ID >= 50013
00166    my_bool my_bool_true = 1;
00167 #endif
00168 
00169    if (!sql1 || !sql2) {
00170       ast_log(LOG_ERROR, "Memory error\n");
00171       return -1;
00172    }
00173 
00174    ast_mutex_lock(&mysql_lock);
00175 
00176 db_reconnect:
00177    if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
00178       /* Attempt to connect */
00179       mysql_init(&mysql);
00180       /* Add option to quickly timeout the connection */
00181       if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout) != 0) {
00182          ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00183       }
00184 #if MYSQL_VERSION_ID >= 50013
00185       /* Add option for automatic reconnection */
00186       if (mysql_options(&mysql, MYSQL_OPT_RECONNECT, &my_bool_true) != 0) {
00187          ast_log(LOG_ERROR, "mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00188       }
00189 #endif
00190       if (ssl_ca || ssl_cert || ssl_key) {
00191          mysql_ssl_set(&mysql, ssl_key ? ast_str_buffer(ssl_key) : NULL, ssl_cert ? ast_str_buffer(ssl_cert) : NULL, ssl_ca ? ast_str_buffer(ssl_ca) : NULL, NULL, NULL);
00192       }
00193       if (mysql_real_connect(&mysql, ast_str_buffer(hostname), ast_str_buffer(dbuser), ast_str_buffer(password), ast_str_buffer(dbname), dbport, dbsock && ast_str_strlen(dbsock) ? ast_str_buffer(dbsock) : NULL, ssl_ca ? CLIENT_SSL : 0)) {
00194          connected = 1;
00195          connect_time = time(NULL);
00196          records = 0;
00197          if (dbcharset) {
00198             ast_str_set(&sql1, 0, "SET NAMES '%s'", ast_str_buffer(dbcharset));
00199             mysql_real_query(&mysql, ast_str_buffer(sql1), ast_str_strlen(sql1));
00200             ast_debug(1, "SQL command as follows: %s\n", ast_str_buffer(sql1));
00201          }
00202       } else {
00203          ast_log(LOG_ERROR, "Cannot connect to database server %s: (%d) %s\n", ast_str_buffer(hostname), mysql_errno(&mysql), mysql_error(&mysql));
00204          connected = 0;
00205       }
00206    } else {
00207       /* Long connection - ping the server */
00208       int error;
00209       if ((error = mysql_ping(&mysql))) {
00210          connected = 0;
00211          records = 0;
00212          switch (mysql_errno(&mysql)) {
00213             case CR_SERVER_GONE_ERROR:
00214             case CR_SERVER_LOST:
00215                ast_log(LOG_ERROR, "Server has gone away. Attempting to reconnect.\n");
00216                break;
00217             default:
00218                ast_log(LOG_ERROR, "Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00219          }
00220          retries--;
00221          if (retries) {
00222             goto db_reconnect;
00223          } else {
00224             ast_log(LOG_ERROR, "Retried to connect five times, giving up.\n");
00225          }
00226       }
00227    }
00228 
00229    if (connected) {
00230       int column_count = 0;
00231       char *cdrname;
00232       char workspace[2048], *value = NULL;
00233       struct column *entry;
00234       struct ast_str *escape = ast_str_thread_get(&escape_buf, 16);
00235 
00236       ast_str_set(&sql1, 0, "INSERT INTO %s (", AS_OR(dbtable, "cdr"));
00237       ast_str_set(&sql2, 0, ") VALUES (");
00238 
00239       AST_RWLIST_RDLOCK(&columns);
00240       AST_RWLIST_TRAVERSE(&columns, entry, list) {
00241          if (!strcmp(entry->name, "calldate")) {
00242             /*!\note
00243              * For some dumb reason, "calldate" used to be formulated using
00244              * the datetime the record was posted, rather than the start
00245              * time of the call.  If someone really wants the old compatible
00246              * behavior, it's provided here.
00247              */
00248             if (calldate_compat) {
00249                struct timeval tv = ast_tvnow();
00250                struct ast_tm tm;
00251                char timestr[128];
00252                ast_localtime(&tv, &tm, ast_str_strlen(cdrzone) ? ast_str_buffer(cdrzone) : NULL);
00253                ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
00254                value = ast_strdupa(timestr);
00255                cdrname = "calldate";
00256             } else {
00257                cdrname = "start";
00258             }
00259          } else {
00260             cdrname = entry->cdrname;
00261          }
00262 
00263          /* Construct SQL */
00264 
00265          /* Need the type and value to determine if we want the raw value or not */
00266          if (entry->staticvalue) {
00267             value = ast_strdupa(entry->staticvalue);
00268          } else if ((!strcmp(cdrname, "start") ||
00269              !strcmp(cdrname, "answer") ||
00270              !strcmp(cdrname, "end") ||
00271              !strcmp(cdrname, "disposition") ||
00272              !strcmp(cdrname, "amaflags")) &&
00273             (strstr(entry->type, "int") ||
00274              strstr(entry->type, "dec") ||
00275              strstr(entry->type, "float") ||
00276              strstr(entry->type, "double") ||
00277              strstr(entry->type, "real") ||
00278              strstr(entry->type, "numeric") ||
00279              strstr(entry->type, "fixed"))) {
00280             ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 1);
00281          } else if (!strcmp(cdrname, "calldate")) {
00282             /* Skip calldate - the value has already been dup'd */
00283          } else {
00284             ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 0);
00285          }
00286 
00287          if (value) {
00288             size_t valsz;
00289 
00290             if (column_count++) {
00291                ast_str_append(&sql1, 0, ",");
00292                ast_str_append(&sql2, 0, ",");
00293             }
00294 
00295             if (!strcasecmp(cdrname, "billsec") &&
00296                (strstr(entry->type, "float") ||
00297                strstr(entry->type, "double") ||
00298                strstr(entry->type, "decimal") ||
00299                strstr(entry->type, "numeric") ||
00300                strstr(entry->type, "real"))) {
00301 
00302                if (!ast_tvzero(cdr->answer)) {
00303                   snprintf(workspace, sizeof(workspace), "%lf",
00304                      (double) (ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0));
00305                } else {
00306                   ast_copy_string(workspace, "0", sizeof(workspace));
00307                }
00308 
00309                if (!ast_strlen_zero(workspace)) {
00310                   value = workspace;
00311                }
00312             }
00313 
00314             if (!strcasecmp(cdrname, "duration") &&
00315                (strstr(entry->type, "float") ||
00316                strstr(entry->type, "double") ||
00317                strstr(entry->type, "decimal") ||
00318                strstr(entry->type, "numeric") ||
00319                strstr(entry->type, "real"))) {
00320 
00321                snprintf(workspace, sizeof(workspace), "%lf",
00322                   (double) (ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0));
00323 
00324                if (!ast_strlen_zero(workspace)) {
00325                   value = workspace;
00326                }
00327             }
00328 
00329             ast_str_make_space(&escape, (valsz = strlen(value)) * 2 + 1);
00330             mysql_real_escape_string(&mysql, ast_str_buffer(escape), value, valsz);
00331 
00332             ast_str_append(&sql1, 0, "`%s`", entry->name);
00333             ast_str_append(&sql2, 0, "'%s'", ast_str_buffer(escape));
00334          }
00335       }
00336       AST_RWLIST_UNLOCK(&columns);
00337 
00338       ast_debug(1, "Inserting a CDR record.\n");
00339       ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
00340 
00341       ast_debug(1, "SQL command as follows: %s\n", ast_str_buffer(sql1));
00342 
00343       if (mysql_real_query(&mysql, ast_str_buffer(sql1), ast_str_strlen(sql1))) {
00344          ast_log(LOG_ERROR, "Failed to insert into database: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00345          mysql_close(&mysql);
00346          connected = 0;
00347       } else {
00348          records++;
00349          totalrecords++;
00350       }
00351    }
00352    ast_mutex_unlock(&mysql_lock);
00353    return 0;
00354 }

static int reload ( void   )  [static]

Definition at line 689 of file cdr_mysql.c.

References ast_mutex_lock, ast_mutex_unlock, my_load_module(), and mysql_lock.

Referenced by handle_cli_moh_reload(), handle_minivm_reload(), and unistim_reload().

00690 {
00691    int ret;
00692 
00693    ast_mutex_lock(&mysql_lock);
00694    ret = my_load_module(1);
00695    ast_mutex_unlock(&mysql_lock);
00696 
00697    return ret;
00698 }

static int unload_module ( void   )  [static]

Definition at line 684 of file cdr_mysql.c.

References my_unload_module().

00685 {
00686    return my_unload_module(0);
00687 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MySQL CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 705 of file cdr_mysql.c.

Definition at line 705 of file cdr_mysql.c.

int calldate_compat = 0 [static]

Definition at line 81 of file cdr_mysql.c.

Initial value:

 {
   AST_CLI_DEFINE(handle_cli_cdr_mysql_status, "Show connection status of cdr_mysql"),
}

Definition at line 157 of file cdr_mysql.c.

struct ast_str * cdrzone = NULL [static]

Definition at line 71 of file cdr_mysql.c.

const char config[] = "cdr_mysql.conf" [static]

time_t connect_time = 0 [static]

Definition at line 77 of file cdr_mysql.c.

Referenced by handle_cli_realtime_pgsql_status(), and pgsql_reconnect().

int connected = 0 [static]

struct ast_str * dbcharset = NULL [static]

Definition at line 71 of file cdr_mysql.c.

Referenced by aMYSQL_connect().

struct ast_str * dbname = NULL [static]

int dbport = 0 [static]

Definition at line 75 of file cdr_mysql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

struct ast_str * dbsock = NULL [static]

Definition at line 71 of file cdr_mysql.c.

Referenced by handle_cli_realtime_pgsql_status(), parse_config(), and pgsql_reconnect().

struct ast_str * dbtable = NULL [static]

Definition at line 71 of file cdr_mysql.c.

struct ast_str * dbuser = NULL [static]

const char desc[] = "MySQL CDR Backend" [static]

struct ast_threadstorage escape_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_escape_buf , .custom_init = NULL , } [static]

Definition at line 65 of file cdr_mysql.c.

Referenced by function_db_keys(), and mysql_log().

struct ast_str* hostname = NULL [static]

MYSQL mysql = { { NULL }, } [static]

ast_mutex_t mysql_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 83 of file cdr_mysql.c.

Referenced by mysql_log(), and reload().

const char name[] = "mysql" [static]

Definition at line 68 of file cdr_mysql.c.

Referenced by __analog_ss_thread(), __ast_channel_alloc_ap(), __dahdi_exception(), _iax2_show_peers_one(), _sip_show_peers_one(), acf_curl_helper(), action_atxfer(), action_blind_transfer(), action_getvar(), action_originate(), action_redirect(), action_sendtext(), action_setvar(), action_status(), action_timeout(), add_rlmi_resource(), adsi_load(), aelsub_exec(), alias_name_cb(), alloc_new_parking_lot(), analog_call(), analog_exception(), analog_ss_thread(), aoc_amount_str(), ast_bridge_snapshot_create(), ast_channel_by_name_cb(), ast_channel_hash_cb(), ast_channel_snapshot_create(), ast_channel_yank(), ast_connected_line_source_parse(), ast_dsp_set_call_progress_zone(), ast_get_chan_applicationmap(), ast_jb_read_conf(), ast_monitor_change_fname(), ast_monitor_start(), ast_parse_caller_presentation(), ast_party_name_charset_parse(), ast_redirecting_reason_parse(), ast_rtp_lookup_mime_multiple2(), ast_set_callerid(), ast_setstate(), ast_sip_auth_vector_destroy(), ast_sip_default_outbound_endpoint(), ast_sip_for_each_aor(), ast_sip_location_add_contact(), ast_sip_presence_xml_find_node_attr(), ast_sip_retrieve_auths(), ast_sip_subscription_get_header(), ast_str2tos(), ast_syslog_facility(), ast_syslog_priority(), AST_TEST_DEFINE(), ast_xmpp_client_config_alloc(), blacklist_read(), bridge_hash_cb(), bridgewait_exec(), bucket_file_metadata_cmp(), bucket_scheme_cmp(), build_calendar(), build_rlmi_body(), cache_update(), caller_id_to_str(), callerid_read(), cc_generic_agent_init(), cel_backend_hash(), change_monitor_action(), channel_hash(), channel_read_rtcp(), channel_role_hash_cb(), channel_snapshot_hash_cb(), channel_spy(), check_user_full(), cli_complete_endpoint(), cli_complete_registration(), cli_tps_ping(), cli_tps_report(), conference_bridge_hash_cb(), config_ldap(), console_call(), count_agents_cb(), db_cmp_fn(), dial_exec_full(), do_immediate_setup(), do_pause_or_unpause(), dtls_handler(), dump_ies(), dump_prov_ies(), el_get(), el_parse(), el_set(), endpoint_lookup(), entry_cmp_fn(), fac2str(), fax_session_tab_complete(), find_channel_parking_lot_name(), function_amiclient(), get_codecs(), get_esc(), get_outbound_endpoint(), group_cmp_fn(), handle_cli_misdn_show_channels(), handle_cli_mobile_search(), handle_cli_osp_show(), handle_cli_status(), handle_cli_test_locales(), handle_manager_bridge_tech_suspend(), handle_redirect(), handle_showchan(), handle_tcptls_connection(), headers_to_vars(), hook_callback(), http_request_headers_get(), iax2_codec_pref_string(), is_registered_cb(), jingle_endpoint_alloc(), jingle_endpoint_cmp(), jingle_endpoint_hash(), jingle_interpret_content(), jingle_interpret_google_transport(), jingle_request(), load_module(), lua_get_variable(), lua_get_variable_value(), lua_set_variable(), lua_set_variable_value(), map_video_codec(), match_agent(), media_info_cmp(), media_info_hash(), menu_hash_cb(), mgcp_call(), mgcp_hangup(), misdn_cfg_get_config_string(), misdn_cfg_get_name(), misdn_hangup(), msg_to_json(), mwi_thread(), my_get_callerid(), new_realtime_sqlite3_db(), ooh323_call(), ooh323_indicate(), oss_call(), oss_request(), output_tests(), parking_lot_cfg_alloc(), parse_cookies(), party_id_write(), peek_read(), peer_cmp_cb(), peer_hash_cb(), phone_call(), phone_request(), phoneprov_callback(), populate_cache(), print_bc_info(), process_echocancel(), process_opcode(), process_returncode(), protocol_hash_fn(), proxy_from_config(), realtime_is_object_matching(), register_verify(), release_chan(), reload_module(), scan_file(), serialize_showchan(), set_event(), set_hangup_source_and_cause(), set_message_vars_from_req(), set_var_handler(), setup_env(), show_config_description(), show_sounds_cb(), sip_acf_channel_read(), sip_msg_send(), sip_outbound_registration_perform(), sip_prepare_socket(), sip_prune_realtime(), sip_queue_hangup_cause(), skel_level_alloc(), skel_level_hash(), softhangup_exec(), sorcery_config_open(), start_monitor_action(), stasis_app_device_states_to_json(), state_notify_build_xml(), stop_monitor_action(), test_item_alloc(), test_item_hash(), tps_hash_cb(), tps_taskprocessor_tab_complete(), transport_tls_cipher_handler(), tty_stty(), unload_module(), update_call_counter(), user_cmp_cb(), user_hash_cb(), vars_to_headers(), write_config_file(), write_metadata(), xmpp_cli_create_collection(), xmpp_cli_create_leafnode(), xmpp_cli_delete_pubsub_node(), xmpp_cli_list_pubsub_nodes(), xmpp_cli_purge_pubsub_nodes(), xmpp_config_hash(), and xpidf_allocate_body().

struct ast_str * password = NULL [static]

int records = 0 [static]

Definition at line 78 of file cdr_mysql.c.

Referenced by AST_TEST_DEFINE(), and dns_naptr_sort().

struct ast_threadstorage sql1_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql1_buf , .custom_init = NULL , } [static]

Definition at line 63 of file cdr_mysql.c.

Referenced by mysql_log().

struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , } [static]

Definition at line 64 of file cdr_mysql.c.

Referenced by acf_odbc_write(), mysql_log(), store_mysql(), and update2_mysql().

struct ast_str* ssl_ca = NULL [static]

Definition at line 73 of file cdr_mysql.c.

struct ast_str * ssl_cert = NULL [static]

Definition at line 73 of file cdr_mysql.c.

struct ast_str * ssl_key = NULL [static]

Definition at line 73 of file cdr_mysql.c.

int timeout = 0 [static]

int totalrecords = 0 [static]

Definition at line 79 of file cdr_mysql.c.


Generated on Thu Apr 16 06:29:24 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6