#include "asterisk.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_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const char | config [] = "cdr_pgsql.conf" |
static PGconn * | conn = NULL |
static int | connected = 0 |
static char * | encoding = NULL |
static int | maxsize = 512 |
static int | maxsize2 = 512 |
static const 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_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
static char * | table = NULL |
static char * | tz = NULL |
Definition in file cdr_pgsql.c.
#define DATE_FORMAT "'%Y-%m-%d %T'" |
Definition at line 52 of file cdr_pgsql.c.
#define LENGTHEN_BUF1 | ( | size | ) |
Definition at line 75 of file cdr_pgsql.c.
#define LENGTHEN_BUF2 | ( | size | ) |
Definition at line 89 of file cdr_pgsql.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 650 of file cdr_pgsql.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 650 of file cdr_pgsql.c.
static int config_module | ( | int | reload | ) | [static] |
Definition at line 379 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_strdupa, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, columns::list, LOG_ERROR, LOG_WARNING, option_debug, pgsql_log(), unload_module, var, and version.
Referenced by load_module(), and reload().
00380 { 00381 struct ast_variable *var; 00382 char *pgerror; 00383 struct columns *cur; 00384 PGresult *result; 00385 const char *tmp; 00386 struct ast_config *cfg; 00387 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00388 00389 if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) { 00390 ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config); 00391 return -1; 00392 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00393 return 0; 00394 00395 if (!(var = ast_variable_browse(cfg, "global"))) { 00396 ast_config_destroy(cfg); 00397 return 0; 00398 } 00399 00400 if (!(tmp = ast_variable_retrieve(cfg, "global", "hostname"))) { 00401 ast_log(LOG_WARNING, "PostgreSQL server hostname not specified. Assuming unix socket connection\n"); 00402 tmp = ""; /* connect via UNIX-socket by default */ 00403 } 00404 00405 if (pghostname) 00406 ast_free(pghostname); 00407 if (!(pghostname = ast_strdup(tmp))) { 00408 ast_config_destroy(cfg); 00409 return -1; 00410 } 00411 00412 if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) { 00413 ast_log(LOG_WARNING, "PostgreSQL database not specified. Assuming asterisk\n"); 00414 tmp = "asteriskcdrdb"; 00415 } 00416 00417 if (pgdbname) 00418 ast_free(pgdbname); 00419 if (!(pgdbname = ast_strdup(tmp))) { 00420 ast_config_destroy(cfg); 00421 return -1; 00422 } 00423 00424 if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) { 00425 ast_log(LOG_WARNING, "PostgreSQL database user not specified. Assuming asterisk\n"); 00426 tmp = "asterisk"; 00427 } 00428 00429 if (pgdbuser) 00430 ast_free(pgdbuser); 00431 if (!(pgdbuser = ast_strdup(tmp))) { 00432 ast_config_destroy(cfg); 00433 return -1; 00434 } 00435 00436 if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { 00437 ast_log(LOG_WARNING, "PostgreSQL database password not specified. Assuming blank\n"); 00438 tmp = ""; 00439 } 00440 00441 if (pgpassword) 00442 ast_free(pgpassword); 00443 if (!(pgpassword = ast_strdup(tmp))) { 00444 ast_config_destroy(cfg); 00445 return -1; 00446 } 00447 00448 if (!(tmp = ast_variable_retrieve(cfg, "global", "port"))) { 00449 ast_log(LOG_WARNING, "PostgreSQL database port not specified. Using default 5432.\n"); 00450 tmp = "5432"; 00451 } 00452 00453 if (pgdbport) 00454 ast_free(pgdbport); 00455 if (!(pgdbport = ast_strdup(tmp))) { 00456 ast_config_destroy(cfg); 00457 return -1; 00458 } 00459 00460 if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) { 00461 ast_log(LOG_WARNING, "CDR table not specified. Assuming cdr\n"); 00462 tmp = "cdr"; 00463 } 00464 00465 if (table) 00466 ast_free(table); 00467 if (!(table = ast_strdup(tmp))) { 00468 ast_config_destroy(cfg); 00469 return -1; 00470 } 00471 00472 if (!(tmp = ast_variable_retrieve(cfg, "global", "encoding"))) { 00473 ast_log(LOG_WARNING, "Encoding not specified. Assuming LATIN9\n"); 00474 tmp = "LATIN9"; 00475 } 00476 00477 if (encoding) { 00478 ast_free(encoding); 00479 } 00480 if (!(encoding = ast_strdup(tmp))) { 00481 ast_config_destroy(cfg); 00482 return -1; 00483 } 00484 00485 if (!(tmp = ast_variable_retrieve(cfg, "global", "timezone"))) { 00486 tmp = ""; 00487 } 00488 00489 if (tz) { 00490 ast_free(tz); 00491 tz = NULL; 00492 } 00493 if (!ast_strlen_zero(tmp) && !(tz = ast_strdup(tmp))) { 00494 ast_config_destroy(cfg); 00495 return -1; 00496 } 00497 00498 if (option_debug) { 00499 if (ast_strlen_zero(pghostname)) { 00500 ast_debug(1, "using default unix socket\n"); 00501 } else { 00502 ast_debug(1, "got hostname of %s\n", pghostname); 00503 } 00504 ast_debug(1, "got port of %s\n", pgdbport); 00505 ast_debug(1, "got user of %s\n", pgdbuser); 00506 ast_debug(1, "got dbname of %s\n", pgdbname); 00507 ast_debug(1, "got password of %s\n", pgpassword); 00508 ast_debug(1, "got sql table name of %s\n", table); 00509 ast_debug(1, "got encoding of %s\n", encoding); 00510 ast_debug(1, "got timezone of %s\n", tz); 00511 } 00512 00513 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00514 if (PQstatus(conn) != CONNECTION_BAD) { 00515 char sqlcmd[768]; 00516 char *fname, *ftype, *flen, *fnotnull, *fdef; 00517 int i, rows, version; 00518 ast_debug(1, "Successfully connected to PostgreSQL database.\n"); 00519 connected = 1; 00520 if (PQsetClientEncoding(conn, encoding)) { 00521 #ifdef HAVE_PGSQL_pg_encoding_to_char 00522 ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn))); 00523 #else 00524 ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default.\n", encoding); 00525 #endif 00526 } 00527 version = PQserverVersion(conn); 00528 00529 if (version >= 70300) { 00530 char *schemaname, *tablename; 00531 if (strchr(table, '.')) { 00532 schemaname = ast_strdupa(table); 00533 tablename = strchr(schemaname, '.'); 00534 *tablename++ = '\0'; 00535 } else { 00536 schemaname = ""; 00537 tablename = table; 00538 } 00539 00540 /* Escape special characters in schemaname */ 00541 if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) { 00542 char *tmp = schemaname, *ptr; 00543 00544 ptr = schemaname = alloca(strlen(tmp) * 2 + 1); 00545 for (; *tmp; tmp++) { 00546 if (strchr("\\'", *tmp)) { 00547 *ptr++ = *tmp; 00548 } 00549 *ptr++ = *tmp; 00550 } 00551 *ptr = '\0'; 00552 } 00553 /* Escape special characters in tablename */ 00554 if (strchr(tablename, '\\') || strchr(tablename, '\'')) { 00555 char *tmp = tablename, *ptr; 00556 00557 ptr = tablename = alloca(strlen(tmp) * 2 + 1); 00558 for (; *tmp; tmp++) { 00559 if (strchr("\\'", *tmp)) { 00560 *ptr++ = *tmp; 00561 } 00562 *ptr++ = *tmp; 00563 } 00564 *ptr = '\0'; 00565 } 00566 00567 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", 00568 tablename, 00569 ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'"); 00570 } else { 00571 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); 00572 } 00573 /* Query the columns */ 00574 result = PQexec(conn, sqlcmd); 00575 if (PQresultStatus(result) != PGRES_TUPLES_OK) { 00576 pgerror = PQresultErrorMessage(result); 00577 ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror); 00578 PQclear(result); 00579 unload_module(); 00580 return AST_MODULE_LOAD_DECLINE; 00581 } 00582 00583 rows = PQntuples(result); 00584 if (rows == 0) { 00585 ast_log(LOG_ERROR, "cdr_pgsql: Failed to query database columns. No columns found, does the table exist?\n"); 00586 PQclear(result); 00587 unload_module(); 00588 return AST_MODULE_LOAD_DECLINE; 00589 } 00590 00591 for (i = 0; i < rows; i++) { 00592 fname = PQgetvalue(result, i, 0); 00593 ftype = PQgetvalue(result, i, 1); 00594 flen = PQgetvalue(result, i, 2); 00595 fnotnull = PQgetvalue(result, i, 3); 00596 fdef = PQgetvalue(result, i, 4); 00597 if (atoi(flen) == -1) { 00598 /* For varchar columns, the maximum length is encoded in a different field */ 00599 flen = PQgetvalue(result, i, 5); 00600 } 00601 ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype); 00602 cur = ast_calloc(1, sizeof(*cur) + strlen(fname) + strlen(ftype) + 2); 00603 if (cur) { 00604 sscanf(flen, "%30d", &cur->len); 00605 cur->name = (char *)cur + sizeof(*cur); 00606 cur->type = (char *)cur + sizeof(*cur) + strlen(fname) + 1; 00607 strcpy(cur->name, fname); 00608 strcpy(cur->type, ftype); 00609 if (*fnotnull == 't') { 00610 cur->notnull = 1; 00611 } else { 00612 cur->notnull = 0; 00613 } 00614 if (!ast_strlen_zero(fdef)) { 00615 cur->hasdefault = 1; 00616 } else { 00617 cur->hasdefault = 0; 00618 } 00619 AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list); 00620 } 00621 } 00622 PQclear(result); 00623 } else { 00624 pgerror = PQerrorMessage(conn); 00625 ast_log(LOG_ERROR, "Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); 00626 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00627 connected = 0; 00628 } 00629 00630 ast_config_destroy(cfg); 00631 00632 return ast_cdr_register(name, ast_module_info->description, pgsql_log); 00633 }
static int load_module | ( | void | ) | [static] |
Definition at line 635 of file cdr_pgsql.c.
References AST_MODULE_LOAD_DECLINE, and config_module().
00636 { 00637 return config_module(0) ? AST_MODULE_LOAD_DECLINE : 0; 00638 }
static int pgsql_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 102 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_tvdiff_us(), ast_tvzero(), ast_verb, DATE_FORMAT, ast_cdr::end, first, columns::hasdefault, LENGTHEN_BUF1, LENGTHEN_BUF2, columns::list, LOG_ERROR, LOG_WARNING, maxsize2, columns::name, columns::notnull, pgsql_lock, ast_cdr::start, columns::type, and value.
Referenced by config_module().
00103 { 00104 struct ast_tm tm; 00105 char *pgerror; 00106 PGresult *result; 00107 00108 ast_mutex_lock(&pgsql_lock); 00109 00110 if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { 00111 conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); 00112 if (PQstatus(conn) != CONNECTION_BAD) { 00113 connected = 1; 00114 if (PQsetClientEncoding(conn, encoding)) { 00115 #ifdef HAVE_PGSQL_pg_encoding_to_char 00116 ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn))); 00117 #else 00118 ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default.\n", encoding); 00119 #endif 00120 } 00121 } else { 00122 pgerror = PQerrorMessage(conn); 00123 ast_log(LOG_ERROR, "Unable to connect to database server %s. Calls will not be logged!\n", pghostname); 00124 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00125 PQfinish(conn); 00126 conn = NULL; 00127 } 00128 } 00129 00130 if (connected) { 00131 struct columns *cur; 00132 struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); 00133 char buf[257], escapebuf[513], *value; 00134 int first = 1; 00135 00136 if (!sql || !sql2) { 00137 if (sql) { 00138 ast_free(sql); 00139 } 00140 if (sql2) { 00141 ast_free(sql2); 00142 } 00143 return -1; 00144 } 00145 00146 ast_str_set(&sql, 0, "INSERT INTO %s (", table); 00147 ast_str_set(&sql2, 0, " VALUES ("); 00148 00149 AST_RWLIST_RDLOCK(&psql_columns); 00150 AST_RWLIST_TRAVERSE(&psql_columns, cur, list) { 00151 /* For fields not set, simply skip them */ 00152 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00153 if (strcmp(cur->name, "calldate") == 0 && !value) { 00154 ast_cdr_getvar(cdr, "start", &value, buf, sizeof(buf), 0, 0); 00155 } 00156 if (!value) { 00157 if (cur->notnull && !cur->hasdefault) { 00158 /* Field is NOT NULL (but no default), must include it anyway */ 00159 LENGTHEN_BUF1(strlen(cur->name) + 2); 00160 ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name); 00161 LENGTHEN_BUF2(3); 00162 ast_str_append(&sql2, 0, "%s''", first ? "" : ","); 00163 first = 0; 00164 } 00165 continue; 00166 } 00167 00168 LENGTHEN_BUF1(strlen(cur->name) + 2); 00169 ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name); 00170 00171 if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) { 00172 if (strncmp(cur->type, "int", 3) == 0) { 00173 LENGTHEN_BUF2(13); 00174 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->start.tv_sec); 00175 } else if (strncmp(cur->type, "float", 5) == 0) { 00176 LENGTHEN_BUF2(31); 00177 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0); 00178 } else { 00179 /* char, hopefully */ 00180 LENGTHEN_BUF2(31); 00181 ast_localtime(&cdr->start, &tm, tz); 00182 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00183 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00184 } 00185 } else if (strcmp(cur->name, "answer") == 0) { 00186 if (strncmp(cur->type, "int", 3) == 0) { 00187 LENGTHEN_BUF2(13); 00188 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->answer.tv_sec); 00189 } else if (strncmp(cur->type, "float", 5) == 0) { 00190 LENGTHEN_BUF2(31); 00191 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0); 00192 } else { 00193 /* char, hopefully */ 00194 LENGTHEN_BUF2(31); 00195 ast_localtime(&cdr->answer, &tm, tz); 00196 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00197 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00198 } 00199 } else if (strcmp(cur->name, "end") == 0) { 00200 if (strncmp(cur->type, "int", 3) == 0) { 00201 LENGTHEN_BUF2(13); 00202 ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->end.tv_sec); 00203 } else if (strncmp(cur->type, "float", 5) == 0) { 00204 LENGTHEN_BUF2(31); 00205 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0); 00206 } else { 00207 /* char, hopefully */ 00208 LENGTHEN_BUF2(31); 00209 ast_localtime(&cdr->end, &tm, tz); 00210 ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00211 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf); 00212 } 00213 } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) { 00214 if (cur->type[0] == 'i') { 00215 /* Get integer, no need to escape anything */ 00216 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00217 LENGTHEN_BUF2(13); 00218 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value); 00219 } else if (strncmp(cur->type, "float", 5) == 0) { 00220 struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer; 00221 LENGTHEN_BUF2(31); 00222 ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0)); 00223 } else { 00224 /* Char field, probably */ 00225 struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer; 00226 LENGTHEN_BUF2(31); 00227 ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0)); 00228 } 00229 } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) { 00230 if (strncmp(cur->type, "int", 3) == 0) { 00231 /* Integer, no need to escape anything */ 00232 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1); 00233 LENGTHEN_BUF2(13); 00234 ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value); 00235 } else { 00236 /* Although this is a char field, there are no special characters in the values for these fields */ 00237 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00238 LENGTHEN_BUF2(31); 00239 ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value); 00240 } 00241 } else { 00242 /* Arbitrary field, could be anything */ 00243 ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0); 00244 if (strncmp(cur->type, "int", 3) == 0) { 00245 long long whatever; 00246 if (value && sscanf(value, "%30lld", &whatever) == 1) { 00247 LENGTHEN_BUF2(26); 00248 ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever); 00249 } else { 00250 LENGTHEN_BUF2(2); 00251 ast_str_append(&sql2, 0, "%s0", first ? "" : ","); 00252 } 00253 } else if (strncmp(cur->type, "float", 5) == 0) { 00254 long double whatever; 00255 if (value && sscanf(value, "%30Lf", &whatever) == 1) { 00256 LENGTHEN_BUF2(51); 00257 ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever); 00258 } else { 00259 LENGTHEN_BUF2(2); 00260 ast_str_append(&sql2, 0, "%s0", first ? "" : ","); 00261 } 00262 /* XXX Might want to handle dates, times, and other misc fields here XXX */ 00263 } else { 00264 if (value) 00265 PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL); 00266 else 00267 escapebuf[0] = '\0'; 00268 LENGTHEN_BUF2(strlen(escapebuf) + 3); 00269 ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf); 00270 } 00271 } 00272 first = 0; 00273 } 00274 AST_RWLIST_UNLOCK(&psql_columns); 00275 LENGTHEN_BUF1(ast_str_strlen(sql2) + 2); 00276 ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2)); 00277 ast_verb(11, "[%s]\n", ast_str_buffer(sql)); 00278 00279 ast_debug(2, "inserting a CDR record.\n"); 00280 00281 /* Test to be sure we're still connected... */ 00282 /* If we're connected, and connection is working, good. */ 00283 /* Otherwise, attempt reconnect. If it fails... sorry... */ 00284 if (PQstatus(conn) == CONNECTION_OK) { 00285 connected = 1; 00286 } else { 00287 ast_log(LOG_ERROR, "Connection was lost... attempting to reconnect.\n"); 00288 PQreset(conn); 00289 if (PQstatus(conn) == CONNECTION_OK) { 00290 ast_log(LOG_ERROR, "Connection reestablished.\n"); 00291 connected = 1; 00292 } else { 00293 pgerror = PQerrorMessage(conn); 00294 ast_log(LOG_ERROR, "Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); 00295 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00296 PQfinish(conn); 00297 conn = NULL; 00298 connected = 0; 00299 ast_mutex_unlock(&pgsql_lock); 00300 ast_free(sql); 00301 ast_free(sql2); 00302 return -1; 00303 } 00304 } 00305 result = PQexec(conn, ast_str_buffer(sql)); 00306 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00307 pgerror = PQresultErrorMessage(result); 00308 ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n"); 00309 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00310 ast_log(LOG_ERROR, "Connection may have been lost... attempting to reconnect.\n"); 00311 PQreset(conn); 00312 if (PQstatus(conn) == CONNECTION_OK) { 00313 ast_log(LOG_ERROR, "Connection reestablished.\n"); 00314 connected = 1; 00315 PQclear(result); 00316 result = PQexec(conn, ast_str_buffer(sql)); 00317 if (PQresultStatus(result) != PGRES_COMMAND_OK) { 00318 pgerror = PQresultErrorMessage(result); 00319 ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); 00320 ast_log(LOG_ERROR, "Reason: %s\n", pgerror); 00321 } 00322 } 00323 ast_mutex_unlock(&pgsql_lock); 00324 PQclear(result); 00325 ast_free(sql); 00326 ast_free(sql2); 00327 return -1; 00328 } 00329 PQclear(result); 00330 ast_free(sql); 00331 ast_free(sql2); 00332 } 00333 ast_mutex_unlock(&pgsql_lock); 00334 return 0; 00335 }
static int reload | ( | void | ) | [static] |
Definition at line 640 of file cdr_pgsql.c.
References config_module().
00641 { 00642 return config_module(1); 00643 }
static int unload_module | ( | void | ) | [static] |
Definition at line 337 of file cdr_pgsql.c.
References ast_cdr_unregister(), ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and columns::list.
00338 { 00339 struct columns *current; 00340 00341 ast_cdr_unregister(name); 00342 00343 PQfinish(conn); 00344 00345 if (pghostname) { 00346 ast_free(pghostname); 00347 } 00348 if (pgdbname) { 00349 ast_free(pgdbname); 00350 } 00351 if (pgdbuser) { 00352 ast_free(pgdbuser); 00353 } 00354 if (pgpassword) { 00355 ast_free(pgpassword); 00356 } 00357 if (pgdbport) { 00358 ast_free(pgdbport); 00359 } 00360 if (table) { 00361 ast_free(table); 00362 } 00363 if (encoding) { 00364 ast_free(encoding); 00365 } 00366 if (tz) { 00367 ast_free(tz); 00368 } 00369 00370 AST_RWLIST_WRLOCK(&psql_columns); 00371 while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) { 00372 ast_free(current); 00373 } 00374 AST_RWLIST_UNLOCK(&psql_columns); 00375 00376 return 0; 00377 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static] |
Definition at line 650 of file cdr_pgsql.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 650 of file cdr_pgsql.c.
const char config[] = "cdr_pgsql.conf" [static] |
Definition at line 55 of file cdr_pgsql.c.
PGconn* conn = NULL [static] |
Definition at line 62 of file cdr_pgsql.c.
int connected = 0 [static] |
Definition at line 57 of file cdr_pgsql.c.
Referenced by aji_initialize(), ast_channel_connected_line_macro(), ast_channel_queue_connected_line_update(), ast_channel_set_connected_line(), ast_channel_update_connected_line(), ast_connected_line_build_data(), ast_connected_line_parse_data(), connectedline_write(), dial_exec_full(), do_forward(), feature_request_and_dial(), handle_request_invite(), handle_request_update(), handle_response_invite(), misdn_queue_connected_line_update(), parked_call_exec(), sip_call(), socket_process(), and wait_for_winner().
char * encoding = NULL [static] |
int maxsize = 512 [static] |
Definition at line 58 of file cdr_pgsql.c.
int maxsize2 = 512 [static] |
Definition at line 58 of file cdr_pgsql.c.
const char name[] = "pgsql" [static] |
Definition at line 54 of file cdr_pgsql.c.
char * pgdbname = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
char * pgdbport = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
char * pgdbuser = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
char* pghostname = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
char * pgpassword = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
ast_mutex_t pgsql_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Definition at line 60 of file cdr_pgsql.c.
Referenced by config_pgsql(), destroy_pgsql(), find_table(), parse_config(), pgsql_log(), realtime_multi_pgsql(), realtime_pgsql(), require_pgsql(), store_pgsql(), unload_module(), update2_pgsql(), and update_pgsql().
char * table = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
char * tz = NULL [static] |
Definition at line 56 of file cdr_pgsql.c.
Referenced by ast_get_indication_zone(), ast_tone_zone_ref(), ast_tone_zone_unref(), ast_unregister_indication_country(), ast_var_indications(), ast_var_indications_table(), complete_country(), complete_indications(), handle_cli_indication_add(), handle_cli_indication_remove(), handle_cli_indication_show(), and in_band_indication().