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
certified/11.2
Jonathan Rose 13 years ago
parent 84642c728f
commit b08d91c3dc

@ -1,7 +1,7 @@
/* /*
* Asterisk -- An open source telephony toolkit. * Asterisk -- An open source telephony toolkit.
* *
* Copyright (C) 2003 - 2006 * Copyright (C) 2003 - 2012
* *
* Matthew D. Hardeman <mhardemn@papersoft.com> * Matthew D. Hardeman <mhardemn@papersoft.com>
* Adapted from the MySQL CDR logger originally by James Sharp * 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(sql); \
ast_free(sql2); \ ast_free(sql2); \
AST_RWLIST_UNLOCK(&psql_columns); \ AST_RWLIST_UNLOCK(&psql_columns); \
ast_mutex_unlock(&pgsql_lock); \
return -1; \ return -1; \
} \ } \
} \ } \
@ -103,6 +104,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
ast_free(sql); \ ast_free(sql); \
ast_free(sql2); \ ast_free(sql2); \
AST_RWLIST_UNLOCK(&psql_columns); \ AST_RWLIST_UNLOCK(&psql_columns); \
ast_mutex_unlock(&pgsql_lock); \
return -1; \ return -1; \
} \ } \
} \ } \
@ -200,12 +202,8 @@ static int pgsql_log(struct ast_cdr *cdr)
int first = 1; int first = 1;
if (!sql || !sql2) { if (!sql || !sql2) {
if (sql) { ast_free(sql);
ast_free(sql); ast_free(sql2);
}
if (sql2) {
ast_free(sql2);
}
return -1; return -1;
} }
@ -336,9 +334,10 @@ static int pgsql_log(struct ast_cdr *cdr)
} }
} }
first = 0; first = 0;
} }
AST_RWLIST_UNLOCK(&psql_columns);
LENGTHEN_BUF1(ast_str_strlen(sql2) + 2); LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
AST_RWLIST_UNLOCK(&psql_columns);
ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2)); ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
ast_verb(11, "[%s]\n", ast_str_buffer(sql)); ast_verb(11, "[%s]\n", ast_str_buffer(sql));
@ -414,45 +413,35 @@ static int pgsql_log(struct ast_cdr *cdr)
return 0; 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; 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_cdr_unregister(name);
ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli)); ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
PQfinish(conn); PQfinish(conn);
if (pghostname) { ast_free(pghostname);
ast_free(pghostname); ast_free(pgdbname);
} ast_free(pgdbuser);
if (pgdbname) { ast_free(pgpassword);
ast_free(pgdbname); ast_free(pgdbport);
} ast_free(table);
if (pgdbuser) { ast_free(encoding);
ast_free(pgdbuser); ast_free(tz);
}
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_RWLIST_WRLOCK(&psql_columns); empty_columns();
while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
ast_free(current);
}
AST_RWLIST_UNLOCK(&psql_columns);
return 0; return 0;
} }
@ -474,9 +463,14 @@ static int config_module(int reload)
return 0; return 0;
} }
ast_mutex_lock(&pgsql_lock);
if (!(var = ast_variable_browse(cfg, "global"))) { if (!(var = ast_variable_browse(cfg, "global"))) {
ast_config_destroy(cfg); 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"))) { 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 */ tmp = ""; /* connect via UNIX-socket by default */
} }
if (pghostname) { ast_free(pghostname);
ast_free(pghostname);
}
if (!(pghostname = ast_strdup(tmp))) { if (!(pghostname = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -497,11 +490,10 @@ static int config_module(int reload)
tmp = "asteriskcdrdb"; tmp = "asteriskcdrdb";
} }
if (pgdbname) { ast_free(pgdbname);
ast_free(pgdbname);
}
if (!(pgdbname = ast_strdup(tmp))) { if (!(pgdbname = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -510,11 +502,10 @@ static int config_module(int reload)
tmp = "asterisk"; tmp = "asterisk";
} }
if (pgdbuser) { ast_free(pgdbuser);
ast_free(pgdbuser);
}
if (!(pgdbuser = ast_strdup(tmp))) { if (!(pgdbuser = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -523,11 +514,10 @@ static int config_module(int reload)
tmp = ""; tmp = "";
} }
if (pgpassword) { ast_free(pgpassword);
ast_free(pgpassword);
}
if (!(pgpassword = ast_strdup(tmp))) { if (!(pgpassword = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -536,11 +526,10 @@ static int config_module(int reload)
tmp = "5432"; tmp = "5432";
} }
if (pgdbport) { ast_free(pgdbport);
ast_free(pgdbport);
}
if (!(pgdbport = ast_strdup(tmp))) { if (!(pgdbport = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -549,11 +538,10 @@ static int config_module(int reload)
tmp = "cdr"; tmp = "cdr";
} }
if (table) { ast_free(table);
ast_free(table);
}
if (!(table = ast_strdup(tmp))) { if (!(table = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -562,11 +550,10 @@ static int config_module(int reload)
tmp = "LATIN9"; tmp = "LATIN9";
} }
if (encoding) { ast_free(encoding);
ast_free(encoding);
}
if (!(encoding = ast_strdup(tmp))) { if (!(encoding = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -574,12 +561,12 @@ static int config_module(int reload)
tmp = ""; tmp = "";
} }
if (tz) { ast_free(tz);
ast_free(tz); tz = NULL;
tz = NULL;
}
if (!ast_strlen_zero(tmp) && !(tz = ast_strdup(tmp))) { if (!ast_strlen_zero(tmp) && !(tz = ast_strdup(tmp))) {
ast_config_destroy(cfg); ast_config_destroy(cfg);
ast_mutex_unlock(&pgsql_lock);
return -1; return -1;
} }
@ -667,6 +654,7 @@ static int config_module(int reload)
ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror); ast_log(LOG_ERROR, "Failed to query database columns: %s\n", pgerror);
PQclear(result); PQclear(result);
unload_module(); unload_module();
ast_mutex_unlock(&pgsql_lock);
return AST_MODULE_LOAD_DECLINE; 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"); ast_log(LOG_ERROR, "cdr_pgsql: Failed to query database columns. No columns found, does the table exist?\n");
PQclear(result); PQclear(result);
unload_module(); unload_module();
ast_mutex_unlock(&pgsql_lock);
return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_DECLINE;
} }
/* Clear out the columns list. */
empty_columns();
for (i = 0; i < rows; i++) { for (i = 0; i < rows; i++) {
fname = PQgetvalue(result, i, 0); fname = PQgetvalue(result, i, 0);
ftype = PQgetvalue(result, i, 1); ftype = PQgetvalue(result, i, 1);
@ -706,7 +698,9 @@ static int config_module(int reload)
} else { } else {
cur->hasdefault = 0; cur->hasdefault = 0;
} }
AST_RWLIST_WRLOCK(&psql_columns);
AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list); AST_RWLIST_INSERT_TAIL(&psql_columns, cur, list);
AST_RWLIST_UNLOCK(&psql_columns);
} }
} }
PQclear(result); PQclear(result);
@ -719,13 +713,18 @@ static int config_module(int reload)
ast_config_destroy(cfg); 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) static int load_module(void)
{ {
ast_cli_register_multiple(cdr_pgsql_status_cli, sizeof(cdr_pgsql_status_cli) / sizeof(struct ast_cli_entry)); 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) static int reload(void)

Loading…
Cancel
Save