Tue Nov 4 13:20:43 2008

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

 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"PostgreSQL RealTime Configuration Driver",.load=load_module,.unload=unload_module,.reload=reload)
 AST_MUTEX_DEFINE_STATIC (pgsql_lock)
static struct ast_configconfig_pgsql (const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
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_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
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

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"PostgreSQL RealTime Configuration Driver"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

AST_MUTEX_DEFINE_STATIC ( pgsql_lock   ) 

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 491 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_reconnect(), pgsqlConn, and RES_CONFIG_PGSQL_CONF.

00494 {
00495    PGresult *result = NULL;
00496    long num_rows;
00497    struct ast_variable *new_v;
00498    struct ast_category *cur_cat = NULL;
00499    char sqlbuf[1024] = "";
00500    char *sql = sqlbuf;
00501    size_t sqlleft = sizeof(sqlbuf);
00502    char last[80] = "";
00503    int last_cat_metric = 0;
00504 
00505    last[0] = '\0';
00506 
00507    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
00508       ast_log(LOG_WARNING, "Postgresql RealTime: Cannot configure myself.\n");
00509       return NULL;
00510    }
00511 
00512    ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
00513    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
00514    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00515 
00516    ast_log(LOG_DEBUG, "Postgresql RealTime: Static SQL: %s\n", sqlbuf);
00517 
00518    /* We now have our complete statement; Lets connect to the server and execute it. */
00519    ast_mutex_lock(&pgsql_lock);
00520    if (!pgsql_reconnect(database)) {
00521       ast_mutex_unlock(&pgsql_lock);
00522       return NULL;
00523    }
00524 
00525    if (!(result = PQexec(pgsqlConn, sqlbuf))) {
00526       ast_log(LOG_WARNING,
00527             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00528       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00529       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00530             PQerrorMessage(pgsqlConn));
00531       ast_mutex_unlock(&pgsql_lock);
00532       return NULL;
00533    } else {
00534       ExecStatusType result_status = PQresultStatus(result);
00535       if (result_status != PGRES_COMMAND_OK
00536          && result_status != PGRES_TUPLES_OK
00537          && result_status != PGRES_NONFATAL_ERROR) {
00538          ast_log(LOG_WARNING,
00539                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00540          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00541          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00542                PQresultErrorMessage(result), PQresStatus(result_status));
00543          ast_mutex_unlock(&pgsql_lock);
00544          return NULL;
00545       }
00546    }
00547 
00548    if ((num_rows = PQntuples(result)) > 0) {
00549       int rowIndex = 0;
00550 
00551       ast_log(LOG_DEBUG, "Postgresql RealTime: Found %ld rows.\n", num_rows);
00552 
00553       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00554          char *field_category = PQgetvalue(result, rowIndex, 0);
00555          char *field_var_name = PQgetvalue(result, rowIndex, 1);
00556          char *field_var_val = PQgetvalue(result, rowIndex, 2);
00557          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
00558          if (!strcmp(field_var_name, "#include")) {
00559             if (!ast_config_internal_load(field_var_val, cfg, 0)) {
00560                PQclear(result);
00561                ast_mutex_unlock(&pgsql_lock);
00562                return NULL;
00563             }
00564             continue;
00565          }
00566 
00567          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
00568             cur_cat = ast_category_new(field_category);
00569             if (!cur_cat)
00570                break;
00571             strcpy(last, field_category);
00572             last_cat_metric = atoi(field_cat_metric);
00573             ast_category_append(cfg, cur_cat);
00574          }
00575          new_v = ast_variable_new(field_var_name, field_var_val);
00576          ast_variable_append(cur_cat, new_v);
00577       }
00578    } else {
00579       ast_log(LOG_WARNING,
00580             "Postgresql RealTime: Could not find config '%s' in database.\n", file);
00581    }
00582 
00583    PQclear(result);
00584    ast_mutex_unlock(&pgsql_lock);
00585 
00586    return cfg;
00587 }

