summaryrefslogtreecommitdiff
path: root/cdr/cdr_pgsql.c
diff options
context:
space:
mode:
authorJonathan Rose <jrose@digium.com>2012-02-07 15:29:14 +0000
committerJonathan Rose <jrose@digium.com>2012-02-07 15:29:14 +0000
commitb08d91c3dc9f0bf48e898b5c1dd91a6c0ea86c70 (patch)
treeb9bd86903b8777208ac321f70919798ea6935805 /cdr/cdr_pgsql.c
parent84642c728fe3f2b3e3a881892e2a7eb3f8c608b9 (diff)
Fix column duplication bug in module reload for cdr_pgsql.
Prior to this patch, attempts to reload cdr_pgsql.so would cause the column list to keep its current data and then add a second copy during the reload. This would cause attempts to log the CDR to the database to fail. This patch also cleans up some unnecessary null checks for ast_free and deals with a few potential locking problems. (closes issue ASTERISK-19216) Reported by: Jacek Konieczny Review: https://reviewboard.asterisk.org/r/1711/ ........ Merged revisions 354263 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 354270 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@354275 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'cdr/cdr_pgsql.c')
-rw-r--r--cdr/cdr_pgsql.c135
1 files changed, 67 insertions, 68 deletions
diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c
index b26e7dac4..4f495f429 100644
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2003 - 2006
+ * Copyright (C) 2003 - 2012
*
* Matthew D. Hardeman <mhardemn@papersoft.com>
* Adapted from the MySQL CDR logger originally by James Sharp
@@ -90,6 +90,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
ast_free(sql); \
ast_free(sql2); \
AST_RWLIST_UNLOCK(&psql_columns); \
+ ast_mutex_unlock(&pgsql_lock); \
return -1; \
} \
} \
@@ -103,6 +104,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
ast_free(sql); \
ast_free(sql2); \
AST_RWLIST_UNLOCK(&psql_columns); \
+ ast_mutex_unlock(&pgsql_lock); \
return -1; \
} \
} \
@@ -198,14 +200,10 @@ static int pgsql_log(struct ast_cdr *cdr)
struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
char buf[257], escapebuf[513], *value;
int first = 1;
-
+
if (!sql || !sql2) {
- if (sql) {
- ast_free(sql);
- }
- if (sql2) {
- ast_free(sql2);
- }
+ ast_free(sql);
+ ast_free(sql2);
return -1;
}
@@ -336,9 +334,10 @@ static int pgsql_log(struct ast_cdr *cdr)
}
}
first = 0;
- }
- AST_RWLIST_UNLOCK(&psql_columns);
+ }
+
LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
+ AST_RWLIST_UNLOCK(&psql_columns);
ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
ast_verb(11, "[%s]\n", ast_str_buffer(sql));
@@ -414,45 +413,35 @@ static int pgsql_log(struct ast_cdr *cdr)
return 0;
}
-static int unload_module(void)
+/* This function should be called without holding the pgsql_columns lock */
+static void empty_columns(void)
{
struct columns *current;
+ AST_RWLIST_WRLOCK(&psql_columns);
+ while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
+ ast_free(current);
+ }
+ AST_RWLIST_UNLOCK(&psql_columns);
+}
+
+static int unload_module(void)
+{
ast_cdr_unregister(name);
ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
PQfinish(conn);
- if (pghostname) {
- ast_free(pghostname);
- }
- if (pgdbname) {
- ast_free(pgdbname);
- }
- if (pgdbuser) {
- ast_free(pgdbuser);
- }
- if (pgpassword) {
- ast_free(pgpassword);
- }
- if (pgdbport) {
- ast_free(pgdbport);
- }
- if (table) {
- ast_free(table);
- }
- if (encoding) {
- ast_free(encoding);
- }
- if (tz) {
- ast_free(tz);
- }
+ ast_free(pghostname);
+ ast_free(pgdbname);
+ ast_free(pgdbuser);
+ ast_free(pgpassword);
+ ast_free(pgdbport);
+ ast_free(table);
+ ast_free(encoding);
+ ast_free(tz);
- AST_RWLIST_WRLOCK(&psql_columns);
- while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
- ast_free(current);
- }
- AST_RWLIST_UNLOCK(&psql_columns);
+ empty_columns();
return 0;
}
@@ -474,9 +463,14 @@ static int config_module(int reload)
return 0;
}
+ ast_mutex_lock(&pgsql_lock);
+
if (!(var = ast_variable_browse(cfg, "global"))) {
ast_config_destroy(cfg);
- return 0;
+ ast_mutex_unlock(&pgsql_lock);
+ ast_log(LOG_NOTICE, "cdr_pgsql configuration contains no global section, skipping module %s.\n",
+ reload ? "reload" : "load");
+ return -1;
}
if (!(tmp = ast_variable_retrieve(cfg, "global", "hostname"))) {
@@ -484,11 +478,10 @@ static int config_module(int reload)
tmp = ""; /* connect via UNIX-socket by default */
}
- if (pghostname) {
- ast_free(pghostname);
- }
+ ast_free(pghostname);
if (!(pghostname = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -497,11 +490,10 @@ static int config_module(int reload)
tmp = "asteriskcdrdb";
}
- if (pgdbname) {
- ast_free(pgdbname);
- }
+ ast_free(pgdbname);
if (!(pgdbname = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -510,11 +502,10 @@ static int config_module(int reload)
tmp = "asterisk";
}
- if (pgdbuser) {
- ast_free(pgdbuser);
- }
+ ast_free(pgdbuser);
if (!(pgdbuser = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -523,11 +514,10 @@ static int config_module(int reload)
tmp = "";
}
- if (pgpassword) {
- ast_free(pgpassword);
- }
+ ast_free(pgpassword);
if (!(pgpassword = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -536,11 +526,10 @@ static int config_module(int reload)
tmp = "5432";
}
- if (pgdbport) {
- ast_free(pgdbport);
- }
+ ast_free(pgdbport);
if (!(pgdbport = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -549,11 +538,10 @@ static int config_module(int reload)
tmp = "cdr";
}
- if (table) {
- ast_free(table);
- }
+ ast_free(table);
if (!(table = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -562,11 +550,10 @@ static int config_module(int reload)
tmp = "LATIN9";
}
- if (encoding) {
- ast_free(encoding);
- }
+ ast_free(encoding);
if (!(encoding = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -574,12 +561,12 @@ static int config_module(int reload)
tmp = "";
}
- if (tz) {
- ast_free(tz);
- tz = NULL;
- }
+ ast_free(tz);
+ tz = NULL;
+
if (!ast_strlen_zero(tmp) && !(tz = ast_strdup(tmp))) {
ast_config_destroy(cfg);
+ ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -667,6 +654,7 @@ static int config_module(int reload)
ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
PQclear(result);
unload_module();
+ ast_mutex_unlock(&pgsql_lock);
return AST_MODULE_LOAD_DECLINE;
}
@@ -675,9 +663,13 @@ static int config_module(int reload)
ast_log(LOG_ERROR, "cdr_pgsql: Failed to query database columns. No columns found, does the table exist?\n");
PQclear(result);
unload_module();
+ ast_mutex_unlock(&pgsql_lock);
return AST_MODULE_LOAD_DECLINE;
}
+ /* Clear out the columns list. */
+ empty_columns();
+
for (i = 0; i < rows; i++) {
fname = PQgetvalue(result, i, 0);
ftype = PQgetvalue(result, i, 1);
@@ -706,7 +698,9 @@ static int config_module(int reload)
} else {
cur->hasdefault = 0;
}
+ AST_RWLIST_WRLOCK(&psql_columns);
AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list);
+ AST_RWLIST_UNLOCK(&psql_columns);
}
}
PQclear(result);
@@ -719,13 +713,18 @@ static int config_module(int reload)
ast_config_destroy(cfg);
- return ast_cdr_register(name, ast_module_info->description, pgsql_log);
+ ast_mutex_unlock(&pgsql_lock);
+ return 0;
}
static int load_module(void)
{
ast_cli_register_multiple(cdr_pgsql_status_cli, sizeof(cdr_pgsql_status_cli) / sizeof(struct ast_cli_entry));
- return config_module(0) ? AST_MODULE_LOAD_DECLINE : 0;
+ if (config_module(0)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ return ast_cdr_register(name, ast_module_info->description, pgsql_log)
+ ? AST_MODULE_LOAD_DECLINE : 0;
}
static int reload(void)