Fri Jan 29 14:25:26 2010

Asterisk developer's documentation


cdr_pgsql.c File Reference

PostgreSQL CDR logger. More...

#include "asterisk.h"
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <libpq-fe.h>
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"

Go to the source code of this file.

Defines

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int load_module (void)
static int my_load_module (void)
static int my_unload_module (void)
static int pgsql_log (struct ast_cdr *cdr)
static int process_my_load_module (struct ast_config *cfg)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "PostgreSQL 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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static const struct ast_module_infoast_module_info = &__mod_info
static char * config = "cdr_pgsql.conf"
static PGconn * conn = NULL
static int connected = 0
static char * name = "pgsql"
static char * pgdbname = NULL
static char * pgdbport = NULL
static char * pgdbuser = NULL
static char * pghostname = NULL
static char * pgpassword = NULL
static ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static char * table = NULL


Detailed Description

PostgreSQL CDR logger.

Author:
Matthew D. Hardeman <mhardemn@papersoft.com>
See also

Definition in file cdr_pgsql.c.


Define Documentation

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

Definition at line 60 of file cdr_pgsql.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 336 of file cdr_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 336 of file cdr_pgsql.c.

static int load_module ( void   )  [static]

Definition at line 312 of file cdr_pgsql.c.

References my_load_module().

00313 {
00314    return my_load_module();
00315 }

static int my_load_module ( void   )  [static]

Definition at line 296 of file cdr_pgsql.c.

References ast_config_destroy(), ast_config_load(), ast_log(), AST_MODULE_LOAD_DECLINE, LOG_WARNING, and process_my_load_module().

Referenced by load_module(), and reload().

00297 {
00298    struct ast_config *cfg;
00299    int res;
00300 
00301    if (!(cfg = ast_config_load(config))) {
00302       ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
00303       return AST_MODULE_LOAD_DECLINE;
00304    }
00305 
00306    res = process_my_load_module(cfg);
00307    ast_config_destroy(cfg);
00308 
00309    return res;
00310 }

static int my_unload_module ( void   )  [static]

Definition at line 193 of file cdr_pgsql.c.

References ast_cdr_unregister(), and free.

Referenced by reload(), and unload_module().

00194 { 
00195    PQfinish(conn);
00196    if (pghostname)
00197       free(pghostname);
00198    if (pgdbname)
00199       free(pgdbname);
00200    if (pgdbuser)
00201       free(pgdbuser);
00202    if (pgpassword)
00203       free(pgpassword);
00204    if (pgdbport)
00205       free(pgdbport);
00206    if (table)
00207       free(table);
00208    ast_cdr_unregister(name);
00209    return 0;
00210 }

static int pgsql_log ( struct ast_cdr cdr  )  [static]

