Mon Mar 19 11:30:37 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"

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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
static int accountlogs
static ast_mutex_t acf_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , 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_RECURSIVE_MUTEX_INITIALIZER_NP , 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 369 of file cdr_csv.c.

static void __unreg_module ( void   )  [static]

Definition at line 369 of file cdr_csv.c.

static int append_date ( char *  buf,
struct timeval  when,
size_t  bufsize 
) [static]

Definition at line 193 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().

00194 {
00195    char tmp[80] = "";
00196    struct ast_tm tm;
00197 
00198    if (strlen(buf) > bufsize - 3)
00199       return -1;
00200 
00201    if (ast_tvzero(when)) {
00202       strncat(buf, ",", bufsize - strlen(buf) - 1);
00203       return 0;
00204    }
00205 
00206    ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL);
00207    ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm);
00208 
00209    return append_string(buf, tmp, bufsize);
00210 }

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 
00180    snprintf(tmp, sizeof(tmp), "%d", s);
00181 
00182    if (pos + strlen(tmp) > bufsize - 3)
00183       return -1;
00184 
00185    strncat(buf, tmp, bufsize - strlen(buf) - 1);
00186    pos = strlen(buf);
00187    buf[pos++] = ',';
00188    buf[pos++] = '\0';
00189 
00190    return 0;
00191 }

static int append_string ( char *  buf,
const char *  s,
size_t  bufsize 
) [static]

Definition at line 148 of file cdr_csv.c.

Referenced by append_date(), and build_csv_record().

00149 {
00150    int pos = strlen(buf), spos = 0, error = -1;
00151 
00152    if (pos >= bufsize - 4)
00153       return -1;
00154 
00155    buf[pos++] = '\"';
00156 
00157    while(pos < bufsize - 3) {
00158       if (!s[spos]) {
00159          error = 0;
00160          break;
00161       }
00162       if (s[spos] == '\"')
00163          buf[pos++] = '\"';
00164       buf[pos++] = s[spos];
00165       spos++;
00166    }
00167 
00168    buf[pos++] = '\"';
00169    buf[pos++] = ',';
00170    buf[pos++] = '\0';
00171 
00172    return error;
00173 }

static int build_csv_record ( char *  buf,
size_t  bufsize,
struct ast_cdr cdr 
) [static]

Definition at line 212 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().

00213 {
00214 
00215    buf[0] = '\0';
00216    /* Account code */
00217    append_string(buf, cdr->accountcode, bufsize);
00218    /* Source */
00219    append_string(buf, cdr->src, bufsize);
00220    /* Destination */
00221    append_string(buf, cdr->dst, bufsize);
00222    /* Destination context */
00223    append_string(buf, cdr->dcontext, bufsize);
00224    /* Caller*ID */
00225    append_string(buf, cdr->clid, bufsize);
00226    /* Channel */
00227    append_string(buf, cdr->channel, bufsize);
00228    /* Destination Channel */
00229    append_string(buf, cdr->dstchannel, bufsize);
00230    /* Last Application */
00231    append_string(buf, cdr->lastapp, bufsize);
00232    /* Last Data */
00233    append_string(buf, cdr->lastdata, bufsize);
00234    /* Start Time */
00235    append_date(buf, cdr->start, bufsize);
00236    /* Answer Time */
00237    append_date(buf, cdr->answer, bufsize);
00238    /* End Time */
00239    append_date(buf, cdr->end, bufsize);
00240    /* Duration */
00241    append_int(buf, cdr->duration, bufsize);
00242    /* Billable seconds */
00243    append_int(buf, cdr->billsec, bufsize);
00244    /* Disposition */
00245    append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
00246    /* AMA Flags */
00247    append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize);
00248    /* Unique ID */
00249    if (loguniqueid)
00250       append_string(buf, cdr->uniqueid, bufsize);
00251    /* append the user field */
00252    if(loguserfield)
00253       append_string(buf, cdr->userfield,bufsize);
00254    /* If we hit the end of our buffer, log an error */
00255    if (strlen(buf) < bufsize - 5) {
00256       /* Trim off trailing comma */
00257       buf[strlen(buf) - 1] = '\0';
00258       strncat(buf, "\n", bufsize - strlen(buf) - 1);
00259       return 0;
00260    }
00261    return -1;
00262 }

static int csv_log ( struct ast_cdr cdr  )  [static]

Definition at line 291 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().

00292 {
00293    FILE *mf = NULL;
00294    /* Make sure we have a big enough buf */
00295    char buf[1024];
00296    char csvmaster[PATH_MAX];
00297    snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
00298 #if 0
00299    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);
00300 #endif
00301    if (build_csv_record(buf, sizeof(buf), cdr)) {
00302       ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
00303       return 0;
00304    }
00305 
00306    /* because of the absolutely unconditional need for the
00307       highest reliability possible in writing billing records,
00308       we open write and close the log file each time */
00309    ast_mutex_lock(&mf_lock);
00310    if ((mf = fopen(csvmaster, "a"))) {
00311       fputs(buf, mf);
00312       fflush(mf); /* be particularly anal here */
00313       fclose(mf);
00314       mf = NULL;
00315       ast_mutex_unlock(&mf_lock);
00316    } else {
00317       ast_mutex_unlock(&mf_lock);
00318       ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
00319    }
00320 
00321    if (accountlogs && !ast_strlen_zero(cdr->accountcode)) {
00322       if (writefile(buf, cdr->accountcode))
00323          ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
00324    }
00325 
00326    return 0;
00327 }

