#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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const struct ast_module_info * | ast_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 = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INITIALIZER } |
static char * | table = NULL |
Definition in file cdr_pgsql.c.
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 60 of file cdr_pgsql.c.
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 }
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 = "6989f2ec67f8497e38c12890500c525b" , .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 = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, 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.