Wed Oct 28 11:45:51 2009

Asterisk developer's documentation


cdr_csv.c File Reference

Comma Separated Value CDR records. More...

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

Include dependency graph for cdr_csv.c:

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 (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 = AST_BUILDOPT_SUM, .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


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 45 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 46 of file cdr_csv.c.

Referenced by csv_log().

#define DATE_FORMAT   "%Y-%m-%d %T"

Definition at line 48 of file cdr_csv.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 356 of file cdr_csv.c.

static void __unreg_module ( void   )  [static]

Definition at line 356 of file cdr_csv.c.

static int append_date ( char *  buf,
struct timeval  tv,
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(tv)) {
00190       strncat(buf, ",", bufsize - strlen(buf) - 1);
00191       return 0;
00192    }
00193 
00194    ast_localtime(&tv, &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_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 }


Variable Documentation

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 356 of file cdr_csv.c.

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

Definition at line 90 of file cdr_csv.c.

Referenced by writefile().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 356 of file cdr_csv.c.

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

Definition at line 54 of file cdr_csv.c.

int loaded = 0 [static]

Definition at line 53 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 51 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 52 of file cdr_csv.c.

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

Definition at line 89 of file cdr_csv.c.

Referenced by csv_log(), and custom_log().

char* name = "csv" [static]

Definition at line 87 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 50 of file cdr_csv.c.


Generated on Wed Oct 28 11:45:51 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6