Fri Jun 19 12:09:31 2009

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>unixodbc</depend>
00033    <depend>ltdl</depend>
00034  ***/
00035 
00036 #include "asterisk.h"
00037 
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 158135 $")
00039 
00040 #include <time.h>
00041 
00042 #include "asterisk/config.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/cdr.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/res_odbc.h"
00047 
00048 #define DATE_FORMAT "%Y-%m-%d %T"
00049 
00050 static char *name = "ODBC";
00051 static char *config_file = "cdr_odbc.conf";
00052 static char *dsn = NULL, *table = NULL;
00053 
00054 enum {
00055    CONFIG_LOGUNIQUEID =       1 << 0,
00056    CONFIG_USEGMTIME =         1 << 1,
00057    CONFIG_DISPOSITIONSTRING = 1 << 2,
00058 };
00059 
00060 static struct ast_flags config = { 0 };
00061 
00062 static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
00063 {
00064    struct ast_cdr *cdr = data;
00065    SQLRETURN ODBC_res;
00066    char sqlcmd[2048] = "", timestr[128];
00067    struct ast_tm tm;
00068    SQLHSTMT stmt;
00069 
00070    ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
00071    ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00072 
00073    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00074       snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00075       "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
00076       "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
00077       "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00078    } else {
00079       snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
00080       "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
00081       "duration,billsec,disposition,amaflags,accountcode) "
00082       "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
00083    }
00084 
00085    ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00086 
00087    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00088       ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
00089       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00090       return NULL;
00091    }
00092 
00093    SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
00094    SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
00095    SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
00096    SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
00097    SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
00098    SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
00099    SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
00100    SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);
00101    SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
00102    SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
00103    if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
00104       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);
00105    else
00106       SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
00107    SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
00108    SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
00109 
00110    if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
00111       SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
00112       SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
00113    }
00114 
00115    ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
00116 
00117    if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
00118       ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
00119       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00120       return NULL;
00121    }
00122 
00123    return stmt;
00124 }
00125 
00126 
00127 static int odbc_log(struct ast_cdr *cdr)
00128 {
00129    struct odbc_obj *obj = ast_odbc_request_obj(dsn, 0);
00130    SQLHSTMT stmt;
00131 
00132    if (!obj) {
00133       ast_log(LOG_ERROR, "Unable to retrieve database handle.  CDR failed.\n");
00134       return -1;
00135    }
00136 
00137    stmt = ast_odbc_direct_execute(obj, execute_cb, cdr);
00138    if (stmt) {
00139       SQLLEN rows = 0;
00140 
00141       SQLRowCount(stmt, &rows);
00142       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00143 
00144       if (rows == 0)
00145          ast_log(LOG_WARNING, "CDR successfully ran, but inserted 0 rows?\n");
00146    } else
00147       ast_log(LOG_ERROR, "CDR direct execute failed\n");
00148    ast_odbc_release_obj(obj);
00149    return 0;
00150 }
00151 
00152 static int odbc_load_module(int reload)
00153 {
00154    int res = 0;
00155    struct ast_config *cfg;
00156    struct ast_variable *var;
00157    const char *tmp;
00158    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00159 
00160    do {
00161       cfg = ast_config_load(config_file, config_flags);
00162       if (!cfg) {
00163          ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
00164          res = AST_MODULE_LOAD_DECLINE;
00165          break;
00166       } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00167          break;
00168 
00169       var = ast_variable_browse(cfg, "global");
00170       if (!var) {
00171          /* nothing configured */
00172          break;
00173       }
00174 
00175       if ((tmp = ast_variable_retrieve(cfg, "global", "dsn")) == NULL) {
00176          ast_log(LOG_WARNING, "cdr_odbc: dsn not specified.  Assuming asteriskdb\n");
00177          tmp = "asteriskdb";
00178       }
00179       if (dsn)
00180          ast_free(dsn);
00181       dsn = ast_strdup(tmp);
00182       if (dsn == NULL) {
00183          res = -1;
00184          break;
00185       }
00186 
00187       if (((tmp = ast_variable_retrieve(cfg, "global", "dispositionstring"))) && ast_true(tmp))
00188          ast_set_flag(&config, CONFIG_DISPOSITIONSTRING);
00189       else
00190          ast_clear_flag(&config, CONFIG_DISPOSITIONSTRING);
00191 
00192       if (((tmp = ast_variable_retrieve(cfg, "global", "loguniqueid"))) && ast_true(tmp)) {
00193          ast_set_flag(&config, CONFIG_LOGUNIQUEID);
00194          ast_debug(1, "cdr_odbc: Logging uniqueid\n");
00195       } else {
00196          ast_clear_flag(&config, CONFIG_LOGUNIQUEID);
00197          ast_debug(1, "cdr_odbc: Not logging uniqueid\n");
00198       }
00199 
00200       if (((tmp = ast_variable_retrieve(cfg, "global", "usegmtime"))) && ast_true(tmp)) {
00201          ast_set_flag(&config, CONFIG_USEGMTIME);
00202          ast_debug(1, "cdr_odbc: Logging in GMT\n");
00203       } else {
00204          ast_clear_flag(&config, CONFIG_USEGMTIME);
00205          ast_debug(1, "cdr_odbc: Logging in local time\n");
00206       }
00207 
00208       if ((tmp = ast_variable_retrieve(cfg, "global", "table")) == NULL) {
00209          ast_log(LOG_WARNING, "cdr_odbc: table not specified.  Assuming cdr\n");
00210          tmp = "cdr";
00211       }
00212       if (table)
00213          ast_free(table);
00214       table = ast_strdup(tmp);
00215       if (table == NULL) {
00216          res = -1;
00217          break;
00218       }
00219 
00220       ast_verb(3, "cdr_odbc: dsn is %s\n", dsn);
00221       ast_verb(3, "cdr_odbc: table is %s\n", table);
00222 
00223       res = ast_cdr_register(name, ast_module_info->description, odbc_log);
00224       if (res) {
00225          ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
00226       }
00227    } while (0);
00228 
00229    if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED)
00230       ast_config_destroy(cfg);
00231    return res;
00232 }
00233 
00234 static int load_module(void)
00235 {
00236    return odbc_load_module(0);
00237 }
00238 
00239 static int unload_module(void)
00240 {
00241    ast_cdr_unregister(name);
00242 
00243    if (dsn) {
00244       ast_verb(11, "cdr_odbc: free dsn\n");
00245       ast_free(dsn);
00246    }
00247    if (table) {
00248       ast_verb(11, "cdr_odbc: free table\n");
00249       ast_free(table);
00250    }
00251 
00252    return 0;
00253 }
00254 
00255 static int reload(void)
00256 {
00257    return odbc_load_module(1);
00258 }
00259 
00260 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC CDR Backend",
00261       .load = load_module,
00262       .unload = unload_module,
00263       .reload = reload,
00264           );

Generated on Fri Jun 19 12:09:31 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7