Mon Jun 27 16:51:04 2011

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 43 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 44 of file cdr_csv.c.

Referenced by csv_log().

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

Definition at line 46 of file cdr_csv.c.


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  when,
size_t  bufsize 
) [static]

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

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

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

Definition at line 171 of file cdr_csv.c.

Referenced by build_csv_record().

00172 {
00173    char tmp[32];
00174    int pos = strlen(buf);
00175 
00176    snprintf(tmp, sizeof(tmp), "%d", s);
00177 
00178    if (pos + strlen(tmp) > bufsize - 3)
00179       return -1;
00180 
00181    strncat(buf, tmp, bufsize - strlen(buf) - 1);
00182    pos = strlen(buf);
00183    buf[pos++] = ',';
00184    buf[pos++] = '\0';
00185 
00186    return 0;
00187 }

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

Definition at line 144 of file cdr_csv.c.

Referenced by append_date(), and build_csv_record().

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

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

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

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

static int csv_log ( struct ast_cdr cdr  )  [static]

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

00288 {
00289    FILE *mf = NULL;
00290    /* Make sure we have a big enough buf */
00291    char buf[1024];
00292    char csvmaster[PATH_MAX];
00293    snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
00294 #if 0
00295    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);
00296 #endif
00297    if (build_csv_record(buf, sizeof(buf), cdr)) {
00298       ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
00299       return 0;
00300    }
00301 
00302    /* because of the absolutely unconditional need for the
00303       highest reliability possible in writing billing records,
00304       we open write and close the log file each time */
00305    ast_mutex_lock(&mf_lock);
00306    if ((mf = fopen(csvmaster, "a"))) {
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 (accountlogs && !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 ( int  reload  )  [static]

Definition at line 91 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.

00092 {
00093    struct ast_config *cfg;
00094    struct ast_variable *var;
00095    const char *tmp;
00096    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00097 
00098    if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00099       ast_log(LOG_WARNING, "unable to load config: %s\n", config);
00100       return 0;
00101    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00102       return 1;
00103 
00104    accountlogs = 1;
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    /* Turn on/off separate files per accountcode. Default is on (as before) */
00121    if ((tmp = ast_variable_retrieve(cfg, "csv", "accountlogs"))) {
00122       accountlogs = ast_true(tmp);
00123       if (accountlogs) {
00124          ast_debug(1, "logging in separate files per accountcode\n");
00125       }
00126    }
00127 
00128    if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) {
00129       loguniqueid = ast_true(tmp);
00130       if (loguniqueid)
00131          ast_debug(1, "logging CDR field UNIQUEID\n");
00132    }
00133 
00134    if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) {
00135       loguserfield = ast_true(tmp);
00136       if (loguserfield)
00137          ast_debug(1, "logging CDR user-defined field\n");
00138    }
00139 
00140    ast_config_destroy(cfg);
00141    return 1;
00142 }

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(0))
00337       return AST_MODULE_LOAD_DECLINE;
00338 
00339    if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) {
00340       ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
00341    } else {
00342       loaded = 1;
00343    }
00344    return res;
00345 }

static int reload ( void   )  [static]

Definition at line 347 of file cdr_csv.c.

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

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

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

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


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

Definition at line 365 of file cdr_csv.c.

int accountlogs [static]

Definition at line 49 of file cdr_csv.c.

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

Definition at line 89 of file cdr_csv.c.

Referenced by writefile().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 365 of file cdr_csv.c.

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

Definition at line 53 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(), builtin_parkcall(), category_get(), custom_log(), dial_exec_full(), 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(), park_exec_full(), 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 52 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 50 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 51 of file cdr_csv.c.

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

Definition at line 88 of file cdr_csv.c.

Referenced by csv_log().

char* name = "csv" [static]

Definition at line 86 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 48 of file cdr_csv.c.

Referenced by load_config().


Generated on Mon Jun 27 16:51:04 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7