Custom SQLite3 CDR records. More...
#include "asterisk.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 | values |
Functions | |
static | AST_LIST_HEAD_STATIC (sql_values, values) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"SQLite3 Custom CDR Module",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CDR_DRIVER,) | |
AST_MUTEX_DEFINE_STATIC (lock) | |
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 char * | columns |
static const char | config_file [] = "cdr_sqlite3_custom.conf" |
static sqlite3 * | db = NULL |
static const char | desc [] = "Customizable SQLite3 CDR Backend" |
static const char | name [] = "cdr_sqlite3_custom" |
static char | table [80] |
Custom SQLite3 CDR records.
Definition in file cdr_sqlite3_custom.c.
static AST_LIST_HEAD_STATIC | ( | sql_values | , | |
values | ||||
) | [static] |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_LOAD_ORDER | , | |||
"SQLite3 Custom CDR Module" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload , |
|||
. | load_pri = AST_MODPRI_CDR_DRIVER | |||
) |
AST_MUTEX_DEFINE_STATIC | ( | lock | ) |
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 value.
Referenced by load_config(), load_module(), and unload_module().
00209 { 00210 struct values *value; 00211 00212 if (!reload && db) { 00213 sqlite3_close(db); 00214 db = NULL; 00215 } 00216 00217 if (columns) { 00218 ast_free(columns); 00219 columns = NULL; 00220 } 00221 00222 while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) { 00223 ast_free(value); 00224 } 00225 }
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, and LOG_WARNING.
Referenced by load_config().
00077 { 00078 char *col = NULL; 00079 char *cols = NULL, *save = NULL; 00080 char *escaped = NULL; 00081 struct ast_str *column_string = NULL; 00082 00083 if (ast_strlen_zero(tmp)) { 00084 ast_log(LOG_WARNING, "Column names not specified. Module not loaded.\n"); 00085 return -1; 00086 } 00087 if (!(column_string = ast_str_create(1024))) { 00088 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table); 00089 return -1; 00090 } 00091 if (!(save = cols = ast_strdup(tmp))) { 00092 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table); 00093 ast_free(column_string); 00094 return -1; 00095 } 00096 while ((col = strsep(&cols, ","))) { 00097 col = ast_strip(col); 00098 escaped = sqlite3_mprintf("%q", col); 00099 if (!escaped) { 00100 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s.'\n", col, table); 00101 ast_free(column_string); 00102 ast_free(save); 00103 return -1; 00104 } 00105 ast_str_append(&column_string, 0, "%s%s", ast_str_strlen(column_string) ? "," : "", escaped); 00106 sqlite3_free(escaped); 00107 } 00108 if (!(columns = ast_strdup(ast_str_buffer(column_string)))) { 00109 ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table); 00110 ast_free(column_string); 00111 ast_free(save); 00112 return -1; 00113 } 00114 ast_free(column_string); 00115 ast_free(save); 00116 00117 return 0; 00118 }
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().
00156 { 00157 struct ast_config *cfg; 00158 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00159 struct ast_variable *mappingvar; 00160 const char *tmp; 00161 00162 if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { 00163 ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated."); 00164 return -1; 00165 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 00166 return 0; 00167 } 00168 00169 if (reload) { 00170 free_config(1); 00171 } 00172 00173 if (!(mappingvar = ast_variable_browse(cfg, "master"))) { 00174 /* Nothing configured */ 00175 ast_config_destroy(cfg); 00176 return -1; 00177 } 00178 00179 /* Mapping must have a table name */ 00180 if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "master", "table"))) { 00181 ast_copy_string(table, tmp, sizeof(table)); 00182 } else { 00183 ast_log(LOG_WARNING, "Table name not specified. Assuming cdr.\n"); 00184 strcpy(table, "cdr"); 00185 } 00186 00187 /* Columns */ 00188 if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) { 00189 ast_config_destroy(cfg); 00190 free_config(0); 00191 return -1; 00192 } 00193 00194 /* Values */ 00195 if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) { 00196 ast_config_destroy(cfg); 00197 free_config(0); 00198 return -1; 00199 } 00200 00201 ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table); 00202 00203 ast_config_destroy(cfg); 00204 00205 return 0; 00206 }
static int load_module | ( | void | ) | [static] |
Definition at line 300 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().
00301 { 00302 char *error; 00303 char filename[PATH_MAX]; 00304 int res; 00305 char *sql; 00306 00307 if (load_config(0)) { 00308 return AST_MODULE_LOAD_DECLINE; 00309 } 00310 00311 /* is the database there? */ 00312 snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR); 00313 res = sqlite3_open(filename, &db); 00314 if (res != SQLITE_OK) { 00315 ast_log(LOG_ERROR, "Could not open database %s.\n", filename); 00316 free_config(0); 00317 return AST_MODULE_LOAD_DECLINE; 00318 } 00319 00320 /* is the table there? */ 00321 sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table); 00322 res = sqlite3_exec(db, sql, NULL, NULL, NULL); 00323 sqlite3_free(sql); 00324 if (res != SQLITE_OK) { 00325 /* We don't use %q for the column list here since we already escaped when building it */ 00326 sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table, columns); 00327 res = sqlite3_exec(db, sql, NULL, NULL, &error); 00328 sqlite3_free(sql); 00329 if (res != SQLITE_OK) { 00330 ast_log(LOG_WARNING, "Unable to create table '%s': %s.\n", table, error); 00331 sqlite3_free(error); 00332 free_config(0); 00333 return AST_MODULE_LOAD_DECLINE; 00334 } 00335 } 00336 00337 res = ast_cdr_register(name, desc, write_cdr); 00338 if (res) { 00339 ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n"); 00340 free_config(0); 00341 return AST_MODULE_LOAD_DECLINE; 00342 } 00343 00344 return AST_MODULE_LOAD_SUCCESS; 00345 }
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(), LOG_ERROR, LOG_WARNING, and value.
Referenced by load_config().
00121 { 00122 char *vals = NULL, *save = NULL; 00123 struct values *value = NULL; 00124 int i; 00125 AST_DECLARE_APP_ARGS(val, 00126 AST_APP_ARG(ues)[200]; /* More than 200 columns in this CDR? Yeah, right... */ 00127 ); 00128 00129 if (ast_strlen_zero(tmp)) { 00130 ast_log(LOG_WARNING, "Values not specified. Module not loaded.\n"); 00131 return -1; 00132 } 00133 if (!(save = vals = ast_strdup(tmp))) { 00134 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for value '%s'\n", tmp); 00135 return -1; 00136 } 00137 AST_STANDARD_RAW_ARGS(val, vals); 00138 for (i = 0; i < val.argc; i++) { 00139 /* Strip the single quotes off if they are there */ 00140 char *v = ast_strip_quoted(val.ues[i], "'", "'"); 00141 value = ast_calloc(sizeof(char), sizeof(*value) + strlen(v)); 00142 if (!value) { 00143 ast_log(LOG_ERROR, "Out of memory creating entry for value '%s'\n", v); 00144 ast_free(save); 00145 return -1; 00146 } 00147 strcpy(value->expression, v); /* SAFE */ 00148 AST_LIST_INSERT_TAIL(&sql_values, value, list); 00149 } 00150 ast_free(save); 00151 00152 return 0; 00153 }
static int reload | ( | void | ) | [static] |
Definition at line 347 of file cdr_sqlite3_custom.c.
References ast_mutex_lock, ast_mutex_unlock, load_config(), and lock.
00348 { 00349 int res = 0; 00350 00351 ast_mutex_lock(&lock); 00352 res = load_config(1); 00353 ast_mutex_unlock(&lock); 00354 00355 return res; 00356 }
static int unload_module | ( | void | ) | [static] |
Definition at line 291 of file cdr_sqlite3_custom.c.
References ast_cdr_unregister(), and free_config().
00292 { 00293 ast_cdr_unregister(name); 00294 00295 free_config(0); 00296 00297 return 0; 00298 }
static int write_cdr | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 227 of file cdr_sqlite3_custom.c.
References ast_cdr_dup(), ast_channel_unref, ast_debug, ast_dummy_channel_alloc, 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, dummy(), lock, LOG_ERROR, pbx_substitute_variables_helper(), and value.
Referenced by load_module().
00228 { 00229 int res = 0; 00230 char *error = NULL; 00231 char *sql = NULL; 00232 int count = 0; 00233 00234 if (db == NULL) { 00235 /* Should not have loaded, but be failsafe. */ 00236 return 0; 00237 } 00238 00239 ast_mutex_lock(&lock); 00240 00241 { /* Make it obvious that only sql should be used outside of this block */ 00242 char *escaped; 00243 char subst_buf[2048]; 00244 struct values *value; 00245 struct ast_channel *dummy; 00246 struct ast_str *value_string = ast_str_create(1024); 00247 00248 dummy = ast_dummy_channel_alloc(); 00249 if (!dummy) { 00250 ast_log(LOG_ERROR, "Unable to allocate channel for variable subsitution.\n"); 00251 ast_free(value_string); 00252 ast_mutex_unlock(&lock); 00253 return 0; 00254 } 00255 dummy->cdr = ast_cdr_dup(cdr); 00256 AST_LIST_TRAVERSE(&sql_values, value, list) { 00257 pbx_substitute_variables_helper(dummy, value->expression, subst_buf, sizeof(subst_buf) - 1); 00258 escaped = sqlite3_mprintf("%q", subst_buf); 00259 ast_str_append(&value_string, 0, "%s'%s'", ast_str_strlen(value_string) ? "," : "", escaped); 00260 sqlite3_free(escaped); 00261 } 00262 sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, ast_str_buffer(value_string)); 00263 ast_debug(1, "About to log: %s\n", sql); 00264 ast_channel_unref(dummy); 00265 ast_free(value_string); 00266 } 00267 00268 /* XXX This seems awful arbitrary... */ 00269 for (count = 0; count < 5; count++) { 00270 res = sqlite3_exec(db, sql, NULL, NULL, &error); 00271 if (res != SQLITE_BUSY && res != SQLITE_LOCKED) { 00272 break; 00273 } 00274 usleep(200); 00275 } 00276 00277 if (error) { 00278 ast_log(LOG_ERROR, "%s. SQL: %s.\n", error, sql); 00279 sqlite3_free(error); 00280 } 00281 00282 if (sql) { 00283 sqlite3_free(sql); 00284 } 00285 00286 ast_mutex_unlock(&lock); 00287 00288 return res; 00289 }
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.
const char desc[] = "Customizable SQLite3 CDR Backend" [static] |
Definition at line 60 of file cdr_sqlite3_custom.c.
const char name[] = "cdr_sqlite3_custom" [static] |
Definition at line 61 of file cdr_sqlite3_custom.c.
char table[80] [static] |
Definition at line 64 of file cdr_sqlite3_custom.c.