Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:53 2007

Asterisk developer's documentation :: Codename Pineapple


res_config_pgsql.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Copyright (C) 1999-2005, Digium, Inc.
00005  * 
00006  * Manuel Guesdon <mguesdon@oxymium.net> - Postgresql RealTime Driver Author/Adaptor
00007  * Mark Spencer <markster@digium.com>  - Asterisk Author
00008  * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
00009  *
00010  * res_config_pgsql.c <Postgresql plugin for RealTime configuration engine>
00011  *
00012  * v1.0   - (07-11-05) - Initial version based on res_config_mysql v2.0
00013  */
00014 
00015 /*! \file
00016  *
00017  * \brief Postgresql plugin for Asterisk RealTime Architecture
00018  *
00019  * \author Mark Spencer <markster@digium.com>
00020  * \author Manuel Guesdon <mguesdon@oxymium.net> - Postgresql RealTime Driver Author/Adaptor
00021  *
00022  * \arg http://www.postgresql.org
00023  */
00024 
00025 /*** MODULEINFO
00026    <depend>pgsql</depend>
00027  ***/
00028 
00029 #include "asterisk.h"
00030 
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 48395 $")
00032 
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <libpq-fe.h>         /* PostgreSQL */
00037 
00038 #include "asterisk/file.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/cli.h"
00048 
00049 AST_MUTEX_DEFINE_STATIC(pgsql_lock);
00050 
00051 #define RES_CONFIG_PGSQL_CONF "res_pgsql.conf"
00052 
00053 PGconn *pgsqlConn = NULL;
00054 
00055 #define MAX_DB_OPTION_SIZE 64
00056 
00057 static char dbhost[MAX_DB_OPTION_SIZE] = "";
00058 static char dbuser[MAX_DB_OPTION_SIZE] = "";
00059 static char dbpass[MAX_DB_OPTION_SIZE] = "";
00060 static char dbname[MAX_DB_OPTION_SIZE] = "";
00061 static char dbsock[MAX_DB_OPTION_SIZE] = "";
00062 static int dbport = 5432;
00063 static time_t connect_time = 0;
00064 
00065 static int parse_config(void);
00066 static int pgsql_reconnect(const char *database);
00067 static int realtime_pgsql_status(int fd, int argc, char **argv);
00068 
00069 static const char cli_realtime_pgsql_status_usage[] =
00070    "Usage: realtime pgsql status\n"
00071    "       Shows connection information for the Postgresql RealTime driver\n";
00072 
00073 static struct ast_cli_entry cli_realtime[] = {
00074    { { "realtime", "pgsql", "status", NULL },
00075    realtime_pgsql_status, "Shows connection information for the Postgresql RealTime driver",
00076    cli_realtime_pgsql_status_usage },
00077 };
00078 
00079 static struct ast_variable *realtime_pgsql(const char *database, const char *table, va_list ap)
00080 {
00081    PGresult *result = NULL;
00082    int num_rows = 0;
00083    char sql[256];
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    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00113           newval);
00114    while ((newparam = va_arg(ap, const char *))) {
00115       newval = va_arg(ap, const char *);
00116       if (!strchr(newparam, ' '))
00117          op = " =";
00118       else
00119          op = "";
00120       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00121              op, newval);
00122    }
00123    va_end(ap);
00124 
00125    /* We now have our complete statement; Lets connect to the server and execute it. */
00126    ast_mutex_lock(&pgsql_lock);
00127    if (!pgsql_reconnect(database)) {
00128       ast_mutex_unlock(&pgsql_lock);
00129       return NULL;
00130    }
00131 
00132    if (!(result = PQexec(pgsqlConn, sql))) {
00133       ast_log(LOG_WARNING,
00134             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00135       if (option_debug) {
00136          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00137          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00138                PQerrorMessage(pgsqlConn));
00139       }
00140       ast_mutex_unlock(&pgsql_lock);
00141       return NULL;
00142    } else {
00143       ExecStatusType result_status = PQresultStatus(result);
00144       if (result_status != PGRES_COMMAND_OK
00145          && result_status != PGRES_TUPLES_OK
00146          && result_status != PGRES_NONFATAL_ERROR) {
00147          ast_log(LOG_WARNING,
00148                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00149          if (option_debug) {
00150             ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00151             ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00152                   PQresultErrorMessage(result), PQresStatus(result_status));
00153          }
00154          ast_mutex_unlock(&pgsql_lock);
00155          return NULL;
00156       }
00157    }
00158 
00159    if (option_debug)
00160       ast_log(LOG_DEBUG, "1Postgresql RealTime: Result=%p Query: %s\n", result, sql);
00161 
00162    if ((num_rows = PQntuples(result)) > 0) {
00163       int i = 0;
00164       int rowIndex = 0;
00165       int numFields = PQnfields(result);
00166       char **fieldnames = NULL;
00167 
00168       if (option_debug)
00169          ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);
00170 
00171       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00172          ast_mutex_unlock(&pgsql_lock);
00173          PQclear(result);
00174          return NULL;
00175       }
00176       for (i = 0; i < numFields; i++)
00177          fieldnames[i] = PQfname(result, i);
00178       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00179          for (i = 0; i < numFields; i++) {
00180             stringp = PQgetvalue(result, rowIndex, i);
00181             while (stringp) {
00182                chunk = strsep(&stringp, ";");
00183                if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
00184                   if (prev) {
00185                      prev->next = ast_variable_new(fieldnames[i], chunk);
00186                      if (prev->next) {
00187                         prev = prev->next;
00188                      }
00189                   } else {
00190                      prev = var = ast_variable_new(fieldnames[i], chunk);
00191                   }
00192                }
00193             }
00194          }
00195       }
00196       free(fieldnames);
00197    } else {
00198       ast_log(LOG_WARNING,
00199             "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00200    }
00201 
00202    ast_mutex_unlock(&pgsql_lock);
00203    PQclear(result);
00204 
00205    return var;
00206 }
00207 
00208 static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
00209 {
00210    PGresult *result = NULL;
00211    int num_rows = 0;
00212    char sql[256];
00213    const char *initfield = NULL;
00214    char *stringp;
00215    char *chunk;
00216    char *op;
00217    const char *newparam, *newval;
00218    struct ast_realloca ra;
00219    struct ast_variable *var = NULL;
00220    struct ast_config *cfg = NULL;
00221    struct ast_category *cat = NULL;
00222 
00223    if (!table) {
00224       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00225       return NULL;
00226    }
00227 
00228    memset(&ra, 0, sizeof(ra));
00229 
00230    if (!(cfg = ast_config_new()))
00231       return NULL;
00232 
00233    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00234    newparam = va_arg(ap, const char *);
00235    newval = va_arg(ap, const char *);
00236    if (!newparam || !newval) {
00237       ast_log(LOG_WARNING,
00238             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00239       if (pgsqlConn) {
00240          PQfinish(pgsqlConn);
00241          pgsqlConn = NULL;
00242       };
00243       return NULL;
00244    }
00245 
00246    initfield = ast_strdupa(newparam);
00247    if ((op = strchr(initfield, ' '))) {
00248       *op = '\0';
00249    }
00250 
00251    /* Create the first part of the query using the first parameter/value pairs we just extracted
00252       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00253 
00254    if (!strchr(newparam, ' '))
00255       op = " =";
00256    else
00257       op = "";
00258 
00259    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00260           newval);
00261    while ((newparam = va_arg(ap, const char *))) {
00262       newval = va_arg(ap, const char *);
00263       if (!strchr(newparam, ' '))
00264          op = " =";
00265       else
00266          op = "";
00267       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00268              op, newval);
00269    }
00270 
00271    if (initfield) {
00272       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00273    }
00274 
00275    va_end(ap);
00276 
00277    /* We now have our complete statement; Lets connect to the server and execute it. */
00278    ast_mutex_lock(&pgsql_lock);
00279    if (!pgsql_reconnect(database)) {
00280       ast_mutex_unlock(&pgsql_lock);
00281       return NULL;
00282    }
00283 
00284    if (!(result = PQexec(pgsqlConn, sql))) {
00285       ast_log(LOG_WARNING,
00286             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00287       if (option_debug) {
00288          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00289          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00290                PQerrorMessage(pgsqlConn));
00291       }
00292       ast_mutex_unlock(&pgsql_lock);
00293       return NULL;
00294    } else {
00295       ExecStatusType result_status = PQresultStatus(result);
00296       if (result_status != PGRES_COMMAND_OK
00297          && result_status != PGRES_TUPLES_OK
00298          && result_status != PGRES_NONFATAL_ERROR) {
00299          ast_log(LOG_WARNING,
00300                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00301          if (option_debug) {
00302             ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00303             ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00304                   PQresultErrorMessage(result), PQresStatus(result_status));
00305          }
00306          ast_mutex_unlock(&pgsql_lock);
00307          return NULL;
00308       }
00309    }
00310 
00311    if (option_debug)
00312       ast_log(LOG_DEBUG, "2Postgresql RealTime: Result=%p Query: %s\n", result, sql);
00313 
00314    if ((num_rows = PQntuples(result)) > 0) {
00315       int numFields = PQnfields(result);
00316       int i = 0;
00317       int rowIndex = 0;
00318       char **fieldnames = NULL;
00319 
00320       if (option_debug)
00321          ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);
00322 
00323       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00324          ast_mutex_unlock(&pgsql_lock);
00325          PQclear(result);
00326          return NULL;
00327       }
00328       for (i = 0; i < numFields; i++)
00329          fieldnames[i] = PQfname(result, i);
00330 
00331       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00332          var = NULL;
00333          if (!(cat = ast_category_new("")))
00334             continue;
00335          for (i = 0; i < numFields; i++) {
00336             stringp = PQgetvalue(result, rowIndex, i);
00337             while (stringp) {
00338                chunk = strsep(&stringp, ";");
00339                if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
00340                   if (initfield && !strcmp(initfield, fieldnames[i])) {
00341                      ast_category_rename(cat, chunk);
00342                   }
00343                   var = ast_variable_new(fieldnames[i], chunk);
00344                   ast_variable_append(cat, var);
00345                }
00346             }
00347          }
00348          ast_category_append(cfg, cat);
00349       }
00350       free(fieldnames);
00351    } else {
00352       ast_log(LOG_WARNING,
00353             "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00354    }
00355 
00356    ast_mutex_unlock(&pgsql_lock);
00357    PQclear(result);
00358 
00359    return cfg;
00360 }
00361 
00362 static int update_pgsql(const char *database, const char *table, const char *keyfield,
00363                   const char *lookup, va_list ap)
00364 {
00365    PGresult *result = NULL;
00366    int numrows = 0;
00367    char sql[256];
00368    const char *newparam, *newval;
00369 
00370    if (!table) {
00371       ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00372       return -1;
00373    }
00374 
00375    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00376    newparam = va_arg(ap, const char *);
00377    newval = va_arg(ap, const char *);
00378    if (!newparam || !newval) {
00379       ast_log(LOG_WARNING,
00380             "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00381       if (pgsqlConn) {
00382          PQfinish(pgsqlConn);
00383          pgsqlConn = NULL;
00384       };
00385       return -1;
00386    }
00387 
00388    /* Create the first part of the query using the first parameter/value pairs we just extracted
00389       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00390 
00391    snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, newval);
00392    while ((newparam = va_arg(ap, const char *))) {
00393       newval = va_arg(ap, const char *);
00394       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam,
00395              newval);
00396    }
00397    va_end(ap);
00398    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield,
00399           lookup);
00400 
00401    if (option_debug)
00402       ast_log(LOG_DEBUG, "Postgresql RealTime: Update SQL: %s\n", sql);
00403 
00404    /* We now have our complete statement; Lets connect to the server and execute it. */
00405    ast_mutex_lock(&pgsql_lock);
00406    if (!pgsql_reconnect(database)) {
00407       ast_mutex_unlock(&pgsql_lock);
00408       return -1;
00409    }
00410 
00411    if (!(result = PQexec(pgsqlConn, sql))) {
00412       ast_log(LOG_WARNING,
00413             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00414       if (option_debug) {
00415          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00416          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00417                PQerrorMessage(pgsqlConn));
00418       }
00419       ast_mutex_unlock(&pgsql_lock);
00420       return -1;
00421    } else {
00422       ExecStatusType result_status = PQresultStatus(result);
00423       if (result_status != PGRES_COMMAND_OK
00424          && result_status != PGRES_TUPLES_OK
00425          && result_status != PGRES_NONFATAL_ERROR) {
00426          ast_log(LOG_WARNING,
00427                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00428          if (option_debug) {
00429             ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00430             ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00431                   PQresultErrorMessage(result), PQresStatus(result_status));
00432          }
00433          ast_mutex_unlock(&pgsql_lock);
00434          return -1;
00435       }
00436    }
00437 
00438    numrows = atoi(PQcmdTuples(result));
00439    ast_mutex_unlock(&pgsql_lock);
00440 
00441    if (option_debug)
00442       ast_log(LOG_DEBUG, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows,
00443             table);
00444 
00445    /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
00446     * An integer greater than zero indicates the number of rows affected
00447     * Zero indicates that no records were updated
00448     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00449     */
00450 
00451    if (numrows >= 0)
00452       return (int) numrows;
00453 
00454    return -1;
00455 }
00456 
00457 static struct ast_config *config_pgsql(const char *database, const char *table,
00458                   const char *file, struct ast_config *cfg,
00459                   int withcomments)
00460 {
00461    PGresult *result = NULL;
00462    long num_rows;
00463    struct ast_variable *new_v;
00464    struct ast_category *cur_cat = NULL;
00465    char sql[250] = "";
00466    char last[80] = "";
00467    int last_cat_metric = 0;
00468 
00469    last[0] = '\0';
00470 
00471    if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
00472       ast_log(LOG_WARNING, "Postgresql RealTime: Cannot configure myself.\n");
00473       return NULL;
00474    }
00475 
00476    snprintf(sql, sizeof(sql),
00477           "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id",
00478           table, file);
00479 
00480    if (option_debug)
00481       ast_log(LOG_DEBUG, "Postgresql RealTime: Static SQL: %s\n", sql);
00482 
00483    /* We now have our complete statement; Lets connect to the server and execute it. */
00484    ast_mutex_lock(&pgsql_lock);
00485    if (!pgsql_reconnect(database)) {
00486       ast_mutex_unlock(&pgsql_lock);
00487       return NULL;
00488    }
00489 
00490    if (!(result = PQexec(pgsqlConn, sql))) {
00491       ast_log(LOG_WARNING,
00492             "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00493       if (option_debug) {
00494          ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00495          ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00496                PQerrorMessage(pgsqlConn));
00497       }
00498       ast_mutex_unlock(&pgsql_lock);
00499       return NULL;
00500    } else {
00501       ExecStatusType result_status = PQresultStatus(result);
00502       if (result_status != PGRES_COMMAND_OK
00503          && result_status != PGRES_TUPLES_OK
00504          && result_status != PGRES_NONFATAL_ERROR) {
00505          ast_log(LOG_WARNING,
00506                "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00507          if (option_debug) {
00508             ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00509             ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00510                   PQresultErrorMessage(result), PQresStatus(result_status));
00511          }
00512          ast_mutex_unlock(&pgsql_lock);
00513          return NULL;
00514       }
00515    }
00516 
00517    if ((num_rows = PQntuples(result)) > 0) {
00518       int numFields = PQnfields(result);
00519       int i = 0;
00520       int rowIndex = 0;
00521       char **fieldnames = NULL;
00522 
00523       if (option_debug)
00524          ast_log(LOG_DEBUG, "Postgresql RealTime: Found %ld rows.\n", num_rows);
00525 
00526       if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00527          ast_mutex_unlock(&pgsql_lock);
00528          PQclear(result);
00529          return NULL;
00530       }
00531       for (i = 0; i < numFields; i++)
00532          fieldnames[i] = PQfname(result, i);
00533 
00534       for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00535          char *field_category = PQgetvalue(result, rowIndex, 0);
00536          char *field_var_name = PQgetvalue(result, rowIndex, 1);
00537          char *field_var_val = PQgetvalue(result, rowIndex, 2);
00538          char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
00539          if (!strcmp(field_var_name, "#include")) {
00540             if (!ast_config_internal_load(field_var_val, cfg, 0)) {
00541                PQclear(result);
00542                ast_mutex_unlock(&pgsql_lock);
00543                return NULL;
00544             }
00545             continue;
00546          }
00547 
00548          if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
00549             cur_cat = ast_category_new(field_category);
00550             if (!cur_cat)
00551                break;
00552             strcpy(last, field_category);
00553             last_cat_metric = atoi(field_cat_metric);
00554             ast_category_append(cfg, cur_cat);
00555          }
00556          new_v = ast_variable_new(field_var_name, field_var_val);
00557          ast_variable_append(cur_cat, new_v);
00558       }
00559    } else {
00560       ast_log(LOG_WARNING,
00561             "Postgresql RealTime: Could not find config '%s' in database.\n", file);
00562    }
00563 
00564    PQclear(result);
00565    ast_mutex_unlock(&pgsql_lock);
00566 
00567    return cfg;
00568 }
00569 
00570 static struct ast_config_engine pgsql_engine = {
00571    .name = "pgsql",
00572    .load_func = config_pgsql,
00573    .realtime_func = realtime_pgsql,
00574    .realtime_multi_func = realtime_multi_pgsql,
00575    .update_func = update_pgsql
00576 };
00577 
00578 static int load_module(void)
00579 {
00580    if(!parse_config())
00581       return AST_MODULE_LOAD_DECLINE;
00582 
00583    ast_mutex_lock(&pgsql_lock);
00584 
00585    if (!pgsql_reconnect(NULL)) {
00586       ast_log(LOG_WARNING,
00587             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00588       if (option_debug)
00589          ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00590                PQerrorMessage(pgsqlConn));
00591    }
00592 
00593    ast_config_engine_register(&pgsql_engine);
00594    if (option_verbose) {
00595       ast_verbose("Postgresql RealTime driver loaded.\n");
00596    }
00597    ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00598 
00599    ast_mutex_unlock(&pgsql_lock);
00600 
00601    return 0;
00602 }
00603 
00604 static int unload_module(void)
00605 {
00606    /* Aquire control before doing anything to the module itself. */
00607    ast_mutex_lock(&pgsql_lock);
00608 
00609    if (pgsqlConn) {
00610       PQfinish(pgsqlConn);
00611       pgsqlConn = NULL;
00612    };
00613    ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00614    ast_config_engine_deregister(&pgsql_engine);
00615    if (option_verbose) {
00616       ast_verbose("Postgresql RealTime unloaded.\n");
00617    }
00618 
00619    ast_module_user_hangup_all();
00620 
00621    /* Unlock so something else can destroy the lock. */
00622    ast_mutex_unlock(&pgsql_lock);
00623 
00624    return 0;
00625 }
00626 
00627 static int reload(void)
00628 {
00629    /* Aquire control before doing anything to the module itself. */
00630    ast_mutex_lock(&pgsql_lock);
00631 
00632    if (pgsqlConn) {
00633       PQfinish(pgsqlConn);
00634       pgsqlConn = NULL;
00635    };
00636    parse_config();
00637 
00638    if (!pgsql_reconnect(NULL)) {
00639       ast_log(LOG_WARNING,
00640             "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00641       if (option_debug)
00642          ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00643                PQerrorMessage(pgsqlConn));
00644    }
00645 
00646    ast_verbose(VERBOSE_PREFIX_2 "Postgresql RealTime reloaded.\n");
00647 
00648    /* Done reloading. Release lock so others can now use driver. */
00649    ast_mutex_unlock(&pgsql_lock);
00650 
00651    return 0;
00652 }
00653 
00654 static int parse_config(void)
00655 {
00656    struct ast_config *config;
00657    const char *s;
00658 
00659    config = ast_config_load(RES_CONFIG_PGSQL_CONF);
00660 
00661    if (!config) {
00662       ast_log(LOG_WARNING, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF);
00663       return 0;
00664    }
00665    if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
00666       ast_log(LOG_WARNING,
00667             "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
00668       strcpy(dbuser, "asterisk");
00669    } else {
00670       ast_copy_string(dbuser, s, sizeof(dbuser));
00671    }
00672 
00673    if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
00674       ast_log(LOG_WARNING,
00675             "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
00676       strcpy(dbpass, "asterisk");
00677    } else {
00678       ast_copy_string(dbpass, s, sizeof(dbpass));
00679    }
00680 
00681    if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
00682       ast_log(LOG_WARNING,
00683             "Postgresql RealTime: No database host found, using localhost via socket.\n");
00684       dbhost[0] = '\0';
00685    } else {
00686       ast_copy_string(dbhost, s, sizeof(dbhost));
00687    }
00688 
00689    if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
00690       ast_log(LOG_WARNING,
00691             "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
00692       strcpy(dbname, "asterisk");
00693    } else {
00694       ast_copy_string(dbname, s, sizeof(dbname));
00695    }
00696 
00697    if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
00698       ast_log(LOG_WARNING,
00699             "Postgresql RealTime: No database port found, using 5432 as default.\n");
00700       dbport = 5432;
00701    } else {
00702       dbport = atoi(s);
00703    }
00704 
00705    if (dbhost && !(s = ast_variable_retrieve(config, "general", "dbsock"))) {
00706       ast_log(LOG_WARNING,
00707             "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
00708       strcpy(dbsock, "/tmp/pgsql.sock");
00709    } else {
00710       ast_copy_string(dbsock, s, sizeof(dbsock));
00711    }
00712    ast_config_destroy(config);
00713 
00714    if (option_debug) {
00715       if (dbhost) {
00716          ast_log(LOG_DEBUG, "Postgresql RealTime Host: %s\n", dbhost);
00717          ast_log(LOG_DEBUG, "Postgresql RealTime Port: %i\n", dbport);
00718       } else {
00719          ast_log(LOG_DEBUG, "Postgresql RealTime Socket: %s\n", dbsock);
00720       }
00721       ast_log(LOG_DEBUG, "Postgresql RealTime User: %s\n", dbuser);
00722       ast_log(LOG_DEBUG, "Postgresql RealTime Password: %s\n", dbpass);
00723       ast_log(LOG_DEBUG, "Postgresql RealTime DBName: %s\n", dbname);
00724    }
00725 
00726    return 1;
00727 }
00728 
00729 static int pgsql_reconnect(const char *database)
00730 {
00731    char my_database[50];
00732 
00733    ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
00734 
00735    /* mutex lock should have been locked before calling this function. */
00736 
00737    if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
00738       PQfinish(pgsqlConn);
00739       pgsqlConn = NULL;
00740    }
00741 
00742    if ((!pgsqlConn) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
00743       char *connInfo = NULL;
00744       unsigned int size = 100 + strlen(dbhost)
00745          + strlen(dbuser)
00746          + strlen(dbpass)
00747          + strlen(my_database);
00748       
00749       if (!(connInfo = ast_malloc(size)))
00750          return 0;
00751       
00752       sprintf(connInfo, "host=%s port=%d dbname=%s user=%s password=%s",
00753                dbhost, dbport, my_database, dbuser, dbpass);
00754       if (option_debug)
00755          ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00756       pgsqlConn = PQconnectdb(connInfo);
00757       if (option_debug)
00758          ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00759       free(connInfo);
00760       connInfo = NULL;
00761       if (option_debug)
00762          ast_log(LOG_DEBUG, "pgsqlConn=%p\n", pgsqlConn);
00763       if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00764          if (option_debug)
00765             ast_log(LOG_DEBUG, "Postgresql RealTime: Successfully connected to database.\n");
00766          connect_time = time(NULL);
00767          return 1;
00768       } else {
00769          ast_log(LOG_ERROR,
00770                "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
00771                dbname, dbhost);
00772          if (option_debug)
00773             ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00774                   PQresultErrorMessage(NULL));
00775          return 0;
00776       }
00777    } else {
00778       if (option_debug)
00779          ast_log(LOG_DEBUG, "Postgresql RealTime: Everything is fine.\n");
00780       return 1;
00781    }
00782 }
00783 
00784 static int realtime_pgsql_status(int fd, int argc, char **argv)
00785 {
00786    char status[256], status2[100] = "";
00787    int ctime = time(NULL) - connect_time;
00788 
00789    if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00790       if (dbhost) {
00791          snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
00792       } else if (dbsock) {
00793          snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
00794       } else {
00795          snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
00796       }
00797 
00798       if (dbuser && *dbuser) {
00799          snprintf(status2, 99, " with username %s", dbuser);
00800       }
00801 
00802       if (ctime > 31536000) {
00803          ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
00804                status, status2, ctime / 31536000, (ctime % 31536000) / 86400,
00805                (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00806       } else if (ctime > 86400) {
00807          ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
00808                status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60,
00809                ctime % 60);
00810       } else if (ctime > 3600) {
00811          ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2,
00812                ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00813       } else if (ctime > 60) {
00814          ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60,
00815                ctime % 60);
00816       } else {
00817          ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
00818       }
00819 
00820       return RESULT_SUCCESS;
00821    } else {
00822       return RESULT_FAILURE;
00823    }
00824 }
00825 
00826 /* needs usecount semantics defined */
00827 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PostgreSQL RealTime Configuration Driver",
00828       .load = load_module,
00829       .unload = unload_module,
00830       .reload = reload
00831           );

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen