Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## Asterisk developer's documentation

# cdr_sqlite.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 2004 - 2005, Holger Schurig
    00005  *
    00006  *
    00007  * Ideas taken from other cdr_*.c files
    00008  *
    00009  * See http://www.asterisk.org for more information about
    00010  * the Asterisk project. Please do not directly contact
    00011  * any of the maintainers of this project for assistance;
    00012  * the project provides a web site, mailing lists and IRC
    00013  * channels for your use.
    00014  *
    00015  * This program is free software, distributed under the terms of
    00016  * the GNU General Public License Version 2. See the LICENSE file
    00017  * at the top of the source tree.
    00018  */
    00019
    00020 /*! \file
    00021  *
    00022  * \brief Store CDR records in a SQLite database.
    00023  *
    00024  * \author Holger Schurig <hs4233@mail.mn-solutions.de>
    00025  *
    00026  * See also
    00027  * \arg \ref Config_cdr
    00028  * \arg http://www.sqlite.org/
    00029  *
    00030  * Creates the database and table on-the-fly
    00031  * \ingroup cdr_drivers
    00032  */
    00033
    00034 #include <sys/types.h>
    00035
    00036 #include <stdio.h>
    00037 #include <unistd.h>
    00038 #include <string.h>
    00039 #include <stdlib.h>
    00040 #include <sqlite.h>
    00041
    00042 #include "asterisk.h"
    00043
    00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 23898 $")
    00045
    00046 #include "asterisk/channel.h"
    00047 #include "asterisk/module.h"
    00048 #include "asterisk/logger.h"
    00049 #include "asterisk/utils.h"
    00050
    00051 #define LOG_UNIQUEID 0
    00052 #define LOG_USERFIELD   0
    00053
    00054 /* When you change the DATE_FORMAT, be sure to change the CHAR(19) below to something else */
    00055 #define DATE_FORMAT "%Y-%m-%d %T"
    00056
    00057 static char *desc = "SQLite CDR Backend";
    00058 static char *name = "sqlite";
    00059 static sqlite* db = NULL;
    00060
    00061 AST_MUTEX_DEFINE_STATIC(sqlite_lock);
    00062
    00063 /*! \brief SQL table format */
    00064 static char sql_create_table[] = "CREATE TABLE cdr ("
    00065 "  AcctId      INTEGER PRIMARY KEY,"
    00066 "  clid     VARCHAR(80),"
    00067 "  src      VARCHAR(80),"
    00068 "  dst      VARCHAR(80),"
    00069 "  dcontext VARCHAR(80),"
    00070 "  channel     VARCHAR(80),"
    00071 "  dstchannel  VARCHAR(80),"
    00072 "  lastapp     VARCHAR(80),"
    00073 "  lastdata VARCHAR(80),"
    00074 "  start    CHAR(19),"
    00075 "  answer      CHAR(19),"
    00076 "  end      CHAR(19),"
    00077 "  duration INTEGER,"
    00078 "  billsec     INTEGER,"
    00079 "  disposition INTEGER,"
    00080 "  amaflags INTEGER,"
    00081 "  accountcode VARCHAR(20)"
    00082 #if LOG_UNIQUEID
    00083 "  ,uniqueid   VARCHAR(32)"
    00084 #endif
    00085 #if LOG_USERFIELD
    00086 "  ,userfield  VARCHAR(255)"
    00087 #endif
    00088 ");";
    00089
    00090 static int sqlite_log(struct ast_cdr *cdr)
    00091 {
    00092    int res = 0;
    00093    char *zErr = 0;
    00094    struct tm tm;
    00095    time_t t;
    00096    char startstr[80], answerstr[80], endstr[80];
    00097    int count;
    00098
    00099    ast_mutex_lock(&sqlite_lock);
    00100
    00101    t = cdr->start.tv_sec;
    00102    localtime_r(&t, &tm);
    00103    strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm);
    00104
    00105    t = cdr->answer.tv_sec;
    00106    localtime_r(&t, &tm);
    00107    strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm);
    00108
    00109    t = cdr->end.tv_sec;
    00110    localtime_r(&t, &tm);
    00111    strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm);
    00112
    00113    for(count=0; count<5; count++) {
    00114       res = sqlite_exec_printf(db,
    00115          "INSERT INTO cdr ("
    00116             "clid,src,dst,dcontext,"
    00117             "channel,dstchannel,lastapp,lastdata, "
    00118             "start,answer,end,"
    00119             "duration,billsec,disposition,amaflags, "
    00120             "accountcode"
    00121 #           if LOG_UNIQUEID
    00122             ",uniqueid"
    00123 #           endif
    00124 #           if LOG_USERFIELD
    00125             ",userfield"
    00126 #           endif
    00127          ") VALUES ("
    00128             "'%q', '%q', '%q', '%q', "
    00129             "'%q', '%q', '%q', '%q', "
    00130             "'%q', '%q', '%q', "
    00131             "%d, %d, %d, %d, "
    00132             "'%q'"
    00133 #           if LOG_UNIQUEID
    00134             ",'%q'"
    00135 #           endif
    00136 #           if LOG_USERFIELD
    00137             ",'%q'"
    00138 #           endif
    00139          ")", NULL, NULL, &zErr,
    00140             cdr->clid, cdr->src, cdr->dst, cdr->dcontext,
    00141             cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata,
    00142             startstr, answerstr, endstr,
    00143             cdr->duration, cdr->billsec, cdr->disposition, cdr->amaflags,
    00144             cdr->accountcode
    00145 #           if LOG_UNIQUEID
    00146             ,cdr->uniqueid
    00147 #           endif
    00148 #           if LOG_USERFIELD
    00149             ,cdr->userfield
    00150 #           endif
    00151          );
    00152       if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
    00153          break;
    00154       usleep(200);
    00155    }
    00156
    00157    if (zErr) {
    00158       ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
    00159       free(zErr);
    00160    }
    00161
    00162    ast_mutex_unlock(&sqlite_lock);
    00163    return res;
    00164 }
    00165
    00166
    00167 char *description(void)
    00168 {
    00169    return desc;
    00170 }
    00171
    00172 int unload_module(void)
    00173 {
    00174    if (db)
    00175       sqlite_close(db);
    00176    ast_cdr_unregister(name);
    00177    return 0;
    00178 }
    00179
    00180 int load_module(void)
    00181 {
    00182    char *zErr;
    00183    char fn[PATH_MAX];
    00184    int res;
    00185
    00186    /* is the database there? */
    00187    snprintf(fn, sizeof(fn), "%s/cdr.db", ast_config_AST_LOG_DIR);
    00188    db = sqlite_open(fn, 0660, &zErr);
    00189    if (!db) {
    00190       ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
    00191       free(zErr);
    00192       return -1;
    00193    }
    00194
    00195    /* is the table there? */
    00196    res = sqlite_exec(db, "SELECT COUNT(AcctId) FROM cdr;", NULL, NULL, NULL);
    00197    if (res) {
    00198       res = sqlite_exec(db, sql_create_table, NULL, NULL, &zErr);
    00199       if (res) {
    00200          ast_log(LOG_ERROR, "cdr_sqlite: Unable to create table 'cdr': %s\n", zErr);
    00201          free(zErr);
    00202          goto err;
    00203       }
    00204
    00205       /* TODO: here we should probably create an index */
    00206    }
    00207
    00208    res = ast_cdr_register(name, desc, sqlite_log);
    00209    if (res) {
    00210       ast_log(LOG_ERROR, "Unable to register SQLite CDR handling\n");
    00211       return -1;
    00212    }
    00213    return 0;
    00214
    00215 err:
    00216    if (db)
    00217       sqlite_close(db);
    00218    return -1;
    00219 }
    00220
    00221 int reload(void)
    00222 {
    00223    return 0;
    00224 }
    00225
    00226 int usecount(void)
    00227 {
    00228    return 0;
    00229 }
    00230
    00231 char *key()
    00232 {
    00233    return ASTERISK_GPL_KEY;
    00234 }