#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 | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"PostgreSQL CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,) | |
AST_MUTEX_DEFINE_STATIC (pgsql_lock) | |
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 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 char * | table = NULL |
See also
Definition in file cdr_pgsql.c.
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 60 of file cdr_pgsql.c.
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"PostgreSQL CDR Backend" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
AST_MUTEX_DEFINE_STATIC | ( | pgsql_lock | ) |
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, 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(), and my_unload_module().
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 }
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.
char * table = NULL [static] |
Definition at line 64 of file cdr_pgsql.c.