2 * Asterisk -- A telephony toolkit for Linux.
4 * Copyright (C) 1999-2005, Digium, Inc.
6 * Manuel Guesdon <mguesdon@oxymium.net> - Postgresql RealTime Driver Author/Adaptor
7 * Mark Spencer <markster@digium.com> - Asterisk Author
8 * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
10 * res_config_pgsql.c <Postgresql plugin for RealTime configuration engine>
12 * v1.0 - (07-11-05) - Initial version based on res_config_mysql v2.0
17 * \brief Postgresql plugin for Asterisk RealTime Architecture
19 * \author Mark Spencer <markster@digium.com>
20 * \author Manuel Guesdon <mguesdon@oxymium.net> - Postgresql RealTime Driver Author/Adaptor
22 * \arg http://www.postgresql.org
26 <depend>pgsql</depend>
31 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include <libpq-fe.h> /* PostgreSQL */
38 #include "asterisk/file.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/config.h"
43 #include "asterisk/module.h"
44 #include "asterisk/lock.h"
45 #include "asterisk/options.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/cli.h"
49 AST_MUTEX_DEFINE_STATIC(pgsql_lock
);
51 #define RES_CONFIG_PGSQL_CONF "res_pgsql.conf"
53 PGconn
*pgsqlConn
= NULL
;
55 #define MAX_DB_OPTION_SIZE 64
57 static char dbhost
[MAX_DB_OPTION_SIZE
] = "";
58 static char dbuser
[MAX_DB_OPTION_SIZE
] = "";
59 static char dbpass
[MAX_DB_OPTION_SIZE
] = "";
60 static char dbname
[MAX_DB_OPTION_SIZE
] = "";
61 static char dbsock
[MAX_DB_OPTION_SIZE
] = "";
62 static int dbport
= 5432;
63 static time_t connect_time
= 0;
65 static int parse_config(void);
66 static int pgsql_reconnect(const char *database
);
67 static int realtime_pgsql_status(int fd
, int argc
, char **argv
);
69 static char cli_realtime_pgsql_status_usage
[] =
70 "Usage: realtime pgsql status\n"
71 " Shows connection information for the Postgresql RealTime driver\n";
73 static struct ast_cli_entry cli_realtime
[] = {
74 { { "realtime", "pgsql", "status", NULL
},
75 realtime_pgsql_status
, "Shows connection information for the Postgresql RealTime driver",
76 cli_realtime_pgsql_status_usage
},
79 static struct ast_variable
*realtime_pgsql(const char *database
, const char *table
, va_list ap
)
81 PGresult
*result
= NULL
;
82 int num_rows
= 0, pgerror
;
83 char sql
[256], escapebuf
[513];
87 const char *newparam
, *newval
;
88 struct ast_variable
*var
= NULL
, *prev
= NULL
;
91 ast_log(LOG_WARNING
, "Postgresql RealTime: No table specified.\n");
95 /* Get the first parameter and first value in our list of passed paramater/value pairs */
96 newparam
= va_arg(ap
, const char *);
97 newval
= va_arg(ap
, const char *);
98 if (!newparam
|| !newval
) {
100 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
108 /* Create the first part of the query using the first parameter/value pairs we just extracted
109 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
110 op
= strchr(newparam
, ' ') ? "" : " =";
112 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
114 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
119 snprintf(sql
, sizeof(sql
), "SELECT * FROM %s WHERE %s%s '%s'", table
, newparam
, op
,
121 while ((newparam
= va_arg(ap
, const char *))) {
122 newval
= va_arg(ap
, const char *);
123 if (!strchr(newparam
, ' '))
128 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
130 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
135 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " AND %s%s '%s'", newparam
,
140 /* We now have our complete statement; Lets connect to the server and execute it. */
141 ast_mutex_lock(&pgsql_lock
);
142 if (!pgsql_reconnect(database
)) {
143 ast_mutex_unlock(&pgsql_lock
);
147 if (!(result
= PQexec(pgsqlConn
, sql
))) {
149 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
150 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
151 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
152 PQerrorMessage(pgsqlConn
));
153 ast_mutex_unlock(&pgsql_lock
);
156 ExecStatusType result_status
= PQresultStatus(result
);
157 if (result_status
!= PGRES_COMMAND_OK
158 && result_status
!= PGRES_TUPLES_OK
159 && result_status
!= PGRES_NONFATAL_ERROR
) {
161 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
162 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
163 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
164 PQresultErrorMessage(result
), PQresStatus(result_status
));
165 ast_mutex_unlock(&pgsql_lock
);
170 ast_log(LOG_DEBUG
, "1Postgresql RealTime: Result=%p Query: %s\n", result
, sql
);
172 if ((num_rows
= PQntuples(result
)) > 0) {
175 int numFields
= PQnfields(result
);
176 char **fieldnames
= NULL
;
178 ast_log(LOG_DEBUG
, "Postgresql RealTime: Found %d rows.\n", num_rows
);
180 if (!(fieldnames
= ast_calloc(1, numFields
* sizeof(char *)))) {
181 ast_mutex_unlock(&pgsql_lock
);
185 for (i
= 0; i
< numFields
; i
++)
186 fieldnames
[i
] = PQfname(result
, i
);
187 for (rowIndex
= 0; rowIndex
< num_rows
; rowIndex
++) {
188 for (i
= 0; i
< numFields
; i
++) {
189 stringp
= PQgetvalue(result
, rowIndex
, i
);
191 chunk
= strsep(&stringp
, ";");
192 if (chunk
&& !ast_strlen_zero(ast_strip(chunk
))) {
194 prev
->next
= ast_variable_new(fieldnames
[i
], chunk
);
199 prev
= var
= ast_variable_new(fieldnames
[i
], chunk
);
205 ast_free(fieldnames
);
208 "Postgresql RealTime: Could not find any rows in table %s.\n", table
);
211 ast_mutex_unlock(&pgsql_lock
);
217 static struct ast_config
*realtime_multi_pgsql(const char *database
, const char *table
, va_list ap
)
219 PGresult
*result
= NULL
;
220 int num_rows
= 0, pgerror
;
221 char sql
[256], escapebuf
[513];
222 const char *initfield
= NULL
;
226 const char *newparam
, *newval
;
227 struct ast_realloca ra
;
228 struct ast_variable
*var
= NULL
;
229 struct ast_config
*cfg
= NULL
;
230 struct ast_category
*cat
= NULL
;
233 ast_log(LOG_WARNING
, "Postgresql RealTime: No table specified.\n");
237 memset(&ra
, 0, sizeof(ra
));
239 if (!(cfg
= ast_config_new()))
242 /* Get the first parameter and first value in our list of passed paramater/value pairs */
243 newparam
= va_arg(ap
, const char *);
244 newval
= va_arg(ap
, const char *);
245 if (!newparam
|| !newval
) {
247 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
255 initfield
= ast_strdupa(newparam
);
256 if ((op
= strchr(initfield
, ' '))) {
260 /* Create the first part of the query using the first parameter/value pairs we just extracted
261 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
263 if (!strchr(newparam
, ' '))
268 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
270 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
275 snprintf(sql
, sizeof(sql
), "SELECT * FROM %s WHERE %s%s '%s'", table
, newparam
, op
,
277 while ((newparam
= va_arg(ap
, const char *))) {
278 newval
= va_arg(ap
, const char *);
279 if (!strchr(newparam
, ' '))
284 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
286 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
291 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " AND %s%s '%s'", newparam
,
296 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " ORDER BY %s", initfield
);
301 /* We now have our complete statement; Lets connect to the server and execute it. */
302 ast_mutex_lock(&pgsql_lock
);
303 if (!pgsql_reconnect(database
)) {
304 ast_mutex_unlock(&pgsql_lock
);
308 if (!(result
= PQexec(pgsqlConn
, sql
))) {
310 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
311 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
312 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
313 PQerrorMessage(pgsqlConn
));
314 ast_mutex_unlock(&pgsql_lock
);
317 ExecStatusType result_status
= PQresultStatus(result
);
318 if (result_status
!= PGRES_COMMAND_OK
319 && result_status
!= PGRES_TUPLES_OK
320 && result_status
!= PGRES_NONFATAL_ERROR
) {
322 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
323 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
324 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
325 PQresultErrorMessage(result
), PQresStatus(result_status
));
326 ast_mutex_unlock(&pgsql_lock
);
331 ast_log(LOG_DEBUG
, "2Postgresql RealTime: Result=%p Query: %s\n", result
, sql
);
333 if ((num_rows
= PQntuples(result
)) > 0) {
334 int numFields
= PQnfields(result
);
337 char **fieldnames
= NULL
;
339 ast_log(LOG_DEBUG
, "Postgresql RealTime: Found %d rows.\n", num_rows
);
341 if (!(fieldnames
= ast_calloc(1, numFields
* sizeof(char *)))) {
342 ast_mutex_unlock(&pgsql_lock
);
346 for (i
= 0; i
< numFields
; i
++)
347 fieldnames
[i
] = PQfname(result
, i
);
349 for (rowIndex
= 0; rowIndex
< num_rows
; rowIndex
++) {
351 if (!(cat
= ast_category_new("")))
353 for (i
= 0; i
< numFields
; i
++) {
354 stringp
= PQgetvalue(result
, rowIndex
, i
);
356 chunk
= strsep(&stringp
, ";");
357 if (chunk
&& !ast_strlen_zero(ast_strip(chunk
))) {
358 if (initfield
&& !strcmp(initfield
, fieldnames
[i
])) {
359 ast_category_rename(cat
, chunk
);
361 var
= ast_variable_new(fieldnames
[i
], chunk
);
362 ast_variable_append(cat
, var
);
366 ast_category_append(cfg
, cat
);
368 ast_free(fieldnames
);
371 "Postgresql RealTime: Could not find any rows in table %s.\n", table
);
374 ast_mutex_unlock(&pgsql_lock
);
380 static int update_pgsql(const char *database
, const char *table
, const char *keyfield
,
381 const char *lookup
, va_list ap
)
383 PGresult
*result
= NULL
;
384 int numrows
= 0, pgerror
;
385 char sql
[256], escapebuf
[513];
386 const char *newparam
, *newval
;
389 ast_log(LOG_WARNING
, "Postgresql RealTime: No table specified.\n");
393 /* Get the first parameter and first value in our list of passed paramater/value pairs */
394 newparam
= va_arg(ap
, const char *);
395 newval
= va_arg(ap
, const char *);
396 if (!newparam
|| !newval
) {
398 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
406 /* Create the first part of the query using the first parameter/value pairs we just extracted
407 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
409 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
411 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
415 snprintf(sql
, sizeof(sql
), "UPDATE %s SET %s = '%s'", table
, newparam
, escapebuf
);
417 while ((newparam
= va_arg(ap
, const char *))) {
418 newval
= va_arg(ap
, const char *);
420 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
422 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
427 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), ", %s = '%s'", newparam
,
432 PQescapeStringConn(pgsqlConn
, escapebuf
, lookup
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
434 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", lookup
);
439 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " WHERE %s = '%s'", keyfield
,
442 ast_log(LOG_DEBUG
, "Postgresql RealTime: Update SQL: %s\n", sql
);
444 /* We now have our complete statement; Lets connect to the server and execute it. */
445 ast_mutex_lock(&pgsql_lock
);
446 if (!pgsql_reconnect(database
)) {
447 ast_mutex_unlock(&pgsql_lock
);
451 if (!(result
= PQexec(pgsqlConn
, sql
))) {
453 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
454 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
455 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
456 PQerrorMessage(pgsqlConn
));
457 ast_mutex_unlock(&pgsql_lock
);
460 ExecStatusType result_status
= PQresultStatus(result
);
461 if (result_status
!= PGRES_COMMAND_OK
462 && result_status
!= PGRES_TUPLES_OK
463 && result_status
!= PGRES_NONFATAL_ERROR
) {
465 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
466 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
467 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
468 PQresultErrorMessage(result
), PQresStatus(result_status
));
469 ast_mutex_unlock(&pgsql_lock
);
474 numrows
= atoi(PQcmdTuples(result
));
475 ast_mutex_unlock(&pgsql_lock
);
477 ast_log(LOG_DEBUG
, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows
,
480 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
481 * An integer greater than zero indicates the number of rows affected
482 * Zero indicates that no records were updated
483 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
487 return (int) numrows
;
492 static struct ast_config
*config_pgsql(const char *database
, const char *table
,
493 const char *file
, struct ast_config
*cfg
,
496 PGresult
*result
= NULL
;
498 struct ast_variable
*new_v
;
499 struct ast_category
*cur_cat
= NULL
;
500 char sqlbuf
[1024] = "";
502 size_t sqlleft
= sizeof(sqlbuf
);
504 int last_cat_metric
= 0;
508 if (!file
|| !strcmp(file
, RES_CONFIG_PGSQL_CONF
)) {
509 ast_log(LOG_WARNING
, "Postgresql RealTime: Cannot configure myself.\n");
513 ast_build_string(&sql
, &sqlleft
, "SELECT category, var_name, var_val, cat_metric FROM %s ", table
);
514 ast_build_string(&sql
, &sqlleft
, "WHERE filename='%s' and commented=0", file
);
515 ast_build_string(&sql
, &sqlleft
, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
517 ast_log(LOG_DEBUG
, "Postgresql RealTime: Static SQL: %s\n", sqlbuf
);
519 /* We now have our complete statement; Lets connect to the server and execute it. */
520 ast_mutex_lock(&pgsql_lock
);
521 if (!pgsql_reconnect(database
)) {
522 ast_mutex_unlock(&pgsql_lock
);
526 if (!(result
= PQexec(pgsqlConn
, sqlbuf
))) {
528 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
529 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
530 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
531 PQerrorMessage(pgsqlConn
));
532 ast_mutex_unlock(&pgsql_lock
);
535 ExecStatusType result_status
= PQresultStatus(result
);
536 if (result_status
!= PGRES_COMMAND_OK
537 && result_status
!= PGRES_TUPLES_OK
538 && result_status
!= PGRES_NONFATAL_ERROR
) {
540 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
541 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
542 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
543 PQresultErrorMessage(result
), PQresStatus(result_status
));
544 ast_mutex_unlock(&pgsql_lock
);
549 if ((num_rows
= PQntuples(result
)) > 0) {
552 ast_log(LOG_DEBUG
, "Postgresql RealTime: Found %ld rows.\n", num_rows
);
554 for (rowIndex
= 0; rowIndex
< num_rows
; rowIndex
++) {
555 char *field_category
= PQgetvalue(result
, rowIndex
, 0);
556 char *field_var_name
= PQgetvalue(result
, rowIndex
, 1);
557 char *field_var_val
= PQgetvalue(result
, rowIndex
, 2);
558 char *field_cat_metric
= PQgetvalue(result
, rowIndex
, 3);
559 if (!strcmp(field_var_name
, "#include")) {
560 if (!ast_config_internal_load(field_var_val
, cfg
, 0)) {
562 ast_mutex_unlock(&pgsql_lock
);
568 if (strcmp(last
, field_category
) || last_cat_metric
!= atoi(field_cat_metric
)) {
569 cur_cat
= ast_category_new(field_category
);
572 strcpy(last
, field_category
);
573 last_cat_metric
= atoi(field_cat_metric
);
574 ast_category_append(cfg
, cur_cat
);
576 new_v
= ast_variable_new(field_var_name
, field_var_val
);
577 ast_variable_append(cur_cat
, new_v
);
581 "Postgresql RealTime: Could not find config '%s' in database.\n", file
);
585 ast_mutex_unlock(&pgsql_lock
);
590 static struct ast_config_engine pgsql_engine
= {
592 .load_func
= config_pgsql
,
593 .realtime_func
= realtime_pgsql
,
594 .realtime_multi_func
= realtime_multi_pgsql
,
595 .update_func
= update_pgsql
598 static int load_module(void)
601 return AST_MODULE_LOAD_DECLINE
;
603 ast_mutex_lock(&pgsql_lock
);
605 if (!pgsql_reconnect(NULL
)) {
607 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
608 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
609 PQerrorMessage(pgsqlConn
));
612 ast_config_engine_register(&pgsql_engine
);
613 if (option_verbose
) {
614 ast_verbose("Postgresql RealTime driver loaded.\n");
616 ast_cli_register_multiple(cli_realtime
, sizeof(cli_realtime
) / sizeof(struct ast_cli_entry
));
618 ast_mutex_unlock(&pgsql_lock
);
623 static int unload_module(void)
625 /* Aquire control before doing anything to the module itself. */
626 ast_mutex_lock(&pgsql_lock
);
632 ast_cli_unregister_multiple(cli_realtime
, sizeof(cli_realtime
) / sizeof(struct ast_cli_entry
));
633 ast_config_engine_deregister(&pgsql_engine
);
634 if (option_verbose
) {
635 ast_verbose("Postgresql RealTime unloaded.\n");
638 ast_module_user_hangup_all();
640 /* Unlock so something else can destroy the lock. */
641 ast_mutex_unlock(&pgsql_lock
);
646 static int reload(void)
648 /* Aquire control before doing anything to the module itself. */
649 ast_mutex_lock(&pgsql_lock
);
657 if (!pgsql_reconnect(NULL
)) {
659 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
660 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
661 PQerrorMessage(pgsqlConn
));
664 ast_verbose(VERBOSE_PREFIX_2
"Postgresql RealTime reloaded.\n");
666 /* Done reloading. Release lock so others can now use driver. */
667 ast_mutex_unlock(&pgsql_lock
);
672 static int parse_config(void)
674 struct ast_config
*config
;
677 config
= ast_config_load(RES_CONFIG_PGSQL_CONF
);
680 ast_log(LOG_WARNING
, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF
);
683 if (!(s
= ast_variable_retrieve(config
, "general", "dbuser"))) {
685 "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
686 strcpy(dbuser
, "asterisk");
688 ast_copy_string(dbuser
, s
, sizeof(dbuser
));
691 if (!(s
= ast_variable_retrieve(config
, "general", "dbpass"))) {
693 "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
694 strcpy(dbpass
, "asterisk");
696 ast_copy_string(dbpass
, s
, sizeof(dbpass
));
699 if (!(s
= ast_variable_retrieve(config
, "general", "dbhost"))) {
701 "Postgresql RealTime: No database host found, using localhost via socket.\n");
704 ast_copy_string(dbhost
, s
, sizeof(dbhost
));
707 if (!(s
= ast_variable_retrieve(config
, "general", "dbname"))) {
709 "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
710 strcpy(dbname
, "asterisk");
712 ast_copy_string(dbname
, s
, sizeof(dbname
));
715 if (!(s
= ast_variable_retrieve(config
, "general", "dbport"))) {
717 "Postgresql RealTime: No database port found, using 5432 as default.\n");
723 if (!ast_strlen_zero(dbhost
)) {
724 /* No socket needed */
725 } else if (!(s
= ast_variable_retrieve(config
, "general", "dbsock"))) {
727 "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
728 strcpy(dbsock
, "/tmp/pgsql.sock");
730 ast_copy_string(dbsock
, s
, sizeof(dbsock
));
732 ast_config_destroy(config
);
734 if (!ast_strlen_zero(dbhost
)) {
735 ast_log(LOG_DEBUG
, "Postgresql RealTime Host: %s\n", dbhost
);
736 ast_log(LOG_DEBUG
, "Postgresql RealTime Port: %i\n", dbport
);
738 ast_log(LOG_DEBUG
, "Postgresql RealTime Socket: %s\n", dbsock
);
740 ast_log(LOG_DEBUG
, "Postgresql RealTime User: %s\n", dbuser
);
741 ast_log(LOG_DEBUG
, "Postgresql RealTime Password: %s\n", dbpass
);
742 ast_log(LOG_DEBUG
, "Postgresql RealTime DBName: %s\n", dbname
);
747 static int pgsql_reconnect(const char *database
)
749 char my_database
[50];
751 ast_copy_string(my_database
, S_OR(database
, dbname
), sizeof(my_database
));
753 /* mutex lock should have been locked before calling this function. */
755 if (pgsqlConn
&& PQstatus(pgsqlConn
) != CONNECTION_OK
) {
760 if ((!pgsqlConn
) && (!ast_strlen_zero(dbhost
) || !ast_strlen_zero(dbsock
)) && !ast_strlen_zero(dbuser
) && !ast_strlen_zero(dbpass
) && !ast_strlen_zero(my_database
)) {
761 char *connInfo
= NULL
;
762 unsigned int size
= 100 + strlen(dbhost
)
765 + strlen(my_database
);
767 if (!(connInfo
= ast_malloc(size
)))
770 sprintf(connInfo
, "host=%s port=%d dbname=%s user=%s password=%s",
771 dbhost
, dbport
, my_database
, dbuser
, dbpass
);
772 ast_log(LOG_DEBUG
, "%u connInfo=%s\n", size
, connInfo
);
773 pgsqlConn
= PQconnectdb(connInfo
);
774 ast_log(LOG_DEBUG
, "%u connInfo=%s\n", size
, connInfo
);
777 ast_log(LOG_DEBUG
, "pgsqlConn=%p\n", pgsqlConn
);
778 if (pgsqlConn
&& PQstatus(pgsqlConn
) == CONNECTION_OK
) {
779 ast_log(LOG_DEBUG
, "Postgresql RealTime: Successfully connected to database.\n");
780 connect_time
= time(NULL
);
784 "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
786 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
787 PQresultErrorMessage(NULL
));
791 ast_log(LOG_DEBUG
, "Postgresql RealTime: Everything is fine.\n");
796 static int realtime_pgsql_status(int fd
, int argc
, char **argv
)
798 char status
[256], status2
[100] = "";
799 int ctime
= time(NULL
) - connect_time
;
801 if (pgsqlConn
&& PQstatus(pgsqlConn
) == CONNECTION_OK
) {
802 if (!ast_strlen_zero(dbhost
)) {
803 snprintf(status
, 255, "Connected to %s@%s, port %d", dbname
, dbhost
, dbport
);
804 } else if (!ast_strlen_zero(dbsock
)) {
805 snprintf(status
, 255, "Connected to %s on socket file %s", dbname
, dbsock
);
807 snprintf(status
, 255, "Connected to %s@%s", dbname
, dbhost
);
810 if (!ast_strlen_zero(dbuser
)) {
811 snprintf(status2
, 99, " with username %s", dbuser
);
814 if (ctime
> 31536000) {
815 ast_cli(fd
, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
816 status
, status2
, ctime
/ 31536000, (ctime
% 31536000) / 86400,
817 (ctime
% 86400) / 3600, (ctime
% 3600) / 60, ctime
% 60);
818 } else if (ctime
> 86400) {
819 ast_cli(fd
, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status
,
820 status2
, ctime
/ 86400, (ctime
% 86400) / 3600, (ctime
% 3600) / 60,
822 } else if (ctime
> 3600) {
823 ast_cli(fd
, "%s%s for %d hours, %d minutes, %d seconds.\n", status
, status2
,
824 ctime
/ 3600, (ctime
% 3600) / 60, ctime
% 60);
825 } else if (ctime
> 60) {
826 ast_cli(fd
, "%s%s for %d minutes, %d seconds.\n", status
, status2
, ctime
/ 60,
829 ast_cli(fd
, "%s%s for %d seconds.\n", status
, status2
, ctime
);
832 return RESULT_SUCCESS
;
834 return RESULT_FAILURE
;
838 /* needs usecount semantics defined */
839 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "PostgreSQL RealTime Configuration Driver",
841 .unload
= unload_module
,