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"
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_info * | ast_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] |
Custom SQLite3 CDR records.
Definition in file cdr_sqlite3_custom.c.
| 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().
| 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;
}
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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.