static int load_module ( void   )  [static]

Definition at line 597 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_reconnect(), and pgsqlConn.

00598 {
00599    if(!parse_config())
00600       return AST_MODULE_LOAD_DECLINE;
00601 
00602    ast_mutex_lock(&pgsql_lock);
00603 
00604    if (!pgsql_reconnect(NULL)) {
00605       ast_log(LOG_WARNING,
00606             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00607       ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00608             PQerrorMessage(pgsqlConn));
00609    }
00610 
00611    ast_config_engine_register(&pgsql_engine);
00612    if (option_verbose) {
00613       ast_verbose("Postgresql RealTime driver loaded.\n");
00614    }
00615    ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00616 
00617    ast_mutex_unlock(&pgsql_lock);
00618 
00619    return 0;
00620 }

static int parse_config ( void   )  [static]

Definition at line 671 of file res_config_pgsql.c.

References ast_config_destroy(), ast_config_load(), 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.

00672 {
00673    struct ast_config *config;
00674    const char *s;
00675 
00676    config = ast_config_load(RES_CONFIG_PGSQL_CONF);
00677 
00678    if (!config) {
00679       ast_log(LOG_WARNING, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF);
00680       return 0;
00681    }
00682    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
00683       ast_log(LOG_WARNING,
00684             "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
00685       strcpy(dbuser, "asterisk");
00686    } else {
00687       ast_copy_string(dbuser, s, sizeof(dbuser));
00688    }
00689 
00690    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
00691       ast_log(LOG_WARNING,
00692             "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
00693       strcpy(dbpass, "asterisk");
00694    } else {
00695       ast_copy_string(dbpass, s, sizeof(dbpass));
00696    }
00697 
00698    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
00699       ast_log(LOG_WARNING,
00700             "Postgresql RealTime: No database host found, using localhost via socket.\n");
00701       dbhost[0] = '\0';
00702    } else {
00703       ast_copy_string(dbhost, s, sizeof(dbhost));
00704    }
00705 
00706    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
00707       ast_log(LOG_WARNING,
00708             "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
00709       strcpy(dbname, "asterisk");
00710    } else {
00711       ast_copy_string(dbname, s, sizeof(dbname));
00712    }
00713 
00714    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
00715       ast_log(LOG_WARNING,
00716             "Postgresql RealTime: No database port found, using 5432 as default.\n");
00717       dbport = 5432;
00718    } else {
00719       dbport = atoi(s);
00720    }
00721 
00722    if (!ast_strlen_zero(dbhost)) {
00723       /* No socket needed */
00724    } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
00725       ast_log(LOG_WARNING,
00726             "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
00727       strcpy(dbsock, "/tmp/pgsql.sock");
00728    } else {
00729       ast_copy_string(dbsock, s, sizeof(dbsock));
00730    }
00731    ast_config_destroy(config);
00732 
00733    if (!ast_strlen_zero(dbhost)) {
00734       ast_log(LOG_DEBUG, "Postgresql RealTime Host: %s\n", dbhost);
00735       ast_log(LOG_DEBUG, "Postgresql RealTime Port: %i\n", dbport);
00736    } else {
00737       ast_log(LOG_DEBUG, "Postgresql RealTime Socket: %s\n", dbsock);
00738    }
00739    ast_log(LOG_DEBUG, "Postgresql RealTime User: %s\n", dbuser);
00740    ast_log(LOG_DEBUG, "Postgresql RealTime Password: %s\n", dbpass);
00741    ast_log(LOG_DEBUG, "Postgresql RealTime DBName: %s\n", dbname);
00742 
00743    return 1;
00744 }

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

Definition at line 746 of file res_config_pgsql.c.

References 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().

