Thu Apr 28 2011 17:13:42

Asterisk developer's documentation


cdr_sqlite3_custom.c File Reference

Custom SQLite3 CDR records. More...

#include "asterisk.h"
#include <time.h>
#include <sqlite3.h>
#include "asterisk/paths.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
Include dependency graph for cdr_sqlite3_custom.c:

Go to the source code of this file.

Data Structures

struct  sql_values
struct  values

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void free_config (int reload)
static int load_column_config (const char *tmp)
static int load_config (int reload)
static int load_module (void)
static int load_values_config (const char *tmp)
static int reload (void)
static int unload_module (void)
static int write_cdr (struct ast_cdr *cdr)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SQLite3 Custom CDR Module" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static char * columns
static const char config_file [] = "cdr_sqlite3_custom.conf"
static sqlite3 * db = NULL
static char * desc = "Customizable SQLite3 CDR Backend"
static ast_mutex_t lock = AST_MUTEX_INIT_VALUE
static char * name = "cdr_sqlite3_custom"
static struct sql_values sql_values
static char table [80]

Detailed Description

Custom SQLite3 CDR records.

Author:
Adapted by Alejandro Rios <alejandro.rios@avatar.com.co> and Russell Bryant <russell@digium.com> from cdr_mysql_custom by Edward Eastman <ed@dm3.co.uk>, and cdr_sqlite by Holger Schurig <hs4233@mail.mn-solutions.de>

Definition in file cdr_sqlite3_custom.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 353 of file cdr_sqlite3_custom.c.

static void __unreg_module ( void  ) [static]

Definition at line 353 of file cdr_sqlite3_custom.c.

static void free_config ( int  reload) [static]

Definition at line 208 of file cdr_sqlite3_custom.c.

References ast_free, AST_LIST_REMOVE_HEAD, and values::list.

Referenced by load_config(), load_module(), and unload_module().

{
   struct values *value;

   if (!reload && db) {
      sqlite3_close(db);
      db = NULL;
   }

   if (columns) {
      ast_free(columns);
      columns = NULL;
   }

   while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) {
      ast_free(value);
   }
}
static int load_column_config ( const char *  tmp) [static]

Definition at line 76 of file cdr_sqlite3_custom.c.

References ast_free, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_strdup, ast_strip(), ast_strlen_zero(), LOG_ERROR, LOG_WARNING, and strsep().

Referenced by load_config().

{
   char *col = NULL;
   char *cols = NULL, *save = NULL;
   char *escaped = NULL;
   struct ast_str *column_string = NULL;

   if (ast_strlen_zero(tmp)) {
      ast_log(LOG_WARNING, "Column names not specified. Module not loaded.\n");
      return -1;
   }
   if (!(column_string = ast_str_create(1024))) {
      ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table);
      return -1;
   }
   if (!(save = cols = ast_strdup(tmp))) {
      ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table);
      ast_free(column_string);
      return -1;
   }
   while ((col = strsep(&cols, ","))) {
      col = ast_strip(col);
      escaped = sqlite3_mprintf("%q", col);
      if (!escaped) {
         ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s.'\n", col, table);
         ast_free(column_string);
         ast_free(save);
         return -1;
      }
      ast_str_append(&column_string, 0, "%s%s", ast_str_strlen(column_string) ? "," : "", escaped);
      sqlite3_free(escaped);
   }
   if (!(columns = ast_strdup(ast_str_buffer(column_string)))) {
      ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table);
      ast_free(column_string);
      ast_free(save);
      return -1;
   }
   ast_free(column_string);
   ast_free(save);

   return 0;
}
static int load_config ( int  reload) [static]

Definition at line 155 of file cdr_sqlite3_custom.c.

References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log(), ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, free_config(), load_column_config(), load_values_config(), and LOG_WARNING.

Referenced by load_module(), and reload().

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

   if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated.");
      return -1;
   } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   }

   if (reload) {
      free_config(1);
   }

   if (!(mappingvar = ast_variable_browse(cfg, "master"))) {
      /* Nothing configured */
      ast_config_destroy(cfg);
      return -1;
   }

   /* Mapping must have a table name */
   if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "master", "table"))) {
      ast_copy_string(table, tmp, sizeof(table));
   } else {
      ast_log(LOG_WARNING, "Table name not specified.  Assuming cdr.\n");
      strcpy(table, "cdr");
   }

   /* Columns */
   if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) {
      ast_config_destroy(cfg);
      free_config(0);
      return -1;
   }

   /* Values */
   if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) {
      ast_config_destroy(cfg);
      free_config(0);
      return -1;
   }

   ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);

   ast_config_destroy(cfg);

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

Definition at line 291 of file cdr_sqlite3_custom.c.

References ast_cdr_register(), ast_config_AST_LOG_DIR, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, free_config(), load_config(), LOG_ERROR, LOG_WARNING, and write_cdr().

{
   char *error;
   char filename[PATH_MAX];
   int res;
   char *sql;

   if (load_config(0)) {
      return AST_MODULE_LOAD_DECLINE;
   }

   /* is the database there? */
   snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR);
   res = sqlite3_open(filename, &db);
   if (res != SQLITE_OK) {
      ast_log(LOG_ERROR, "Could not open database %s.\n", filename);
      free_config(0);
      return AST_MODULE_LOAD_DECLINE;
   }

   /* is the table there? */
   sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table);
   res = sqlite3_exec(db, sql, NULL, NULL, NULL);
   sqlite3_free(sql);
   if (res != SQLITE_OK) {
      /* We don't use %q for the column list here since we already escaped when building it */
      sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table, columns);
      res = sqlite3_exec(db, sql, NULL, NULL, &error);
      sqlite3_free(sql);
      if (res != SQLITE_OK) {
         ast_log(LOG_WARNING, "Unable to create table '%s': %s.\n", table, error);
         sqlite3_free(error);
         free_config(0);
         return AST_MODULE_LOAD_DECLINE;
      }
   }

   res = ast_cdr_register(name, desc, write_cdr);
   if (res) {
      ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n");
      free_config(0);
      return AST_MODULE_LOAD_DECLINE;
   }

   return AST_MODULE_LOAD_SUCCESS;
}
static int load_values_config ( const char *  tmp) [static]

