#include "asterisk.h"
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/logger.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 tv, 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 (void) |
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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static ast_mutex_t | acf_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static const 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_MUTEX_INITIALIZER ) |
static char * | name = "csv" |
static int | usegmtime = 0 |
Definition in file cdr_csv.c.
#define CSV_LOG_DIR "/cdr-csv" |
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 55 of file cdr_csv.c.
Referenced by append_date(), build_query(), build_radius_record(), get_date(), manager_log(), pgsql_log(), and sqlite_log().
static int append_date | ( | char * | buf, | |
struct timeval | tv, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 189 of file cdr_csv.c.
References append_string(), ast_localtime(), ast_tvzero(), DATE_FORMAT, and t.
00190 { 00191 char tmp[80] = ""; 00192 struct tm tm; 00193 time_t t; 00194 t = tv.tv_sec; 00195 if (strlen(buf) > bufsize - 3) 00196 return -1; 00197 if (ast_tvzero(tv)) { 00198 strncat(buf, ",", bufsize - strlen(buf) - 1); 00199 return 0; 00200 } 00201 if (usegmtime) { 00202 gmtime_r(&t,&tm); 00203 } else { 00204 ast_localtime(&t, &tm, NULL); 00205 } 00206 strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); 00207 return append_string(buf, tmp, bufsize); 00208 }
static int append_int | ( | char * | buf, | |
int | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 175 of file cdr_csv.c.
Referenced by build_csv_record().
00176 { 00177 char tmp[32]; 00178 int pos = strlen(buf); 00179 snprintf(tmp, sizeof(tmp), "%d", s); 00180 if (pos + strlen(tmp) > bufsize - 3) 00181 return -1; 00182 strncat(buf, tmp, bufsize - strlen(buf) - 1); 00183 pos = strlen(buf); 00184 buf[pos++] = ','; 00185 buf[pos++] = '\0'; 00186 return 0; 00187 }
static int append_string | ( | char * | buf, | |
char * | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 150 of file cdr_csv.c.
Referenced by append_date(), and build_csv_record().
00151 { 00152 int pos = strlen(buf); 00153 int spos = 0; 00154 int error = 0; 00155 if (pos >= bufsize - 4) 00156 return -1; 00157 buf[pos++] = '\"'; 00158 error = -1; 00159 while(pos < bufsize - 3) { 00160 if (!s[spos]) { 00161 error = 0; 00162 break; 00163 } 00164 if (s[spos] == '\"') 00165 buf[pos++] = '\"'; 00166 buf[pos++] = s[spos]; 00167 spos++; 00168 } 00169 buf[pos++] = '\"'; 00170 buf[pos++] = ','; 00171 buf[pos++] = '\0'; 00172 return error; 00173 }
static int build_csv_record | ( | char * | buf, | |
size_t | bufsize, | |||
struct ast_cdr * | cdr | |||
) | [static] |
Definition at line 210 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().
00211 { 00212 00213 buf[0] = '\0'; 00214 /* Account code */ 00215 append_string(buf, cdr->accountcode, bufsize); 00216 /* Source */ 00217 append_string(buf, cdr->src, bufsize); 00218 /* Destination */ 00219 append_string(buf, cdr->dst, bufsize); 00220 /* Destination context */ 00221 append_string(buf, cdr->dcontext, bufsize); 00222 /* Caller*ID */ 00223 append_string(buf, cdr->clid, bufsize); 00224 /* Channel */ 00225 append_string(buf, cdr->channel, bufsize); 00226 /* Destination Channel */ 00227 append_string(buf, cdr->dstchannel, bufsize); 00228 /* Last Application */ 00229 append_string(buf, cdr->lastapp, bufsize); 00230 /* Last Data */ 00231 append_string(buf, cdr->lastdata, bufsize); 00232 /* Start Time */ 00233 append_date(buf, cdr->start, bufsize); 00234 /* Answer Time */ 00235 append_date(buf, cdr->answer, bufsize); 00236 /* End Time */ 00237 append_date(buf, cdr->end, bufsize); 00238 /* Duration */ 00239 append_int(buf, cdr->duration, bufsize); 00240 /* Billable seconds */ 00241 append_int(buf, cdr->billsec, bufsize); 00242 /* Disposition */ 00243 append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); 00244 /* AMA Flags */ 00245 append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); 00246 /* Unique ID */ 00247 if (loguniqueid) 00248 append_string(buf, cdr->uniqueid, bufsize); 00249 /* append the user field */ 00250 if(loguserfield) 00251 append_string(buf, cdr->userfield,bufsize); 00252 /* If we hit the end of our buffer, log an error */ 00253 if (strlen(buf) < bufsize - 5) { 00254 /* Trim off trailing comma */ 00255 buf[strlen(buf) - 1] = '\0'; 00256 strncat(buf, "\n", bufsize - strlen(buf) - 1); 00257 return 0; 00258 } 00259 return -1; 00260 }
static int csv_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 288 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().
00289 { 00290 FILE *mf = NULL; 00291 /* Make sure we have a big enough buf */ 00292 char buf[1024]; 00293 char csvmaster[PATH_MAX]; 00294 snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); 00295 #if 0 00296 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); 00297 #endif 00298 if (build_csv_record(buf, sizeof(buf), cdr)) { 00299 ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); 00300 } else { 00301 /* because of the absolutely unconditional need for the 00302 highest reliability possible in writing billing records, 00303 we open write and close the log file each time */ 00304 ast_mutex_lock(&mf_lock); 00305 mf = fopen(csvmaster, "a"); 00306 if (mf) { 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 (!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 | ( | void | ) | [static] |
Definition at line 99 of file cdr_csv.c.
References ast_config_destroy(), ast_config_load(), ast_log(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), LOG_DEBUG, LOG_WARNING, and var.
00100 { 00101 struct ast_config *cfg; 00102 struct ast_variable *var; 00103 const char *tmp; 00104 00105 usegmtime = 0; 00106 loguniqueid = 0; 00107 loguserfield = 0; 00108 00109 cfg = ast_config_load(config); 00110 00111 if (!cfg) { 00112 ast_log(LOG_WARNING, "unable to load config: %s\n", config); 00113 return 0; 00114 } 00115 00116 var = ast_variable_browse(cfg, "csv"); 00117 if (!var) { 00118 ast_config_destroy(cfg); 00119 return 0; 00120 } 00121 00122 tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"); 00123 if (tmp) { 00124 usegmtime = ast_true(tmp); 00125 if (usegmtime) { 00126 ast_log(LOG_DEBUG, "logging time in GMT\n"); 00127 } 00128 } 00129 00130 tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"); 00131 if (tmp) { 00132 loguniqueid = ast_true(tmp); 00133 if (loguniqueid) { 00134 ast_log(LOG_DEBUG, "logging CDR field UNIQUEID\n"); 00135 } 00136 } 00137 00138 tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"); 00139 if (tmp) { 00140 loguserfield = ast_true(tmp); 00141 if (loguserfield) { 00142 ast_log(LOG_DEBUG, "logging CDR user-defined field\n"); 00143 } 00144 } 00145 00146 ast_config_destroy(cfg); 00147 return 1; 00148 }
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()) 00337 return AST_MODULE_LOAD_DECLINE; 00338 00339 res = ast_cdr_register(name, ast_module_info->description, csv_log); 00340 if (res) { 00341 ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); 00342 } else { 00343 loaded = 1; 00344 } 00345 return res; 00346 }
static int reload | ( | void | ) | [static] |
Definition at line 348 of file cdr_csv.c.
References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.
00349 { 00350 if (load_config()) { 00351 loaded = 1; 00352 } else { 00353 loaded = 0; 00354 ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); 00355 ast_cdr_unregister(name); 00356 } 00357 00358 return 0; 00359 }
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 262 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().
00263 { 00264 char tmp[PATH_MAX]; 00265 FILE *f; 00266 if (strchr(acc, '/') || (acc[0] == '.')) { 00267 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); 00268 return -1; 00269 } 00270 snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", (char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); 00271 00272 ast_mutex_lock(&acf_lock); 00273 f = fopen(tmp, "a"); 00274 if (!f) { 00275 ast_mutex_unlock(&acf_lock); 00276 ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); 00277 return -1; 00278 } 00279 fputs(s, f); 00280 fflush(f); 00281 fclose(f); 00282 ast_mutex_unlock(&acf_lock); 00283 00284 return 0; 00285 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
ast_mutex_t acf_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
const 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_MUTEX_INITIALIZER ) [static] |