Sat Aug 6 00:40:03 2011

Asterisk developer's documentation


res_config_pgsql.c File Reference

Postgresql plugin for Asterisk RealTime Architecture. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libpq-fe.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"

Go to the source code of this file.

Defines

#define MAX_DB_OPTION_SIZE   64
#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

Functions

static void __reg_module (void)
static void __unreg_module (void)
static struct ast_configconfig_pgsql (const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
static char * decode_chunk (char *chunk)
static char * encode_chunk (const char *chunk, char *buf, size_t len)
static int load_module (void)
static int parse_config (void)
static int pgsql_reconnect (const char *database)
static struct ast_configrealtime_multi_pgsql (const char *database, const char *table, va_list ap)
static struct ast_variablerealtime_pgsql (const char *database, const char *table, va_list ap)
static int realtime_pgsql_status (int fd, int argc, char **argv)
static int reload (void)
static int unload_module (void)
static int update_pgsql (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "PostgreSQL RealTime Configuration Driver" , .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload }
static const struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_realtime []
static char cli_realtime_pgsql_status_usage []
static time_t connect_time = 0
static char dbhost [MAX_DB_OPTION_SIZE] = ""
static char dbname [MAX_DB_OPTION_SIZE] = ""
static char dbpass [MAX_DB_OPTION_SIZE] = ""
static int dbport = 5432
static char dbsock [MAX_DB_OPTION_SIZE] = ""
static char dbuser [MAX_DB_OPTION_SIZE] = ""
static struct ast_config_engine pgsql_engine
static ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
PGconn * pgsqlConn = NULL


Detailed Description

Postgresql plugin for Asterisk RealTime Architecture.

Author:
Mark Spencer <markster@digium.com>

Manuel Guesdon <mguesdon@oxymium.net> - Postgresql RealTime Driver Author/Adaptor

Definition in file res_config_pgsql.c.


Define Documentation

#define MAX_DB_OPTION_SIZE   64

Definition at line 55 of file res_config_pgsql.c.

#define RES_CONFIG_PGSQL_CONF   "res_pgsql.conf"

Definition at line 51 of file res_config_pgsql.c.

Referenced by config_pgsql(), and parse_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 873 of file res_config_pgsql.c.

static void __unreg_module ( void   )  [static]

Definition at line 873 of file res_config_pgsql.c.

static struct ast_config* config_pgsql ( const char *  database,
const char *  table,
const char *  file,
struct ast_config cfg,
int  withcomments 
) [static]

Definition at line 522 of file res_config_pgsql.c.

References ast_build_string(), ast_category_append(), ast_category_new(), ast_config_internal_load(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_append(), ast_variable_new(), last, LOG_DEBUG, LOG_WARNING, pgsql_lock, pgsql_reconnect(), pgsqlConn, and RES_CONFIG_PGSQL_CONF.

00525 {
00526    PGresult *result = NULL;
00527    long num_rows;
00528    struct ast_variable *new_v;
00529    struct ast_category *cur_cat = NULL;
00530    char sqlbuf[1024] = "";
00531    char *sql = sqlbuf;
00532    size_t sqlleft = sizeof(sqlbuf);
00533    char last[80] = "";
00534    int last_cat_metric = 0;
00535 
00536    last[0] = '\0';
00537 
00538    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
00539       ast_log(LOG_WARNING, "Postgresql RealTime: Cannot configure myself.\n");
00540       return NULL;
00541    }
00542 
00543    ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
00544    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
00545    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00546 
00547    ast_log(LOG_DEBUG, "Postgresql RealTime: Static SQL: %s\n", sqlbuf);
00548 
00549    /* We now have our complete statement; Lets connect to the server and execute it. */
00550    ast_mutex_lock(&pgsql_lock);
00551    if (!pgsql_reconnect(database)) {
00552       ast_mutex_unlock(&pgsql_lock);
00553       return NULL;
00554    }
00555 
00556    if (!(result = PQexec(pgsqlConn, sqlbuf))) {
00557       ast_log(LOG_WARNING,
00558             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00559       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00560       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00561             PQerrorMessage(pgsqlConn));
00562       ast_mutex_unlock(&pgsql_lock);
00563       return NULL;
00564    } else {
00565       ExecStatusType result_status = PQresultStatus(result);
00566       if (result_status != PGRES_COMMAND_OK
00567          && result_status != PGRES_TUPLES_OK
00568          && result_status != PGRES_NONFATAL_ERROR) {
00569          ast_log(LOG_WARNING,
00570                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00571          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00572          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00573                PQresultErrorMessage(result), PQresStatus(result_status));
00574          ast_mutex_unlock(&pgsql_lock);
00575          return NULL;
00576       }
00577    }
00578 
00579    if ((num_rows = PQntuples(result)) > 0) {
00580       int rowIndex = 0;
00581 
00582       ast_log(LOG_DEBUG, "Postgresql RealTime: Found %ld rows.\n", num_rows);
00583 
00584       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00585          char *field_category = PQgetvalue(result, rowIndex, 0);
00586          char *field_var_name = PQgetvalue(result, rowIndex, 1);
00587          char *field_var_val = PQgetvalue(result, rowIndex, 2);
00588          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
00589          if (!strcmp(field_var_name, "#include")) {
00590             if (!ast_config_internal_load(field_var_val, cfg, 0)) {
00591                PQclear(result);
00592                ast_mutex_unlock(&pgsql_lock);
00593                return NULL;
00594             }
00595             continue;
00596          }
00597 
00598          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
00599             cur_cat = ast_category_new(field_category);
00600             if (!cur_cat)
00601                break;
00602             strcpy(last, field_category);
00603             last_cat_metric = atoi(field_cat_metric);
00604             ast_category_append(cfg, cur_cat);
00605          }
00606          new_v = ast_variable_new(field_var_name, field_var_val);
00607          ast_variable_append(cur_cat, new_v);
00608       }
00609    } else {
00610       ast_log(LOG_WARNING,
00611             "Postgresql RealTime: Could not find config '%s' in database.\n", file);
00612    }
00613 
00614    PQclear(result);
00615    ast_mutex_unlock(&pgsql_lock);
00616 
00617    return cfg;
00618 }

