#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"
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_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 PGresult * | result = 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 303 of file cdr_pgsql.c.
References my_load_module().
00304 { 00305 return my_load_module(); 00306 }
static int my_load_module | ( | void | ) | [static] |
Definition at line 287 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().
00288 { 00289 struct ast_config *cfg; 00290 int res; 00291 00292 if (!(cfg = ast_config_load(config))) { 00293 ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config); 00294 return AST_MODULE_LOAD_DECLINE; 00295 } 00296 00297 res = process_my_load_module(cfg); 00298 ast_config_destroy(cfg); 00299 00300 return res; 00301 }
static int my_unload_module | ( | void | ) | [static] |
Definition at line 183 of file cdr_pgsql.c.
References ast_cdr_unregister(), and free.
00184 { 00185 if (conn) 00186 PQfinish(conn); 00187 if (pghostname) 00188 free(pghostname); 00189 if (pgdbname) 00190 free(pgdbname); 00191 if (pgdbuser) 00192 free(pgdbuser); 00193 if (pgpassword) 00194 free(pgpassword); 00195 if (pgdbport) 00196 free(pgdbport); 00197 if (table) 00198 free(table); 00199 ast_cdr_unregister(name); 00200 return 0; 00201 }
static int pgsql_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 72 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, option_debug, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, ast_cdr::userfield, and userfield.
Referenced by load_module(), and process_my_load_module().
00073 { 00074 struct tm tm; 00075 static char timestr[128]; 00076 static char sqlcmd[2048]; 00077 char *pgerror; 00078 00079 ast_mutex_lock(&pgsql_lock); 00080 00081 localtime_r(&cdr->start.tv_sec,&tm); 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 } 00093 } 00094 00095 if (connected) { 00096 char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; 00097 char *uniqueid=NULL, *userfield=NULL; 00098 00099 /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ 00100 if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) 00101 PQescapeString(clid, cdr->clid, strlen(cdr->clid)); 00102 if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) 00103 PQescapeString(dcontext, cdr->dcontext, strlen(cdr->dcontext)); 00104 if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) 00105 PQescapeString(channel, cdr->channel, strlen(cdr->channel)); 00106 if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) 00107 PQescapeString(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel)); 00108 if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) 00109 PQescapeString(lastapp, cdr->lastapp, strlen(cdr->lastapp)); 00110 if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) 00111 PQescapeString(lastdata, cdr->lastdata, strlen(cdr->lastdata)); 00112 if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) 00113 PQescapeString(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid)); 00114 if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL) 00115 PQescapeString(userfield, cdr->userfield, strlen(cdr->userfield)); 00116 00117 /* Check for all alloca failures above at once */ 00118 if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield)) { 00119 ast_log(LOG_ERROR, "cdr_pgsql: Out of memory error (insert fails)\n"); 00120 ast_mutex_unlock(&pgsql_lock); 00121 return -1; 00122 } 00123 00124 if (option_debug > 1) 00125 ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n"); 00126 00127 /* XXX: need to check string length, and, may be, realloc buffer */ 00128 snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel," 00129 "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES" 00130 " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')", 00131 table,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, 00132 cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield); 00133 00134 if (option_debug > 2) 00135 ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed: %s\n",sqlcmd); 00136 00137 /* Test to be sure we're still connected... */ 00138 /* If we're connected, and connection is working, good. */ 00139 /* Otherwise, attempt reconnect. If it fails... sorry... */ 00140 if (PQstatus(conn) == CONNECTION_OK) { 00141 connected = 1; 00142 } else { 00143 ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n"); 00144 PQreset(conn); 00145 if (PQstatus(conn) == CONNECTION_OK) { 00146 ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); 00147 connected = 1; 00148 } else { 00149 pgerror = PQerrorMessage(conn); 00150 ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); 00151 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); 00152 connected = 0; 00153 ast_mutex_unlock(&pgsql_lock); 00154 return -1; 00155 } 00156 } 00157 result = PQexec(conn, sqlcmd); 00158 if ( PQresultStatus(result) != PGRES_COMMAND_OK) { 00159 pgerror = PQresultErrorMessage(result); 00160 ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n"); 00161 ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); 00162 ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n"); 00163 PQreset(conn); 00164 if (PQstatus(conn) == CONNECTION_OK) { 00165 ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); 00166 connected = 1; 00167 result = PQexec(conn, sqlcmd); 00168 if ( PQresultStatus(result) != PGRES_COMMAND_OK) 00169 { 00170 pgerror = PQresultErrorMessage(result); 00171 ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); 00172 ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); 00173 } 00174 } 00175 ast_mutex_unlock(&pgsql_lock); 00176 return -1; 00177 } 00178 } 00179 ast_mutex_unlock(&pgsql_lock); 00180 return 0; 00181 }
static int process_my_load_module | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 203 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().
00204 { 00205 struct ast_variable *var; 00206 char *pgerror; 00207 const char *tmp; 00208 00209 if (!(var = ast_variable_browse(cfg, "global"))) 00210 return 0; 00211 00212 if (!(tmp = ast_variable_retrieve(cfg,"global","hostname"))) { 00213 ast_log(LOG_WARNING,"PostgreSQL server hostname not specified. Assuming unix socket connection\n"); 00214 tmp = ""; /* connect via UNIX-socket by default */ 00215 } 00216 00217 if (!(pghostname = ast_strdup(tmp))) 00218 return -1; 00219 00220 if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) { 00221 ast_log(LOG_WARNING,"PostgreSQL database not specified. Assuming asterisk\n"); 00222 tmp = "asterisk"; 00223 } 00224 00225 if (!(pgdbname = ast_strdup(tmp))) 00226 return -1; 00227 00228 if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) { 00229 ast_log(LOG_WARNING,"PostgreSQL database user not specified. Assuming asterisk\n"); 00230 tmp = "asterisk"; 00231 } 00232 00233 if (!(pgdbuser = ast_strdup(tmp))) 00234 return -1; 00235 00236 if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { 00237 ast_log(LOG_WARNING,"PostgreSQL database password not specified. Assuming blank\n"); 00238 tmp = ""; 00239 } 00240 00241 if (!(pgpassword = ast_strdup(tmp))) 00242 return -1; 00243 00244 if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) { 00245 ast_log(LOG_WARNING,"PostgreSQL database port not specified. Using default 5432.\n"); 00246 tmp = "5432"; 00247 } 00248 00249 if (!(pgdbport = ast_strdup(tmp))) 00250 return -1; 00251 00252 if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) { 00253 ast_log(LOG_WARNING,"CDR table not specified. Assuming cdr\n"); 00254 tmp = "cdr"; 00255 } 00256 00257 if (!(table = ast_strdup(tmp))) 00258 return -1; 00259 00260 if (option_debug) { 00261 if (ast_strlen_zero(pghostname)) 00262 ast_log(LOG_DEBUG, "cdr_pgsql: using default unix socket\n"); 00263 else 00264 ast_log(LOG_DEBUG, "cdr_pgsql: got hostname of %s\n", pghostname); 00265 ast_log(LOG_DEBUG, "cdr_pgsql: got port of %s\n", pgdbport); 00266 ast_log(LOG_DEBUG, "cdr_pgsql: got user of %s\n", pgdbuser); 00267 ast_log(LOG_DEBUG, "cdr_pgsql: got dbname of %s\n", pgdbname); 00268 ast_log(LOG_DEBUG, "cdr_pgsql: got password of %s\n", pgpassword); 00269 ast_log(LOG_DEBUG, "cdr_pgsql: got sql table name of %s\n", table); 00270 } 00271 00272 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00273 if (PQstatus(conn) != CONNECTION_BAD) { 00274 if (option_debug) 00275 ast_log(LOG_DEBUG, "Successfully connected to PostgreSQL database.\n"); 00276 connected = 1; 00277 } else { 00278 pgerror = PQerrorMessage(conn); 00279 ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); 00280 ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); 00281 connected = 0; 00282 } 00283 00284 return ast_cdr_register(name, ast_module_info->description, pgsql_log); 00285 }
static int reload | ( | void | ) | [static] |
Definition at line 313 of file cdr_pgsql.c.
References my_load_module(), and my_unload_module().
00314 { 00315 my_unload_module(); 00316 return my_load_module(); 00317 }
static int unload_module | ( | void | ) | [static] |
Definition at line 308 of file cdr_pgsql.c.
References my_unload_module().
00309 { 00310 return my_unload_module(); 00311 }
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.
Referenced by cdr_pgsql_connect(), pgsql_log(), pgsql_test_connection(), reload(), and unload_module().
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.
PGresult* result = NULL [static] |
Definition at line 70 of file cdr_pgsql.c.
Referenced by ast_app_getdata(), ast_channel_spy_read_frame(), ast_config_internal_load(), ast_config_load(), ast_config_load_with_comments(), ast_privacy_check(), ast_rtp_lookup_pt(), ast_speech_results_free(), ast_speech_results_get(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), cdr_pgsql_connect(), check_sip_domain(), complete_sip_peer(), complete_sip_user(), complete_skinny_reset(), config_mysql(), config_pgsql(), detzcode(), dundi_lookup(), dundi_lookup_internal(), find_result(), get_member_status(), httpstatus_callback(), mgcpsock_read(), MYSQL_exec(), ogg_vorbis_open(), osp_check_destination(), osp_lookup(), osp_next(), osplookup_exec(), ospnext_exec(), pgsql_log(), radius_log(), read_samples(), realtime_multi_mysql(), realtime_multi_pgsql(), realtime_mysql(), realtime_pgsql(), speech_grammar(), speech_read(), speech_score(), speech_text(), static_callback(), tmcomp(), and update_pgsql().
char * table = NULL [static] |
Definition at line 64 of file cdr_pgsql.c.