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
);
207 ast_log(LOG_DEBUG
, "Postgresql RealTime: Could not find any rows in table %s.\n", table
);
210 ast_mutex_unlock(&pgsql_lock
);
216 static struct ast_config
*realtime_multi_pgsql(const char *database
, const char *table
, va_list ap
)
218 PGresult
*result
= NULL
;
219 int num_rows
= 0, pgerror
;
220 char sql
[256], escapebuf
[513];
221 const char *initfield
= NULL
;
225 const char *newparam
, *newval
;
226 struct ast_realloca ra
;
227 struct ast_variable
*var
= NULL
;
228 struct ast_config
*cfg
= NULL
;
229 struct ast_category
*cat
= NULL
;
232 ast_log(LOG_WARNING
, "Postgresql RealTime: No table specified.\n");
236 memset(&ra
, 0, sizeof(ra
));
238 if (!(cfg
= ast_config_new()))
241 /* Get the first parameter and first value in our list of passed paramater/value pairs */
242 newparam
= va_arg(ap
, const char *);
243 newval
= va_arg(ap
, const char *);
244 if (!newparam
|| !newval
) {
246 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
254 initfield
= ast_strdupa(newparam
);
255 if ((op
= strchr(initfield
, ' '))) {
259 /* Create the first part of the query using the first parameter/value pairs we just extracted
260 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
262 if (!strchr(newparam
, ' '))
267 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
269 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
274 snprintf(sql
, sizeof(sql
), "SELECT * FROM %s WHERE %s%s '%s'", table
, newparam
, op
,
276 while ((newparam
= va_arg(ap
, const char *))) {
277 newval
= va_arg(ap
, const char *);
278 if (!strchr(newparam
, ' '))
283 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
285 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
290 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " AND %s%s '%s'", newparam
,
295 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " ORDER BY %s", initfield
);
300 /* We now have our complete statement; Lets connect to the server and execute it. */
301 ast_mutex_lock(&pgsql_lock
);
302 if (!pgsql_reconnect(database
)) {
303 ast_mutex_unlock(&pgsql_lock
);
307 if (!(result
= PQexec(pgsqlConn
, sql
))) {
309 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
310 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
311 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
312 PQerrorMessage(pgsqlConn
));
313 ast_mutex_unlock(&pgsql_lock
);
316 ExecStatusType result_status
= PQresultStatus(result
);
317 if (result_status
!= PGRES_COMMAND_OK
318 && result_status
!= PGRES_TUPLES_OK
319 && result_status
!= PGRES_NONFATAL_ERROR
) {
321 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
322 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
323 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
324 PQresultErrorMessage(result
), PQresStatus(result_status
));
325 ast_mutex_unlock(&pgsql_lock
);
330 ast_log(LOG_DEBUG
, "2Postgresql RealTime: Result=%p Query: %s\n", result
, sql
);
332 if ((num_rows
= PQntuples(result
)) > 0) {
333 int numFields
= PQnfields(result
);
336 char **fieldnames
= NULL
;
338 ast_log(LOG_DEBUG
, "Postgresql RealTime: Found %d rows.\n", num_rows
);
340 if (!(fieldnames
= ast_calloc(1, numFields
* sizeof(char *)))) {
341 ast_mutex_unlock(&pgsql_lock
);
345 for (i
= 0; i
< numFields
; i
++)
346 fieldnames
[i
] = PQfname(result
, i
);
348 for (rowIndex
= 0; rowIndex
< num_rows
; rowIndex
++) {
350 if (!(cat
= ast_category_new("")))
352 for (i
= 0; i
< numFields
; i
++) {
353 stringp
= PQgetvalue(result
, rowIndex
, i
);
355 chunk
= strsep(&stringp
, ";");
356 if (chunk
&& !ast_strlen_zero(ast_strip(chunk
))) {
357 if (initfield
&& !strcmp(initfield
, fieldnames
[i
])) {
358 ast_category_rename(cat
, chunk
);
360 var
= ast_variable_new(fieldnames
[i
], chunk
);
361 ast_variable_append(cat
, var
);
365 ast_category_append(cfg
, cat
);
367 ast_free(fieldnames
);
370 "Postgresql RealTime: Could not find any rows in table %s.\n", table
);
373 ast_mutex_unlock(&pgsql_lock
);
379 static int update_pgsql(const char *database
, const char *table
, const char *keyfield
,
380 const char *lookup
, va_list ap
)
382 PGresult
*result
= NULL
;
383 int numrows
= 0, pgerror
;
384 char sql
[256], escapebuf
[513];
385 const char *newparam
, *newval
;
388 ast_log(LOG_WARNING
, "Postgresql RealTime: No table specified.\n");
392 /* Get the first parameter and first value in our list of passed paramater/value pairs */
393 newparam
= va_arg(ap
, const char *);
394 newval
= va_arg(ap
, const char *);
395 if (!newparam
|| !newval
) {
397 "Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
405 /* Create the first part of the query using the first parameter/value pairs we just extracted
406 If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
408 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
410 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
414 snprintf(sql
, sizeof(sql
), "UPDATE %s SET %s = '%s'", table
, newparam
, escapebuf
);
416 while ((newparam
= va_arg(ap
, const char *))) {
417 newval
= va_arg(ap
, const char *);
419 PQescapeStringConn(pgsqlConn
, escapebuf
, newval
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
421 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", newval
);
426 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), ", %s = '%s'", newparam
,
431 PQescapeStringConn(pgsqlConn
, escapebuf
, lookup
, (sizeof(escapebuf
) - 1) / 2, &pgerror
);
433 ast_log(LOG_ERROR
, "Postgres detected invalid input: '%s'\n", lookup
);
438 snprintf(sql
+ strlen(sql
), sizeof(sql
) - strlen(sql
), " WHERE %s = '%s'", keyfield
,
441 ast_log(LOG_DEBUG
, "Postgresql RealTime: Update SQL: %s\n", sql
);
443 /* We now have our complete statement; Lets connect to the server and execute it. */
444 ast_mutex_lock(&pgsql_lock
);
445 if (!pgsql_reconnect(database
)) {
446 ast_mutex_unlock(&pgsql_lock
);
450 if (!(result
= PQexec(pgsqlConn
, sql
))) {
452 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
453 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
454 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
455 PQerrorMessage(pgsqlConn
));
456 ast_mutex_unlock(&pgsql_lock
);
459 ExecStatusType result_status
= PQresultStatus(result
);
460 if (result_status
!= PGRES_COMMAND_OK
461 && result_status
!= PGRES_TUPLES_OK
462 && result_status
!= PGRES_NONFATAL_ERROR
) {
464 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
465 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
466 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
467 PQresultErrorMessage(result
), PQresStatus(result_status
));
468 ast_mutex_unlock(&pgsql_lock
);
473 numrows
= atoi(PQcmdTuples(result
));
474 ast_mutex_unlock(&pgsql_lock
);
476 ast_log(LOG_DEBUG
, "Postgresql RealTime: Updated %d rows on table: %s\n", numrows
,
479 /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
480 * An integer greater than zero indicates the number of rows affected
481 * Zero indicates that no records were updated
482 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
486 return (int) numrows
;
491 static struct ast_config
*config_pgsql(const char *database
, const char *table
,
492 const char *file
, struct ast_config
*cfg
,
495 PGresult
*result
= NULL
;
497 struct ast_variable
*new_v
;
498 struct ast_category
*cur_cat
= NULL
;
499 char sqlbuf
[1024] = "";
501 size_t sqlleft
= sizeof(sqlbuf
);
503 int last_cat_metric
= 0;
507 if (!file
|| !strcmp(file
, RES_CONFIG_PGSQL_CONF
)) {
508 ast_log(LOG_WARNING
, "Postgresql RealTime: Cannot configure myself.\n");
512 ast_build_string(&sql
, &sqlleft
, "SELECT category, var_name, var_val, cat_metric FROM %s ", table
);
513 ast_build_string(&sql
, &sqlleft
, "WHERE filename='%s' and commented=0", file
);
514 ast_build_string(&sql
, &sqlleft
, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
516 ast_log(LOG_DEBUG
, "Postgresql RealTime: Static SQL: %s\n", sqlbuf
);
518 /* We now have our complete statement; Lets connect to the server and execute it. */
519 ast_mutex_lock(&pgsql_lock
);
520 if (!pgsql_reconnect(database
)) {
521 ast_mutex_unlock(&pgsql_lock
);
525 if (!(result
= PQexec(pgsqlConn
, sqlbuf
))) {
527 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
528 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
529 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s\n",
530 PQerrorMessage(pgsqlConn
));
531 ast_mutex_unlock(&pgsql_lock
);
534 ExecStatusType result_status
= PQresultStatus(result
);
535 if (result_status
!= PGRES_COMMAND_OK
536 && result_status
!= PGRES_TUPLES_OK
537 && result_status
!= PGRES_NONFATAL_ERROR
) {
539 "Postgresql RealTime: Failed to query database. Check debug for more info.\n");
540 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query: %s\n", sql
);
541 ast_log(LOG_DEBUG
, "Postgresql RealTime: Query Failed because: %s (%s)\n",
542 PQresultErrorMessage(result
), PQresStatus(result_status
));
543 ast_mutex_unlock(&pgsql_lock
);
548 if ((num_rows
= PQntuples(result
)) > 0) {
551 ast_log(LOG_DEBUG
, "Postgresql RealTime: Found %ld rows.\n", num_rows
);
553 for (rowIndex
= 0; rowIndex
< num_rows
; rowIndex
++) {
554 char *field_category
= PQgetvalue(result
, rowIndex
, 0);
555 char *field_var_name
= PQgetvalue(result
, rowIndex
, 1);
556 char *field_var_val
= PQgetvalue(result
, rowIndex
, 2);
557 char *field_cat_metric
= PQgetvalue(result
, rowIndex
, 3);
558 if (!strcmp(field_var_name
, "#include")) {
559 if (!ast_config_internal_load(field_var_val
, cfg
, 0)) {
561 ast_mutex_unlock(&pgsql_lock
);
567 if (strcmp(last
, field_category
) || last_cat_metric
!= atoi(field_cat_metric
)) {
568 cur_cat
= ast_category_new(field_category
);
571 strcpy(last
, field_category
);
572 last_cat_metric
= atoi(field_cat_metric
);
573 ast_category_append(cfg
, cur_cat
);
575 new_v
= ast_variable_new(field_var_name
, field_var_val
);
576 ast_variable_append(cur_cat
, new_v
);
580 "Postgresql RealTime: Could not find config '%s' in database.\n", file
);
584 ast_mutex_unlock(&pgsql_lock
);
589 static struct ast_config_engine pgsql_engine
= {
591 .load_func
= config_pgsql
,
592 .realtime_func
= realtime_pgsql
,
593 .realtime_multi_func
= realtime_multi_pgsql
,
594 .update_func
= update_pgsql
597 static int load_module(void)
600 return AST_MODULE_LOAD_DECLINE
;
602 ast_mutex_lock(&pgsql_lock
);
604 if (!pgsql_reconnect(NULL
)) {
606 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
607 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
608 PQerrorMessage(pgsqlConn
));
611 ast_config_engine_register(&pgsql_engine
);
612 if (option_verbose
) {
613 ast_verbose("Postgresql RealTime driver loaded.\n");
615 ast_cli_register_multiple(cli_realtime
, sizeof(cli_realtime
) / sizeof(struct ast_cli_entry
));
617 ast_mutex_unlock(&pgsql_lock
);
622 static int unload_module(void)
624 /* Aquire control before doing anything to the module itself. */
625 ast_mutex_lock(&pgsql_lock
);
631 ast_cli_unregister_multiple(cli_realtime
, sizeof(cli_realtime
) / sizeof(struct ast_cli_entry
));
632 ast_config_engine_deregister(&pgsql_engine
);
633 if (option_verbose
) {
634 ast_verbose("Postgresql RealTime unloaded.\n");
637 ast_module_user_hangup_all();
639 /* Unlock so something else can destroy the lock. */
640 ast_mutex_unlock(&pgsql_lock
);
645 static int reload(void)
647 /* Aquire control before doing anything to the module itself. */
648 ast_mutex_lock(&pgsql_lock
);
656 if (!pgsql_reconnect(NULL
)) {
658 "Postgresql RealTime: Couldn't establish connection. Check debug.\n");
659 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
660 PQerrorMessage(pgsqlConn
));
663 ast_verbose(VERBOSE_PREFIX_2
"Postgresql RealTime reloaded.\n");
665 /* Done reloading. Release lock so others can now use driver. */
666 ast_mutex_unlock(&pgsql_lock
);
671 static int parse_config(void)
673 struct ast_config
*config
;
676 config
= ast_config_load(RES_CONFIG_PGSQL_CONF
);
679 ast_log(LOG_WARNING
, "Unable to load config %s\n",RES_CONFIG_PGSQL_CONF
);
682 if (!(s
= ast_variable_retrieve(config
, "general", "dbuser"))) {
684 "Postgresql RealTime: No database user found, using 'asterisk' as default.\n");
685 strcpy(dbuser
, "asterisk");
687 ast_copy_string(dbuser
, s
, sizeof(dbuser
));
690 if (!(s
= ast_variable_retrieve(config
, "general", "dbpass"))) {
692 "Postgresql RealTime: No database password found, using 'asterisk' as default.\n");
693 strcpy(dbpass
, "asterisk");
695 ast_copy_string(dbpass
, s
, sizeof(dbpass
));
698 if (!(s
= ast_variable_retrieve(config
, "general", "dbhost"))) {
700 "Postgresql RealTime: No database host found, using localhost via socket.\n");
703 ast_copy_string(dbhost
, s
, sizeof(dbhost
));
706 if (!(s
= ast_variable_retrieve(config
, "general", "dbname"))) {
708 "Postgresql RealTime: No database name found, using 'asterisk' as default.\n");
709 strcpy(dbname
, "asterisk");
711 ast_copy_string(dbname
, s
, sizeof(dbname
));
714 if (!(s
= ast_variable_retrieve(config
, "general", "dbport"))) {
716 "Postgresql RealTime: No database port found, using 5432 as default.\n");
722 if (!ast_strlen_zero(dbhost
)) {
723 /* No socket needed */
724 } else if (!(s
= ast_variable_retrieve(config
, "general", "dbsock"))) {
726 "Postgresql RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
727 strcpy(dbsock
, "/tmp/pgsql.sock");
729 ast_copy_string(dbsock
, s
, sizeof(dbsock
));
731 ast_config_destroy(config
);
733 if (!ast_strlen_zero(dbhost
)) {
734 ast_log(LOG_DEBUG
, "Postgresql RealTime Host: %s\n", dbhost
);
735 ast_log(LOG_DEBUG
, "Postgresql RealTime Port: %i\n", dbport
);
737 ast_log(LOG_DEBUG
, "Postgresql RealTime Socket: %s\n", dbsock
);
739 ast_log(LOG_DEBUG
, "Postgresql RealTime User: %s\n", dbuser
);
740 ast_log(LOG_DEBUG
, "Postgresql RealTime Password: %s\n", dbpass
);
741 ast_log(LOG_DEBUG
, "Postgresql RealTime DBName: %s\n", dbname
);
746 static int pgsql_reconnect(const char *database
)
748 char my_database
[50];
750 ast_copy_string(my_database
, S_OR(database
, dbname
), sizeof(my_database
));
752 /* mutex lock should have been locked before calling this function. */
754 if (pgsqlConn
&& PQstatus(pgsqlConn
) != CONNECTION_OK
) {
759 if ((!pgsqlConn
) && (!ast_strlen_zero(dbhost
) || !ast_strlen_zero(dbsock
)) && !ast_strlen_zero(dbuser
) && !ast_strlen_zero(dbpass
) && !ast_strlen_zero(my_database
)) {
760 char *connInfo
= NULL
;
761 unsigned int size
= 100 + strlen(dbhost
)
764 + strlen(my_database
);
766 if (!(connInfo
= ast_malloc(size
)))
769 sprintf(connInfo
, "host=%s port=%d dbname=%s user=%s password=%s",
770 dbhost
, dbport
, my_database
, dbuser
, dbpass
);
771 ast_log(LOG_DEBUG
, "%u connInfo=%s\n", size
, connInfo
);
772 pgsqlConn
= PQconnectdb(connInfo
);
773 ast_log(LOG_DEBUG
, "%u connInfo=%s\n", size
, connInfo
);
776 ast_log(LOG_DEBUG
, "pgsqlConn=%p\n", pgsqlConn
);
777 if (pgsqlConn
&& PQstatus(pgsqlConn
) == CONNECTION_OK
) {
778 ast_log(LOG_DEBUG
, "Postgresql RealTime: Successfully connected to database.\n");
779 connect_time
= time(NULL
);
783 "Postgresql RealTime: Failed to connect database server %s on %s. Check debug for more info.\n",
785 ast_log(LOG_DEBUG
, "Postgresql RealTime: Cannot Connect: %s\n",
786 PQresultErrorMessage(NULL
));
790 ast_log(LOG_DEBUG
, "Postgresql RealTime: Everything is fine.\n");
795 static int realtime_pgsql_status(int fd
, int argc
, char **argv
)
797 char status
[256], status2
[100] = "";
798 int ctime
= time(NULL
) - connect_time
;
800 if (pgsqlConn
&& PQstatus(pgsqlConn
) == CONNECTION_OK
) {
801 if (!ast_strlen_zero(dbhost
)) {
802 snprintf(status
, 255, "Connected to %s@%s, port %d", dbname
, dbhost
, dbport
);
803 } else if (!ast_strlen_zero(dbsock
)) {
804 snprintf(status
, 255, "Connected to %s on socket file %s", dbname
, dbsock
);
806 snprintf(status
, 255, "Connected to %s@%s", dbname
, dbhost
);
809 if (!ast_strlen_zero(dbuser
)) {
810 snprintf(status2
, 99, " with username %s", dbuser
);
813 if (ctime
> 31536000) {
814 ast_cli(fd
, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
815 status
, status2
, ctime
/ 31536000, (ctime
% 31536000) / 86400,
816 (ctime
% 86400) / 3600, (ctime
% 3600) / 60, ctime
% 60);
817 } else if (ctime
> 86400) {
818 ast_cli(fd
, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status
,
819 status2
, ctime
/ 86400, (ctime
% 86400) / 3600, (ctime
% 3600) / 60,
821 } else if (ctime
> 3600) {
822 ast_cli(fd
, "%s%s for %d hours, %d minutes, %d seconds.\n", status
, status2
,
823 ctime
/ 3600, (ctime
% 3600) / 60, ctime
% 60);
824 } else if (ctime
> 60) {
825 ast_cli(fd
, "%s%s for %d minutes, %d seconds.\n", status
, status2
, ctime
/ 60,
828 ast_cli(fd
, "%s%s for %d seconds.\n", status
, status2
, ctime
);
831 return RESULT_SUCCESS
;
833 return RESULT_FAILURE
;
837 /* needs usecount semantics defined */
838 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "PostgreSQL RealTime Configuration Driver",
840 .unload
= unload_module
,