Sat Aug 6 00:39:40 2011

Asterisk developer's documentation


cdr_csv.c File Reference

Comma Separated Value CDR records. More...

#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_infoast_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


Detailed Description

Comma Separated Value CDR records.

Author:
Mark Spencer <markster@digium.com>

Definition in file cdr_csv.c.


Define Documentation

#define CSV_LOG_DIR   "/cdr-csv"

Definition at line 52 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 53 of file cdr_csv.c.

Referenced by csv_log().

#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().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 365 of file cdr_csv.c.

static void __unreg_module ( void   )  [static]

Definition at line 365 of file cdr_csv.c.

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 }


Variable Documentation

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]

Definition at line 365 of file cdr_csv.c.

ast_mutex_t acf_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 97 of file cdr_csv.c.

Referenced by writefile().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 365 of file cdr_csv.c.

char* config = "cdr.conf" [static]

Definition at line 61 of file cdr_csv.c.

int loaded = 0 [static]

Definition at line 60 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 58 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 59 of file cdr_csv.c.

ast_mutex_t mf_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 96 of file cdr_csv.c.

Referenced by csv_log(), and custom_log().

char* name = "csv" [static]

Definition at line 94 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 57 of file cdr_csv.c.


Generated on Sat Aug 6 00:39:40 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7