Definition at line 71 of file cdr_pgsql.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr_disp2str(), ast_localtime(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, DATE_FORMAT, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_ERROR, option_debug, pgsql_lock, ast_cdr::src, ast_cdr::start, t, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by process_my_load_module().

00072 {
00073    struct tm tm;
00074    time_t t = cdr->start.tv_sec;
00075    char sqlcmd[2048] = "", timestr[128];
00076    char *pgerror;
00077    PGresult *result;
00078 
00079    ast_mutex_lock(&pgsql_lock);
00080 
00081    ast_localtime(&t, &tm, NULL);
00082    strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00083 
00084    if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
00085       conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00086       if (PQstatus(conn) != CONNECTION_BAD) {
00087          connected = 1;
00088       } else {
00089          pgerror = PQerrorMessage(conn);
00090          ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s.  Calls will not be logged!\n", pghostname);
00091          ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
00092          PQfinish(conn);
00093          conn = NULL;
00094       }
00095    }
00096 
00097    if (connected) {
00098       char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
00099       char *src=NULL, *dst=NULL, *uniqueid=NULL, *userfield=NULL;
00100       int pgerr;
00101 
00102       /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
00103       if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL)
00104          PQescapeStringConn(conn, clid, cdr->clid, strlen(cdr->clid), &pgerr);
00105       if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL)
00106          PQescapeStringConn(conn, dcontext, cdr->dcontext, strlen(cdr->dcontext), &pgerr);
00107       if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL)
00108          PQescapeStringConn(conn, channel, cdr->channel, strlen(cdr->channel), &pgerr);
00109       if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL)
00110          PQescapeStringConn(conn, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel), &pgerr);
00111       if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL)
00112          PQescapeStringConn(conn, lastapp, cdr->lastapp, strlen(cdr->lastapp), &pgerr);
00113       if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL)
00114          PQescapeStringConn(conn, lastdata, cdr->lastdata, strlen(cdr->lastdata), &pgerr);
00115       if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL)
00116          PQescapeStringConn(conn, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid), &pgerr);
00117       if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL)
00118          PQescapeStringConn(conn, userfield, cdr->userfield, strlen(cdr->userfield), &pgerr);
00119       if ((src = alloca(strlen(cdr->src) * 2 + 1)) != NULL)
00120          PQescapeStringConn(conn, src, cdr->src, strlen(cdr->src), &pgerr);
00121       if ((dst = alloca(strlen(cdr->dst) * 2 + 1)) != NULL)
00122          PQescapeStringConn(conn, dst, cdr->dst, strlen(cdr->dst), &pgerr);
00123 
00124       /* Check for all alloca failures above at once */
00125       if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield) || (!src) || (!dst)) {
00126          ast_log(LOG_ERROR, "cdr_pgsql:  Out of memory error (insert fails)\n");
00127          ast_mutex_unlock(&pgsql_lock);
00128          return -1;
00129       }
00130 
00131       if (option_debug > 1)
00132          ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n");
00133 
00134       snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,"
00135              "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES"
00136              " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')",
00137              table, timestr, clid, src, dst, dcontext, channel, dstchannel, lastapp, lastdata,
00138              cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield);
00139       
00140       if (option_debug > 2)
00141          ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed:  %s\n",sqlcmd);
00142       
00143       /* Test to be sure we're still connected... */
00144       /* If we're connected, and connection is working, good. */
00145       /* Otherwise, attempt reconnect.  If it fails... sorry... */
00146       if (PQstatus(conn) == CONNECTION_OK) {
00147          connected = 1;
00148       } else {
00149          ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n");
00150          PQreset(conn);
00151          if (PQstatus(conn) == CONNECTION_OK) {
00152             ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n");
00153             connected = 1;
00154          } else {
00155             pgerror = PQerrorMessage(conn);
00156             ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname);
00157             ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
00158             PQfinish(conn);
00159             conn = NULL;
00160             connected = 0;
00161             ast_mutex_unlock(&pgsql_lock);
00162             return -1;
00163          }
00164       }
00165       result = PQexec(conn, sqlcmd);
00166       if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00167          pgerror = PQresultErrorMessage(result);
00168          ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n");
00169          ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
00170          ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n");
00171          PQreset(conn);
00172          if (PQstatus(conn) == CONNECTION_OK) {
00173             ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n");
00174             connected = 1;
00175             PQclear(result);
00176             result = PQexec(conn, sqlcmd);
00177             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00178                pgerror = PQresultErrorMessage(result);
00179                ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
00180                ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
00181             }
00182          }
00183          ast_mutex_unlock(&pgsql_lock);
00184          PQclear(result);
00185          return -1;
00186       }
00187       PQclear(result);
00188    }
00189    ast_mutex_unlock(&pgsql_lock);
00190    return 0;
00191 }

static int process_my_load_module ( struct ast_config cfg  )  [static]

Definition at line 212 of file cdr_pgsql.c.

References ast_cdr_register(), ast_log(), ast_strdup, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, option_debug, pgsql_log(), and var.

Referenced by my_load_module().