Definition at line 120 of file cdr_sqlite3_custom.c.

References AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_STANDARD_RAW_ARGS, ast_strdup, ast_strip_quoted(), ast_strlen_zero(), values::expression, values::list, LOG_ERROR, and LOG_WARNING.

Referenced by load_config().

{
   char *vals = NULL, *save = NULL;
   struct values *value = NULL;
   int i;
   AST_DECLARE_APP_ARGS(val,
      AST_APP_ARG(ues)[200]; /* More than 200 columns in this CDR?  Yeah, right... */
   );

   if (ast_strlen_zero(tmp)) {
      ast_log(LOG_WARNING, "Values not specified. Module not loaded.\n");
      return -1;
   }
   if (!(save = vals = ast_strdup(tmp))) {
      ast_log(LOG_ERROR, "Out of memory creating temporary buffer for value '%s'\n", tmp);
      return -1;
   }
   AST_STANDARD_RAW_ARGS(val, vals);
   for (i = 0; i < val.argc; i++) {
      /* Strip the single quotes off if they are there */
      char *v = ast_strip_quoted(val.ues[i], "'", "'");
      value = ast_calloc(sizeof(char), sizeof(*value) + strlen(v));
      if (!value) {
         ast_log(LOG_ERROR, "Out of memory creating entry for value '%s'\n", v);
         ast_free(save);
         return -1;
      }
      strcpy(value->expression, v); /* SAFE */
      AST_LIST_INSERT_TAIL(&sql_values, value, list);
   }
   ast_free(save);

   return 0;
}
static int reload ( void  ) [static]

Definition at line 338 of file cdr_sqlite3_custom.c.

References ast_mutex_lock(), ast_mutex_unlock(), load_config(), and lock.

{
   int res = 0;

   ast_mutex_lock(&lock);
   res = load_config(1);
   ast_mutex_unlock(&lock);

   return res;
}
static int unload_module ( void  ) [static]

Definition at line 282 of file cdr_sqlite3_custom.c.

References ast_cdr_unregister(), and free_config().

{
   ast_cdr_unregister(name);

   free_config(0);

   return 0;
}
static int write_cdr ( struct ast_cdr cdr) [static]

Definition at line 227 of file cdr_sqlite3_custom.c.

References ast_debug, ast_free, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_channel::cdr, values::expression, values::list, lock, LOG_ERROR, and pbx_substitute_variables_helper().

Referenced by load_module().

{
   int res = 0;
   char *error = NULL;
   char *sql = NULL;
   struct ast_channel dummy = { 0, };
   int count = 0;

   if (db == NULL) {
      /* Should not have loaded, but be failsafe. */
      return 0;
   }

   ast_mutex_lock(&lock);

   { /* Make it obvious that only sql should be used outside of this block */
      char *escaped;
      char subst_buf[2048];
      struct values *value;
      struct ast_str *value_string = ast_str_create(1024);
      dummy.cdr = cdr;
      AST_LIST_TRAVERSE(&sql_values, value, list) {
         pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
         escaped = sqlite3_mprintf("%q", subst_buf);
         ast_str_append(&value_string, 0, "%s'%s'", ast_str_strlen(value_string) ? "," : "", escaped);
         sqlite3_free(escaped);
      }
      sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, ast_str_buffer(value_string));
      ast_debug(1, "About to log: %s\n", sql);
      ast_free(value_string);
   }

   /* XXX This seems awful arbitrary... */
   for (count = 0; count < 5; count++) {
      res = sqlite3_exec(db, sql, NULL, NULL, &error);
      if (res != SQLITE_BUSY && res != SQLITE_LOCKED) {
         break;
      }
      usleep(200);
   }

   if (error) {
      ast_log(LOG_ERROR, "%s. SQL: %s.\n", error, sql);
      sqlite3_free(error);
   }

   if (sql) {
      sqlite3_free(sql);
   }

   ast_mutex_unlock(&lock);

   return res;
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SQLite3 Custom CDR Module" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 353 of file cdr_sqlite3_custom.c.

Definition at line 353 of file cdr_sqlite3_custom.c.

char* columns [static]

Definition at line 65 of file cdr_sqlite3_custom.c.

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

Definition at line 58 of file cdr_sqlite3_custom.c.

sqlite3* db = NULL [static]

Definition at line 62 of file cdr_sqlite3_custom.c.

char* desc = "Customizable SQLite3 CDR Backend" [static]

Definition at line 60 of file cdr_sqlite3_custom.c.

ast_mutex_t lock = AST_MUTEX_INIT_VALUE [static]

Definition at line 56 of file cdr_sqlite3_custom.c.

char* name = "cdr_sqlite3_custom" [static]

Definition at line 61 of file cdr_sqlite3_custom.c.

struct sql_values sql_values [static]
char table[80] [static]

Definition at line 64 of file cdr_sqlite3_custom.c.