Fri Nov 12 11:54:40 2010

Asterisk developer's documentation


cdr_pgsql.c File Reference

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"
Include dependency graph for cdr_pgsql.c:

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_infoast_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

Detailed Description

PostgreSQL CDR logger.

Author:
Matthew D. Hardeman <mhardemn@papersoft.com>
ExtRef:
PostgreSQL http://www.postgresql.org/

See also

Definition in file cdr_pgsql.c.


Define Documentation

#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.


Function Documentation

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 }


Variable Documentation

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.

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.


Generated by  doxygen 1.6.2