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: 182808 $")
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_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 }
00215
00216 static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
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
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
00260
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
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 }
00378
00379 static int update_pgsql(const char *database, const char *table, const char *keyfield,
00380 const char *lookup, va_list ap)
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
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
00406
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
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
00480
00481
00482
00483
00484
00485 if (numrows >= 0)
00486 return (int) numrows;
00487
00488 return -1;
00489 }
00490
00491 static struct ast_config *config_pgsql(const char *database, const char *table,
00492 const char *file, struct ast_config *cfg,
00493 int withcomments)
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
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 }
00588
00589 static struct ast_config_engine pgsql_engine = {
00590 .name = "pgsql",
00591 .load_func = config_pgsql,
00592 .realtime_func = realtime_pgsql,
00593 .realtime_multi_func = realtime_multi_pgsql,
00594 .update_func = update_pgsql
00595 };
00596
00597 static int load_module(void)
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 }
00621
00622 static int unload_module(void)
00623 {
00624
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
00640 ast_mutex_unlock(&pgsql_lock);
00641
00642 return 0;
00643 }
00644
00645 static int reload(void)
00646 {
00647
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
00666 ast_mutex_unlock(&pgsql_lock);
00667
00668 return 0;
00669 }
00670
00671 static int parse_config(void)
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
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 }
00745
00746 static int pgsql_reconnect(const char *database)
00747 {
00748 char my_database[50];
00749
00750 ast_copy_string(my_database, S_OR(database, dbname), sizeof(my_database));
00751
00752
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 }
00794
00795 static int realtime_pgsql_status(int fd, int argc, char **argv)
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 }
00836
00837
00838 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PostgreSQL RealTime Configuration Driver",
00839 .load = load_module,
00840 .unload = unload_module,
00841 .reload = reload
00842 );