static char* decode_chunk ( char *  chunk  )  [static]

Definition at line 98 of file res_config_pgsql.c.

00099 {
00100    char *orig = chunk;
00101    for (; *chunk; chunk++) {
00102       if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
00103          sscanf(chunk + 1, "%02hhX", chunk);
00104          memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
00105       }
00106    }
00107    return orig;
00108 }

static char* encode_chunk ( const char *  chunk,
char *  buf,
size_t  len 
) [static]

Definition at line 79 of file res_config_pgsql.c.

Referenced by realtime_multi_pgsql(), realtime_pgsql(), and update_pgsql().

00080 {
00081    char *cptr = buf;
00082    for (; *chunk && cptr < buf + len; chunk++) {
00083       if (strchr(";^", *chunk)) {
00084          snprintf(cptr, buf + len - cptr, "^%02hhX", *chunk);
00085          cptr += 3;
00086       } else {
00087          *cptr++ = *chunk;
00088       }
00089    }
00090    if (cptr < buf + len) {
00091       *cptr = '\0';
00092    } else {
00093       buf[len - 1] = '\0';
00094    }
00095    return buf;
00096 }

static int load_module ( void   )  [static]

Definition at line 628 of file res_config_pgsql.c.

References ast_cli_register_multiple(), ast_config_engine_register(), ast_log(), AST_MODULE_LOAD_DECLINE, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), cli_realtime, LOG_DEBUG, LOG_WARNING, option_verbose, parse_config(), pgsql_engine, pgsql_lock, pgsql_reconnect(), and pgsqlConn.

00629 {
00630    if(!parse_config())
00631       return AST_MODULE_LOAD_DECLINE;
00632 
00633    ast_mutex_lock(&pgsql_lock);
00634 
00635    if (!pgsql_reconnect(NULL)) {
00636       ast_log(LOG_WARNING,
00637             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00638       ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00639             PQerrorMessage(pgsqlConn));
00640    }
00641 
00642    ast_config_engine_register(&pgsql_engine);
00643    if (option_verbose) {
00644       ast_verbose("Postgresql RealTime driver loaded.\n");
00645    }
00646    ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00647 
00648    ast_mutex_unlock(&pgsql_lock);
00649 
00650    return 0;
00651 }

static int parse_config ( void   )  [static]

Definition at line 702 of file res_config_pgsql.c.

References ast_config_destroy(), ast_config_load(), ast_copy_string(), ast_log(), ast_strlen_zero(), ast_variable_retrieve(), config, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_DEBUG, LOG_WARNING, RES_CONFIG_PGSQL_CONF, and s.

00703 {
00704    struct ast_config *config;
00705    const char *s;
00706 
00707    config = ast_config_load(RES_CONFIG_PGSQL_CONF);
00708 
00709    if (!config) {
00710       ast_log(LOG_WARNING, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF);
00711       return 0;
00712    }
00713    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
00714       ast_log(LOG_WARNING,
00715             "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
00716       strcpy(dbuser, "asterisk");
00717    } else {
00718       ast_copy_string(dbuser, s, sizeof(dbuser));
00719    }
00720 
00721    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
00722       ast_log(LOG_WARNING,
00723             "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
00724       strcpy(dbpass, "asterisk");
00725    } else {
00726       ast_copy_string(dbpass, s, sizeof(dbpass));
00727    }
00728 
00729    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
00730       ast_log(LOG_WARNING,
00731             "Postgresql RealTime: No database host found, using localhost via socket.\n");
00732       dbhost[0] = '\0';
00733    } else {
00734       ast_copy_string(dbhost, s, sizeof(dbhost));
00735    }
00736 
00737    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
00738       ast_log(LOG_WARNING,
00739             "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
00740       strcpy(dbname, "asterisk");
00741    } else {
00742       ast_copy_string(dbname, s, sizeof(dbname));
00743    }
00744 
00745    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
00746       ast_log(LOG_WARNING,
00747             "Postgresql RealTime: No database port found, using 5432 as default.\n");
00748       dbport = 5432;
00749    } else {
00750       dbport = atoi(s);
00751    }
00752 
00753    if (!ast_strlen_zero(dbhost)) {
00754       /* No socket needed */
00755    } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
00756       ast_log(LOG_WARNING,
00757             "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
00758       strcpy(dbsock, "/tmp/pgsql.sock");
00759    } else {
00760       ast_copy_string(dbsock, s, sizeof(dbsock));
00761    }
00762    ast_config_destroy(config);
00763 
00764    if (!ast_strlen_zero(dbhost)) {
00765       ast_log(LOG_DEBUG, "Postgresql RealTime Host: %s\n", dbhost);
00766       ast_log(LOG_DEBUG, "Postgresql RealTime Port: %i\n", dbport);
00767    } else {
00768       ast_log(LOG_DEBUG, "Postgresql RealTime Socket: %s\n", dbsock);
00769    }
00770    ast_log(LOG_DEBUG, "Postgresql RealTime User: %s\n", dbuser);
00771    ast_log(LOG_DEBUG, "Postgresql RealTime Password: %s\n", dbpass);
00772    ast_log(LOG_DEBUG, "Postgresql RealTime DBName: %s\n", dbname);
00773 
00774    return 1;
00775 }

static int pgsql_reconnect ( const char *  database  )  [static]

Definition at line 777 of file res_config_pgsql.c.

References ast_copy_string(), ast_free, ast_log(), ast_malloc, ast_strlen_zero(), connect_time, dbhost, dbname, dbpass, dbport, dbsock, dbuser, LOG_DEBUG, LOG_ERROR, pgsqlConn, and S_OR.

Referenced by config_pgsql(), load_module(), realtime_multi_pgsql(), realtime_pgsql(), reload(), and update_pgsql().