00747 {
00748    char my_database[50];
00749 
00750    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
00751 
00752    /* mutex lock should have been locked before calling this function. */
00753 
00754    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
00755       PQfinish(pgsqlConn);
00756       pgsqlConn = NULL;
00757    }
00758 
00759    if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(dbpass) && !ast_strlen_zero(my_database)) {
00760       char *connInfo = NULL;
00761       unsigned int size = 100 + strlen(dbhost)
00762          + strlen(dbuser)
00763          + strlen(dbpass)
00764          + strlen(my_database);
00765       
00766       if (!(connInfo = ast_malloc(size)))
00767          return 0;
00768       
00769       sprintf(connInfo, "host=%s port=%d dbname=%s user=%s password=%s",
00770                dbhost, dbport, my_database, dbuser, dbpass);
00771       ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00772       pgsqlConn = PQconnectdb(connInfo);
00773       ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00774       ast_free(connInfo);
00775       connInfo = NULL;
00776       ast_log(LOG_DEBUG, "pgsqlConn=%p\n", pgsqlConn);
00777       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00778          ast_log(LOG_DEBUG, "Postgresql RealTime: Successfully connected to database.\n");
00779          connect_time = time(NULL);
00780          return 1;
00781       } else {
00782          ast_log(LOG_ERROR,
00783                "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
00784                dbname, dbhost);
00785          ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00786                PQresultErrorMessage(NULL));
00787          return 0;
00788       }
00789    } else {
00790       ast_log(LOG_DEBUG, "Postgresql RealTime: Everything is fine.\n");
00791       return 1;
00792    }
00793 }

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

Definition at line 216 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_strlen_zero(), ast_variable_append(), ast_variable_new(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, pgsql_reconnect(), pgsqlConn, strsep(), and var.

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

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

Definition at line 79 of file res_config_pgsql.c.

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

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

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

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

00796 {
00797    char status[256], status2[100] = "";
00798    int ctime = time(NULL) - connect_time;
00799 
00800    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00801       if (!ast_strlen_zero(dbhost)) {
00802          snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
00803       } else if (!ast_strlen_zero(dbsock)) {
00804          snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
00805       } else {
00806          snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
00807       }
00808 
00809       if (!ast_strlen_zero(dbuser)) {
00810          snprintf(status2, 99, " with username %s", dbuser);
00811       }
00812 
00813       if (ctime > 31536000) {
00814          ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
00815                status, status2, ctime / 31536000, (ctime % 31536000) / 86400,
00816                (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00817       } else if (ctime > 86400) {
00818          ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
00819                status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60,
00820                ctime % 60);
00821       } else if (ctime > 3600) {
00822          ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2,
00823                ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00824       } else if (ctime > 60) {
00825          ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60,
00826                ctime % 60);
00827       } else {
00828          ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
00829       }
00830 
00831       return RESULT_SUCCESS;
00832    } else {
00833       return RESULT_FAILURE;
00834    }
00835 }

static int reload ( void   )  [static]

Definition at line 645 of file res_config_pgsql.c.

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

00646 {
00647    /* Aquire control before doing anything to the module itself. */
00648    ast_mutex_lock(&pgsql_lock);
00649 
00650    if (pgsqlConn) {
00651       PQfinish(pgsqlConn);
00652       pgsqlConn = NULL;
00653    };
00654    parse_config();
00655 
00656    if (!pgsql_reconnect(NULL)) {
00657       ast_log(LOG_WARNING,
00658             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00659       ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00660             PQerrorMessage(pgsqlConn));
00661    }
00662 
00663    ast_verbose(VERBOSE_PREFIX_2 "Postgresql RealTime reloaded.\n");
00664 
00665    /* Done reloading. Release lock so others can now use driver. */
00666    ast_mutex_unlock(&pgsql_lock);
00667 
00668    return 0;
00669 }

static int unload_module ( void   )  [static]

Definition at line 622 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, and pgsqlConn.

