Mon Mar 12 2012 21:27:19

Asterisk developer's documentation


cdr_odbc.c File Reference

ODBC CDR Backend. More...

#include "asterisk.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/res_odbc.h"
Include dependency graph for cdr_odbc.c:

Go to the source code of this file.

Defines

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

Enumerations

enum  {
  CONFIG_LOGUNIQUEID = 1 << 0, CONFIG_USEGMTIME = 1 << 1, CONFIG_DISPOSITIONSTRING = 1 << 2, CONFIG_HRTIME = 1 << 3,
  CONFIG_REGISTERED = 1 << 4
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static SQLHSTMT execute_cb (struct odbc_obj *obj, void *data)
static int load_module (void)
static int odbc_load_module (int reload)
static int odbc_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_LOAD_ORDER , .description = "ODBC 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, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_flags config = { 0 }
static const char config_file [] = "cdr_odbc.conf"
static char * dsn = NULL
static const char name [] = "ODBC"
static char * table = NULL

Detailed Description

ODBC CDR Backend.

Author:
Brian K. West <brian@bkw.org>

See also:

Definition in file cdr_odbc.c.


Define Documentation

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

Definition at line 46 of file cdr_odbc.c.

Referenced by execute_cb().


Enumeration Type Documentation

anonymous enum
Enumerator:
CONFIG_LOGUNIQUEID 
CONFIG_USEGMTIME 
CONFIG_DISPOSITIONSTRING 
CONFIG_HRTIME 
CONFIG_REGISTERED 

Definition at line 52 of file cdr_odbc.c.

     {
   CONFIG_LOGUNIQUEID =       1 << 0,
   CONFIG_USEGMTIME =         1 << 1,
   CONFIG_DISPOSITIONSTRING = 1 << 2,
   CONFIG_HRTIME =            1 << 3,
   CONFIG_REGISTERED =        1 << 4,
};

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 298 of file cdr_odbc.c.

static void __unreg_module ( void  ) [static]

Definition at line 298 of file cdr_odbc.c.

static SQLHSTMT execute_cb ( struct odbc_obj obj,
void *  data 
) [static]

Definition at line 62 of file cdr_odbc.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_localtime(), ast_strftime(), ast_test_flag, ast_tvdiff_us(), ast_tvzero(), ast_verb, ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, odbc_obj::con, CONFIG_DISPOSITIONSTRING, CONFIG_HRTIME, CONFIG_LOGUNIQUEID, CONFIG_USEGMTIME, DATE_FORMAT, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by odbc_log().

{
   struct ast_cdr *cdr = data;
   SQLRETURN ODBC_res;
   char sqlcmd[2048] = "", timestr[128];
   struct ast_tm tm;
   SQLHSTMT stmt;

   ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
   ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);

   if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
      snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
      "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
      "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
      "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
   } else {
      snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
      "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
      "duration,billsec,disposition,amaflags,accountcode) "
      "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
   }

   ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);

   if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
      ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      return NULL;
   }

   SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL);
   SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL);
   SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL);
   SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL);
   SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL);
   SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL);
   SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL);
   SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL);

   if (ast_test_flag(&config, CONFIG_HRTIME)) {
      double hrbillsec = 0.0;
      double hrduration;

      if (!ast_tvzero(cdr->answer)) {
         hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0;
      }
      hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0;

      SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrduration, 0, NULL);
      SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrbillsec, 0, NULL);
   } else {
      SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL);
      SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
   }

   if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
      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);
   else
      SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
   SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
   SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);

   if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
      SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
      SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
   }

   ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);

   if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
      ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      return NULL;
   }

   return stmt;
}
static int load_module ( void  ) [static]

Definition at line 267 of file cdr_odbc.c.

References odbc_load_module().

{
   return odbc_load_module(0);
}
static int odbc_load_module ( int  reload) [static]

Definition at line 167 of file cdr_odbc.c.

