Fri Feb 10 06:35:07 2012

Asterisk developer's documentation


cdr_csv.c File Reference

Comma Separated Value CDR records. More...

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

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


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

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 48 of file cdr_csv.c.

Referenced by csv_log().

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

Definition at line 50 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  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 }


Variable Documentation

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]

Definition at line 356 of file cdr_csv.c.

int accountlogs = 1 [static]

Definition at line 53 of file cdr_csv.c.

ast_mutex_t acf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 93 of file cdr_csv.c.

Referenced by writefile().

Definition at line 356 of file cdr_csv.c.

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

int loaded = 0 [static]

Definition at line 56 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 54 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 55 of file cdr_csv.c.

ast_mutex_t mf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 92 of file cdr_csv.c.

Referenced by csv_log().

char* name = "csv" [static]

Definition at line 90 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 52 of file cdr_csv.c.

Referenced by load_config().


Generated on Fri Feb 10 06:35:08 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6