00623 {
00624    /* Aquire control before doing anything to the module itself. */
00625    ast_mutex_lock(&pgsql_lock);
00626 
00627    if (pgsqlConn) {
00628       PQfinish(pgsqlConn);
00629       pgsqlConn = NULL;
00630    };
00631    ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00632    ast_config_engine_deregister(&pgsql_engine);
00633    if (option_verbose) {
00634       ast_verbose("Postgresql RealTime unloaded.\n");
00635    }
00636 
00637    ast_module_user_hangup_all();
00638 
00639    /* Unlock so something else can destroy the lock. */
00640    ast_mutex_unlock(&pgsql_lock);
00641 
00642    return 0;
00643 }

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

Definition at line 379 of file res_config_pgsql.c.

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

00381 {
00382    PGresult *result = NULL;
00383    int numrows = 0, pgerror;
00384    char sql[256], escapebuf[513];
00385    const char *newparam, *newval;
00386 
00387    if (!table) {
00388       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00389       return -1;
00390    }
00391 
00392    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00393    newparam = va_arg(ap, const char *);
00394    newval = va_arg(ap, const char *);
00395    if (!newparam || !newval) {
00396       ast_log(LOG_WARNING,
00397             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00398       if (pgsqlConn) {
00399          PQfinish(pgsqlConn);
00400          pgsqlConn = NULL;
00401       };
00402       return -1;
00403    }
00404 
00405    /* Create the first part of the query using the first parameter/value pairs we just extracted
00406       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00407 
00408    PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00409    if (pgerror) {
00410       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00411       va_end(ap);
00412       return -1;
00413    }
00414    snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, escapebuf);
00415 
00416    while ((newparam = va_arg(ap, const char *))) {
00417       newval = va_arg(ap, const char *);
00418 
00419       PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00420       if (pgerror) {
00421          ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00422          va_end(ap);
00423          return -1;
00424       }
00425 
00426       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam,
00427              escapebuf);
00428    }
00429    va_end(ap);
00430 
00431    PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
00432    if (pgerror) {
00433       ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
00434       va_end(ap);
00435       return -1;
00436    }
00437 
00438    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield,
00439           escapebuf);
00440 
00441    ast_log(LOG_DEBUG, "Postgresql RealTime: Update SQL: %s\n", sql);
00442 
00443    /* We now have our complete statement; Lets connect to the server and execute it. */
00444    ast_mutex_lock(&pgsql_lock);
00445    if (!pgsql_reconnect(database)) {
00446       ast_mutex_unlock(&pgsql_lock);
00447       return -1;
00448    }
00449 
00450    if (!(result = PQexec(pgsqlConn, sql))) {
00451       ast_log(LOG_WARNING,
00452             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00453       ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00454       ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00455             PQerrorMessage(pgsqlConn));
00456       ast_mutex_unlock(&pgsql_lock);
00457       return -1;
00458    } else {
00459       ExecStatusType result_status = PQresultStatus(result);
00460       if (result_status != PGRES_COMMAND_OK
00461          && result_status != PGRES_TUPLES_OK
00462          && result_status != PGRES_NONFATAL_ERROR) {
00463          ast_log(LOG_WARNING,
00464                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00465          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00466          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00467                PQresultErrorMessage(result), PQresStatus(result_status));
00468          ast_mutex_unlock(&pgsql_lock);
00469          return -1;
00470       }
00471    }
00472 
00473    numrows = atoi(PQcmdTuples(result));
00474    ast_mutex_unlock(&pgsql_lock);
00475 
00476    ast_log(LOG_DEBUG, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows,
00477          table);
00478 
00479    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00480     * An integer greater than zero indicates the number of rows affected
00481     * Zero indicates that no records were updated
00482     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00483     */
00484 
00485    if (numrows >= 0)
00486       return (int) numrows;
00487 
00488    return -1;
00489 }


Variable Documentation

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 589 of file res_config_pgsql.c.

Referenced by load_module(), and unload_module().

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 Tue Nov 4 13:20:43 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7