diff --git a/src/modules/db_postgres/doc/db_postgres_admin.xml b/src/modules/db_postgres/doc/db_postgres_admin.xml
index bb04acd4669..ebee12784f8 100644
--- a/src/modules/db_postgres/doc/db_postgres_admin.xml
+++ b/src/modules/db_postgres/doc/db_postgres_admin.xml
@@ -86,9 +86,10 @@ modparam("db_postgres", "retries", 3)
timeout (integer)
Setting this variable to any value larger than zero (which is the
- default value) enables both a connection timeout and a query
- timeout. If a connection attempt or a query takes longer than this
- many seconds, the operation will be aborted and an error will be
+ default value) enables mainly query timeout. For backward compatibility
+ it also enables connection timeout if connect_timeout param is not set
+ using the con_param below. If a connection attempt or a query takes longer
+ than this many seconds, the operation will be aborted and an error will be
returned.
@@ -170,6 +171,26 @@ modparam("db_postgres", "bytea_output_escape", 0)
+
+ con_param (str)
+
+ Specifies the connection string parameters.
+ Parameter definition must be in the format param1=value1;param2=value2.
+ Many parameters can be set.
+
+
+ NOTE: See postgres connection keyword list (https://www.postgresql.org/docs/12/libpq-connect.html#LIBPQ-PARAMKEYWORDS)
+
+
+ Set con_param parameter
+
+...
+modparam("db_postgres", "con_param", "connect_timeout=15;tcp_user_timeout=5000")
+...
+
+
+
+
diff --git a/src/modules/db_postgres/km_pg_con.c b/src/modules/db_postgres/km_pg_con.c
index 634381becd6..895c644db67 100644
--- a/src/modules/db_postgres/km_pg_con.c
+++ b/src/modules/db_postgres/km_pg_con.c
@@ -38,6 +38,7 @@
extern int pg_bytea_output_escape;
+extern pg_con_param_t* pg_con_param_list;
/*!
* \brief Create a new connection
@@ -52,9 +53,9 @@ struct pg_con *db_postgres_new_connection(struct db_id *id)
struct pg_con *ptr;
char *ports;
int i = 0;
- const char *keywords[10], *values[10];
- char to[16];
+ const char *keywords[32], *values[32];
PGresult *res = NULL;
+ pg_con_param_t* pg_con_param;
LM_DBG("db_id = %p\n", id);
@@ -75,7 +76,6 @@ struct pg_con *db_postgres_new_connection(struct db_id *id)
memset(keywords, 0, (sizeof(char *) * 10));
memset(values, 0, (sizeof(char *) * 10));
- memset(to, 0, (sizeof(char) * 16));
if(id->port) {
ports = int2str(id->port, 0);
@@ -97,10 +97,13 @@ struct pg_con *db_postgres_new_connection(struct db_id *id)
values[i++] = id->username;
keywords[i] = "password";
values[i++] = id->password;
- if(pg_timeout > 0) {
- snprintf(to, sizeof(to) - 1, "%d", pg_timeout + 3);
- keywords[i] = "connect_timeout";
- values[i++] = to;
+
+ /* add other connection parameters */
+ pg_con_param = pg_con_param_list;
+ while(pg_con_param){
+ keywords[i] = pg_con_param->name;
+ values[i++] = pg_con_param->value;
+ pg_con_param = pg_con_param->next;
}
keywords[i] = values[i] = NULL;
diff --git a/src/modules/db_postgres/pg_con.c b/src/modules/db_postgres/pg_con.c
index 62cf14922d5..83a262400a4 100644
--- a/src/modules/db_postgres/pg_con.c
+++ b/src/modules/db_postgres/pg_con.c
@@ -45,6 +45,7 @@
#include
#include
+extern pg_con_param_t* pg_con_param_list;
/* Override the default notice processor to output the messages
* using SER's output subsystem.
@@ -244,8 +245,8 @@ int pg_con_connect(db_con_t *con)
struct pg_uri *puri;
char *port_str;
int ret, i = 0;
- const char *keywords[10], *values[10];
- char to[16];
+ const char *keywords[32], *values[32];
+ pg_con_param_t* pg_con_param;
pcon = DB_GET_PAYLOAD(con);
puri = DB_GET_PAYLOAD(con->uri);
@@ -278,11 +279,14 @@ int pg_con_connect(db_con_t *con)
values[i++] = puri->username;
keywords[i] = "password";
values[i++] = puri->password;
- if(pg_timeout > 0) {
- snprintf(to, sizeof(to) - 1, "%d", pg_timeout + 3);
- keywords[i] = "connect_timeout";
- values[i++] = to;
- }
+
+ /* add other connection parameters */
+ pg_con_param = pg_con_param_list;
+ while(pg_con_param){
+ keywords[i] = pg_con_param->name;
+ values[i++] = pg_con_param->value;
+ pg_con_param = pg_con_param->next;
+ }
keywords[i] = values[i] = NULL;
diff --git a/src/modules/db_postgres/pg_mod.c b/src/modules/db_postgres/pg_mod.c
index 4fc40ac6e87..077af842619 100644
--- a/src/modules/db_postgres/pg_mod.c
+++ b/src/modules/db_postgres/pg_mod.c
@@ -39,6 +39,7 @@
#include "db_postgres.h"
#include "../../core/sr_module.h"
+#include "../../core/parser/parse_param.h"
#ifdef PG_TEST
#include
@@ -50,7 +51,6 @@ MODULE_VERSION
static int pg_mod_init(void);
static void pg_mod_destroy(void);
-int pg_connect_timeout = 0; /* Default is unlimited */
int pg_retries =
2; /* How many times should the module try re-execute failed commands.
* 0 disables reconnecting */
@@ -60,6 +60,10 @@ int pg_timeout = 0; /* default = no timeout */
int pg_keepalive = 0;
int pg_bytea_output_escape = 1;
+pg_con_param_t* pg_con_param_list = 0;
+static int pg_con_param(modparam_t type, void *val);
+static int pg_init_com_params();
+
/*
* Postgres module interface
*/
@@ -93,6 +97,7 @@ static param_export_t params[] = {
{"timeout", PARAM_INT, &pg_timeout},
{"tcp_keepalive", PARAM_INT, &pg_keepalive},
{"bytea_output_escape", PARAM_INT, &pg_bytea_output_escape},
+ {"con_param", PARAM_STRING|USE_FUNC_PARAM, (void*)pg_con_param},
{0, 0, 0}
};
@@ -543,6 +548,11 @@ static int pg_mod_init(void)
#endif /* PG_TEST */
if(pg_init_lock_set(pg_lockset) < 0)
return -1;
+
+ if(pg_init_com_params() < 0){
+ return -1;
+ }
+
return km_postgres_mod_init();
}
@@ -551,4 +561,144 @@ static void pg_mod_destroy(void)
pg_destroy_lock_set();
}
+static void free_con_param_list()
+{
+ pg_con_param_t *tmp = NULL;
+ pg_con_param_t *con_param = pg_con_param_list;
+ while(con_param)
+ {
+ if(con_param->name)
+ {
+ shm_free(con_param->name);
+ }
+ if(con_param->value)
+ {
+ shm_free(con_param->value);
+ }
+ tmp = con_param->next;
+ shm_free(con_param);
+ con_param = tmp;
+ }
+}
+
+static int add_con_param(str *name, str *value)
+{
+ /* malloc for param */
+ pg_con_param_t *con_param = (pg_con_param_t*)shm_malloc(sizeof(pg_con_param_t));
+ if(con_param == 0) {
+ LM_ERR("no more shm memory\n");
+ goto error;
+ }
+
+ /* parse name */
+ con_param->name = (char*)shm_malloc(name->len + 1);
+ if(con_param->name == NULL){
+ LM_ERR("no more shm memory while parsing name\n");
+ goto error;
+ }
+ memcpy(con_param->name, name->s, name->len);
+ con_param->name[name->len] = '\0';
+
+ /* parse value */
+ con_param->value = (char*)shm_malloc(value->len + 1);
+ if(con_param->value == NULL){
+ LM_ERR("no more shm memory while parsing value\n");
+ goto error;
+ }
+ memcpy(con_param->value, value->s, value->len);
+ con_param->value[value->len] = '\0';
+
+ /* add param to the linked list */
+ con_param->next = pg_con_param_list;
+ pg_con_param_list = con_param;
+ return 0;
+
+error:
+ free_con_param_list();
+ return -1;
+}
+
+static int pg_init_com_params()
+{
+ str connect_timeout_str = str_init("connect_timeout");
+ int ret = 0;
+
+ int connect_timeout_set = 0;
+ if(pg_con_param_list != NULL)
+ {
+ LM_INFO("postgres connection params:");
+ pg_con_param_t *con_param = pg_con_param_list;
+ while(con_param)
+ {
+ LM_INFO("%s=%s", con_param->name, con_param->value);
+
+ /* check if connect_timeout parameter is set */
+ if(strncmp(con_param->name, connect_timeout_str.s, connect_timeout_str.len) == 0)
+ {
+ connect_timeout_set = 1;
+ }
+
+ con_param = con_param->next;
+ }
+ }
+
+ /* For backward compatibility take pg_timeout param into account */
+ if(pg_timeout > 0 && connect_timeout_set == 0)
+ {
+ str connect_timeout_val_str;
+ char timeout_val[16] = {0};
+
+ snprintf(timeout_val, sizeof(timeout_val) - 1, "%d", pg_timeout);
+ connect_timeout_val_str.s = timeout_val;
+ connect_timeout_val_str.len = strlen(connect_timeout_val_str.s);
+
+ /* add connect_timeout parameter with pg_timeout value */
+ ret = add_con_param(&connect_timeout_str, &connect_timeout_val_str);
+ LM_INFO("%.*s=%.*s added with given timeout param",
+ connect_timeout_str.len, connect_timeout_str.s,
+ connect_timeout_val_str.len, connect_timeout_val_str.s);
+ }
+
+ return ret;
+}
+
+static int pg_con_param(modparam_t type, void *val) {
+ param_t* params_list=NULL;
+ param_hooks_t phooks;
+ param_t *pit=NULL;
+ str s;
+
+ if(val==NULL){
+ free_con_param_list();
+ return -1;
+ }
+ s.s = (char*)val;
+ s.len = strlen(s.s);
+ if(s.s[s.len-1]==';'){
+ s.len--;
+ }
+
+ if (parse_params(&s, CLASS_ANY, &phooks, ¶ms_list)<0){
+ free_con_param_list();
+ return -1;
+ }
+
+ /* parse parameter values */
+ for (pit=params_list; pit; pit=pit->next) {
+
+ if(pit->name.len == 0 || pit->body.len == 0) {
+ LM_ERR("invalid con_param parameter\n");
+ free_con_param_list();
+ return -1;
+ }
+
+ if(add_con_param(&pit->name, &pit->body) < 0){
+ free_con_param_list();
+ return -1;
+ }
+
+ }
+ return 0;
+}
+
/** @} */
diff --git a/src/modules/db_postgres/pg_mod.h b/src/modules/db_postgres/pg_mod.h
index 4e622b60d1b..6b97a0878b1 100644
--- a/src/modules/db_postgres/pg_mod.h
+++ b/src/modules/db_postgres/pg_mod.h
@@ -38,6 +38,12 @@ extern int pg_retries;
extern int pg_timeout;
extern int pg_keepalive;
+typedef struct pg_con_param_s {
+ char* name;
+ char* value;
+ struct pg_con_param_s* next;
+} pg_con_param_t;
+
/** @} */
#endif /* _PG_MOD_H */