References ast_cdr_register(), ast_cdr_unregister(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_debug, ast_free, ast_log(), AST_MODULE_LOAD_DECLINE, ast_set_flag, ast_strdup, ast_test_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_DISPOSITIONSTRING, CONFIG_FLAG_FILEUNCHANGED, CONFIG_HRTIME, CONFIG_LOGUNIQUEID, CONFIG_REGISTERED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, CONFIG_USEGMTIME, ast_module_info::description, LOG_ERROR, LOG_WARNING, odbc_log(), and var.

Referenced by load_module(), and reload().

{
   int res = 0;
   struct ast_config *cfg;
   struct ast_variable *var;
   const char *tmp;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   do {
      cfg = ast_config_load(config_file, config_flags);
      if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
         ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
         res = AST_MODULE_LOAD_DECLINE;
         break;
      } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
         break;

      var = ast_variable_browse(cfg, "global");
      if (!var) {
         /* nothing configured */
         break;
      }

      if ((tmp = ast_variable_retrieve(cfg, "global", "dsn")) == NULL) {
         ast_log(LOG_WARNING, "cdr_odbc: dsn not specified.  Assuming asteriskdb\n");
         tmp = "asteriskdb";
      }
      if (dsn)
         ast_free(dsn);
      dsn = ast_strdup(tmp);
      if (dsn == NULL) {
         res = -1;
         break;
      }

      if (((tmp = ast_variable_retrieve(cfg, "global", "dispositionstring"))) && ast_true(tmp))
         ast_set_flag(&config, CONFIG_DISPOSITIONSTRING);
      else
         ast_clear_flag(&config, CONFIG_DISPOSITIONSTRING);

      if (((tmp = ast_variable_retrieve(cfg, "global", "loguniqueid"))) && ast_true(tmp)) {
         ast_set_flag(&config, CONFIG_LOGUNIQUEID);
         ast_debug(1, "cdr_odbc: Logging uniqueid\n");
      } else {
         ast_clear_flag(&config, CONFIG_LOGUNIQUEID);
         ast_debug(1, "cdr_odbc: Not logging uniqueid\n");
      }

      if (((tmp = ast_variable_retrieve(cfg, "global", "usegmtime"))) && ast_true(tmp)) {
         ast_set_flag(&config, CONFIG_USEGMTIME);
         ast_debug(1, "cdr_odbc: Logging in GMT\n");
      } else {
         ast_clear_flag(&config, CONFIG_USEGMTIME);
         ast_debug(1, "cdr_odbc: Logging in local time\n");
      }

      if (((tmp = ast_variable_retrieve(cfg, "global", "hrtime"))) && ast_true(tmp)) {
         ast_set_flag(&config, CONFIG_HRTIME);
         ast_debug(1, "cdr_odbc: Logging billsec and duration fields as floats\n");
      } else {
         ast_clear_flag(&config, CONFIG_HRTIME);
         ast_debug(1, "cdr_odbc: Logging billsec and duration fields as integers\n");
      }

      if ((tmp = ast_variable_retrieve(cfg, "global", "table")) == NULL) {
         ast_log(LOG_WARNING, "cdr_odbc: table not specified.  Assuming cdr\n");
         tmp = "cdr";
      }
      if (table)
         ast_free(table);
      table = ast_strdup(tmp);
      if (table == NULL) {
         res = -1;
         break;
      }

      ast_verb(3, "cdr_odbc: dsn is %s\n", dsn);
      ast_verb(3, "cdr_odbc: table is %s\n", table);

      if (!ast_test_flag(&config, CONFIG_REGISTERED)) {
         res = ast_cdr_register(name, ast_module_info->description, odbc_log);
         if (res) {
            ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
         } else {
            ast_set_flag(&config, CONFIG_REGISTERED);
         }
      }
   } while (0);

   if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
      ast_cdr_unregister(name);
      ast_clear_flag(&config, CONFIG_REGISTERED);
   }

   if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
      ast_config_destroy(cfg);
   }
   return res;
}
static int odbc_log ( struct ast_cdr cdr) [static]

Definition at line 142 of file cdr_odbc.c.

References ast_log(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, execute_cb(), LOG_ERROR, and LOG_WARNING.

Referenced by odbc_load_module().

{
   struct odbc_obj *obj = ast_odbc_request_obj(dsn, 0);
   SQLHSTMT stmt;

   if (!obj) {
      ast_log(LOG_ERROR, "Unable to retrieve database handle.  CDR failed.\n");
      return -1;
   }

   stmt = ast_odbc_direct_execute(obj, execute_cb, cdr);
   if (stmt) {
      SQLLEN rows = 0;

      SQLRowCount(stmt, &rows);
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);

      if (rows == 0)
         ast_log(LOG_WARNING, "CDR successfully ran, but inserted 0 rows?\n");
   } else
      ast_log(LOG_ERROR, "CDR direct execute failed\n");
   ast_odbc_release_obj(obj);
   return 0;
}
static int reload ( void  ) [static]

Definition at line 288 of file cdr_odbc.c.

References odbc_load_module().

{
   return odbc_load_module(1);
}
static int unload_module ( void  ) [static]

Definition at line 272 of file cdr_odbc.c.

References ast_cdr_unregister(), ast_free, and ast_verb.

{
   ast_cdr_unregister(name);

   if (dsn) {
      ast_verb(11, "cdr_odbc: free dsn\n");
      ast_free(dsn);
   }
   if (table) {
      ast_verb(11, "cdr_odbc: free table\n");
      ast_free(table);
   }

   return 0;
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "ODBC 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, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static]

Definition at line 298 of file cdr_odbc.c.

Definition at line 298 of file cdr_odbc.c.

struct ast_flags config = { 0 } [static]

Definition at line 60 of file cdr_odbc.c.

const char config_file[] = "cdr_odbc.conf" [static]

Definition at line 49 of file cdr_odbc.c.

char* dsn = NULL [static]
const char name[] = "ODBC" [static]

Definition at line 48 of file cdr_odbc.c.