00778 {
00779    char my_database[50];
00780 
00781    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
00782 
00783    /* mutex lock should have been locked before calling this function. */
00784 
00785    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
00786       PQfinish(pgsqlConn);
00787       pgsqlConn = NULL;
00788    }
00789 
00790    if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(dbpass) && !ast_strlen_zero(my_database)) {
00791       char *connInfo = NULL;
00792       unsigned int size = 100 + strlen(dbhost)
00793          + strlen(dbuser)
00794          + strlen(dbpass)
00795          + strlen(my_database);
00796       
00797       if (!(connInfo = ast_malloc(size)))
00798          return 0;
00799       
00800       sprintf(connInfo, "host=%s port=%d dbname=%s user=%s password=%s",
00801                dbhost, dbport, my_database, dbuser, dbpass);
00802       ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00803       pgsqlConn = PQconnectdb(connInfo);
00804       ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00805       ast_free(connInfo);
00806       connInfo = NULL;
00807       ast_log(LOG_DEBUG, "pgsqlConn=%p\n", pgsqlConn);
00808       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00809          ast_log(LOG_DEBUG, "Postgresql RealTime: Successfully connected to database.\n");
00810          connect_time = time(NULL);
00811          return 1;
00812       } else {
00813          ast_log(LOG_ERROR,
00814                "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
00815                dbname, dbhost);
00816          ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00817                PQresultErrorMessage(NULL));
00818          return 0;
00819       }
00820    } else {
00821       ast_log(LOG_DEBUG, "Postgresql RealTime: Everything is fine.\n");
00822       return 1;
00823    }
00824 }

static struct ast_config* realtime_multi_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 247 of file res_config_pgsql.c.

References ast_calloc, ast_category_append(), ast_category_new(), ast_category_rename(), ast_config_new(), ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), decode_chunk(), encode_chunk(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), pgsqlConn, and var.

