Thu Apr 28 2011 17:13:29

Asterisk developer's documentation


cdr_odbc.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2003-2005, Digium, Inc.
00005  *
00006  * Brian K. West <brian@bkw.org>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief ODBC CDR Backend
00022  *
00023  * \author Brian K. West <brian@bkw.org>
00024  *
00025  * See also:
00026  * \arg http://www.unixodbc.org
00027  * \arg \ref Config_cdr
00028  * \ingroup cdr_drivers
00029  */
00030 
00031 /*** MODULEINFO
00032    <depend>res_odbc</depend>
00033  ***/
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 283318 $")
00038 
00039 #include <time.h>
00040 
00041 #include "asterisk/config.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/cdr.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/res_odbc.h"
00046 
00047 #define DATE_FORMAT "%Y-%m-%d %T"
00048 
00049 static char *name = "ODBC";
00050 static char *config_file = "cdr_odbc.conf";
00051 static char *dsn = NULL, *table = NULL;
00052 
00053 enum {
00054    CONFIG_LOGUNIQUEID =       1 << 0,
00055    CONFIG_USEGMTIME =         1 << 1,
00056    CONFIG_DISPOSITIONSTRING = 1 << 2,
00057 };
00058 
00059 static struct ast_flags config = { 0 };
00060 
00061 static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
00062 {
00063    struct ast_cdr *cdr = data;
00064    SQLRETURN ODBC_res;
00065    char sqlcmd[2048] = "", timestr[128];
00066    struct ast_tm tm;
00067    SQLHSTMT stmt;
00068 
00069    ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
00070    ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00071 
00072    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00073       snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00074       "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
00075       "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
00076       "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00077    } else {
00078       snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00079       "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
00080       "duration,billsec,disposition,amaflags,accountcode) "
00081       "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00082    }
00083 
00084    ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00085 
00086    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00087       ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
00088       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00089       return NULL;
00090    }
00091 
00092    SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
00093    SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
00094    SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
00095    SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
00096    SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
00097    SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
00098    SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
00099    SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);
00100    SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
00101    SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
00102    if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
00103       SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL);
00104    else
00105       SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
00106    SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
00107    SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
00108 
00109    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00110       SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
00111       SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
00112    }
00113 
00114    ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
00115 
00116    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00117       ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
00118       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00119       return NULL;
00120    }
00121 
00122    return stmt;
00123 }
00124 
00125 
00126 static int odbc_log(struct ast_cdr *cdr)
00127 {
00128    struct odbc_obj *obj = ast_odbc_request_obj(dsn, 0);
00129    SQLHSTMT stmt;
00130 
00131    if (!obj) {
00132       ast_log(LOG_ERROR, "Unable to retrieve database handle.  CDR failed.\n");
00133       return -1;
00134    }
00135 
00136    stmt = ast_odbc_direct_execute(obj, execute_cb, cdr);
00137    if (stmt) {
00138       SQLLEN rows = 0;
00139 
00140       SQLRowCount(stmt, &rows);
00141       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00142 
00143       if (rows == 0)
00144          ast_log(LOG_WARNING, "CDR successfully ran, but inserted 0 rows?\n");
00145    } else
00146       ast_log(LOG_ERROR, "CDR direct execute failed\n");
00147    ast_odbc_release_obj(obj);
00148    return 0;
00149 }
00150 
00151 static int odbc_load_module(int reload)
00152 {
00153    int res = 0;
00154    struct ast_config *cfg;
00155    struct ast_variable *var;
00156    const char *tmp;
00157    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00158 
00159    do {
00160       cfg = ast_config_load(config_file, config_flags);
00161       if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
00162          ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
00163          res = AST_MODULE_LOAD_DECLINE;
00164          break;
00165       } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00166          break;
00167 
00168       var = ast_variable_browse(cfg, "global");
00169       if (!var) {
00170          /* nothing configured */
00171          break;
00172       }
00173 
00174       if ((tmp = ast_variable_retrieve(cfg, "global", "dsn")) == NULL) {
00175          ast_log(LOG_WARNING, "cdr_odbc: dsn not specified.  Assuming asteriskdb\n");
00176          tmp = "asteriskdb";
00177       }
00178       if (dsn)
00179          ast_free(dsn);
00180       dsn = ast_strdup(tmp);
00181       if (dsn == NULL) {
00182          res = -1;
00183          break;
00184       }
00185 
00186       if (((tmp = ast_variable_retrieve(cfg, "global", "dispositionstring"))) && ast_true(tmp))
00187          ast_set_flag(&config, CONFIG_DISPOSITIONSTRING);
00188       else
00189          ast_clear_flag(&config, CONFIG_DISPOSITIONSTRING);
00190 
00191       if (((tmp = ast_variable_retrieve(cfg, "global", "loguniqueid"))) && ast_true(tmp)) {
00192          ast_set_flag(&config, CONFIG_LOGUNIQUEID);
00193          ast_debug(1, "cdr_odbc: Logging uniqueid\n");
00194       } else {
00195          ast_clear_flag(&config, CONFIG_LOGUNIQUEID);
00196          ast_debug(1, "cdr_odbc: Not logging uniqueid\n");
00197       }
00198 
00199       if (((tmp = ast_variable_retrieve(cfg, "global", "usegmtime"))) && ast_true(tmp)) {
00200          ast_set_flag(&config, CONFIG_USEGMTIME);
00201          ast_debug(1, "cdr_odbc: Logging in GMT\n");
00202       } else {
00203          ast_clear_flag(&config, CONFIG_USEGMTIME);
00204          ast_debug(1, "cdr_odbc: Logging in local time\n");
00205       }
00206 
00207       if ((tmp = ast_variable_retrieve(cfg, "global", "table")) == NULL) {
00208          ast_log(LOG_WARNING, "cdr_odbc: table not specified.  Assuming cdr\n");
00209          tmp = "cdr";
00210       }
00211       if (table)
00212          ast_free(table);
00213       table = ast_strdup(tmp);
00214       if (table == NULL) {
00215          res = -1;
00216          break;
00217       }
00218 
00219       ast_verb(3, "cdr_odbc: dsn is %s\n", dsn);
00220       ast_verb(3, "cdr_odbc: table is %s\n", table);
00221 
00222       res = ast_cdr_register(name, ast_module_info->description, odbc_log);
00223       if (res) {
00224          ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
00225       }
00226    } while (0);
00227 
00228    if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID)
00229       ast_config_destroy(cfg);
00230    return res;
00231 }
00232 
00233 static int load_module(void)
00234 {
00235    return odbc_load_module(0);
00236 }
00237 
00238 static int unload_module(void)
00239 {
00240    ast_cdr_unregister(name);
00241 
00242    if (dsn) {
00243       ast_verb(11, "cdr_odbc: free dsn\n");
00244       ast_free(dsn);
00245    }
00246    if (table) {
00247       ast_verb(11, "cdr_odbc: free table\n");
00248       ast_free(table);
00249    }
00250 
00251    return 0;
00252 }
00253 
00254 static int reload(void)
00255 {
00256    return odbc_load_module(1);
00257 }
00258 
00259 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC CDR Backend",
00260       .load = load_module,
00261       .unload = unload_module,
00262       .reload = reload,
00263           );