00213 {
00214    struct ast_variable *var;
00215         char *pgerror;
00216    const char *tmp;
00217 
00218    if (!(var = ast_variable_browse(cfg, "global")))
00219       return 0;
00220 
00221    if (!(tmp = ast_variable_retrieve(cfg,"global","hostname"))) {
00222       ast_log(LOG_WARNING,"PostgreSQL server hostname not specified.  Assuming unix socket connection\n");
00223       tmp = "";   /* connect via UNIX-socket by default */
00224    }
00225    
00226    if (!(pghostname = ast_strdup(tmp)))
00227       return -1;
00228 
00229    if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) {
00230       ast_log(LOG_WARNING,"PostgreSQL database not specified.  Assuming asterisk\n");
00231       tmp = "asteriskcdrdb";
00232    }
00233 
00234    if (!(pgdbname = ast_strdup(tmp)))
00235       return -1;
00236 
00237    if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) {
00238       ast_log(LOG_WARNING,"PostgreSQL database user not specified.  Assuming asterisk\n");
00239       tmp = "asterisk";
00240    }
00241 
00242    if (!(pgdbuser = ast_strdup(tmp)))
00243       return -1;
00244 
00245    if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) {
00246       ast_log(LOG_WARNING,"PostgreSQL database password not specified.  Assuming blank\n");
00247       tmp = "";
00248    }
00249 
00250    if (!(pgpassword = ast_strdup(tmp)))
00251       return -1;
00252 
00253    if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) {
00254       ast_log(LOG_WARNING,"PostgreSQL database port not specified.  Using default 5432.\n");
00255       tmp = "5432";
00256    }
00257 
00258    if (!(pgdbport = ast_strdup(tmp)))
00259       return -1;
00260 
00261    if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) {
00262       ast_log(LOG_WARNING,"CDR table not specified.  Assuming cdr\n");
00263       tmp = "cdr";
00264    }
00265 
00266    if (!(table = ast_strdup(tmp)))
00267       return -1;
00268 
00269    if (option_debug) {
00270          if (ast_strlen_zero(pghostname))
00271          ast_log(LOG_DEBUG, "cdr_pgsql: using default unix socket\n");
00272       else
00273          ast_log(LOG_DEBUG, "cdr_pgsql: got hostname of %s\n", pghostname);
00274       ast_log(LOG_DEBUG, "cdr_pgsql: got port of %s\n", pgdbport);
00275       ast_log(LOG_DEBUG, "cdr_pgsql: got user of %s\n", pgdbuser);
00276       ast_log(LOG_DEBUG, "cdr_pgsql: got dbname of %s\n", pgdbname);
00277       ast_log(LOG_DEBUG, "cdr_pgsql: got password of %s\n", pgpassword);
00278       ast_log(LOG_DEBUG, "cdr_pgsql: got sql table name of %s\n", table);
00279    }
00280    
00281    conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00282    if (PQstatus(conn) != CONNECTION_BAD) {
00283       if (option_debug)
00284          ast_log(LOG_DEBUG, "Successfully connected to PostgreSQL database.\n");
00285       connected = 1;
00286    } else {
00287                 pgerror = PQerrorMessage(conn);
00288       ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
00289                 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
00290       connected = 0;
00291    }
00292 
00293    return ast_cdr_register(name, ast_module_info->description, pgsql_log);
00294 }

static int reload ( void   )  [static]

Definition at line 322 of file cdr_pgsql.c.

References ast_mutex_lock(), ast_mutex_unlock(), my_load_module(), my_unload_module(), and pgsql_lock.

00323 {
00324    int res;
00325    ast_mutex_lock(&pgsql_lock);
00326    my_unload_module();
00327    res = my_load_module();
00328    ast_mutex_unlock(&pgsql_lock);
00329    return res;
00330 }

static int unload_module ( void   )  [static]

Definition at line 317 of file cdr_pgsql.c.

References my_unload_module().

00318 {
00319    return my_unload_module();
00320 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "PostgreSQL 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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 336 of file cdr_pgsql.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 336 of file cdr_pgsql.c.

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

Definition at line 63 of file cdr_pgsql.c.

PGconn* conn = NULL [static]

Definition at line 69 of file cdr_pgsql.c.

int connected = 0 [static]

Definition at line 65 of file cdr_pgsql.c.

char* name = "pgsql" [static]

Definition at line 62 of file cdr_pgsql.c.

char * pgdbname = NULL [static]

Definition at line 64 of file cdr_pgsql.c.

char * pgdbport = NULL [static]

Definition at line 64 of file cdr_pgsql.c.

char * pgdbuser = NULL [static]

Definition at line 64 of file cdr_pgsql.c.

char* pghostname = NULL [static]

Definition at line 64 of file cdr_pgsql.c.

char * pgpassword = NULL [static]

Definition at line 64 of file cdr_pgsql.c.

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

Definition at line 67 of file cdr_pgsql.c.

Referenced by config_pgsql(), load_module(), pgsql_log(), realtime_multi_pgsql(), realtime_pgsql(), reload(), unload_module(), and update_pgsql().

char * table = NULL [static]

Definition at line 64 of file cdr_pgsql.c.


Generated on Fri Jan 29 14:25:26 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7