00248 {
00249    PGresult *result = NULL;
00250    int num_rows = 0, pgerror;
00251    char sql[256], escapebuf[2049], semibuf[1024];
00252    const char *initfield = NULL;
00253    char *stringp;
00254    char *chunk;
00255    char *op;
00256    const char *newparam, *newval;
00257    struct ast_realloca ra;
00258    struct ast_variable *var = NULL;
00259    struct ast_config *cfg = NULL;
00260    struct ast_category *cat = NULL;
00261 
00262    if (!table) {
00263       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00264       return NULL;
00265    }
00266 
00267    memset(&ra, 0, sizeof(ra));
00268 
00269    if (!(cfg = ast_config_new()))
00270       return NULL;
00271 
00272    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00273    newparam = va_arg(ap, const char *);
00274    newval = va_arg(ap, const char *);
00275    if (!newparam || !newval) {
00276       ast_log(LOG_WARNING,
00277             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00278       if (pgsqlConn) {
00279          PQfinish(pgsqlConn);
00280          pgsqlConn = NULL;
00281       };
00282       return NULL;
00283    }
00284 
00285    initfield = ast_strdupa(newparam);
00286    if ((op = strchr(initfield, ' '))) {
00287       *op = '\0';
00288    }
00289 
00290    /* Create the first part of the query using the first parameter/value pairs we just extracted
00291       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00292 
00293    if (!strchr(newparam, ' '))
00294       op = " =";
00295    else
00296       op = "";
00297 
00298    PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00299    if (pgerror) {
00300       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00301       va_end(ap);
00302       return NULL;
00303    }
00304 
00305    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00306           escapebuf);
00307    while ((newparam = va_arg(ap, const char *))) {
00308       newval = va_arg(ap, const char *);
00309       if (!strchr(newparam, ' '))
00310          op = " =";
00311       else
00312          op = "";
00313 
00314       PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00315       if (pgerror) {
00316          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00317          va_end(ap);
00318          return NULL;
00319       }
00320 
00321       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00322              op, escapebuf);
00323    }
00324 
00325    if (initfield) {
00326       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00327    }
00328 
00329    va_end(ap);
00330 
00331    /* We now have our complete statement; Lets connect to the server and execute it. */
00332    ast_mutex_lock(&pgsql_lock);
00333    if (!pgsql_reconnect(database)) {
00334       ast_mutex_unlock(&pgsql_lock);
00335       return NULL;
00336    }
00337 
00338    if (!(result = PQexec(pgsqlConn, sql))) {
00339       ast_log(LOG_WARNING,
00340             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00341       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00342       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00343             PQerrorMessage(pgsqlConn));
00344       ast_mutex_unlock(&pgsql_lock);
00345       return NULL;
00346    } else {
00347       ExecStatusType result_status = PQresultStatus(result);
00348       if (result_status != PGRES_COMMAND_OK
00349          && result_status != PGRES_TUPLES_OK
00350          && result_status != PGRES_NONFATAL_ERROR) {
00351          ast_log(LOG_WARNING,
00352                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00353          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00354          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00355                PQresultErrorMessage(result), PQresStatus(result_status));
00356          ast_mutex_unlock(&pgsql_lock);
00357          return NULL;
00358       }
00359    }
00360 
00361    ast_log(LOG_DEBUG, "2Postgresql RealTime: Result=%p Query: %s\n", result, sql);
00362 
00363    if ((num_rows = PQntuples(result)) > 0) {
00364       int numFields = PQnfields(result);
00365       int i = 0;
00366       int rowIndex = 0;
00367       char **fieldnames = NULL;
00368 
00369       ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);
00370 
00371       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00372          ast_mutex_unlock(&pgsql_lock);
00373          PQclear(result);
00374          return NULL;
00375       }
00376       for (i = 0; i < numFields; i++)
00377          fieldnames[i] = PQfname(result, i);
00378 
00379       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00380          var = NULL;
00381          if (!(cat = ast_category_new("")))
00382             continue;
00383          for (i = 0; i < numFields; i++) {
00384             stringp = PQgetvalue(result, rowIndex, i);
00385             while (stringp) {
00386                chunk = strsep(&stringp, ";");
00387                if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
00388                   if (initfield && !strcmp(initfield, fieldnames[i])) {
00389                      ast_category_rename(cat, chunk);
00390                   }
00391                   var = ast_variable_new(fieldnames[i], chunk);
00392                   ast_variable_append(cat, var);
00393                }
00394             }
00395          }
00396          ast_category_append(cfg, cat);
00397       }
00398       ast_free(fieldnames);
00399    } else {
00400       ast_log(LOG_DEBUG,
00401             "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00402    }
00403 
00404    ast_mutex_unlock(&pgsql_lock);
00405    PQclear(result);
00406 
00407    return cfg;
00408 }

static struct ast_variable* realtime_pgsql ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 110 of file res_config_pgsql.c.

References ast_calloc, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strip(), ast_strlen_zero(), ast_variable_new(), decode_chunk(), encode_chunk(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_variable::next, pgsql_lock, pgsql_reconnect(), and var.

00111 {
00112    PGresult *result = NULL;
00113    int num_rows = 0, pgerror;
00114    char sql[256], escapebuf[2049], semibuf[1024];
00115    char *stringp;
00116    char *chunk;
00117    char *op;
00118    const char *newparam, *newval;
00119    struct ast_variable *var = NULL, *prev = NULL;
00120 
00121    if (!table) {
00122       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00123       return NULL;
00124    }
00125 
00126    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00127    newparam = va_arg(ap, const char *);
00128    newval = va_arg(ap, const char *);
00129    if (!newparam || !newval) {
00130       ast_log(LOG_WARNING,
00131             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00132       if (pgsqlConn) {
00133          PQfinish(pgsqlConn);
00134          pgsqlConn = NULL;
00135       };
00136       return NULL;
00137    }
00138 
00139    /* Create the first part of the query using the first parameter/value pairs we just extracted
00140       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00141    op = strchr(newparam, ' ') ? "" : " =";
00142 
00143    PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00144    if (pgerror) {
00145       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00146       va_end(ap);
00147       return NULL;
00148    }
00149 
00150    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00151           escapebuf);
00152    while ((newparam = va_arg(ap, const char *))) {
00153       newval = va_arg(ap, const char *);
00154       if (!strchr(newparam, ' '))
00155          op = " =";
00156       else
00157          op = "";
00158 
00159       PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00160       if (pgerror) {
00161          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00162          va_end(ap);
00163          return NULL;
00164       }
00165 
00166       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00167              op, escapebuf);
00168    }
00169    va_end(ap);
00170 
00171    /* We now have our complete statement; Lets connect to the server and execute it. */
00172    ast_mutex_lock(&pgsql_lock);
00173    if (!pgsql_reconnect(database)) {
00174       ast_mutex_unlock(&pgsql_lock);
00175       return NULL;
00176    }
00177 
00178    if (!(result = PQexec(pgsqlConn, sql))) {
00179       ast_log(LOG_WARNING,
00180             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00181       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00182       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00183             PQerrorMessage(pgsqlConn));
00184       ast_mutex_unlock(&pgsql_lock);
00185       return NULL;
00186    } else {
00187       ExecStatusType result_status = PQresultStatus(result);
00188       if (result_status != PGRES_COMMAND_OK
00189          && result_status != PGRES_TUPLES_OK
00190          && result_status != PGRES_NONFATAL_ERROR) {
00191          ast_log(LOG_WARNING,
00192                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00193          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00194          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00195                PQresultErrorMessage(result), PQresStatus(result_status));
00196          ast_mutex_unlock(&pgsql_lock);
00197          return NULL;
00198       }
00199    }
00200 
00201    ast_log(LOG_DEBUG, "Postgresql RealTime: Result=%p Query: %s\n", result, sql);
00202 
00203    if ((num_rows = PQntuples(result)) > 0) {
00204       int i = 0;
00205       int rowIndex = 0;
00206       int numFields = PQnfields(result);
00207       char **fieldnames = NULL;
00208 
00209       ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);
00210 
00211       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00212          ast_mutex_unlock(&pgsql_lock);
00213          PQclear(result);
00214          return NULL;
00215       }
00216       for (i = 0; i < numFields; i++)
00217          fieldnames[i] = PQfname(result, i);
00218       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00219          for (i = 0; i < numFields; i++) {
00220             stringp = PQgetvalue(result, rowIndex, i);
00221             while (stringp) {
00222                chunk = strsep(&stringp, ";");
00223                if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
00224                   if (prev) {
00225                      prev->next = ast_variable_new(fieldnames[i], chunk);
00226                      if (prev->next) {
00227                         prev = prev->next;
00228                      }
00229                   } else {
00230                      prev = var = ast_variable_new(fieldnames[i], chunk);
00231                   }
00232                }
00233             }
00234          }
00235       }
00236       ast_free(fieldnames);
00237    } else {
00238       ast_log(LOG_DEBUG, "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00239    }
00240 
00241    ast_mutex_unlock(&pgsql_lock);
00242    PQclear(result);
00243 
00244    return var;
00245 }

static int realtime_pgsql_status ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 826 of file res_config_pgsql.c.

References ast_cli(), ast_strlen_zero(), connect_time, dbhost, dbname, dbport, dbsock, dbuser, pgsqlConn, RESULT_FAILURE, and RESULT_SUCCESS.

00827 {
00828    char status[256], status2[100] = "";
00829    int ctime = time(NULL) - connect_time;
00830 
00831    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00832       if (!ast_strlen_zero(dbhost)) {
00833          snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
00834       } else if (!ast_strlen_zero(dbsock)) {
00835          snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
00836       } else {
00837          snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
00838       }
00839 
00840       if (!ast_strlen_zero(dbuser)) {
00841          snprintf(status2, 99, " with username %s", dbuser);
00842       }
00843 
00844       if (ctime > 31536000) {
00845          ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
00846                status, status2, ctime / 31536000, (ctime % 31536000) / 86400,
00847                (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00848       } else if (ctime > 86400) {
00849          ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
00850                status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60,
00851                ctime % 60);
00852       } else if (ctime > 3600) {
00853          ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2,
00854                ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00855       } else if (ctime > 60) {
00856          ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60,
00857                ctime % 60);
00858       } else {
00859          ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
00860       }
00861 
00862       return RESULT_SUCCESS;
00863    } else {
00864       return RESULT_FAILURE;
00865    }
00866 }

