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