PostgreSQL CDR logger. More...
#include "asterisk.h"#include <time.h>#include <libpq-fe.h>#include "asterisk/config.h"#include "asterisk/channel.h"#include "asterisk/cdr.h"#include "asterisk/module.h"
Go to the source code of this file.
Data Structures | |
| struct | columns |
| struct | psql_columns |
Defines | |
| #define | DATE_FORMAT "'%Y-%m-%d %T'" |
| #define | LENGTHEN_BUF1(size) |
| #define | LENGTHEN_BUF2(size) |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | config_module (int reload) |
| static int | load_module (void) |
| static int | pgsql_log (struct ast_cdr *cdr) |
| static int | reload (void) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static char * | config = "cdr_pgsql.conf" |
| static PGconn * | conn = NULL |
| static int | connected = 0 |
| static int | maxsize = 512 |
| static int | maxsize2 = 512 |
| 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_RECURSIVE_MUTEX_INITIALIZER_NP ) |
| static char * | table = NULL |
PostgreSQL CDR logger.
See also
Definition in file cdr_pgsql.c.
| #define DATE_FORMAT "'%Y-%m-%d %T'" |
Definition at line 53 of file cdr_pgsql.c.
| #define LENGTHEN_BUF1 | ( | size | ) |
Definition at line 76 of file cdr_pgsql.c.
| #define LENGTHEN_BUF2 | ( | size | ) |
Definition at line 90 of file cdr_pgsql.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 590 of file cdr_pgsql.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 590 of file cdr_pgsql.c.
| static int config_module | ( | int | reload | ) | [static] |
Definition at line 362 of file cdr_pgsql.c.
References ast_calloc, ast_cdr_register(), ast_config_destroy(), ast_config_load, ast_debug, ast_free, ast_log(), AST_MODULE_LOAD_DECLINE, AST_RWLIST_INSERT_TAIL, ast_strdup, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, columns::hasdefault, columns::len, LOG_ERROR, LOG_WARNING, columns::name, columns::notnull, option_debug, pgsql_log(), columns::type, unload_module, var, and version.
Referenced by load_module(), and reload().
00363 { 00364 struct ast_variable *var; 00365 char *pgerror; 00366 struct columns *cur; 00367 PGresult *result; 00368 const char *tmp; 00369 struct ast_config *cfg; 00370 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00371 00372 if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) { 00373 ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config); 00374 return -1; 00375 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00376 return 0; 00377 00378 if (!(var = ast_variable_browse(cfg, "global"))) { 00379 ast_config_destroy(cfg); 00380 return 0; 00381 } 00382 00383 if (!(tmp = ast_variable_retrieve(cfg, "global", "hostname"))) { 00384 ast_log(LOG_WARNING, "PostgreSQL server hostname not specified. Assuming unix socket connection\n"); 00385 tmp = ""; /* connect via UNIX-socket by default */ 00386 } 00387 00388 if (pghostname) 00389 ast_free(pghostname); 00390 if (!(pghostname = ast_strdup(tmp))) { 00391 ast_config_destroy(cfg); 00392 return -1; 00393 } 00394 00395 if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) { 00396 ast_log(LOG_WARNING, "PostgreSQL database not specified. Assuming asterisk\n"); 00397 tmp = "asteriskcdrdb"; 00398 } 00399 00400 if (pgdbname) 00401 ast_free(pgdbname); 00402 if (!(pgdbname = ast_strdup(tmp))) { 00403 ast_config_destroy(cfg); 00404 return -1; 00405 } 00406 00407 if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) { 00408 ast_log(LOG_WARNING, "PostgreSQL database user not specified. Assuming asterisk\n"); 00409 tmp = "asterisk"; 00410 } 00411 00412 if (pgdbuser) 00413 ast_free(pgdbuser); 00414 if (!(pgdbuser = ast_strdup(tmp))) { 00415 ast_config_destroy(cfg); 00416 return -1; 00417 } 00418 00419 if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { 00420 ast_log(LOG_WARNING, "PostgreSQL database password not specified. Assuming blank\n"); 00421 tmp = ""; 00422 } 00423 00424 if (pgpassword) 00425 ast_free(pgpassword); 00426 if (!(pgpassword = ast_strdup(tmp))) { 00427 ast_config_destroy(cfg); 00428 return -1; 00429 } 00430 00431 if (!(tmp = ast_variable_retrieve(cfg, "global", "port"))) { 00432 ast_log(LOG_WARNING, "PostgreSQL database port not specified. Using default 5432.\n"); 00433 tmp = "5432"; 00434 } 00435 00436 if (pgdbport) 00437 ast_free(pgdbport); 00438 if (!(pgdbport = ast_strdup(tmp))) { 00439 ast_config_destroy(cfg); 00440 return -1; 00441 } 00442 00443 if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) { 00444 ast_log(LOG_WARNING, "CDR table not specified. Assuming cdr\n"); 00445 tmp = "cdr"; 00446 } 00447 00448 if (table) 00449 ast_free(table); 00450 if (!(table = ast_strdup(tmp))) { 00451 ast_config_destroy(cfg); 00452 return -1; 00453 } 00454 00455 if (option_debug) { 00456 if (ast_strlen_zero(pghostname)) { 00457 ast_debug(1, "using default unix socket\n"); 00458 } else { 00459 ast_debug(1, "got hostname of %s\n", pghostname); 00460 } 00461 ast_debug(1, "got port of %s\n", pgdbport); 00462 ast_debug(1, "got user of %s\n", pgdbuser); 00463 ast_debug(1, "got dbname of %s\n", pgdbname); 00464 ast_debug(1, "got password of %s\n", pgpassword); 00465 ast_debug(1, "got sql table name of %s\n", table); 00466 } 00467 00468 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00469 if (PQstatus(conn) != CONNECTION_BAD) { 00470 char sqlcmd[768]; 00471 char *fname, *ftype, *flen, *fnotnull, *fdef; 00472 int i, rows, version; 00473 ast_debug(1, "Successfully connected to PostgreSQL database.\n"); 00474 connected = 1; 00475 version = PQserverVersion(conn); 00476 00477 if (version >= 70300) { 00478 char *schemaname, *tablename; 00479 if (strchr(table, '.')) { 00480 schemaname = ast_strdupa(table); 00481 tablename = strchr(schemaname, '.'); 00482 *tablename++ = '\0'; 00483 } else { 00484 schemaname = ""; 00485 tablename = table; 00486 } 00487 00488 /* Escape special characters in schemaname */ 00489 if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) { 00490 char *tmp = schemaname, *ptr; 00491 00492 ptr = schemaname = alloca(strlen(tmp) * 2 + 1); 00493 for (; *tmp; tmp++) { 00494 if (strchr("\\'", *tmp)) { 00495 *ptr++ = *tmp; 00496 } 00497 *ptr++ = *tmp; 00498 } 00499 *ptr = '\0'; 00500 } 00501 /* Escape special characters in tablename */ 00502 if (strchr(tablename, '\\') || strchr(tablename, '\'')) { 00503 char *tmp = tablename, *ptr; 00504 00505 ptr = tablename = alloca(strlen(tmp) * 2 + 1); 00506 for (; *tmp; tmp++) { 00507 if (strchr("\\'", *tmp)) { 00508 *ptr++ = *tmp; 00509 } 00510 *ptr++ = *tmp; 00511 } 00512 *ptr = '\0'; 00513 } 00514 00515 snprintf(sqlcmd, sizeof(sqlcmd), "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND c.relname = '%s' AND n.nspname = %s%s%s) INNER JOIN pg_catalog.pg_attribute a ON (NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum ORDER BY n.nspname, c.relname, attnum", 00516 tablename, 00517 ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'"); 00518 } else { 00519 snprintf(sqlcmd, sizeof(sqlcmd), "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", table); 00520 } 00521 /* Query the columns */ 00522 result = PQexec(conn, sqlcmd); 00523 if (PQresultStatus(result) != PGRES_TUPLES_OK) { 00524 pgerror = PQresultErrorMessage(result); 00525 ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror); 00526 PQclear(result); 00527 unload_module(); 00528 return AST_MODULE_LOAD_DECLINE; 00529 } 00530 00531 rows = PQntuples(result); 00532 for (i = 0; i < rows; i++) { 00533 fname = PQgetvalue(result, i, 0); 00534 ftype = PQgetvalue(result, i, 1); 00535 flen = PQgetvalue(result, i, 2); 00536 fnotnull = PQgetvalue(result, i, 3); 00537 fdef = PQgetvalue(result, i, 4); 00538 if (atoi(flen) == -1) { 00539 /* For varchar columns, the maximum length is encoded in a different field */ 00540 flen = PQgetvalue(result, i, 5); 00541 } 00542 ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype); 00543 cur = ast_calloc(1, sizeof(*cur) + strlen(fname) + strlen(ftype) + 2); 00544 if (cur) { 00545 sscanf(flen, "%30d", &cur->len); 00546 cur->name = (char *)cur + sizeof(*cur); 00547 cur->type = (char *)cur + sizeof(*cur) + strlen(fname) + 1; 00548 strcpy(cur->name, fname); 00549 strcpy(cur->type, ftype); 00550 if (*fnotnull == 't') { 00551 cur->notnull = 1; 00552 } else { 00553 cur->notnull = 0; 00554 } 00555 if (!ast_strlen_zero(fdef)) { 00556 cur->hasdefault = 1; 00557 } else { 00558 cur->hasdefault = 0; 00559 } 00560 AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list); 00561 } 00562 } 00563 PQclear(result); 00564 } else { 00565 pgerror = PQerrorMessage(conn); 00566 ast_log(LOG_ERROR, "Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); 00567 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00568 connected = 0; 00569 } 00570 00571 ast_config_destroy(cfg); 00572 00573 return ast_cdr_register(name, ast_module_info->description, pgsql_log); 00574 }
| static int load_module | ( | void | ) | [static] |
Definition at line 576 of file cdr_pgsql.c.
References AST_MODULE_LOAD_DECLINE, and config_module().
00577 { 00578 return config_module(0) ? AST_MODULE_LOAD_DECLINE : 0; 00579 }
| static int pgsql_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 103 of file cdr_pgsql.c.
References ast_cdr::answer, ast_cdr_getvar(), ast_debug, ast_free, ast_localtime(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_strlen(), ast_strftime(), ast_verb, buf, DATE_FORMAT, ast_cdr::end, first, columns::hasdefault, LENGTHEN_BUF1, LENGTHEN_BUF2, LOG_ERROR, maxsize2, columns::name, columns::notnull, pgsql_lock, ast_cdr::start, and columns::type.
Referenced by config_module().
00104 { 00105 struct ast_tm tm; 00106 char *pgerror; 00107 PGresult *result; 00108 00109 ast_mutex_lock(&pgsql_lock); 00110 00111 if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { 00112 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00113 if (PQstatus(conn) != CONNECTION_BAD) { 00114 connected = 1; 00115 } else { 00116 pgerror = PQerrorMessage(conn); 00117 ast_log(LOG_ERROR, "Unable to connect to database server %s. Calls will not be logged!\n", pghostname); 00118 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00119 PQfinish(conn); 00120 conn = NULL; 00121 } 00122 } 00123 00124 if (connected) { 00125 struct columns *cur; 00126 struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); 00127 char buf[257], escapebuf[513], *value; 00128 int first = 1; 00129 00130 if (!sql || !sql2) { 00131 if (sql) { 00132 ast_free(sql); 00133 } 00134 if (sql2) { 00135 ast_free(sql2); 00136 } 00137 return -1; 00138 } 00139 00140 ast_str_set(&sql, 0, "INSERT INTO %s (", table); 00141 ast_str_set(&sql2, 0, " VALUES ("); 00142 00143 AST_RWLIST_RDLOCK(&psql_columns); 00144 AST_RWLIST_TRAVERSE(&psql_columns, cur, list) { 00145 /* For fields not set, simply skip them */ 00146 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00147 if (strcmp(cur->name, "calldate") == 0 && !value) { 00148 ast_cdr_getvar(cdr, "start", &value, buf, sizeof(buf), 0, 0); 00149 } 00150 if (!value) { 00151 if (cur->notnull && !cur->hasdefault) { 00152 /* Field is NOT NULL (but no default), must include it anyway */ 00153 LENGTHEN_BUF1(strlen(cur->name) + 2); 00154 ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name); 00155 LENGTHEN_BUF2(3); 00156 ast_str_append(&sql2, 0, "%s''", first ? "" : ","); 00157 first = 0; 00158 } 00159 continue; 00160 } 00161 00162 LENGTHEN_BUF1(strlen(cur->name) + 2); 00163 ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name); 00164 00165 if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) { 00166 if (strncmp(cur->type, "int", 3) == 0) { 00167 LENGTHEN_BUF2(13); 00168 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->start.tv_sec); 00169 } else if (strncmp(cur->type, "float", 5) == 0) { 00170 LENGTHEN_BUF2(31); 00171 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0); 00172 } else { 00173 /* char, hopefully */ 00174 LENGTHEN_BUF2(31); 00175 ast_localtime(&cdr->start, &tm, NULL); 00176 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00177 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00178 } 00179 } else if (strcmp(cur->name, "answer") == 0) { 00180 if (strncmp(cur->type, "int", 3) == 0) { 00181 LENGTHEN_BUF2(13); 00182 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->answer.tv_sec); 00183 } else if (strncmp(cur->type, "float", 5) == 0) { 00184 LENGTHEN_BUF2(31); 00185 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0); 00186 } else { 00187 /* char, hopefully */ 00188 LENGTHEN_BUF2(31); 00189 ast_localtime(&cdr->start, &tm, NULL); 00190 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00191 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00192 } 00193 } else if (strcmp(cur->name, "end") == 0) { 00194 if (strncmp(cur->type, "int", 3) == 0) { 00195 LENGTHEN_BUF2(13); 00196 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->end.tv_sec); 00197 } else if (strncmp(cur->type, "float", 5) == 0) { 00198 LENGTHEN_BUF2(31); 00199 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0); 00200 } else { 00201 /* char, hopefully */ 00202 LENGTHEN_BUF2(31); 00203 ast_localtime(&cdr->end, &tm, NULL); 00204 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00205 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00206 } 00207 } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) { 00208 if (cur->type[0] == 'i') { 00209 /* Get integer, no need to escape anything */ 00210 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00211 LENGTHEN_BUF2(13); 00212 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value); 00213 } else if (strncmp(cur->type, "float", 5) == 0) { 00214 struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer; 00215 LENGTHEN_BUF2(31); 00216 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0); 00217 } else { 00218 /* Char field, probably */ 00219 struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer; 00220 LENGTHEN_BUF2(31); 00221 ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0); 00222 } 00223 } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) { 00224 if (strncmp(cur->type, "int", 3) == 0) { 00225 /* Integer, no need to escape anything */ 00226 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1); 00227 LENGTHEN_BUF2(13); 00228 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value); 00229 } else { 00230 /* Although this is a char field, there are no special characters in the values for these fields */ 00231 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00232 LENGTHEN_BUF2(31); 00233 ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value); 00234 } 00235 } else { 00236 /* Arbitrary field, could be anything */ 00237 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00238 if (strncmp(cur->type, "int", 3) == 0) { 00239 long long whatever; 00240 if (value && sscanf(value, "%30lld", &whatever) == 1) { 00241 LENGTHEN_BUF2(26); 00242 ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever); 00243 } else { 00244 LENGTHEN_BUF2(2); 00245 ast_str_append(&sql2, 0, "%s0", first ? "" : ","); 00246 } 00247 } else if (strncmp(cur->type, "float", 5) == 0) { 00248 long double whatever; 00249 if (value && sscanf(value, "%30Lf", &whatever) == 1) { 00250 LENGTHEN_BUF2(51); 00251 ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever); 00252 } else { 00253 LENGTHEN_BUF2(2); 00254 ast_str_append(&sql2, 0, "%s0", first ? "" : ","); 00255 } 00256 /* XXX Might want to handle dates, times, and other misc fields here XXX */ 00257 } else { 00258 if (value) 00259 PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL); 00260 else 00261 escapebuf[0] = '\0'; 00262 LENGTHEN_BUF2(strlen(escapebuf) + 3); 00263 ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf); 00264 } 00265 } 00266 first = 0; 00267 } 00268 AST_RWLIST_UNLOCK(&psql_columns); 00269 LENGTHEN_BUF1(ast_str_strlen(sql2) + 2); 00270 ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2)); 00271 ast_verb(11, "[%s]\n", ast_str_buffer(sql)); 00272 00273 ast_debug(2, "inserting a CDR record.\n"); 00274 00275 /* Test to be sure we're still connected... */ 00276 /* If we're connected, and connection is working, good. */ 00277 /* Otherwise, attempt reconnect. If it fails... sorry... */ 00278 if (PQstatus(conn) == CONNECTION_OK) { 00279 connected = 1; 00280 } else { 00281 ast_log(LOG_ERROR, "Connection was lost... attempting to reconnect.\n"); 00282 PQreset(conn); 00283 if (PQstatus(conn) == CONNECTION_OK) { 00284 ast_log(LOG_ERROR, "Connection reestablished.\n"); 00285 connected = 1; 00286 } else { 00287 pgerror = PQerrorMessage(conn); 00288 ast_log(LOG_ERROR, "Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); 00289 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00290 PQfinish(conn); 00291 conn = NULL; 00292 connected = 0; 00293 ast_mutex_unlock(&pgsql_lock); 00294 ast_free(sql); 00295 ast_free(sql2); 00296 return -1; 00297 } 00298 } 00299 result = PQexec(conn, ast_str_buffer(sql)); 00300 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00301 pgerror = PQresultErrorMessage(result); 00302 ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n"); 00303 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00304 ast_log(LOG_ERROR, "Connection may have been lost... attempting to reconnect.\n"); 00305 PQreset(conn); 00306 if (PQstatus(conn) == CONNECTION_OK) { 00307 ast_log(LOG_ERROR, "Connection reestablished.\n"); 00308 connected = 1; 00309 PQclear(result); 00310 result = PQexec(conn, ast_str_buffer(sql)); 00311 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00312 pgerror = PQresultErrorMessage(result); 00313 ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); 00314 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00315 } 00316 } 00317 ast_mutex_unlock(&pgsql_lock); 00318 PQclear(result); 00319 ast_free(sql); 00320 ast_free(sql2); 00321 return -1; 00322 } 00323 PQclear(result); 00324 ast_free(sql); 00325 ast_free(sql2); 00326 } 00327 ast_mutex_unlock(&pgsql_lock); 00328 return 0; 00329 }
| static int reload | ( | void | ) | [static] |
Definition at line 581 of file cdr_pgsql.c.
References config_module().
00582 { 00583 return config_module(1); 00584 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 331 of file cdr_pgsql.c.
References ast_cdr_unregister(), ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
00332 { 00333 struct columns *current; 00334 ast_cdr_unregister(name); 00335 00336 /* Give all threads time to finish */ 00337 usleep(1); 00338 PQfinish(conn); 00339 00340 if (pghostname) 00341 ast_free(pghostname); 00342 if (pgdbname) 00343 ast_free(pgdbname); 00344 if (pgdbuser) 00345 ast_free(pgdbuser); 00346 if (pgpassword) 00347 ast_free(pgpassword); 00348 if (pgdbport) 00349 ast_free(pgdbport); 00350 if (table) 00351 ast_free(table); 00352 00353 AST_RWLIST_WRLOCK(&psql_columns); 00354 while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) { 00355 ast_free(current); 00356 } 00357 AST_RWLIST_UNLOCK(&psql_columns); 00358 00359 return 0; 00360 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 590 of file cdr_pgsql.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 590 of file cdr_pgsql.c.
char* config = "cdr_pgsql.conf" [static] |
Definition at line 56 of file cdr_pgsql.c.
PGconn* conn = NULL [static] |
Definition at line 63 of file cdr_pgsql.c.
int connected = 0 [static] |
Definition at line 58 of file cdr_pgsql.c.
Referenced by aji_initialize().
int maxsize = 512 [static] |
Definition at line 59 of file cdr_pgsql.c.
int maxsize2 = 512 [static] |
Definition at line 59 of file cdr_pgsql.c.
Referenced by pgsql_log().
char* name = "pgsql" [static] |
Definition at line 55 of file cdr_pgsql.c.
char * pgdbname = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
char * pgdbport = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
char * pgdbuser = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
char* pghostname = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
char * pgpassword = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |
Definition at line 61 of file cdr_pgsql.c.
Referenced by pgsql_log().
char * table = NULL [static] |
Definition at line 57 of file cdr_pgsql.c.
1.6.2