static int reload ( void   )  [static]

Definition at line 676 of file res_config_pgsql.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), LOG_DEBUG, LOG_WARNING, parse_config(), pgsql_lock, pgsql_reconnect(), pgsqlConn, and VERBOSE_PREFIX_2.

00677 {
00678    /* Aquire control before doing anything to the module itself. */
00679    ast_mutex_lock(&pgsql_lock);
00680 
00681    if (pgsqlConn) {
00682       PQfinish(pgsqlConn);
00683       pgsqlConn = NULL;
00684    };
00685    parse_config();
00686 
00687    if (!pgsql_reconnect(NULL)) {
00688       ast_log(LOG_WARNING,
00689             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00690       ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00691             PQerrorMessage(pgsqlConn));
00692    }
00693 
00694    ast_verbose(VERBOSE_PREFIX_2 "Postgresql RealTime reloaded.\n");
00695 
00696    /* Done reloading. Release lock so others can now use driver. */
00697    ast_mutex_unlock(&pgsql_lock);
00698 
00699    return 0;
00700 }

static int unload_module ( void   )  [static]

Definition at line 653 of file res_config_pgsql.c.

References ast_cli_unregister_multiple(), ast_config_engine_deregister(), ast_module_user_hangup_all, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), cli_realtime, option_verbose, pgsql_engine, pgsql_lock, and pgsqlConn.

