Fri May 26 01:46:44 2006

Asterisk developer's documentation


cdr_pgsql.c File Reference

PostgreSQL CDR logger. More...

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

Include dependency graph for cdr_pgsql.c:

Go to the source code of this file.

Defines

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

Functions

 AST_MUTEX_DEFINE_STATIC (pgsql_lock)
char * description (void)
 Provides a description of the module.
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
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)
int reload (void)
 Reload stuff.
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

static char * config = "cdr_pgsql.conf"
PGconn * conn
static int connected = 0
static char * desc = "PostgreSQL CDR Backend"
static char * name = "pgsql"
static char * pgdbname = NULL
static char * pgdbport = NULL
static char * pgdbsock = NULL
static char * pgdbuser = NULL
static char * pghostname = NULL
static char * pgpassword = NULL
PGresult * result
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 57 of file cdr_pgsql.c.


Function Documentation

AST_MUTEX_DEFINE_STATIC pgsql_lock   ) 
 

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 177 of file cdr_pgsql.c.

00178 {
00179    return desc;
00180 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 351 of file cdr_pgsql.c.

References ASTERISK_GPL_KEY.

00352 {
00353    return ASTERISK_GPL_KEY;
00354 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 324 of file cdr_pgsql.c.

References my_load_module().

00325 {
00326    return my_load_module();
00327 }

static int my_load_module void   )  [static]
 

Definition at line 310 of file cdr_pgsql.c.

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

Referenced by load_module(), and reload().

00311 {
00312    struct ast_config *cfg;
00313    int res;
00314    cfg = ast_config_load(config);
00315    if (!cfg) {
00316       ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
00317       return 0;
00318    }
00319    res = process_my_load_module(cfg);
00320    ast_config_destroy(cfg);
00321    return res;
00322 }

static int my_unload_module void   )  [static]
 

Definition at line 182 of file cdr_pgsql.c.

References ast_cdr_unregister(), and free.

Referenced by reload(), and unload_module().

00183 { 
00184    if (conn)
00185       PQfinish(conn);
00186    if (pghostname)
00187       free(pghostname);
00188    if (pgdbname)
00189       free(pgdbname);
00190    if (pgdbuser)
00191       free(pgdbuser);
00192    if (pgdbsock)
00193       free(pgdbsock);
00194    if (pgpassword)
00195       free(pgpassword);
00196    if (pgdbport)
00197       free(pgdbport);
00198    if (table)
00199       free(table);
00200    ast_cdr_unregister(name);
00201    return 0;
00202 }

static int pgsql_log struct ast_cdr cdr  )  [static]
 

Definition at line 70 of file cdr_pgsql.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr_disp2str(), 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, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by process_my_load_module().

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

static int process_my_load_module struct ast_config cfg  )  [static]
 

Definition at line 204 of file cdr_pgsql.c.

References ast_cdr_register(), ast_log(), ast_variable_browse(), ast_variable_retrieve(), cfg, LOG_DEBUG, LOG_ERROR, LOG_WARNING, pgsql_log(), strdup, and var.

Referenced by my_load_module().

00205 {
00206    int res;
00207    struct ast_variable *var;
00208         char *pgerror;
00209    char *tmp;
00210 
00211    var = ast_variable_browse(cfg, "global");
00212    if (!var) {
00213       /* nothing configured */
00214       return 0;
00215    }
00216 
00217    tmp = ast_variable_retrieve(cfg,"global","hostname");
00218    if (tmp == NULL) {
00219       ast_log(LOG_WARNING,"PostgreSQL server hostname not specified.  Assuming localhost\n");
00220       tmp = "localhost";
00221    }
00222    pghostname = strdup(tmp);
00223    if (pghostname == NULL) {
00224       ast_log(LOG_ERROR,"Out of memory error.\n");
00225       return -1;
00226    }
00227 
00228    tmp = ast_variable_retrieve(cfg,"global","dbname");
00229    if (tmp == NULL) {
00230       ast_log(LOG_WARNING,"PostgreSQL database not specified.  Assuming asterisk\n");
00231       tmp = "asteriskcdrdb";
00232    }
00233    pgdbname = strdup(tmp);
00234    if (pgdbname == NULL) {
00235       ast_log(LOG_ERROR,"Out of memory error.\n");
00236       return -1;
00237    }
00238 
00239    tmp = ast_variable_retrieve(cfg,"global","user");
00240    if (tmp == NULL) {
00241       ast_log(LOG_WARNING,"PostgreSQL database user not specified.  Assuming root\n");
00242       tmp = "root";
00243    }
00244    pgdbuser = strdup(tmp);
00245    if (pgdbuser == NULL) {
00246       ast_log(LOG_ERROR,"Out of memory error.\n");
00247       return -1;
00248    }
00249 
00250    tmp = ast_variable_retrieve(cfg,"global","password");
00251    if (tmp == NULL) {
00252       ast_log(LOG_WARNING,"PostgreSQL database password not specified.  Assuming blank\n");
00253       tmp = "";
00254    }
00255    pgpassword = strdup(tmp);
00256    if (pgpassword == NULL) {
00257       ast_log(LOG_ERROR,"Out of memory error.\n");
00258       return -1;
00259    }
00260 
00261    tmp = ast_variable_retrieve(cfg,"global","port");
00262    if (tmp == NULL) {
00263       ast_log(LOG_WARNING,"PostgreSQL database port not specified.  Using default 5432.\n");
00264       tmp = "5432";
00265    }
00266    pgdbport = strdup(tmp);
00267    if (pgdbport == NULL) {
00268       ast_log(LOG_ERROR,"Out of memory error.\n");
00269       return -1;
00270    }
00271 
00272    tmp = ast_variable_retrieve(cfg,"global","table");
00273    if (tmp == NULL) {
00274       ast_log(LOG_WARNING,"CDR table not specified.  Assuming cdr\n");
00275       tmp = "cdr";
00276    }
00277    table = strdup(tmp);
00278    if (table == NULL) {
00279       ast_log(LOG_ERROR,"Out of memory error.\n");
00280       return -1;
00281    }
00282 
00283    ast_log(LOG_DEBUG,"cdr_pgsql: got hostname of %s\n",pghostname);
00284    ast_log(LOG_DEBUG,"cdr_pgsql: got port of %s\n",pgdbport);
00285    if (pgdbsock)
00286       ast_log(LOG_DEBUG,"cdr_pgsql: got sock file of %s\n",pgdbsock);
00287    ast_log(LOG_DEBUG,"cdr_pgsql: got user of %s\n",pgdbuser);
00288    ast_log(LOG_DEBUG,"cdr_pgsql: got dbname of %s\n",pgdbname);
00289    ast_log(LOG_DEBUG,"cdr_pgsql: got password of %s\n",pgpassword);
00290    ast_log(LOG_DEBUG,"cdr_pgsql: got sql table name of %s\n",table);
00291    
00292    conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00293    if (PQstatus(conn) != CONNECTION_BAD) {
00294       ast_log(LOG_DEBUG,"Successfully connected to PostgreSQL database.\n");
00295       connected = 1;
00296    } else {
00297                 pgerror = PQerrorMessage(conn);
00298       ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
00299                 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
00300       connected = 0;
00301    }
00302 
00303    res = ast_cdr_register(name, desc, pgsql_log);
00304    if (res) {
00305       ast_log(LOG_ERROR, "Unable to register PGSQL CDR handling\n");
00306    }
00307    return res;
00308 }

int reload void   ) 
 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 334 of file cdr_pgsql.c.

References my_load_module(), and my_unload_module().

00335 {
00336    my_unload_module();
00337    return my_load_module();
00338 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 329 of file cdr_pgsql.c.

References my_unload_module().

00330 {
00331    return my_unload_module();
00332 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 340 of file cdr_pgsql.c.

References ast_mutex_trylock(), and ast_mutex_unlock().

00341 {
00342    /* To be able to unload the module */
00343    if ( ast_mutex_trylock(&pgsql_lock) ) {
00344       return 1;
00345    } else {
00346       ast_mutex_unlock(&pgsql_lock);
00347       return 0;
00348    }
00349 }


Variable Documentation

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

Definition at line 61 of file cdr_pgsql.c.

PGconn* conn
 

Definition at line 67 of file cdr_pgsql.c.

int connected = 0 [static]
 

Definition at line 63 of file cdr_pgsql.c.

char* desc = "PostgreSQL CDR Backend" [static]
 

Definition at line 59 of file cdr_pgsql.c.

char* name = "pgsql" [static]
 

Definition at line 60 of file cdr_pgsql.c.

char * pgdbname = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

char * pgdbport = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

char * pgdbsock = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

char * pgdbuser = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

char* pghostname = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

char * pgpassword = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.

PGresult* result
 

Definition at line 68 of file cdr_pgsql.c.

Referenced by aopen_read(), ast_channel_spy_read_frame(), ast_config_internal_load(), ast_config_load(), ast_osp_lookup(), ast_osp_next(), ast_privacy_check(), ast_waitfordigit(), bestdata_read(), check_sip_domain(), complete_sip_peer(), complete_sip_user(), cut_exec(), detzcode(), dial_exec_full(), dundi_lookup(), dundi_lookup_internal(), get_member_status(), i4l_read(), i4l_write(), mgcpsock_read(), ogg_vorbis_open(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), PGSQL_exec(), read_samples(), sort_exec(), and tmcomp().

char * table = NULL [static]
 

Definition at line 62 of file cdr_pgsql.c.


Generated on Fri May 26 01:46:45 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6