static int load_config ( int  reload  )  [static]

Definition at line 95 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_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, and var.

00096 {
00097    struct ast_config *cfg;
00098    struct ast_variable *var;
00099    const char *tmp;
00100    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00101 
00102    if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00103       ast_log(LOG_WARNING, "unable to load config: %s\n", config);
00104       return 0;
00105    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00106       return 1;
00107 
00108    accountlogs = 1;
00109    usegmtime = 0;
00110    loguniqueid = 0;
00111    loguserfield = 0;
00112 
00113    if (!(var = ast_variable_browse(cfg, "csv"))) {
00114       ast_config_destroy(cfg);
00115       return 0;
00116    }
00117 
00118    if ((tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"))) {
00119       usegmtime = ast_true(tmp);
00120       if (usegmtime)
00121          ast_debug(1, "logging time in GMT\n");
00122    }
00123 
00124    /* Turn on/off separate files per accountcode. Default is on (as before) */
00125    if ((tmp = ast_variable_retrieve(cfg, "csv", "accountlogs"))) {
00126       accountlogs = ast_true(tmp);
00127       if (accountlogs) {
00128          ast_debug(1, "logging in separate files per accountcode\n");
00129       }
00130    }
00131 
00132    if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) {
00133       loguniqueid = ast_true(tmp);
00134       if (loguniqueid)
00135          ast_debug(1, "logging CDR field UNIQUEID\n");
00136    }
00137 
00138    if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) {
00139       loguserfield = ast_true(tmp);
00140       if (loguserfield)
00141          ast_debug(1, "logging CDR user-defined field\n");
00142    }
00143 
00144    ast_config_destroy(cfg);
00145    return 1;
00146 }

static int load_module ( void   )  [static]

Definition at line 336 of file cdr_csv.c.

References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.

00337 {
00338    int res;
00339 
00340    if(!load_config(0))
00341       return AST_MODULE_LOAD_DECLINE;
00342 
00343    if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) {
00344       ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
00345    } else {
00346       loaded = 1;
00347    }
00348    return res;
00349 }

static int reload ( void   )  [static]

Definition at line 351 of file cdr_csv.c.

References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.

00352 {
00353    if (load_config(1)) {
00354       loaded = 1;
00355    } else {
00356       loaded = 0;
00357       ast_log(LOG_WARNING, "No [csv] section in cdr.conf.  Unregistering backend.\n");
00358       ast_cdr_unregister(name);
00359    }
00360 
00361    return 0;
00362 }

static int unload_module ( void   )  [static]

Definition at line 329 of file cdr_csv.c.

References ast_cdr_unregister().

00330 {
00331    ast_cdr_unregister(name);
00332    loaded = 0;
00333    return 0;
00334 }

static int writefile ( char *  s,
char *  acc 
) [static]

Definition at line 264 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().

00265 {
00266    char tmp[PATH_MAX];
00267    FILE *f;
00268 
00269    if (strchr(acc, '/') || (acc[0] == '.')) {
00270       ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
00271       return -1;
00272    }
00273 
00274    snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
00275 
00276    ast_mutex_lock(&acf_lock);
00277    if (!(f = fopen(tmp, "a"))) {
00278       ast_mutex_unlock(&acf_lock);
00279       ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno));
00280       return -1;
00281    }
00282    fputs(s, f);
00283    fflush(f);
00284    fclose(f);
00285    ast_mutex_unlock(&acf_lock);
00286 
00287    return 0;
00288 }


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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static]

Definition at line 369 of file cdr_csv.c.

int accountlogs [static]

Definition at line 53 of file cdr_csv.c.

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

Definition at line 93 of file cdr_csv.c.

Referenced by writefile().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 369 of file cdr_csv.c.

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

Definition at line 57 of file cdr_csv.c.

Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_bridge_timelimit(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_insert(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_generic_bridge(), ast_get_cc_agent_dialstring(), ast_get_cc_agent_policy(), ast_get_cc_callback_macro(), ast_get_cc_max_agents(), ast_get_cc_max_monitors(), ast_get_cc_monitor_policy(), ast_get_cc_offer_timer(), ast_get_cc_recall_timer(), ast_get_ccbs_available_timer(), ast_get_ccnr_available_timer(), ast_readconfig(), ast_set_cc_agent_dialstring(), ast_set_cc_agent_policy(), ast_set_cc_callback_macro(), ast_set_cc_max_agents(), ast_set_cc_max_monitors(), ast_set_cc_monitor_policy(), ast_set_cc_offer_timer(), ast_set_cc_recall_timer(), ast_set_ccbs_available_timer(), ast_set_ccnr_available_timer(), ast_variable_browse(), ast_variable_retrieve(), build_peer(), builtin_atxfer(), category_get(), custom_log(), dial_exec_full(), do_monitor(), do_reload(), execute_cb(), feature_interpret(), feature_interpret_helper(), handle_t38_options(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), odbc_load_module(), parked_call_exec(), parse_config(), read_config_maps(), reload_config(), set_bridge_features_on_config(), set_config_flags(), and setup_dahdi_int().

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_RECURSIVE_MUTEX_INITIALIZER_NP , 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 Mon Mar 19 11:30:37 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7