00654 {
00655    /* Aquire control before doing anything to the module itself. */
00656    ast_mutex_lock(&pgsql_lock);
00657 
00658    if (pgsqlConn) {
00659       PQfinish(pgsqlConn);
00660       pgsqlConn = NULL;
00661    };
00662    ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00663    ast_config_engine_deregister(&pgsql_engine);
00664    if (option_verbose) {
00665       ast_verbose("Postgresql RealTime unloaded.\n");
00666    }
00667 
00668    ast_module_user_hangup_all();
00669 
00670    /* Unlock so something else can destroy the lock. */
00671    ast_mutex_unlock(&pgsql_lock);
00672 
00673    return 0;
00674 }

static int update_pgsql ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Definition at line 410 of file res_config_pgsql.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), encode_chunk(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, pgsql_lock, pgsql_reconnect(), and pgsqlConn.

00412 {
00413    PGresult *result = NULL;
00414    int numrows = 0, pgerror;
00415    char sql[256], escapebuf[2049], semibuf[1024];
00416    const char *newparam, *newval;
00417 
00418    if (!table) {
00419       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00420       return -1;
00421    }
00422 
00423    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00424    newparam = va_arg(ap, const char *);
00425    newval = va_arg(ap, const char *);
00426    if (!newparam || !newval) {
00427       ast_log(LOG_WARNING,
00428             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00429       if (pgsqlConn) {
00430          PQfinish(pgsqlConn);
00431          pgsqlConn = NULL;
00432       };
00433       return -1;
00434    }
00435 
00436    /* Create the first part of the query using the first parameter/value pairs we just extracted
00437       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00438 
00439    PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00440    if (pgerror) {
00441       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00442       va_end(ap);
00443       return -1;
00444    }
00445    snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, escapebuf);
00446 
00447    while ((newparam = va_arg(ap, const char *))) {
00448       newval = va_arg(ap, const char *);
00449 
00450       PQescapeStringConn(pgsqlConn, escapebuf, encode_chunk(newval, semibuf, sizeof(semibuf)), (sizeof(escapebuf) - 1) / 2, &pgerror);
00451       if (pgerror) {
00452          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00453          va_end(ap);
00454          return -1;
00455       }
00456 
00457       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam,
00458              escapebuf);
00459    }
00460    va_end(ap);
00461 
00462    PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
00463    if (pgerror) {
00464       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
00465       va_end(ap);
00466       return -1;
00467    }
00468 
00469    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield,
00470           escapebuf);
00471 
00472    ast_log(LOG_DEBUG, "Postgresql RealTime: Update SQL: %s\n", sql);
00473 
00474    /* We now have our complete statement; Lets connect to the server and execute it. */
00475    ast_mutex_lock(&pgsql_lock);
00476    if (!pgsql_reconnect(database)) {
00477       ast_mutex_unlock(&pgsql_lock);
00478       return -1;
00479    }
00480 
00481    if (!(result = PQexec(pgsqlConn, sql))) {
00482       ast_log(LOG_WARNING,
00483             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00484       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00485       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00486             PQerrorMessage(pgsqlConn));
00487       ast_mutex_unlock(&pgsql_lock);
00488       return -1;
00489    } else {
00490       ExecStatusType result_status = PQresultStatus(result);
00491       if (result_status != PGRES_COMMAND_OK
00492          && result_status != PGRES_TUPLES_OK
00493          && result_status != PGRES_NONFATAL_ERROR) {
00494          ast_log(LOG_WARNING,
00495                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00496          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00497          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00498                PQresultErrorMessage(result), PQresStatus(result_status));
00499          ast_mutex_unlock(&pgsql_lock);
00500          return -1;
00501       }
00502    }
00503 
00504    numrows = atoi(PQcmdTuples(result));
00505    ast_mutex_unlock(&pgsql_lock);
00506 
00507    ast_log(LOG_DEBUG, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows,
00508          table);
00509 
00510    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00511     * An integer greater than zero indicates the number of rows affected
00512     * Zero indicates that no records were updated
00513     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00514     */
00515 
00516    if (numrows >= 0)
00517       return (int) numrows;
00518 
00519    return -1;
00520 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "PostgreSQL RealTime Configuration Driver" , .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload } [static]

Definition at line 873 of file res_config_pgsql.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 873 of file res_config_pgsql.c.

struct ast_cli_entry cli_realtime[] [static]

Initial value:

 {
   { { "realtime", "pgsql", "status", NULL },
   realtime_pgsql_status, "Shows connection information for the Postgresql RealTime driver",
   cli_realtime_pgsql_status_usage },
}

Definition at line 73 of file res_config_pgsql.c.

char cli_realtime_pgsql_status_usage[] [static]

Initial value:

   "Usage: realtime pgsql status\n"
   "       Shows connection information for the Postgresql RealTime driver\n"

Definition at line 69 of file res_config_pgsql.c.

time_t connect_time = 0 [static]

Definition at line 63 of file res_config_pgsql.c.

Referenced by pgsql_reconnect(), and realtime_pgsql_status().

char dbhost[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 57 of file res_config_pgsql.c.

Referenced by parse_config(), pgsql_reconnect(), and realtime_pgsql_status().

char dbname[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 60 of file res_config_pgsql.c.

char dbpass[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 59 of file res_config_pgsql.c.

Referenced by parse_config(), and pgsql_reconnect().

int dbport = 5432 [static]

Definition at line 62 of file res_config_pgsql.c.

Referenced by parse_config(), pgsql_reconnect(), and realtime_pgsql_status().

char dbsock[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 61 of file res_config_pgsql.c.

Referenced by parse_config(), pgsql_reconnect(), and realtime_pgsql_status().

char dbuser[MAX_DB_OPTION_SIZE] = "" [static]

Definition at line 58 of file res_config_pgsql.c.

struct ast_config_engine pgsql_engine [static]

Definition at line 620 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

ast_mutex_t pgsql_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 49 of file res_config_pgsql.c.

PGconn* pgsqlConn = NULL

Definition at line 53 of file res_config_pgsql.c.

Referenced by config_pgsql(), load_module(), pgsql_reconnect(), realtime_multi_pgsql(), realtime_pgsql_status(), reload(), unload_module(), and update_pgsql().


Generated on Sat Aug 6 00:40:03 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7