Wed Aug 18 22:34:05 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"

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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 93 of file cdr_pgsql.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 597 of file cdr_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 597 of file cdr_pgsql.c.

static int config_module ( int  reload  )  [static]

Definition at line 369 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_FILEUNCHANGED, columns::list, LOG_ERROR, LOG_WARNING, option_debug, pgsql_log(), unload_module(), var, and version.

Referenced by load_module(), and reload().

00370 {
00371    struct ast_variable *var;
00372    char *pgerror;
00373    struct columns *cur;
00374    PGresult *result;
00375    const char *tmp;
00376    struct ast_config *cfg;
00377    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00378 
00379    if ((cfg = ast_config_load(config, config_flags)) == NULL) {
00380       ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
00381       return -1;
00382    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00383       return 0;
00384 
00385    if (!(var = ast_variable_browse(cfg, "global"))) {
00386       ast_config_destroy(cfg);
00387       return 0;
00388    }
00389 
00390    if (!(tmp = ast_variable_retrieve(cfg, "global", "hostname"))) {
00391       ast_log(LOG_WARNING, "PostgreSQL server hostname not specified.  Assuming unix socket connection\n");
00392       tmp = "";   /* connect via UNIX-socket by default */
00393    }
00394 
00395    if (pghostname)
00396       ast_free(pghostname);
00397    if (!(pghostname = ast_strdup(tmp))) {
00398       ast_config_destroy(cfg);
00399       return -1;
00400    }
00401 
00402    if (!(tmp = ast_variable_retrieve(cfg, "global", "dbname"))) {
00403       ast_log(LOG_WARNING, "PostgreSQL database not specified.  Assuming asterisk\n");
00404       tmp = "asteriskcdrdb";
00405    }
00406 
00407    if (pgdbname)
00408       ast_free(pgdbname);
00409    if (!(pgdbname = ast_strdup(tmp))) {
00410       ast_config_destroy(cfg);
00411       return -1;
00412    }
00413 
00414    if (!(tmp = ast_variable_retrieve(cfg, "global", "user"))) {
00415       ast_log(LOG_WARNING, "PostgreSQL database user not specified.  Assuming asterisk\n");
00416       tmp = "asterisk";
00417    }
00418 
00419    if (pgdbuser)
00420       ast_free(pgdbuser);
00421    if (!(pgdbuser = ast_strdup(tmp))) {
00422       ast_config_destroy(cfg);
00423       return -1;
00424    }
00425 
00426    if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) {
00427       ast_log(LOG_WARNING, "PostgreSQL database password not specified.  Assuming blank\n");
00428       tmp = "";
00429    }
00430 
00431    if (pgpassword)
00432       ast_free(pgpassword);
00433    if (!(pgpassword = ast_strdup(tmp))) {
00434       ast_config_destroy(cfg);
00435       return -1;
00436    }
00437 
00438    if (!(tmp = ast_variable_retrieve(cfg, "global", "port"))) {
00439       ast_log(LOG_WARNING, "PostgreSQL database port not specified.  Using default 5432.\n");
00440       tmp = "5432";
00441    }
00442 
00443    if (pgdbport)
00444       ast_free(pgdbport);
00445    if (!(pgdbport = ast_strdup(tmp))) {
00446       ast_config_destroy(cfg);
00447       return -1;
00448    }
00449 
00450    if (!(tmp = ast_variable_retrieve(cfg, "global", "table"))) {
00451       ast_log(LOG_WARNING, "CDR table not specified.  Assuming cdr\n");
00452       tmp = "cdr";
00453    }
00454 
00455    if (table)
00456       ast_free(table);
00457    if (!(table = ast_strdup(tmp))) {
00458       ast_config_destroy(cfg);
00459       return -1;
00460    }
00461 
00462    if (option_debug) {
00463       if (ast_strlen_zero(pghostname)) {
00464          ast_debug(1, "using default unix socket\n");
00465       } else {
00466          ast_debug(1, "got hostname of %s\n", pghostname);
00467       }
00468       ast_debug(1, "got port of %s\n", pgdbport);
00469       ast_debug(1, "got user of %s\n", pgdbuser);
00470       ast_debug(1, "got dbname of %s\n", pgdbname);
00471       ast_debug(1, "got password of %s\n", pgpassword);
00472       ast_debug(1, "got sql table name of %s\n", table);
00473    }
00474 
00475    conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00476    if (PQstatus(conn) != CONNECTION_BAD) {
00477       char sqlcmd[768];
00478       char *fname, *ftype, *flen, *fnotnull, *fdef;
00479       int i, rows, version;
00480       ast_debug(1, "Successfully connected to PostgreSQL database.\n");
00481       connected = 1;
00482       version = PQserverVersion(conn);
00483 
00484       if (version >= 70300) {
00485          char *schemaname, *tablename;
00486          if (strchr(table, '.')) {
00487             schemaname = ast_strdupa(table);
00488             tablename = strchr(schemaname, '.');
00489             *tablename++ = '\0';
00490          } else {
00491             schemaname = "";
00492             tablename = table;
00493          }
00494 
00495          /* Escape special characters in schemaname */
00496          if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
00497             char *tmp = schemaname, *ptr;
00498 
00499             ptr = schemaname = alloca(strlen(tmp) * 2 + 1);
00500             for (; *tmp; tmp++) {
00501                if (strchr("\\'", *tmp)) {
00502                   *ptr++ = *tmp;
00503                }
00504                *ptr++ = *tmp;
00505             }
00506             *ptr = '\0';
00507          }
00508          /* Escape special characters in tablename */
00509          if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
00510             char *tmp = tablename, *ptr;
00511 
00512             ptr = tablename = alloca(strlen(tmp) * 2 + 1);
00513             for (; *tmp; tmp++) {
00514                if (strchr("\\'", *tmp)) {
00515                   *ptr++ = *tmp;
00516                }
00517                *ptr++ = *tmp;
00518             }
00519             *ptr = '\0';
00520          }
00521 
00522          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",
00523             tablename,
00524             ast_strlen_zero(schemaname) ? "" : "'", ast_strlen_zero(schemaname) ? "current_schema()" : schemaname, ast_strlen_zero(schemaname) ? "" : "'");
00525       } else {
00526          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);
00527       }
00528       /* Query the columns */
00529       result = PQexec(conn, sqlcmd);
00530       if (PQresultStatus(result) != PGRES_TUPLES_OK) {
00531          pgerror = PQresultErrorMessage(result);
00532          ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
00533          PQclear(result);
00534          unload_module();
00535          return AST_MODULE_LOAD_DECLINE;
00536       }
00537 
00538       rows = PQntuples(result);
00539       for (i = 0; i < rows; i++) {
00540          fname = PQgetvalue(result, i, 0);
00541          ftype = PQgetvalue(result, i, 1);
00542          flen = PQgetvalue(result, i, 2);
00543          fnotnull = PQgetvalue(result, i, 3);
00544          fdef = PQgetvalue(result, i, 4);
00545          if (atoi(flen) == -1) {
00546             /* For varchar columns, the maximum length is encoded in a different field */
00547             flen = PQgetvalue(result, i, 5);
00548          }
00549          ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
00550          cur = ast_calloc(1, sizeof(*cur) + strlen(fname) + strlen(ftype) + 2);
00551          if (cur) {
00552             sscanf(flen, "%30d", &cur->len);
00553             cur->name = (char *)cur + sizeof(*cur);
00554             cur->type = (char *)cur + sizeof(*cur) + strlen(fname) + 1;
00555             strcpy(cur->name, fname);
00556             strcpy(cur->type, ftype);
00557             if (*fnotnull == 't') {
00558                cur->notnull = 1;
00559             } else {
00560                cur->notnull = 0;
00561             }
00562             if (!ast_strlen_zero(fdef)) {
00563                cur->hasdefault = 1;
00564             } else {
00565                cur->hasdefault = 0;
00566             }
00567             AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list);
00568          }
00569       }
00570       PQclear(result);
00571    } else {
00572       pgerror = PQerrorMessage(conn);
00573       ast_log(LOG_ERROR, "Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
00574       ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00575       connected = 0;
00576    }
00577 
00578    ast_config_destroy(cfg);
00579 
00580    return ast_cdr_register(name, ast_module_info->description, pgsql_log);
00581 }

