#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 307 of file cdr_pgsql.c.
References my_load_module().
00308 { 00309 return my_load_module(); 00310 }
static int my_load_module | ( | void | ) | [static] |
Definition at line 291 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().
00292 { 00293 struct ast_config *cfg; 00294 int res; 00295 00296 if (!(cfg = ast_config_load(config))) { 00297 ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config); 00298 return AST_MODULE_LOAD_DECLINE; 00299 } 00300 00301 res = process_my_load_module(cfg); 00302 ast_config_destroy(cfg); 00303 00304 return res; 00305 }
static int my_unload_module | ( | void | ) | [static] |
Definition at line 188 of file cdr_pgsql.c.
References ast_cdr_unregister(), and free.
Referenced by reload(), and unload_module().
00189 { 00190 PQfinish(conn); 00191 if (pghostname) 00192 free(pghostname); 00193 if (pgdbname) 00194 free(pgdbname); 00195 if (pgdbuser) 00196 free(pgdbuser); 00197 if (pgpassword) 00198 free(pgpassword); 00199 if (pgdbport) 00200 free(pgdbport); 00201 if (table) 00202 free(table); 00203 ast_cdr_unregister(name); 00204 return 0; 00205 }
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 *uniqueid=NULL, *userfield=NULL; 00100 00101 /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ 00102 if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) 00103 PQescapeString(clid, cdr->clid, strlen(cdr->clid)); 00104 if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) 00105 PQescapeString(dcontext, cdr->dcontext, strlen(cdr->dcontext)); 00106 if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) 00107 PQescapeString(channel, cdr->channel, strlen(cdr->channel)); 00108 if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) 00109 PQescapeString(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); 00110 if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) 00111 PQescapeString(lastapp, cdr->lastapp, strlen(cdr->lastapp)); 00112 if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) 00113 PQescapeString(lastdata, cdr->lastdata, strlen(cdr->lastdata)); 00114 if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) 00115 PQescapeString(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); 00116 if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL) 00117 PQescapeString(userfield, cdr->userfield, strlen(cdr->userfield)); 00118 00119 /* Check for all alloca failures above at once */ 00120 if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield)) { 00121 ast_log(LOG_ERROR, "cdr_pgsql: Out of memory error (insert fails)\n"); 00122 ast_mutex_unlock(&pgsql_lock); 00123 return -1; 00124 } 00125 00126 if (option_debug > 1) 00127 ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n"); 00128 00129 snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel," 00130 "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES" 00131 " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')", 00132 table,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, 00133 cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield); 00134 00135 if (option_debug > 2) 00136 ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed: %s\n",sqlcmd); 00137 00138 /* Test to be sure we're still connected... */ 00139 /* If we're connected, and connection is working, good. */ 00140 /* Otherwise, attempt reconnect. If it fails... sorry... */ 00141 if (PQstatus(conn) == CONNECTION_OK) { 00142 connected = 1; 00143 } else { 00144 ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n"); 00145 PQreset(conn); 00146 if (PQstatus(conn) == CONNECTION_OK) { 00147 ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); 00148 connected = 1; 00149 } else { 00150 pgerror = PQerrorMessage(conn); 00151 ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); 00152 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); 00153 PQfinish(conn); 00154 conn = NULL; 00155 connected = 0; 00156 ast_mutex_unlock(&pgsql_lock); 00157 return -1; 00158 } 00159 } 00160 result = PQexec(conn, sqlcmd); 00161 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00162 pgerror = PQresultErrorMessage(result); 00163 ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n"); 00164 ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); 00165 ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n"); 00166 PQreset(conn); 00167 if (PQstatus(conn) == CONNECTION_OK) { 00168 ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); 00169 connected = 1; 00170 PQclear(result); 00171 result = PQexec(conn, sqlcmd); 00172 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00173 pgerror = PQresultErrorMessage(result); 00174 ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); 00175 ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); 00176 } 00177 } 00178 ast_mutex_unlock(&pgsql_lock); 00179 PQclear(result); 00180 return -1; 00181 } 00182 PQclear(result); 00183 } 00184 ast_mutex_unlock(&pgsql_lock); 00185 return 0; 00186 }
static int process_my_load_module | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 207 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().
00208 { 00209 struct ast_variable *var; 00210 char *pgerror; 00211 const char *tmp; 00212 00213 if (!(var = ast_variable_browse(cfg, "global"))) 00214 return 0; 00215 00216 if (!(tmp = ast_variable_retrieve(cfg,"global","hostname"))) { 00217 ast_log(LOG_WARNING,"PostgreSQL server hostname not specified. Assuming unix socket connection\n"); 00218 tmp = ""; /* connect via UNIX-socket by default */ 00219 } 00220 00221 if (!(pghostname = ast_strdup(tmp))) 00222 return -1; 00223 00224 if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) { 00225 ast_log(LOG_WARNING,"PostgreSQL database not specified. Assuming asterisk\n"); 00226 tmp = "asteriskcdrdb"; 00227 } 00228 00229 if (!(pgdbname = ast_strdup(tmp))) 00230 return -1; 00231 00232 if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) { 00233 ast_log(LOG_WARNING,"PostgreSQL database user not specified. Assuming asterisk\n"); 00234 tmp = "asterisk"; 00235 } 00236 00237 if (!(pgdbuser = ast_strdup(tmp))) 00238 return -1; 00239 00240 if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { 00241 ast_log(LOG_WARNING,"PostgreSQL database password not specified. Assuming blank\n"); 00242 tmp = ""; 00243 } 00244 00245 if (!(pgpassword = ast_strdup(tmp))) 00246 return -1; 00247 00248 if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) { 00249 ast_log(LOG_WARNING,"PostgreSQL database port not specified. Using default 5432.\n"); 00250 tmp = "5432"; 00251 } 00252 00253 if (!(pgdbport = ast_strdup(tmp))) 00254 return -1; 00255 00256 if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) { 00257 ast_log(LOG_WARNING,"CDR table not specified. Assuming cdr\n"); 00258 tmp = "cdr"; 00259 } 00260 00261 if (!(table = ast_strdup(tmp))) 00262 return -1; 00263 00264 if (option_debug) { 00265 if (ast_strlen_zero(pghostname)) 00266 ast_log(LOG_DEBUG, "cdr_pgsql: using default unix socket\n"); 00267 else 00268 ast_log(LOG_DEBUG, "cdr_pgsql: got hostname of %s\n", pghostname); 00269 ast_log(LOG_DEBUG, "cdr_pgsql: got port of %s\n", pgdbport); 00270 ast_log(LOG_DEBUG, "cdr_pgsql: got user of %s\n", pgdbuser); 00271 ast_log(LOG_DEBUG, "cdr_pgsql: got dbname of %s\n", pgdbname); 00272 ast_log(LOG_DEBUG, "cdr_pgsql: got password of %s\n", pgpassword); 00273 ast_log(LOG_DEBUG, "cdr_pgsql: got sql table name of %s\n", table); 00274 } 00275 00276 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00277 if (PQstatus(conn) != CONNECTION_BAD) { 00278 if (option_debug) 00279 ast_log(LOG_DEBUG, "Successfully connected to PostgreSQL database.\n"); 00280 connected = 1; 00281 } else { 00282 pgerror = PQerrorMessage(conn); 00283 ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); 00284 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); 00285 connected = 0; 00286 } 00287 00288 return ast_cdr_register(name, ast_module_info->description, pgsql_log); 00289 }
static int reload | ( | void | ) | [static] |
Definition at line 317 of file cdr_pgsql.c.
References ast_mutex_lock(), ast_mutex_unlock(), my_load_module(), and my_unload_module().
00318 { 00319 int res; 00320 ast_mutex_lock(&pgsql_lock); 00321 my_unload_module(); 00322 res = my_load_module(); 00323 ast_mutex_unlock(&pgsql_lock); 00324 return res; 00325 }
static int unload_module | ( | void | ) | [static] |
Definition at line 312 of file cdr_pgsql.c.
References my_unload_module().
00313 { 00314 return my_unload_module(); 00315 }
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.