#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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } |
| static int | accountlogs = 1 |
| static ast_mutex_t | acf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } |
| 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 = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } |
| 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 179 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().
00180 { 00181 char tmp[80] = ""; 00182 struct ast_tm tm; 00183 00184 if (strlen(buf) > bufsize - 3) 00185 return -1; 00186 00187 if (ast_tvzero(when)) { 00188 strncat(buf, ",", bufsize - strlen(buf) - 1); 00189 return 0; 00190 } 00191 00192 ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL); 00193 ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); 00194 00195 return append_string(buf, tmp, bufsize); 00196 }
| static int append_int | ( | char * | buf, | |
| int | s, | |||
| size_t | bufsize | |||
| ) | [static] |
Definition at line 161 of file cdr_csv.c.
Referenced by build_csv_record().
00162 { 00163 char tmp[32]; 00164 int pos = strlen(buf); 00165 00166 snprintf(tmp, sizeof(tmp), "%d", s); 00167 00168 if (pos + strlen(tmp) > bufsize - 3) 00169 return -1; 00170 00171 strncat(buf, tmp, bufsize - strlen(buf) - 1); 00172 pos = strlen(buf); 00173 buf[pos++] = ','; 00174 buf[pos++] = '\0'; 00175 00176 return 0; 00177 }
| static int append_string | ( | char * | buf, | |
| const char * | s, | |||
| size_t | bufsize | |||
| ) | [static] |
Definition at line 134 of file cdr_csv.c.
Referenced by append_date(), and build_csv_record().
00135 { 00136 int pos = strlen(buf), spos = 0, error = -1; 00137 00138 if (pos >= bufsize - 4) 00139 return -1; 00140 00141 buf[pos++] = '\"'; 00142 00143 while(pos < bufsize - 3) { 00144 if (!s[spos]) { 00145 error = 0; 00146 break; 00147 } 00148 if (s[spos] == '\"') 00149 buf[pos++] = '\"'; 00150 buf[pos++] = s[spos]; 00151 spos++; 00152 } 00153 00154 buf[pos++] = '\"'; 00155 buf[pos++] = ','; 00156 buf[pos++] = '\0'; 00157 00158 return error; 00159 }
| static int build_csv_record | ( | char * | buf, | |
| size_t | bufsize, | |||
| struct ast_cdr * | cdr | |||
| ) | [static] |
Definition at line 198 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().
00199 { 00200 00201 buf[0] = '\0'; 00202 /* Account code */ 00203 append_string(buf, cdr->accountcode, bufsize); 00204 /* Source */ 00205 append_string(buf, cdr->src, bufsize); 00206 /* Destination */ 00207 append_string(buf, cdr->dst, bufsize); 00208 /* Destination context */ 00209 append_string(buf, cdr->dcontext, bufsize); 00210 /* Caller*ID */ 00211 append_string(buf, cdr->clid, bufsize); 00212 /* Channel */ 00213 append_string(buf, cdr->channel, bufsize); 00214 /* Destination Channel */ 00215 append_string(buf, cdr->dstchannel, bufsize); 00216 /* Last Application */ 00217 append_string(buf, cdr->lastapp, bufsize); 00218 /* Last Data */ 00219 append_string(buf, cdr->lastdata, bufsize); 00220 /* Start Time */ 00221 append_date(buf, cdr->start, bufsize); 00222 /* Answer Time */ 00223 append_date(buf, cdr->answer, bufsize); 00224 /* End Time */ 00225 append_date(buf, cdr->end, bufsize); 00226 /* Duration */ 00227 append_int(buf, cdr->duration, bufsize); 00228 /* Billable seconds */ 00229 append_int(buf, cdr->billsec, bufsize); 00230 /* Disposition */ 00231 append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); 00232 /* AMA Flags */ 00233 append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); 00234 /* Unique ID */ 00235 if (loguniqueid) 00236 append_string(buf, cdr->uniqueid, bufsize); 00237 /* append the user field */ 00238 if(loguserfield) 00239 append_string(buf, cdr->userfield,bufsize); 00240 /* If we hit the end of our buffer, log an error */ 00241 if (strlen(buf) < bufsize - 5) { 00242 /* Trim off trailing comma */ 00243 buf[strlen(buf) - 1] = '\0'; 00244 strncat(buf, "\n", bufsize - strlen(buf) - 1); 00245 return 0; 00246 } 00247 return -1; 00248 }
| static int csv_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 277 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().
00278 { 00279 FILE *mf = NULL; 00280 /* Make sure we have a big enough buf */ 00281 char buf[1024]; 00282 char csvmaster[PATH_MAX]; 00283 snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); 00284 #if 0 00285 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); 00286 #endif 00287 if (build_csv_record(buf, sizeof(buf), cdr)) { 00288 ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); 00289 return 0; 00290 } 00291 00292 /* because of the absolutely unconditional need for the 00293 highest reliability possible in writing billing records, 00294 we open write and close the log file each time */ 00295 ast_mutex_lock(&mf_lock); 00296 if ((mf = fopen(csvmaster, "a"))) { 00297 fputs(buf, mf); 00298 fflush(mf); /* be particularly anal here */ 00299 fclose(mf); 00300 mf = NULL; 00301 ast_mutex_unlock(&mf_lock); 00302 } else { 00303 ast_mutex_unlock(&mf_lock); 00304 ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); 00305 } 00306 00307 if (accountlogs && !ast_strlen_zero(cdr->accountcode)) { 00308 if (writefile(buf, cdr->accountcode)) 00309 ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); 00310 } 00311 00312 return 0; 00313 }
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 95 of file cdr_csv.c.
References ast_config_destroy(), ast_config_load, ast_log(), ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, ast_variable::name, ast_variable::next, and ast_variable::value.
00096 { 00097 struct ast_config *cfg; 00098 struct ast_variable *v; 00099 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00100 00101 if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 00102 ast_log(LOG_WARNING, "unable to load config: %s\n", config); 00103 return 0; 00104 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 00105 return 1; 00106 } 00107 00108 accountlogs = 1; 00109 usegmtime = 0; 00110 loguniqueid = 0; 00111 loguserfield = 0; 00112 00113 if (!(v = ast_variable_browse(cfg, "csv"))) { 00114 ast_config_destroy(cfg); 00115 return 0; 00116 } 00117 00118 for (; v; v = v->next) { 00119 if (!strcasecmp(v->name, "usegmtime")) { 00120 usegmtime = ast_true(v->value); 00121 } else if (!strcasecmp(v->name, "accountlogs")) { 00122 /* Turn on/off separate files per accountcode. Default is on (as before) */ 00123 accountlogs = ast_true(v->value); 00124 } else if (!strcasecmp(v->name, "loguniqueid")) { 00125 loguniqueid = ast_true(v->value); 00126 } else if (!strcasecmp(v->name, "loguserfield")) { 00127 loguserfield = ast_true(v->value); 00128 } 00129 } 00130 ast_config_destroy(cfg); 00131 return 1; 00132 }
| static int load_module | ( | void | ) | [static] |
Definition at line 322 of file cdr_csv.c.
References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.
00323 { 00324 int res; 00325 00326 if (!load_config(0)) { 00327 return AST_MODULE_LOAD_DECLINE; 00328 } 00329 00330 if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) { 00331 ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); 00332 } else { 00333 loaded = 1; 00334 } 00335 return res; 00336 }
| static int reload | ( | void | ) | [static] |
Definition at line 338 of file cdr_csv.c.
References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.
00339 { 00340 if (load_config(1)) { 00341 loaded = 1; 00342 } else { 00343 loaded = 0; 00344 ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); 00345 ast_cdr_unregister(name); 00346 } 00347 00348 return 0; 00349 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 315 of file cdr_csv.c.
References ast_cdr_unregister().
00316 { 00317 ast_cdr_unregister(name); 00318 loaded = 0; 00319 return 0; 00320 }
| static int writefile | ( | char * | s, | |
| char * | acc | |||
| ) | [static] |
Definition at line 250 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().
00251 { 00252 char tmp[PATH_MAX]; 00253 FILE *f; 00254 00255 if (strchr(acc, '/') || (acc[0] == '.')) { 00256 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); 00257 return -1; 00258 } 00259 00260 snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); 00261 00262 ast_mutex_lock(&acf_lock); 00263 if (!(f = fopen(tmp, "a"))) { 00264 ast_mutex_unlock(&acf_lock); 00265 ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); 00266 return -1; 00267 } 00268 fputs(s, f); 00269 fflush(f); 00270 fclose(f); 00271 ast_mutex_unlock(&acf_lock); 00272 00273 return 0; 00274 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static] |
int accountlogs = 1 [static] |
ast_mutex_t acf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
const char config[] = "cdr.conf" [static] |
Definition at line 57 of file cdr_csv.c.
Referenced by ast_config_new(), ast_readconfig(), custom_log(), do_reload(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), parse_config(), read_config_maps(), reload_config(), and set_config().
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |
ast_mutex_t mf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static] |
int usegmtime = 0 [static] |
1.5.6