#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
Go to the source code of this file.
Defines | |
#define | CSV_LOG_DIR "/cdr-csv" |
#define | CSV_MASTER "/Master.csv" |
#define | DATE_FORMAT "%Y-%m-%d %T" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | append_date (char *buf, struct timeval when, size_t bufsize) |
static int | append_int (char *buf, int s, size_t bufsize) |
static int | append_string (char *buf, const char *s, size_t bufsize) |
static int | build_csv_record (char *buf, size_t bufsize, struct ast_cdr *cdr) |
static int | csv_log (struct ast_cdr *cdr) |
static int | load_config (int reload) |
static int | load_module (void) |
static int | reload (void) |
static int | unload_module (void) |
static int | writefile (char *s, char *acc) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values 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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } |
static int | accountlogs |
static ast_mutex_t | acf_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const char | config [] = "cdr.conf" |
static int | loaded = 0 |
static int | loguniqueid = 0 |
static int | loguserfield = 0 |
static ast_mutex_t | mf_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } |
static char * | name = "csv" |
static int | usegmtime = 0 |
Definition in file cdr_csv.c.
#define CSV_LOG_DIR "/cdr-csv" |
static int append_date | ( | char * | buf, | |
struct timeval | when, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 189 of file cdr_csv.c.
References append_string(), ast_localtime(), ast_strftime(), ast_tvzero(), and DATE_FORMAT.
Referenced by build_csv_record(), transmit_invite(), transmit_response_with_date(), transmit_response_with_minse(), and transmit_response_with_unsupported().
00190 { 00191 char tmp[80] = ""; 00192 struct ast_tm tm; 00193 00194 if (strlen(buf) > bufsize - 3) 00195 return -1; 00196 00197 if (ast_tvzero(when)) { 00198 strncat(buf, ",", bufsize - strlen(buf) - 1); 00199 return 0; 00200 } 00201 00202 ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL); 00203 ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); 00204 00205 return append_string(buf, tmp, bufsize); 00206 }
static int append_int | ( | char * | buf, | |
int | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 171 of file cdr_csv.c.
Referenced by build_csv_record().
00172 { 00173 char tmp[32]; 00174 int pos = strlen(buf); 00175 00176 snprintf(tmp, sizeof(tmp), "%d", s); 00177 00178 if (pos + strlen(tmp) > bufsize - 3) 00179 return -1; 00180 00181 strncat(buf, tmp, bufsize - strlen(buf) - 1); 00182 pos = strlen(buf); 00183 buf[pos++] = ','; 00184 buf[pos++] = '\0'; 00185 00186 return 0; 00187 }
static int append_string | ( | char * | buf, | |
const char * | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 144 of file cdr_csv.c.
Referenced by append_date(), and build_csv_record().
00145 { 00146 int pos = strlen(buf), spos = 0, error = -1; 00147 00148 if (pos >= bufsize - 4) 00149 return -1; 00150 00151 buf[pos++] = '\"'; 00152 00153 while(pos < bufsize - 3) { 00154 if (!s[spos]) { 00155 error = 0; 00156 break; 00157 } 00158 if (s[spos] == '\"') 00159 buf[pos++] = '\"'; 00160 buf[pos++] = s[spos]; 00161 spos++; 00162 } 00163 00164 buf[pos++] = '\"'; 00165 buf[pos++] = ','; 00166 buf[pos++] = '\0'; 00167 00168 return error; 00169 }
static int build_csv_record | ( | char * | buf, | |
size_t | bufsize, | |||
struct ast_cdr * | cdr | |||
) | [static] |
Definition at line 208 of file cdr_csv.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, append_date(), append_int(), append_string(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, 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 csv_log().
00209 { 00210 00211 buf[0] = '\0'; 00212 /* Account code */ 00213 append_string(buf, cdr->accountcode, bufsize); 00214 /* Source */ 00215 append_string(buf, cdr->src, bufsize); 00216 /* Destination */ 00217 append_string(buf, cdr->dst, bufsize); 00218 /* Destination context */ 00219 append_string(buf, cdr->dcontext, bufsize); 00220 /* Caller*ID */ 00221 append_string(buf, cdr->clid, bufsize); 00222 /* Channel */ 00223 append_string(buf, cdr->channel, bufsize); 00224 /* Destination Channel */ 00225 append_string(buf, cdr->dstchannel, bufsize); 00226 /* Last Application */ 00227 append_string(buf, cdr->lastapp, bufsize); 00228 /* Last Data */ 00229 append_string(buf, cdr->lastdata, bufsize); 00230 /* Start Time */ 00231 append_date(buf, cdr->start, bufsize); 00232 /* Answer Time */ 00233 append_date(buf, cdr->answer, bufsize); 00234 /* End Time */ 00235 append_date(buf, cdr->end, bufsize); 00236 /* Duration */ 00237 append_int(buf, cdr->duration, bufsize); 00238 /* Billable seconds */ 00239 append_int(buf, cdr->billsec, bufsize); 00240 /* Disposition */ 00241 append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); 00242 /* AMA Flags */ 00243 append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); 00244 /* Unique ID */ 00245 if (loguniqueid) 00246 append_string(buf, cdr->uniqueid, bufsize); 00247 /* append the user field */ 00248 if(loguserfield) 00249 append_string(buf, cdr->userfield,bufsize); 00250 /* If we hit the end of our buffer, log an error */ 00251 if (strlen(buf) < bufsize - 5) { 00252 /* Trim off trailing comma */ 00253 buf[strlen(buf) - 1] = '\0'; 00254 strncat(buf, "\n", bufsize - strlen(buf) - 1); 00255 return 0; 00256 } 00257 return -1; 00258 }
static int csv_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 287 of file cdr_csv.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_config_AST_LOG_DIR, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_cdr::billsec, build_csv_record(), ast_cdr::channel, CSV_LOG_DIR, CSV_MASTER, ast_cdr::disposition, ast_cdr::dst, ast_cdr::duration, errno, LOG_ERROR, LOG_WARNING, mf_lock, ast_cdr::src, and writefile().
Referenced by load_module().
00288 { 00289 FILE *mf = NULL; 00290 /* Make sure we have a big enough buf */ 00291 char buf[1024]; 00292 char csvmaster[PATH_MAX]; 00293 snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); 00294 #if 0 00295 printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode); 00296 #endif 00297 if (build_csv_record(buf, sizeof(buf), cdr)) { 00298 ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); 00299 return 0; 00300 } 00301 00302 /* because of the absolutely unconditional need for the 00303 highest reliability possible in writing billing records, 00304 we open write and close the log file each time */ 00305 ast_mutex_lock(&mf_lock); 00306 if ((mf = fopen(csvmaster, "a"))) { 00307 fputs(buf, mf); 00308 fflush(mf); /* be particularly anal here */ 00309 fclose(mf); 00310 mf = NULL; 00311 ast_mutex_unlock(&mf_lock); 00312 } else { 00313 ast_mutex_unlock(&mf_lock); 00314 ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); 00315 } 00316 00317 if (accountlogs && !ast_strlen_zero(cdr->accountcode)) { 00318 if (writefile(buf, cdr->accountcode)) 00319 ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); 00320 } 00321 00322 return 0; 00323 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 91 of file cdr_csv.c.
References ast_config_destroy(), ast_config_load, ast_debug, ast_log(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, and var.
00092 { 00093 struct ast_config *cfg; 00094 struct ast_variable *var; 00095 const char *tmp; 00096 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00097 00098 if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 00099 ast_log(LOG_WARNING, "unable to load config: %s\n", config); 00100 return 0; 00101 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00102 return 1; 00103 00104 accountlogs = 1; 00105 usegmtime = 0; 00106 loguniqueid = 0; 00107 loguserfield = 0; 00108 00109 if (!(var = ast_variable_browse(cfg, "csv"))) { 00110 ast_config_destroy(cfg); 00111 return 0; 00112 } 00113 00114 if ((tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"))) { 00115 usegmtime = ast_true(tmp); 00116 if (usegmtime) 00117 ast_debug(1, "logging time in GMT\n"); 00118 } 00119 00120 /* Turn on/off separate files per accountcode. Default is on (as before) */ 00121 if ((tmp = ast_variable_retrieve(cfg, "csv", "accountlogs"))) { 00122 accountlogs = ast_true(tmp); 00123 if (accountlogs) { 00124 ast_debug(1, "logging in separate files per accountcode\n"); 00125 } 00126 } 00127 00128 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) { 00129 loguniqueid = ast_true(tmp); 00130 if (loguniqueid) 00131 ast_debug(1, "logging CDR field UNIQUEID\n"); 00132 } 00133 00134 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) { 00135 loguserfield = ast_true(tmp); 00136 if (loguserfield) 00137 ast_debug(1, "logging CDR user-defined field\n"); 00138 } 00139 00140 ast_config_destroy(cfg); 00141 return 1; 00142 }
static int load_module | ( | void | ) | [static] |
Definition at line 332 of file cdr_csv.c.
References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.
00333 { 00334 int res; 00335 00336 if(!load_config(0)) 00337 return AST_MODULE_LOAD_DECLINE; 00338 00339 if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) { 00340 ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); 00341 } else { 00342 loaded = 1; 00343 } 00344 return res; 00345 }
static int reload | ( | void | ) | [static] |
Definition at line 347 of file cdr_csv.c.
References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.
00348 { 00349 if (load_config(1)) { 00350 loaded = 1; 00351 } else { 00352 loaded = 0; 00353 ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); 00354 ast_cdr_unregister(name); 00355 } 00356 00357 return 0; 00358 }
static int unload_module | ( | void | ) | [static] |
Definition at line 325 of file cdr_csv.c.
References ast_cdr_unregister().
00326 { 00327 ast_cdr_unregister(name); 00328 loaded = 0; 00329 return 0; 00330 }
static int writefile | ( | char * | s, | |
char * | acc | |||
) | [static] |
Definition at line 260 of file cdr_csv.c.
References acf_lock, ast_config_AST_LOG_DIR, ast_log(), ast_mutex_lock, ast_mutex_unlock, CSV_LOG_DIR, errno, f, LOG_ERROR, and LOG_WARNING.
Referenced by csv_log().
00261 { 00262 char tmp[PATH_MAX]; 00263 FILE *f; 00264 00265 if (strchr(acc, '/') || (acc[0] == '.')) { 00266 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); 00267 return -1; 00268 } 00269 00270 snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); 00271 00272 ast_mutex_lock(&acf_lock); 00273 if (!(f = fopen(tmp, "a"))) { 00274 ast_mutex_unlock(&acf_lock); 00275 ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); 00276 return -1; 00277 } 00278 fputs(s, f); 00279 fflush(f); 00280 fclose(f); 00281 ast_mutex_unlock(&acf_lock); 00282 00283 return 0; 00284 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values 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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static] |
int accountlogs [static] |
ast_mutex_t acf_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
const char config[] = "cdr.conf" [static] |
Definition at line 53 of file cdr_csv.c.
Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_bridge_timelimit(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_insert(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_generic_bridge(), ast_get_cc_agent_dialstring(), ast_get_cc_agent_policy(), ast_get_cc_callback_macro(), ast_get_cc_max_agents(), ast_get_cc_max_monitors(), ast_get_cc_monitor_policy(), ast_get_cc_offer_timer(), ast_get_cc_recall_timer(), ast_get_ccbs_available_timer(), ast_get_ccnr_available_timer(), ast_readconfig(), ast_set_cc_agent_dialstring(), ast_set_cc_agent_policy(), ast_set_cc_callback_macro(), ast_set_cc_max_agents(), ast_set_cc_max_monitors(), ast_set_cc_monitor_policy(), ast_set_cc_offer_timer(), ast_set_cc_recall_timer(), ast_set_ccbs_available_timer(), ast_set_ccnr_available_timer(), ast_variable_browse(), ast_variable_retrieve(), build_peer(), builtin_atxfer(), builtin_parkcall(), category_get(), custom_log(), dial_exec_full(), do_reload(), execute_cb(), feature_interpret(), feature_interpret_helper(), handle_t38_options(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), odbc_load_module(), park_exec_full(), parse_config(), read_config_maps(), reload_config(), set_bridge_features_on_config(), set_config_flags(), and setup_dahdi_int().
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |
ast_mutex_t mf_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } [static] |
int usegmtime = 0 [static] |