#include "asterisk.h"
#include <time.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, 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_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static ast_mutex_t | acf_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char * | config = "cdr.conf" |
static int | loaded = 0 |
static int | loguniqueid = 0 |
static int | loguserfield = 0 |
static ast_mutex_t | mf_lock = ((ast_mutex_t) 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 181 of file cdr_csv.c.
References append_string(), ast_localtime(), ast_strftime(), ast_tvzero(), and DATE_FORMAT.
00182 { 00183 char tmp[80] = ""; 00184 struct ast_tm tm; 00185 00186 if (strlen(buf) > bufsize - 3) 00187 return -1; 00188 00189 if (ast_tvzero(when)) { 00190 strncat(buf, ",", bufsize - strlen(buf) - 1); 00191 return 0; 00192 } 00193 00194 ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL); 00195 ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); 00196 00197 return append_string(buf, tmp, bufsize); 00198 }
static int append_int | ( | char * | buf, | |
int | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 163 of file cdr_csv.c.
Referenced by build_csv_record().
00164 { 00165 char tmp[32]; 00166 int pos = strlen(buf); 00167 00168 snprintf(tmp, sizeof(tmp), "%d", s); 00169 00170 if (pos + strlen(tmp) > bufsize - 3) 00171 return -1; 00172 00173 strncat(buf, tmp, bufsize - strlen(buf) - 1); 00174 pos = strlen(buf); 00175 buf[pos++] = ','; 00176 buf[pos++] = '\0'; 00177 00178 return 0; 00179 }
static int append_string | ( | char * | buf, | |
char * | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 136 of file cdr_csv.c.
Referenced by append_date(), and build_csv_record().
00137 { 00138 int pos = strlen(buf), spos = 0, error = -1; 00139 00140 if (pos >= bufsize - 4) 00141 return -1; 00142 00143 buf[pos++] = '\"'; 00144 00145 while(pos < bufsize - 3) { 00146 if (!s[spos]) { 00147 error = 0; 00148 break; 00149 } 00150 if (s[spos] == '\"') 00151 buf[pos++] = '\"'; 00152 buf[pos++] = s[spos]; 00153 spos++; 00154 } 00155 00156 buf[pos++] = '\"'; 00157 buf[pos++] = ','; 00158 buf[pos++] = '\0'; 00159 00160 return error; 00161 }
static int build_csv_record | ( | char * | buf, | |
size_t | bufsize, | |||
struct ast_cdr * | cdr | |||
) | [static] |
Definition at line 200 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().
00201 { 00202 00203 buf[0] = '\0'; 00204 /* Account code */ 00205 append_string(buf, cdr->accountcode, bufsize); 00206 /* Source */ 00207 append_string(buf, cdr->src, bufsize); 00208 /* Destination */ 00209 append_string(buf, cdr->dst, bufsize); 00210 /* Destination context */ 00211 append_string(buf, cdr->dcontext, bufsize); 00212 /* Caller*ID */ 00213 append_string(buf, cdr->clid, bufsize); 00214 /* Channel */ 00215 append_string(buf, cdr->channel, bufsize); 00216 /* Destination Channel */ 00217 append_string(buf, cdr->dstchannel, bufsize); 00218 /* Last Application */ 00219 append_string(buf, cdr->lastapp, bufsize); 00220 /* Last Data */ 00221 append_string(buf, cdr->lastdata, bufsize); 00222 /* Start Time */ 00223 append_date(buf, cdr->start, bufsize); 00224 /* Answer Time */ 00225 append_date(buf, cdr->answer, bufsize); 00226 /* End Time */ 00227 append_date(buf, cdr->end, bufsize); 00228 /* Duration */ 00229 append_int(buf, cdr->duration, bufsize); 00230 /* Billable seconds */ 00231 append_int(buf, cdr->billsec, bufsize); 00232 /* Disposition */ 00233 append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); 00234 /* AMA Flags */ 00235 append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); 00236 /* Unique ID */ 00237 if (loguniqueid) 00238 append_string(buf, cdr->uniqueid, bufsize); 00239 /* append the user field */ 00240 if(loguserfield) 00241 append_string(buf, cdr->userfield,bufsize); 00242 /* If we hit the end of our buffer, log an error */ 00243 if (strlen(buf) < bufsize - 5) { 00244 /* Trim off trailing comma */ 00245 buf[strlen(buf) - 1] = '\0'; 00246 strncat(buf, "\n", bufsize - strlen(buf) - 1); 00247 return 0; 00248 } 00249 return -1; 00250 }
static int csv_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 279 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, buf, 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().
00280 { 00281 FILE *mf = NULL; 00282 /* Make sure we have a big enough buf */ 00283 char buf[1024]; 00284 char csvmaster[PATH_MAX]; 00285 snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); 00286 #if 0 00287 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); 00288 #endif 00289 if (build_csv_record(buf, sizeof(buf), cdr)) { 00290 ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); 00291 return 0; 00292 } 00293 00294 /* because of the absolutely unconditional need for the 00295 highest reliability possible in writing billing records, 00296 we open write and close the log file each time */ 00297 ast_mutex_lock(&mf_lock); 00298 if ((mf = fopen(csvmaster, "a"))) { 00299 fputs(buf, mf); 00300 fflush(mf); /* be particularly anal here */ 00301 fclose(mf); 00302 mf = NULL; 00303 ast_mutex_unlock(&mf_lock); 00304 } else { 00305 ast_mutex_unlock(&mf_lock); 00306 ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); 00307 } 00308 00309 if (!ast_strlen_zero(cdr->accountcode)) { 00310 if (writefile(buf, cdr->accountcode)) 00311 ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); 00312 } 00313 00314 return 0; 00315 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 92 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_FILEUNCHANGED, LOG_WARNING, and var.
00093 { 00094 struct ast_config *cfg; 00095 struct ast_variable *var; 00096 const char *tmp; 00097 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00098 00099 if (!(cfg = ast_config_load(config, config_flags))) { 00100 ast_log(LOG_WARNING, "unable to load config: %s\n", config); 00101 return 0; 00102 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00103 return 1; 00104 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 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) { 00121 loguniqueid = ast_true(tmp); 00122 if (loguniqueid) 00123 ast_debug(1, "logging CDR field UNIQUEID\n"); 00124 } 00125 00126 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) { 00127 loguserfield = ast_true(tmp); 00128 if (loguserfield) 00129 ast_debug(1, "logging CDR user-defined field\n"); 00130 } 00131 00132 ast_config_destroy(cfg); 00133 return 1; 00134 }
static int load_module | ( | void | ) | [static] |
Definition at line 324 of file cdr_csv.c.
References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.
00325 { 00326 int res; 00327 00328 if(!load_config(0)) 00329 return AST_MODULE_LOAD_DECLINE; 00330 00331 if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) { 00332 ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); 00333 } else { 00334 loaded = 1; 00335 } 00336 return res; 00337 }
static int reload | ( | void | ) | [static] |
Definition at line 339 of file cdr_csv.c.
References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.
00340 { 00341 if (load_config(1)) { 00342 loaded = 1; 00343 } else { 00344 loaded = 0; 00345 ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); 00346 ast_cdr_unregister(name); 00347 } 00348 00349 return 0; 00350 }
static int unload_module | ( | void | ) | [static] |
Definition at line 317 of file cdr_csv.c.
References ast_cdr_unregister().
00318 { 00319 ast_cdr_unregister(name); 00320 loaded = 0; 00321 return 0; 00322 }
static int writefile | ( | char * | s, | |
char * | acc | |||
) | [static] |
Definition at line 252 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().
00253 { 00254 char tmp[PATH_MAX]; 00255 FILE *f; 00256 00257 if (strchr(acc, '/') || (acc[0] == '.')) { 00258 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); 00259 return -1; 00260 } 00261 00262 snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); 00263 00264 ast_mutex_lock(&acf_lock); 00265 if (!(f = fopen(tmp, "a"))) { 00266 ast_mutex_unlock(&acf_lock); 00267 ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); 00268 return -1; 00269 } 00270 fputs(s, f); 00271 fflush(f); 00272 fclose(f); 00273 ast_mutex_unlock(&acf_lock); 00274 00275 return 0; 00276 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
ast_mutex_t acf_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |
ast_mutex_t mf_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |