#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 |
Definition in file cdr_pgsql.c.
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 57 of file cdr_pgsql.c.
AST_MUTEX_DEFINE_STATIC | ( | pgsql_lock | ) |
char* description | ( | void | ) |
Provides a description of the 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; }
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.
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.
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).
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.
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 }
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_rtp_lookup_pt(), 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.