static int load_module ( void   )  [static]

Definition at line 583 of file cdr_pgsql.c.

References AST_MODULE_LOAD_DECLINE, and config_module().

00584 {
00585    return config_module(0) ? AST_MODULE_LOAD_DECLINE : 0;
00586 }

static int pgsql_log ( struct ast_cdr cdr  )  [static]

Definition at line 109 of file cdr_pgsql.c.

References ast_cdr::answer, ast_calloc, 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_strftime(), ast_verb, buf, DATE_FORMAT, ast_cdr::end, columns::hasdefault, LENGTHEN_BUF1, LENGTHEN_BUF2, columns::list, LOG_ERROR, maxsize2, columns::name, columns::notnull, pgsql_lock, ast_cdr::start, and columns::type.

Referenced by config_module().

00110 {
00111    struct ast_tm tm;
00112    char *pgerror;
00113    PGresult *result;
00114 
00115    ast_mutex_lock(&pgsql_lock);
00116 
00117    if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
00118       conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
00119       if (PQstatus(conn) != CONNECTION_BAD) {
00120          connected = 1;
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       int lensql, lensql2, sizesql = maxsize, sizesql2 = maxsize2, newsize;
00133       char *sql = ast_calloc(sizeof(char), sizesql), *sql2 = ast_calloc(sizeof(char), sizesql2), *tmp, *value;
00134       char buf[257], escapebuf[513];
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       lensql = snprintf(sql, sizesql, "INSERT INTO %s (", table);
00147       lensql2 = snprintf(sql2, sizesql2, " 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                lensql += snprintf(sql + lensql, sizesql - lensql, "\"%s\",", cur->name);
00161                LENGTHEN_BUF2(3);
00162                strcat(sql2, "'',");
00163                lensql2 += 3;
00164             }
00165             continue;
00166          }
00167 
00168          LENGTHEN_BUF1(strlen(cur->name) + 2);
00169          lensql += snprintf(sql + lensql, sizesql - lensql, "\"%s\",", 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(12);
00174                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", (long) cdr->start.tv_sec);
00175             } else if (strncmp(cur->type, "float", 5) == 0) {
00176                LENGTHEN_BUF2(30);
00177                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
00178             } else {
00179                /* char, hopefully */
00180                LENGTHEN_BUF2(30);
00181                ast_localtime(&cdr->start, &tm, NULL);
00182                lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
00183             }
00184          } else if (strcmp(cur->name, "answer") == 0) {
00185             if (strncmp(cur->type, "int", 3) == 0) {
00186                LENGTHEN_BUF2(12);
00187                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", (long) cdr->answer.tv_sec);
00188             } else if (strncmp(cur->type, "float", 5) == 0) {
00189                LENGTHEN_BUF2(30);
00190                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
00191             } else {
00192                /* char, hopefully */
00193                LENGTHEN_BUF2(30);
00194                ast_localtime(&cdr->start, &tm, NULL);
00195                lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
00196             }
00197          } else if (strcmp(cur->name, "end") == 0) {
00198             if (strncmp(cur->type, "int", 3) == 0) {
00199                LENGTHEN_BUF2(12);
00200                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", (long) cdr->end.tv_sec);
00201             } else if (strncmp(cur->type, "float", 5) == 0) {
00202                LENGTHEN_BUF2(30);
00203                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
00204             } else {
00205                /* char, hopefully */
00206                LENGTHEN_BUF2(30);
00207                ast_localtime(&cdr->end, &tm, NULL);
00208                lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
00209             }
00210          } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
00211             if (cur->type[0] == 'i') {
00212                /* Get integer, no need to escape anything */
00213                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00214                LENGTHEN_BUF2(12);
00215                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%s", value);
00216             } else if (strncmp(cur->type, "float", 5) == 0) {
00217                struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
00218                LENGTHEN_BUF2(30);
00219                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
00220             } else {
00221                /* Char field, probably */
00222                struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
00223                LENGTHEN_BUF2(30);
00224                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%f'", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
00225             }
00226          } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
00227             if (strncmp(cur->type, "int", 3) == 0) {
00228                /* Integer, no need to escape anything */
00229                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1);
00230                LENGTHEN_BUF2(12);
00231                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%s", value);
00232             } else {
00233                /* Although this is a char field, there are no special characters in the values for these fields */
00234                ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00235                LENGTHEN_BUF2(30);
00236                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%s'", value);
00237             }
00238          } else {
00239             /* Arbitrary field, could be anything */
00240             ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
00241             if (strncmp(cur->type, "int", 3) == 0) {
00242                long long whatever;
00243                if (value && sscanf(value, "%30lld", &whatever) == 1) {
00244                   LENGTHEN_BUF2(25);
00245                   lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lld", whatever);
00246                } else {
00247                   LENGTHEN_BUF2(1);
00248                   lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "0");
00249                }
00250             } else if (strncmp(cur->type, "float", 5) == 0) {
00251                long double whatever;
00252                if (value && sscanf(value, "%30Lf", &whatever) == 1) {
00253                   LENGTHEN_BUF2(50);
00254                   lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%30Lf", whatever);
00255                } else {
00256                   LENGTHEN_BUF2(1);
00257                   lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "0");
00258                }
00259             /* XXX Might want to handle dates, times, and other misc fields here XXX */
00260             } else {
00261                if (value)
00262                   PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL);
00263                else
00264                   escapebuf[0] = '\0';
00265                LENGTHEN_BUF2(strlen(escapebuf) + 2);
00266                lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%s'", escapebuf);
00267             }
00268          }
00269          LENGTHEN_BUF2(1);
00270          strcat(sql2 + lensql2, ",");
00271          lensql2++;
00272       }
00273       AST_RWLIST_UNLOCK(&psql_columns);
00274       LENGTHEN_BUF1(lensql2);
00275       sql[lensql - 1] = ')';
00276       sql2[lensql2 - 1] = ')';
00277       strcat(sql + lensql, sql2);
00278       ast_verb(11, "[%s]\n", sql);
00279 
00280       ast_debug(2, "inserting a CDR record.\n");
00281 
00282       /* Test to be sure we're still connected... */
00283       /* If we're connected, and connection is working, good. */
00284       /* Otherwise, attempt reconnect.  If it fails... sorry... */
00285       if (PQstatus(conn) == CONNECTION_OK) {
00286          connected = 1;
00287       } else {
00288          ast_log(LOG_ERROR, "Connection was lost... attempting to reconnect.\n");
00289          PQreset(conn);
00290          if (PQstatus(conn) == CONNECTION_OK) {
00291             ast_log(LOG_ERROR, "Connection reestablished.\n");
00292             connected = 1;
00293          } else {
00294             pgerror = PQerrorMessage(conn);
00295             ast_log(LOG_ERROR, "Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname);
00296             ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00297             PQfinish(conn);
00298             conn = NULL;
00299             connected = 0;
00300             ast_mutex_unlock(&pgsql_lock);
00301             ast_free(sql);
00302             ast_free(sql2);
00303             return -1;
00304          }
00305       }
00306       result = PQexec(conn, sql);
00307       if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00308          pgerror = PQresultErrorMessage(result);
00309          ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n");
00310          ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00311          ast_log(LOG_ERROR, "Connection may have been lost... attempting to reconnect.\n");
00312          PQreset(conn);
00313          if (PQstatus(conn) == CONNECTION_OK) {
00314             ast_log(LOG_ERROR, "Connection reestablished.\n");
00315             connected = 1;
00316             PQclear(result);
00317             result = PQexec(conn, sql);
00318             if (PQresultStatus(result) != PGRES_COMMAND_OK) {
00319                pgerror = PQresultErrorMessage(result);
00320                ast_log(LOG_ERROR, "HARD ERROR!  Attempted reconnection failed.  DROPPING CALL RECORD!\n");
00321                ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
00322             }
00323          }
00324          ast_mutex_unlock(&pgsql_lock);
00325          PQclear(result);
00326          ast_free(sql);
00327          ast_free(sql2);
00328          return -1;
00329       }
00330       PQclear(result);
00331       ast_free(sql);
00332       ast_free(sql2);
00333    }
00334    ast_mutex_unlock(&pgsql_lock);
00335    return 0;
00336 }

