diff --git a/modules/db_postgres/README b/modules/db_postgres/README
index cefcefc0b00..99d711be150 100644
--- a/modules/db_postgres/README
+++ b/modules/db_postgres/README
@@ -53,15 +53,16 @@ Chapter 1. Admin Guide
1.2.1. OpenSIPS Modules
The following modules must be loaded before this module:
- * No dependencies on other OpenSIPS modules.
+
+ tls_wolfssl - if use_tls=1 is specified
+ tls_mgm - if use_tls=1 is specified
1.2.2. External Libraries or Applications
The following libraries or applications must be installed
before running OpenSIPS with this module loaded:
* PostgreSQL library - e.g., libpq5.
- * PostgreSQL devel library - to compile the module (e.g.,
- libpq-dev).
+ * PostgreSQL devel library - to compile the module (e.g., libpq-dev).
1.3. Exported Parameters
@@ -100,7 +101,7 @@ modparam("db_postgres", "max_db_queries", 2)
succeed, OpenSIPS will block until the connection becomes back
available and gets successfully established. This is the
default behavior of the library and is the behavior prior to
- the adition of this parameter.
+ the addition of this parameter.
Default value is 5.
@@ -109,6 +110,51 @@ modparam("db_postgres", "max_db_queries", 2)
modparam("db_postgres", "timeout", 2)
...
+1.3.4. use_tls (integer)
+
+ Warning: wolfSSL is the required TLS/SSL Library
+
+ This feature is not compatible with OpenSSL for the reasons defined in
+ https://blog.opensips.org/2021/02/11/exploring-ssl-tls-libraries-for-opensips-3-2
+
+ Setting this parameter will allow you to use TLS for PostgreSQL
+ connections. In order to enable TLS for a specific connection,
+ you can use the "tls_domain=dom_name" URL parameter in the
+ db_url of the respective OpenSIPS module. This should be placed
+ at the end of the URL after the '?' character.
+
+ When using this parameter, you must also ensure that tls_mgm is
+ loaded and properly configured. Refer to the the module for
+ additional info regarding TLS client domains.
+
+ Note that if you want to use this feature, the TLS domain must
+ be provisioned in the configuration file, NOT in the database.
+ In case you are loading TLS certificates from the database, you
+ must at least define one domain in the configuration script, to
+ use for the initial connection to the DB.
+
+ Also, you can NOT enable TLS for the connection to the database
+ of the tls_mgm module itself.
+
+ Default value is 0 (not enabled)
+
+ Example 1.6. Set the use_tls parameter
+...
+loadmodule "tls_wolfssl"
+loadmodule "tls_mgm"
+loadmodule "db_postgres"
+...
+modparam("tls_mgm", "client_domain", "dom1")
+modparam("tls_mgm", "certificate", "[dom1]/etc/pki/tls/certs/opensips.pem")
+modparam("tls_mgm", "private_key", "[dom1]/etc/pki/tls/private/opensips.key")
+modparam("tls_mgm", "ca_list", "[dom1]/etc/pki/tls/certs/ca.pem")
+...
+modparam("db_postgres", "use_tls", 1)
+...
+loadmodule "usrloc"
+modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tls_domain=dom1")
+...
+
1.4. Exported Functions
NONE
@@ -135,9 +181,9 @@ Chapter 2. Contributors
9. Klaus Darilion 10 6 139 67
10. Vlad Paiu (@vladpaiu) 9 7 102 34
- All remaining contributors: Ancuta Onofrei, Norman Brandinger,
- Maksym Sobolyev (@sobomax), Vlad Patrascu (@rvlad-patrascu),
- Andrei Pelinescu-Onciul, Dusan Klinec (@ph4r05), Eseanu Marius
+ All remaining contributors: Ancuta Onofrei, Maksym Sobolyev
+ (@sobomax), Vlad Patrascu (@rvlad-patrascu), Andrei
+ Pelinescu-Onciul, Dusan Klinec (@ph4r05), Eseanu Marius
Cristian (@eseanucristian), Ruslan Bukin, Ryan Bullock
(@rrb3942), Konstantin Bokarius, Razvan Pistolea, Aron
Podrigal, Dan Pascu (@danpascu), Peter Lemenkov (@lemenkov),
@@ -163,7 +209,7 @@ Chapter 2. Contributors
Table 2.2. Most recently active contributors^(1) to this module
Name Commit Activity
- 1. Norman Brandinger (@NormB) Aug 2006 - Aug 2021
+ 1. Norm Brandinger (@NormB) Oct 2006 - Jul 2021
2. Razvan Crainea (@razvancrainea) Oct 2011 - Sep 2019
3. Dan Pascu (@danpascu) May 2019 - May 2019
4. Liviu Chircu (@liviuchircu) Sep 2012 - May 2019
@@ -173,14 +219,14 @@ Chapter 2. Contributors
8. Vlad Paiu (@vladpaiu) Jan 2011 - Feb 2019
9. Peter Lemenkov (@lemenkov) Jun 2018 - Jun 2018
10. Jarrod Baumann (@jarrodb) Mar 2016 - Mar 2016
+ 11. Dusan Klinec (@ph4r05) Dec 2015 - Dec 2015
- All remaining contributors: Dusan Klinec (@ph4r05), Aron
- Podrigal, Eseanu Marius Cristian (@eseanucristian), Razvan
- Pistolea, Ruslan Bukin, Henning Westerholt (@henningw),
- Daniel-Constantin Mierla (@miconda), Konstantin Bokarius, Edson
- Gellert Schubert, Ancuta Onofrei, Klaus Darilion, Norman
- Brandinger, Maksym Sobolyev (@sobomax), Jan Janak (@janakj),
- Greg Fausak, Andrei Pelinescu-Onciul.
+ All remaining contributors: Aron Podrigal, Eseanu Marius
+ Cristian (@eseanucristian), Razvan Pistolea, Ruslan Bukin,
+ Henning Westerholt (@henningw), Daniel-Constantin Mierla
+ (@miconda), Konstantin Bokarius, Edson Gellert Schubert, Ancuta
+ Onofrei, Klaus Darilion, Maksym Sobolyev (@sobomax), Jan Janak
+ (@janakj), Greg Fausak, Andrei Pelinescu-Onciul.
(1) including any documentation-related commits, excluding
merge commits
@@ -189,12 +235,13 @@ Chapter 3. Documentation
3.1. Contributors
- Last edited by: Liviu Chircu (@liviuchircu), Razvan Crainea
- (@razvancrainea), Peter Lemenkov (@lemenkov), Aron Podrigal,
- Eseanu Marius Cristian (@eseanucristian), Bogdan-Andrei Iancu
- (@bogdan-iancu), Vlad Paiu (@vladpaiu), Daniel-Constantin
- Mierla (@miconda), Konstantin Bokarius, Edson Gellert Schubert,
- Henning Westerholt (@henningw), Jan Janak (@janakj).
+ Last edited by: Norm Brandinger (@NormB) Liviu Chircu
+ (@liviuchircu), Razvan Crainea (@razvancrainea), Peter
+ Lemenkov (@lemenkov), Aron Podrigal, Eseanu Marius Cristian
+ (@eseanucristian), Bogdan-Andrei Iancu (@bogdan-iancu),
+ Vlad Paiu (@vladpaiu), Daniel-Constantin Mierla (@miconda),
+ Konstantin Bokarius, Edson Gellert Schubert, Henning
+ Westerholt (@henningw), Jan Janak (@janakj).
Documentation Copyrights:
diff --git a/modules/db_postgres/db_postgres.c b/modules/db_postgres/db_postgres.c
index 5881d77673f..c9e36e4cb57 100644
--- a/modules/db_postgres/db_postgres.c
+++ b/modules/db_postgres/db_postgres.c
@@ -31,11 +31,12 @@
#include "../../db/db_con.h"
#include "../../db/db.h"
#include "../../db/db_cap.h"
+#include "../tls_mgm/api.h"
#include "dbase.h"
#include "db_postgres.h"
int db_postgres_exec_query_threshold = 0; /* Warning in case DB query
- takes too long disabled by default*/
+ takes too long disabled by default*/
int max_db_queries = 2;
int pq_timeout = DEFAULT_PSQL_TIMEOUT;
@@ -51,6 +52,10 @@ static cmd_export_t cmds[] = {
{0,0,{{0,0,0}},0}
};
+struct tls_mgm_binds tls_api;
+struct tls_domain *tls_dom;
+int use_tls = 0;
+
/*
* Exported parameters
*/
@@ -58,15 +63,24 @@ static param_export_t params[] = {
{"exec_query_threshold", INT_PARAM, &db_postgres_exec_query_threshold},
{"max_db_queries", INT_PARAM, &max_db_queries},
{"timeout", INT_PARAM, &pq_timeout},
+ {"use_tls", INT_PARAM, &use_tls},
{0, 0, 0}
};
+static module_dependency_t *get_deps_use_tls(param_export_t *param)
+{
+ if (*(int *)param->param_pointer == 0)
+ return NULL;
+
+ return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_mgm", DEP_ABORT);
+}
+
static dep_export_t deps = {
{ /* OpenSIPS module dependencies */
- { MOD_TYPE_DEFAULT, "tls_mgm", DEP_SILENT },
{ MOD_TYPE_NULL, NULL, 0 },
},
{ /* modparam dependencies */
+ { "use_tls", get_deps_use_tls },
{ NULL, NULL },
},
};
@@ -98,19 +112,31 @@ struct module_exports exports = {
static int mod_init(void)
{
LM_INFO("initializing...\n");
-
+
if(max_db_queries < 1){
LM_WARN("Invalid number for max_db_queries\n");
max_db_queries = 2;
}
-
+
+ if (use_tls && load_tls_mgm_api(&tls_api) != 0) {
+ LM_ERR("failed to load tls_mgm API!\n");
+ return -1;
+ }
+
+ if (use_tls && module_loaded("tls_openssl")) {
+ LM_ERR("use_tls and tls_openssl are incompatible. Instead, use tls_wolfssl\n");
+ return -1;
+ }
+
return 0;
}
int db_postgres_bind_api(const str* mod, db_func_t *dbb)
{
- if(dbb==NULL)
+ if(!dbb) {
+ LM_ERR("%.*s dbb parameter is NULL\n", mod->len, mod->s);
return -1;
+ }
memset(dbb, 0, sizeof(db_func_t));
@@ -132,4 +158,3 @@ int db_postgres_bind_api(const str* mod, db_func_t *dbb)
dbb->cap |= DB_CAP_MULTIPLE_INSERT;
return 0;
}
-
diff --git a/modules/db_postgres/db_postgres.h b/modules/db_postgres/db_postgres.h
index 9d2b2a56dac..11086bba6b4 100644
--- a/modules/db_postgres/db_postgres.h
+++ b/modules/db_postgres/db_postgres.h
@@ -29,4 +29,8 @@
#define DEFAULT_PSQL_TIMEOUT 5
extern int pq_timeout;
+extern int use_tls;
+
+extern struct tls_mgm_binds tls_api;
+
#endif /* DB_POSTGRES_H */
diff --git a/modules/db_postgres/dbase.c b/modules/db_postgres/dbase.c
index 7c1419985c3..5bbdfc8992e 100644
--- a/modules/db_postgres/dbase.c
+++ b/modules/db_postgres/dbase.c
@@ -473,7 +473,7 @@ int db_postgres_free_result(db_con_t* _con, db_res_t* _r)
* _op: operators
* _v: values of the keys that must match
* _c: column names to return
- * _n: nmber of key=values pairs to compare
+ * _n: number of key=values pairs to compare
* _nc: number of columns to return
* _o: order by the specified column
*/
@@ -503,7 +503,7 @@ int db_postgres_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
*
* Input:
* db_con_t* _con Structure representing the database connection
- * db_res_t** _r pointer to a structure represending the result set
+ * db_res_t** _r pointer to a structure representing the result set
*
* Output:
* return 0: If the status of the last command produced a result set and,
@@ -516,7 +516,7 @@ int db_postgres_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
* Notes:
* A new result structure is allocated on every call to this routine.
*
- * If this routine returns 0, it is the callers responsbility to free the
+ * If this routine returns 0, it is the callers' responsibility to free the
* result structure. If this routine returns < 0, then the result structure
* is freed before returning to the caller.
*
diff --git a/modules/db_postgres/dbase.h b/modules/db_postgres/dbase.h
index 9242be71700..2448f2284b9 100644
--- a/modules/db_postgres/dbase.h
+++ b/modules/db_postgres/dbase.h
@@ -42,10 +42,8 @@
/**
* Postgres default timeout
*/
-#define DEFAULT_POSTGRES_TIMEOUT 5
extern int pg_timeout;
-
/**
* Initialize database connection
*/
@@ -61,7 +59,6 @@ void db_postgres_close(db_con_t* _h);
*/
int db_postgres_store_result(const db_con_t* _h, db_res_t** _r);
-
/**
* Free all memory allocated by get_result
*/
diff --git a/modules/db_postgres/doc/db_postgres_admin.xml b/modules/db_postgres/doc/db_postgres_admin.xml
index a5929f574cd..db0113c96b7 100644
--- a/modules/db_postgres/doc/db_postgres_admin.xml
+++ b/modules/db_postgres/doc/db_postgres_admin.xml
@@ -112,6 +112,58 @@ modparam("db_postgres", "max_db_queries", 2)
...
modparam("db_postgres", "timeout", 2)
...
+
+
+
+
+
+ use_tls (integer)
+
+ Warning: the tls_openssl module cannot be used
+ when setting this parameter. Use the tls_wolfssl
+ module instead if a TLS/SSL Library is required.
+
+
+ Setting this parameter will allow you to use TLS for PostgreSQL connections.
+ In order to enable TLS for a specific connection, you can use the
+ "tls_domain=dom_name" URL parameter in the db_url of
+ the respective OpenSIPS module. This should be placed at the end of the
+ URL after the '?' character.
+
+
+ When using this parameter, you must also ensure that
+ tls_mgm is loaded and properly configured. Refer to
+ the the module for additional info regarding TLS client domains.
+
+
+ Note that if you want to use this feature, the TLS domain must be
+ provisioned in the configuration file, NOT in
+ the database. In case you are loading TLS certificates from the
+ database, you must at least define one domain in the
+ configuration script, to use for the initial connection to the DB.
+
+
+ Also, you can NOT enable TLS for the connection
+ to the database of the tls_mgm module itself.
+
+
+
+ Default value is 0 (not enabled)
+
+
+
+ Set the use_tls parameter
+
+...
+modparam("tls_mgm", "client_domain", "dom1")
+modparam("tls_mgm", "certificate", "[dom1]/etc/pki/tls/certs/opensips.pem")
+modparam("tls_mgm", "private_key", "[dom1]/etc/pki/tls/private/opensips.key")
+modparam("tls_mgm", "ca_list", "[dom1]/etc/pki/tls/certs/ca.pem")
+...
+modparam("db_postgres", "use_tls", 1)
+...
+modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tls_domain=dom1")
+...
diff --git a/modules/db_postgres/pg_con.c b/modules/db_postgres/pg_con.c
index f22dc755f84..d9e60ff55d4 100644
--- a/modules/db_postgres/pg_con.c
+++ b/modules/db_postgres/pg_con.c
@@ -19,21 +19,64 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "db_postgres.h"
+
+#include
+#include
+
#include "pg_con.h"
+#include "db_postgres.h"
+#include "dbase.h"
+
+#include "../tls_mgm/api.h"
#include "../../mem/mem.h"
#include "../../dprint.h"
#include "../../ut.h"
-#include
-#include
-#define PSQL_PARAMS_MAX 7
+#define PSQL_PARAMS_MAX 15
+#define DB_TLS_DOMAIN_PARAM_EQ_LEN 11
+#define EXPAND_DBNAME 1
-/*
- * Create a new connection structure,
- * open the PostgreSQL connection and set reference count to 1
- */
-struct pg_con* db_postgres_new_connection(struct db_id* id)
+/* locate tls_domain=[dom] in the parameter string */
+/* if found, a new string with tls_domain=[dom] is returned and MUST be freed */
+/* if not found, NULL is returned */
+char *get_postgres_tls_dom(struct db_id* id)
+{
+ char *output = NULL;
+ char *index = strstr(id->parameters, DB_TLS_DOMAIN_PARAM_EQ);
+
+ if (index) {
+ int len;
+ char *end = strchr(index, '&');
+ if (end) {
+ len = end - index;
+ } else {
+ len = strlen(index);
+ }
+ output = (char *)pkg_malloc(len+1);
+ memcpy(output, index, len);
+ output[len] = '\0';
+ }
+ return output;
+}
+
+/* helper routine to remove a substring from a string */
+void rmSubstr(char *str, const char *toRemove)
+{
+ size_t length = strlen(toRemove);
+ while((str = strstr(str, toRemove)))
+ {
+ memmove(str, str + length, 1 + strlen(str + length));
+ }
+}
+
+/* helper routine to remove a character at an index from a string */
+void removeChar(char *str, unsigned int index) {
+ char *src;
+ for (src = str+index; *src != '\0'; *src = *(src+1),++src) ;
+ *src = '\0';
+}
+
+int db_postgres_connect(struct pg_con* ptr)
{
#define PSQL_PARAM(_k, _v) \
do { \
@@ -41,65 +84,119 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
values[p] = (_v); \
p++; \
} while (0);
- struct pg_con* ptr;
const char *keywords[PSQL_PARAMS_MAX];
const char *values[PSQL_PARAMS_MAX];
- char *ports;
- char *dbname;
- int p = 0, lend, lenp;
+ int p = 0;
- LM_DBG("db_id = %p\n", id);
+ char *ports = NULL;
+ int len = 0;
+ char *tls_domain = NULL;
+ char *copy = NULL;
+ str tls_domain_name = {0, 0};
+ struct db_id* id = NULL;
- if (!id) {
- LM_ERR("invalid db_id parameter value\n");
- return 0;
+ if (ptr) {
+ id = ptr->id;
+ } else {
+ LM_ERR("connection ptr parameter invalid\n");
+ return -1;
}
- ptr = (struct pg_con*)pkg_malloc(sizeof(struct pg_con));
- if (!ptr) {
- LM_ERR("failed trying to allocated %lu bytes for connection structure."
- "\n", (unsigned long)sizeof(struct pg_con));
- return 0;
+ if (id->parameters) {
+ int len = strlen(id->parameters);
+ copy = (char *)pkg_malloc(len+1);
+ memcpy(copy, id->parameters, len);
+ copy[len] = '\0';
+
+ /* locate tls_domain=[dom] in the parameter string */
+ /* if found, a new string with tls_domain=[dom] is returned and MUST be freed */
+ /* if not found, NULL is returned */
+ tls_domain = get_postgres_tls_dom(id);
}
- LM_DBG("%p=pkg_malloc(%zu)\n", ptr, sizeof(struct pg_con));
- memset(ptr, 0, sizeof(struct pg_con));
- ptr->ref = 1;
+ /* If tls_domain=[dom] is found in the parameter list, set str tls_domain_name and remove it */
+ if (tls_domain) {
+ tls_domain_name.s = tls_domain + DB_TLS_DOMAIN_PARAM_EQ_LEN; // tls_domain=
+ tls_domain_name.len = (int)strlen(tls_domain + DB_TLS_DOMAIN_PARAM_EQ_LEN); // len of [dom]
+
+ LM_DBG("TLS domain(%d): %.*s\n", tls_domain_name.len, tls_domain_name.len, tls_domain_name.s);
+
+ // remove tls_domain=[dom]
+ rmSubstr(copy, tls_domain);
- if (id->parameters) {
- lend = strlen(id->database);
- lenp = strlen(id->parameters);
- dbname = pkg_malloc(7 /* "dbname=" */ +
- lend + 1 /* ? */ + lenp + 1 /* '\0' */);
- if (!dbname) {
- LM_ERR("oom for building database name!\n");
- goto err;
+ // if tls_domain was the first parameter
+ // before rmSubstr() tls_domain=[dom]&application_name=opensips&connect_timeout=100
+ // after rmSubstr() &application_name=opensips&connect_timeout=100
+ if (*copy == '&') {
+ memmove(copy, copy+1, strlen(copy));
}
- memcpy(dbname, "dbname=", 7);
- memcpy(dbname + 7, id->database, lend);
- lend += 7;
- dbname[lend] = ' ';
- lend += 1;
- memcpy(dbname + lend, id->parameters, lenp);
- dbname[lend + lenp] = '\0';
- /* convert '&' to spaces */
- for (; dbname[lend] != '\0'; lend++) {
- if (dbname[lend] == '&' && lend > 2 &&
- (dbname[lend-1] != '\\' || (dbname[lend-2] != '\\')))
- dbname[lend] = ' ';
+ // if tls_domain was the last parameter
+ // before rmSubstr() application_name=opensips&connect_timeout=100&tls_domain=[dom]
+ // after rmSubstr() &application_name=opensips&connect_timeout=100&
+ len = strlen(copy);
+ if (copy[len-1] == '&') {
+ copy[len-1] = '\0';
}
- } else
- dbname = id->database;
- if (id->port) {
- ports = int2str(id->port, 0);
- LM_DBG("opening connection: postgres://xxxx:xxxx@%s:%d/%s\n", ZSW(id->host),
- id->port, ZSW(dbname));
- PSQL_PARAM("port", ports);
- } else {
- ports = NULL;
- LM_DBG("opening connection: postgres://xxxx:xxxx@%s/%s\n", ZSW(id->host),
- ZSW(dbname));
+ // if tls_domain was a middle parameter
+ // before rmSubstr() application_name=opensips&tls_domain=[dom]&connect_timeout=100
+ // after rmSubstr() &application_name=opensips&&connect_timeout=100
+ char *index = strstr(copy, "&&");
+ if (index) {
+ removeChar(copy, index-copy);
+ }
+
+ pkg_free(tls_domain);
+ }
+
+ /* If use_tls is specified and tls_domain=[dom] was found in the parameter list */
+ /* configure the SSL connection parameters */
+ if (use_tls && tls_domain_name.len) {
+ /* the connection should use TLS */
+ if (!ptr->tls_dom) {
+ ptr->tls_dom = tls_api.find_client_domain_name(&tls_domain_name);
+ if (!ptr->tls_dom) {
+ LM_ERR("TLS domain: %.*s not found\n", tls_domain_name.len, tls_domain_name.s);
+ return -1;
+ }
+ }
+
+ LM_DBG("SSL key file: %.*s\n", ptr->tls_dom->pkey.len, ptr->tls_dom->pkey.s);
+ LM_DBG("SSL cert file: %.*s\n", ptr->tls_dom->cert.len, ptr->tls_dom->cert.s);
+ LM_DBG("SSL ca file: %.*s\n", ptr->tls_dom->ca.len, ptr->tls_dom->ca.s);
+ LM_DBG("SSL verify_cert: %d\n", ptr->tls_dom->verify_cert);
+
+ if (ptr->tls_dom->verify_cert == 1) {
+ PSQL_PARAM("sslmode", "verify-ca");
+ }
+
+ PSQL_PARAM("sslkey", ptr->tls_dom->pkey.s);
+ PSQL_PARAM("sslcert", ptr->tls_dom->cert.s);
+ PSQL_PARAM("sslrootcert", ptr->tls_dom->ca.s);
+ }
+
+ /* force the default timeout */
+ /* If connect_timeout is specified in the parameter list, it will override this value */
+ if (pq_timeout > 0) {
+ PSQL_PARAM("connect_timeout", int2str(pq_timeout, 0));
+ }
+
+ if (copy) {
+ /* Change parameters to connection string: convert '&' to space */
+ for (int i=0; copy[i] != '\0'; i++) {
+ if (copy[i] == '&' ) {
+ copy[i] = ' ';
+ }
+ }
+
+ /* PQconnectdbParams(keywords, values, EXPAND_DBNAME) */
+ /* When expand_dbname is non-zero, the value for the first dbname key word is checked to see if it is a connection string. */
+ /* If so, it is expanded into the individual connection parameters extracted from the string. */
+ /* The value is considered to be a connection string, rather than just a database name, */
+ /* if it contains an equal sign (=) or it begins with a URI scheme designator. */
+ /* Only the first occurrence of dbname is treated in this way; any subsequent dbname parameter is processed as a plain database name. */
+ LM_DBG("connection string (%ld): %s\n", strlen(copy), copy);
+ PSQL_PARAM("dbname", copy);
}
if (id->host)
@@ -108,38 +205,109 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
PSQL_PARAM("user", id->username);
if (id->password)
PSQL_PARAM("password", id->password);
+ if (id->database) {
+ PSQL_PARAM("dbname", id->database);
+ }
- PSQL_PARAM("dbname", dbname);
+ if (id->port) {
+ ports = int2str(id->port, 0);
+ LM_DBG("opening connection: postgres://xxxx:xxxx@%s:%d/%s %s\n", ZSW(id->host), id->port, ZSW(id->database), ZSW(copy));
+ PSQL_PARAM("port", ports);
+ } else {
+ ports = NULL;
+ LM_DBG("opening connection: postgres://xxxx:xxxx@%s/%s %s\n", ZSW(id->host), ZSW(id->database), ZSW(copy));
+ }
- /* force the default timeout */
- if (pq_timeout > 0)
- PSQL_PARAM("connect_timeout", int2str(pq_timeout, 0));
+ /* End of the parameter list */
PSQL_PARAM(0, 0);
- ptr->con = PQconnectdbParams(keywords, values, 1);
- if (dbname != id->database)
- pkg_free(dbname);
+ /* Print the parameter list created by PGSQL_PARAM */
+ for (int i=0; icon = PQconnectdbParams(keywords, values, EXPAND_DBNAME);
+
+ /* After the connection is attempted, there is no need to keep the copy of the parameter list */
+ if (copy) {
+ pkg_free(copy);
+ }
- if( (ptr->con == 0) || (PQstatus(ptr->con) != CONNECTION_OK) )
+ /* If an error happened while trying to connect, cleanup */
+ if(!ptr->con || (PQstatus(ptr->con) != CONNECTION_OK) )
{
- LM_ERR("%s\n", PQerrorMessage(ptr->con));
+ LM_ERR("PQconnectdbParams: %s\n", PQerrorMessage(ptr->con));
PQfinish(ptr->con);
- goto err;
+ return -1;
}
ptr->connected = 1;
ptr->timestamp = time(0);
+
+ return 0;
+}
+
+/*
+ * Create a new connection structure,
+ * open the PostgreSQL connection and set reference count to 1
+ */
+struct pg_con* db_postgres_new_connection(struct db_id* id)
+{
+ struct pg_con* ptr = NULL;
+
+ if (!id) {
+ LM_ERR("invalid db_id parameter value\n");
+ return 0;
+ } else {
+ LM_DBG("db_id = %p\n", id);
+ }
+
+ ptr = (struct pg_con*)pkg_malloc(sizeof(struct pg_con));
+ if (!ptr) {
+ LM_ERR("failed trying to allocated %lu bytes for connection structure."
+ "\n", (unsigned long)sizeof(struct pg_con));
+ return 0;
+ }
+
+ LM_DBG("db_id: %p %p=pkg_malloc(%zu)\n", id, ptr, sizeof(struct pg_con));
+ memset(ptr, 0, sizeof(struct pg_con));
+
+ ptr->ref = 1;
ptr->id = id;
- return ptr;
+ LM_DBG("calling db_postgres_connect ptr = %p, db_id = %p\n", ptr, ptr->id);
- err:
- if (ptr) {
- LM_ERR("cleaning up %p=pkg_free()\n", ptr);
- pkg_free(ptr);
+ if (db_postgres_connect(ptr)!=0) {
+ LM_ERR("initial connect failed, cleaning up %p=pkg_free()\n", ptr);
+ if (ptr) {
+ pkg_free(ptr);
+ }
+ return 0;
}
- return 0;
-#undef PSQL_PARAM
+
+ /* Print connection information */
+ PQconninfoOption *conninfo = NULL;
+ conninfo = PQconninfo(ptr->con);
+ if (!conninfo) {
+ LM_DBG("unable to get connection options for ptr = %p con = %p\n", ptr, ptr->con);
+ } else {
+ for (int i=0; conninfo[i].keyword != NULL; i++) {
+ if (!strncmp(conninfo[i].keyword, "password", 8) || !strncmp(conninfo[i].keyword, "user", 4)) {
+ continue;
+ }
+ LM_DBG("con(%p) %s=%s\n", ptr->con, conninfo[i].keyword, conninfo[i].val);
+ }
+ PQconninfoFree(conninfo);
+ }
+
+ return ptr;
}
/*
@@ -148,12 +316,22 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
*/
struct pg_con* db_postgres_new_async_connection(struct db_id* id)
{
- struct pg_con * ret = db_postgres_new_connection(id);
- if (ret) {
- PQsetnonblocking(ret->con, 1);
+ struct pg_con *ptr;
+
+ if (!id) {
+ LM_ERR("invalid db_id parameter value\n");
+ return 0;
+ } else {
+ LM_DBG("db_id = %p\n", id);
+ }
+
+ ptr = db_postgres_new_connection(id);
+
+ if (ptr) {
+ PQsetnonblocking(ptr->con, 1);
}
- return ret;
+ return ptr;
}
/*
@@ -162,11 +340,21 @@ struct pg_con* db_postgres_new_async_connection(struct db_id* id)
void db_postgres_free_connection(struct pool_con* con)
{
- if (!con) return;
+ if (!con) {
+ LM_ERR("invalid connection parameter value\n");
+ return;
+ } else {
+ LM_DBG("connection = %p\n", con);
+ }
struct pg_con * _c;
_c = (struct pg_con*)con;
+ if (_c->tls_dom) {
+ tls_api.release_domain(_c->tls_dom);
+ _c->tls_dom = NULL;
+ }
+
if (_c->res) {
LM_DBG("PQclear(%p)\n", _c->res);
PQclear(_c->res);
@@ -178,6 +366,6 @@ void db_postgres_free_connection(struct pool_con* con)
PQfinish(_c->con);
_c->con = 0;
}
- LM_DBG("pkg_free(%p)\n", _c);
+ LM_DBG("cleaning up connection pkg_free(%p)\n", _c);
pkg_free(_c);
}
diff --git a/modules/db_postgres/pg_con.h b/modules/db_postgres/pg_con.h
index 3215b40a9ea..e081edd876b 100644
--- a/modules/db_postgres/pg_con.h
+++ b/modules/db_postgres/pg_con.h
@@ -34,6 +34,7 @@
#include "../../db/db_pool.h"
#include "../../db/db_id.h"
+#include "../tls_mgm/tls_helper.h"
#include
#include
@@ -56,6 +57,8 @@ struct pg_con {
char** row; /* Actual row in the result */
time_t timestamp; /* Timestamp of last query */
+ struct tls_domain *tls_dom;; /* TLS domain */
+
};
#define CON_SQLURL(db_con) (((struct pg_con*)((db_con)->tail))->sqlurl)