00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00032
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <libpq-fe.h>
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 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, 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
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
00109
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
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_WARNING,
00208 "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00209 }
00210
00211 ast_mutex_unlock(&pgsql_lock);
00212 PQclear(result);
00213
00214 return var;
00215 }
00216
00217 static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
00218 {
00219 PGresult *result = NULL;
00220 int num_rows = 0, pgerror;
00221 char sql[256], escapebuf[513];
00222 const char *initfield = NULL;
00223 char *stringp;
00224 char *chunk;
00225 char *op;
00226 const char *newparam, *newval;
00227 struct ast_realloca ra;
00228 struct ast_variable *var = NULL;
00229 struct ast_config *cfg = NULL;
00230 struct ast_category *cat = NULL;
00231
00232 if (!table) {
00233 ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00234 return NULL;
00235 }
00236
00237 memset(&ra, 0, sizeof(ra));
00238
00239 if (!(cfg = ast_config_new()))
00240 return NULL;
00241
00242
00243 newparam = va_arg(ap, const char *);
00244 newval = va_arg(ap, const char *);
00245 if (!newparam || !newval) {
00246 ast_log(LOG_WARNING,
00247 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00248 if (pgsqlConn) {
00249 PQfinish(pgsqlConn);
00250 pgsqlConn = NULL;
00251 };
00252 return NULL;
00253 }
00254
00255 initfield = ast_strdupa(newparam);
00256 if ((op = strchr(initfield, ' '))) {
00257 *op = '\0';
00258 }
00259
00260
00261
00262
00263 if (!strchr(newparam, ' '))
00264 op = " =";
00265 else
00266 op = "";
00267
00268 PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00269 if (pgerror) {
00270 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00271 va_end(ap);
00272 return NULL;
00273 }
00274
00275 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
00276 escapebuf);
00277 while ((newparam = va_arg(ap, const char *))) {
00278 newval = va_arg(ap, const char *);
00279 if (!strchr(newparam, ' '))
00280 op = " =";
00281 else
00282 op = "";
00283
00284 PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00285 if (pgerror) {
00286 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00287 va_end(ap);
00288 return NULL;
00289 }
00290
00291 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
00292 op, escapebuf);
00293 }
00294
00295 if (initfield) {
00296 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00297 }
00298
00299 va_end(ap);
00300
00301
00302 ast_mutex_lock(&pgsql_lock);
00303 if (!pgsql_reconnect(database)) {
00304 ast_mutex_unlock(&pgsql_lock);
00305 return NULL;
00306 }
00307
00308 if (!(result = PQexec(pgsqlConn, sql))) {
00309 ast_log(LOG_WARNING,
00310 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00311 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00312 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00313 PQerrorMessage(pgsqlConn));
00314 ast_mutex_unlock(&pgsql_lock);
00315 return NULL;
00316 } else {
00317 ExecStatusType result_status = PQresultStatus(result);
00318 if (result_status != PGRES_COMMAND_OK
00319 && result_status != PGRES_TUPLES_OK
00320 && result_status != PGRES_NONFATAL_ERROR) {
00321 ast_log(LOG_WARNING,
00322 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00323 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00324 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00325 PQresultErrorMessage(result), PQresStatus(result_status));
00326 ast_mutex_unlock(&pgsql_lock);
00327 return NULL;
00328 }
00329 }
00330
00331 ast_log(LOG_DEBUG, "2Postgresql RealTime: Result=%p Query: %s\n", result, sql);
00332
00333 if ((num_rows = PQntuples(result)) > 0) {
00334 int numFields = PQnfields(result);
00335 int i = 0;
00336 int rowIndex = 0;
00337 char **fieldnames = NULL;
00338
00339 ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);
00340
00341 if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
00342 ast_mutex_unlock(&pgsql_lock);
00343 PQclear(result);
00344 return NULL;
00345 }
00346 for (i = 0; i < numFields; i++)
00347 fieldnames[i] = PQfname(result, i);
00348
00349 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00350 var = NULL;
00351 if (!(cat = ast_category_new("")))
00352 continue;
00353 for (i = 0; i < numFields; i++) {
00354 stringp = PQgetvalue(result, rowIndex, i);
00355 while (stringp) {
00356 chunk = strsep(&stringp, ";");
00357 if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
00358 if (initfield && !strcmp(initfield, fieldnames[i])) {
00359 ast_category_rename(cat, chunk);
00360 }
00361 var = ast_variable_new(fieldnames[i], chunk);
00362 ast_variable_append(cat, var);
00363 }
00364 }
00365 }
00366 ast_category_append(cfg, cat);
00367 }
00368 ast_free(fieldnames);
00369 } else {
00370 ast_log(LOG_WARNING,
00371 "Postgresql RealTime: Could not find any rows in table %s.\n", table);
00372 }
00373
00374 ast_mutex_unlock(&pgsql_lock);
00375 PQclear(result);
00376
00377 return cfg;
00378 }
00379
00380 static int update_pgsql(const char *database, const char *table, const char *keyfield,
00381 const char *lookup, va_list ap)
00382 {
00383 PGresult *result = NULL;
00384 int numrows = 0, pgerror;
00385 char sql[256], escapebuf[513];
00386 const char *newparam, *newval;
00387
00388 if (!table) {
00389 ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
00390 return -1;
00391 }
00392
00393
00394 newparam = va_arg(ap, const char *);
00395 newval = va_arg(ap, const char *);
00396 if (!newparam || !newval) {
00397 ast_log(LOG_WARNING,
00398 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00399 if (pgsqlConn) {
00400 PQfinish(pgsqlConn);
00401 pgsqlConn = NULL;
00402 };
00403 return -1;
00404 }
00405
00406
00407
00408
00409 PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00410 if (pgerror) {
00411 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00412 va_end(ap);
00413 return -1;
00414 }
00415 snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, escapebuf);
00416
00417 while ((newparam = va_arg(ap, const char *))) {
00418 newval = va_arg(ap, const char *);
00419
00420 PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
00421 if (pgerror) {
00422 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
00423 va_end(ap);
00424 return -1;
00425 }
00426
00427 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam,
00428 escapebuf);
00429 }
00430 va_end(ap);
00431
00432 PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
00433 if (pgerror) {
00434 ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
00435 va_end(ap);
00436 return -1;
00437 }
00438
00439 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield,
00440 escapebuf);
00441
00442 ast_log(LOG_DEBUG, "Postgresql RealTime: Update SQL: %s\n", sql);
00443
00444
00445 ast_mutex_lock(&pgsql_lock);
00446 if (!pgsql_reconnect(database)) {
00447 ast_mutex_unlock(&pgsql_lock);
00448 return -1;
00449 }
00450
00451 if (!(result = PQexec(pgsqlConn, sql))) {
00452 ast_log(LOG_WARNING,
00453 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00454 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00455 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00456 PQerrorMessage(pgsqlConn));
00457 ast_mutex_unlock(&pgsql_lock);
00458 return -1;
00459 } else {
00460 ExecStatusType result_status = PQresultStatus(result);
00461 if (result_status != PGRES_COMMAND_OK
00462 && result_status != PGRES_TUPLES_OK
00463 && result_status != PGRES_NONFATAL_ERROR) {
00464 ast_log(LOG_WARNING,
00465 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00466 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00467 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00468 PQresultErrorMessage(result), PQresStatus(result_status));
00469 ast_mutex_unlock(&pgsql_lock);
00470 return -1;
00471 }
00472 }
00473
00474 numrows = atoi(PQcmdTuples(result));
00475 ast_mutex_unlock(&pgsql_lock);
00476
00477 ast_log(LOG_DEBUG, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows,
00478 table);
00479
00480
00481
00482
00483
00484
00485
00486 if (numrows >= 0)
00487 return (int) numrows;
00488
00489 return -1;
00490 }
00491
00492 static struct ast_config *config_pgsql(const char *database, const char *table,
00493 const char *file, struct ast_config *cfg,
00494 int withcomments)
00495 {
00496 PGresult *result = NULL;
00497 long num_rows;
00498 struct ast_variable *new_v;
00499 struct ast_category *cur_cat = NULL;
00500 char sqlbuf[1024] = "";
00501 char *sql = sqlbuf;
00502 size_t sqlleft = sizeof(sqlbuf);
00503 char last[80] = "";
00504 int last_cat_metric = 0;
00505
00506 last[0] = '\0';
00507
00508 if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
00509 ast_log(LOG_WARNING, "Postgresql RealTime: Cannot configure myself.\n");
00510 return NULL;
00511 }
00512
00513 ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
00514 ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
00515 ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00516
00517 ast_log(LOG_DEBUG, "Postgresql RealTime: Static SQL: %s\n", sqlbuf);
00518
00519
00520 ast_mutex_lock(&pgsql_lock);
00521 if (!pgsql_reconnect(database)) {
00522 ast_mutex_unlock(&pgsql_lock);
00523 return NULL;
00524 }
00525
00526 if (!(result = PQexec(pgsqlConn, sqlbuf))) {
00527 ast_log(LOG_WARNING,
00528 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00529 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00530 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
00531 PQerrorMessage(pgsqlConn));
00532 ast_mutex_unlock(&pgsql_lock);
00533 return NULL;
00534 } else {
00535 ExecStatusType result_status = PQresultStatus(result);
00536 if (result_status != PGRES_COMMAND_OK
00537 && result_status != PGRES_TUPLES_OK
00538 && result_status != PGRES_NONFATAL_ERROR) {
00539 ast_log(LOG_WARNING,
00540 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
00541 ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
00542 ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
00543 PQresultErrorMessage(result), PQresStatus(result_status));
00544 ast_mutex_unlock(&pgsql_lock);
00545 return NULL;
00546 }
00547 }
00548
00549 if ((num_rows = PQntuples(result)) > 0) {
00550 int rowIndex = 0;
00551
00552 ast_log(LOG_DEBUG, "Postgresql RealTime: Found %ld rows.\n", num_rows);
00553
00554 for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
00555 char *field_category = PQgetvalue(result, rowIndex, 0);
00556 char *field_var_name = PQgetvalue(result, rowIndex, 1);
00557 char *field_var_val = PQgetvalue(result, rowIndex, 2);
00558 char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
00559 if (!strcmp(field_var_name, "#include")) {
00560 if (!ast_config_internal_load(field_var_val, cfg, 0)) {
00561 PQclear(result);
00562 ast_mutex_unlock(&pgsql_lock);
00563 return NULL;
00564 }
00565 continue;
00566 }
00567
00568 if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
00569 cur_cat = ast_category_new(field_category);
00570 if (!cur_cat)
00571 break;
00572 strcpy(last, field_category);
00573 last_cat_metric = atoi(field_cat_metric);
00574 ast_category_append(cfg, cur_cat);
00575 }
00576 new_v = ast_variable_new(field_var_name, field_var_val);
00577 ast_variable_append(cur_cat, new_v);
00578 }
00579 } else {
00580 ast_log(LOG_WARNING,
00581 "Postgresql RealTime: Could not find config '%s' in database.\n", file);
00582 }
00583
00584 PQclear(result);
00585 ast_mutex_unlock(&pgsql_lock);
00586
00587 return cfg;
00588 }
00589
00590 static struct ast_config_engine pgsql_engine = {
00591 .name = "pgsql",
00592 .load_func = config_pgsql,
00593 .realtime_func = realtime_pgsql,
00594 .realtime_multi_func = realtime_multi_pgsql,
00595 .update_func = update_pgsql
00596 };
00597
00598 static int load_module(void)
00599 {
00600 if(!parse_config())
00601 return AST_MODULE_LOAD_DECLINE;
00602
00603 ast_mutex_lock(&pgsql_lock);
00604
00605 if (!pgsql_reconnect(NULL)) {
00606 ast_log(LOG_WARNING,
00607 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00608 ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00609 PQerrorMessage(pgsqlConn));
00610 }
00611
00612 ast_config_engine_register(&pgsql_engine);
00613 if (option_verbose) {
00614 ast_verbose("Postgresql RealTime driver loaded.\n");
00615 }
00616 ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00617
00618 ast_mutex_unlock(&pgsql_lock);
00619
00620 return 0;
00621 }
00622
00623 static int unload_module(void)
00624 {
00625
00626 ast_mutex_lock(&pgsql_lock);
00627
00628 if (pgsqlConn) {
00629 PQfinish(pgsqlConn);
00630 pgsqlConn = NULL;
00631 };
00632 ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
00633 ast_config_engine_deregister(&pgsql_engine);
00634 if (option_verbose) {
00635 ast_verbose("Postgresql RealTime unloaded.\n");
00636 }
00637
00638 ast_module_user_hangup_all();
00639
00640
00641 ast_mutex_unlock(&pgsql_lock);
00642
00643 return 0;
00644 }
00645
00646 static int reload(void)
00647 {
00648
00649 ast_mutex_lock(&pgsql_lock);
00650
00651 if (pgsqlConn) {
00652 PQfinish(pgsqlConn);
00653 pgsqlConn = NULL;
00654 };
00655 parse_config();
00656
00657 if (!pgsql_reconnect(NULL)) {
00658 ast_log(LOG_WARNING,
00659 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
00660 ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00661 PQerrorMessage(pgsqlConn));
00662 }
00663
00664 ast_verbose(VERBOSE_PREFIX_2 "Postgresql RealTime reloaded.\n");
00665
00666
00667 ast_mutex_unlock(&pgsql_lock);
00668
00669 return 0;
00670 }
00671
00672 static int parse_config(void)
00673 {
00674 struct ast_config *config;
00675 const char *s;
00676
00677 config = ast_config_load(RES_CONFIG_PGSQL_CONF);
00678
00679 if (!config) {
00680 ast_log(LOG_WARNING, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF);
00681 return 0;
00682 }
00683 if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
00684 ast_log(LOG_WARNING,
00685 "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
00686 strcpy(dbuser, "asterisk");
00687 } else {
00688 ast_copy_string(dbuser, s, sizeof(dbuser));
00689 }
00690
00691 if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
00692 ast_log(LOG_WARNING,
00693 "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
00694 strcpy(dbpass, "asterisk");
00695 } else {
00696 ast_copy_string(dbpass, s, sizeof(dbpass));
00697 }
00698
00699 if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
00700 ast_log(LOG_WARNING,
00701 "Postgresql RealTime: No database host found, using localhost via socket.\n");
00702 dbhost[0] = '\0';
00703 } else {
00704 ast_copy_string(dbhost, s, sizeof(dbhost));
00705 }
00706
00707 if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
00708 ast_log(LOG_WARNING,
00709 "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
00710 strcpy(dbname, "asterisk");
00711 } else {
00712 ast_copy_string(dbname, s, sizeof(dbname));
00713 }
00714
00715 if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
00716 ast_log(LOG_WARNING,
00717 "Postgresql RealTime: No database port found, using 5432 as default.\n");
00718 dbport = 5432;
00719 } else {
00720 dbport = atoi(s);
00721 }
00722
00723 if (!ast_strlen_zero(dbhost)) {
00724
00725 } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
00726 ast_log(LOG_WARNING,
00727 "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
00728 strcpy(dbsock, "/tmp/pgsql.sock");
00729 } else {
00730 ast_copy_string(dbsock, s, sizeof(dbsock));
00731 }
00732 ast_config_destroy(config);
00733
00734 if (!ast_strlen_zero(dbhost)) {
00735 ast_log(LOG_DEBUG, "Postgresql RealTime Host: %s\n", dbhost);
00736 ast_log(LOG_DEBUG, "Postgresql RealTime Port: %i\n", dbport);
00737 } else {
00738 ast_log(LOG_DEBUG, "Postgresql RealTime Socket: %s\n", dbsock);
00739 }
00740 ast_log(LOG_DEBUG, "Postgresql RealTime User: %s\n", dbuser);
00741 ast_log(LOG_DEBUG, "Postgresql RealTime Password: %s\n", dbpass);
00742 ast_log(LOG_DEBUG, "Postgresql RealTime DBName: %s\n", dbname);
00743
00744 return 1;
00745 }
00746
00747 static int pgsql_reconnect(const char *database)
00748 {
00749 char my_database[50];
00750
00751 ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
00752
00753
00754
00755 if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) {
00756 PQfinish(pgsqlConn);
00757 pgsqlConn = NULL;
00758 }
00759
00760 if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(dbpass) && !ast_strlen_zero(my_database)) {
00761 char *connInfo = NULL;
00762 unsigned int size = 100 + strlen(dbhost)
00763 + strlen(dbuser)
00764 + strlen(dbpass)
00765 + strlen(my_database);
00766
00767 if (!(connInfo = ast_malloc(size)))
00768 return 0;
00769
00770 sprintf(connInfo, "host=%s port=%d dbname=%s user=%s password=%s",
00771 dbhost, dbport, my_database, dbuser, dbpass);
00772 ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00773 pgsqlConn = PQconnectdb(connInfo);
00774 ast_log(LOG_DEBUG, "%u connInfo=%s\n", size, connInfo);
00775 ast_free(connInfo);
00776 connInfo = NULL;
00777 ast_log(LOG_DEBUG, "pgsqlConn=%p\n", pgsqlConn);
00778 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00779 ast_log(LOG_DEBUG, "Postgresql RealTime: Successfully connected to database.\n");
00780 connect_time = time(NULL);
00781 return 1;
00782 } else {
00783 ast_log(LOG_ERROR,
00784 "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
00785 dbname, dbhost);
00786 ast_log(LOG_DEBUG, "Postgresql RealTime: Cannot Connect: %s\n",
00787 PQresultErrorMessage(NULL));
00788 return 0;
00789 }
00790 } else {
00791 ast_log(LOG_DEBUG, "Postgresql RealTime: Everything is fine.\n");
00792 return 1;
00793 }
00794 }
00795
00796 static int realtime_pgsql_status(int fd, int argc, char **argv)
00797 {
00798 char status[256], status2[100] = "";
00799 int ctime = time(NULL) - connect_time;
00800
00801 if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
00802 if (!ast_strlen_zero(dbhost)) {
00803 snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
00804 } else if (!ast_strlen_zero(dbsock)) {
00805 snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
00806 } else {
00807 snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
00808 }
00809
00810 if (!ast_strlen_zero(dbuser)) {
00811 snprintf(status2, 99, " with username %s", dbuser);
00812 }
00813
00814 if (ctime > 31536000) {
00815 ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
00816 status, status2, ctime / 31536000, (ctime % 31536000) / 86400,
00817 (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00818 } else if (ctime > 86400) {
00819 ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status,
00820 status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60,
00821 ctime % 60);
00822 } else if (ctime > 3600) {
00823 ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2,
00824 ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00825 } else if (ctime > 60) {
00826 ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60,
00827 ctime % 60);
00828 } else {
00829 ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
00830 }
00831
00832 return RESULT_SUCCESS;
00833 } else {
00834 return RESULT_FAILURE;
00835 }
00836 }
00837
00838
00839 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PostgreSQL RealTime Configuration Driver",
00840 .load = load_module,
00841 .unload = unload_module,
00842 .reload = reload
00843 );