static int reload ( void   )  [static]

Definition at line 588 of file cdr_pgsql.c.

References config_module().

00589 {
00590    return config_module(1);
00591 }

static int unload_module ( void   )  [static]

Definition at line 338 of file cdr_pgsql.c.

References ast_cdr_unregister(), ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and columns::list.

00339 {
00340    struct columns *current;
00341    ast_cdr_unregister(name);
00342 
00343    /* Give all threads time to finish */
00344    usleep(1);
00345    PQfinish(conn);
00346 
00347    if (pghostname)
00348       ast_free(pghostname);
00349    if (pgdbname)
00350       ast_free(pgdbname);
00351    if (pgdbuser)
00352       ast_free(pgdbuser);
00353    if (pgpassword)
00354       ast_free(pgpassword);
00355    if (pgdbport)
00356       ast_free(pgdbport);
00357    if (table)
00358       ast_free(table);
00359 
00360    AST_RWLIST_WRLOCK(&psql_columns);
00361    while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
00362       ast_free(current);
00363    }
00364    AST_RWLIST_UNLOCK(&psql_columns);
00365 
00366    return 0;
00367 }


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 597 of file cdr_pgsql.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 597 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.

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 config_pgsql(), destroy_pgsql(), parse_config(), pgsql_log(), realtime_multi_pgsql(), realtime_pgsql(), require_pgsql(), store_pgsql(), unload_module(), and update_pgsql().

char * table = NULL [static]

Definition at line 57 of file cdr_pgsql.c.


Generated on Wed Aug 18 22:34:05 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7