summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-10-27 20:04:17 +0000
committerMatthew Jordan <mjordan@digium.com>2013-10-27 20:04:17 +0000
commit3713fa5c9f9bab64f21a3602c4a201bcb2458084 (patch)
tree14a82dae119e398850640e050a97801bcffd3d96
parent2e24dfe4d1c44f978607aaee80225db8e18967fc (diff)
Prevent CDR backends from unregistering while billing data is in flight
This patch makes it so that CDR backends cannot be unregistered while active CDR records exist. This helps to prevent billing data from being lost during restarts and shutdowns. Review: https://reviewboard.asterisk.org/r/2880/ ........ Merged revisions 402081 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402082 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--addons/cdr_mysql.c14
-rw-r--r--cdr/cdr_adaptive_odbc.c5
-rw-r--r--cdr/cdr_csv.c5
-rw-r--r--cdr/cdr_custom.c4
-rw-r--r--cdr/cdr_manager.c24
-rw-r--r--cdr/cdr_odbc.c8
-rw-r--r--cdr/cdr_pgsql.c5
-rw-r--r--cdr/cdr_radius.c5
-rw-r--r--cdr/cdr_sqlite.c5
-rw-r--r--cdr/cdr_sqlite3_custom.c4
-rw-r--r--cdr/cdr_syslog.c4
-rw-r--r--cdr/cdr_tds.c6
-rw-r--r--include/asterisk/cdr.h21
-rw-r--r--main/cdr.c78
14 files changed, 152 insertions, 36 deletions
diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c
index 25b55b35f..b00a3f345 100644
--- a/addons/cdr_mysql.c
+++ b/addons/cdr_mysql.c
@@ -384,9 +384,11 @@ static int my_unload_module(int reload)
}
dbport = 0;
- ast_cdr_unregister(name);
-
- return 0;
+ if (reload) {
+ return ast_cdr_backend_suspend(name);
+ } else {
+ return ast_cdr_unregister(name);
+ }
}
static int my_load_config_string(struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
@@ -660,7 +662,11 @@ static int my_load_module(int reload)
return AST_MODULE_LOAD_FAILURE;
}
- res = ast_cdr_register(name, desc, mysql_log);
+ if (!reload) {
+ res = ast_cdr_register(name, desc, mysql_log);
+ } else {
+ res = ast_cdr_backend_unsuspend(name);
+ }
if (res) {
ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
} else {
diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c
index 0a9cfdbdd..4078b79ba 100644
--- a/cdr/cdr_adaptive_odbc.c
+++ b/cdr/cdr_adaptive_odbc.c
@@ -767,7 +767,10 @@ early_release:
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
ast_cdr_register(name, ast_module_info->description, odbc_log);
ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index a6f8a4dc0..1cc1747c6 100644
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -315,7 +315,10 @@ static int csv_log(struct ast_cdr *cdr)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
loaded = 0;
return 0;
}
diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c
index 2a3b1a1dd..51235db7f 100644
--- a/cdr/cdr_custom.c
+++ b/cdr/cdr_custom.c
@@ -184,7 +184,9 @@ static int custom_log(struct ast_cdr *cdr)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
if (AST_RWLIST_WRLOCK(&sinks)) {
ast_cdr_register(name, ast_module_info->description, custom_log);
diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c
index e3ae7a57d..90c5dbd23 100644
--- a/cdr/cdr_manager.c
+++ b/cdr/cdr_manager.c
@@ -86,8 +86,9 @@ static int load_config(int reload)
if (!cfg) {
/* Standard configuration */
ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
- if (enablecdr)
- ast_cdr_unregister(name);
+ if (enablecdr) {
+ ast_cdr_backend_suspend(name);
+ }
enablecdr = 0;
return -1;
}
@@ -135,10 +136,11 @@ static int load_config(int reload)
ast_config_destroy(cfg);
- if (enablecdr && !newenablecdr)
- ast_cdr_unregister(name);
- else if (!enablecdr && newenablecdr)
- ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
+ if (!newenablecdr) {
+ ast_cdr_backend_suspend(name);
+ } else if (newenablecdr) {
+ ast_cdr_backend_unsuspend(name);
+ }
enablecdr = newenablecdr;
return 0;
@@ -210,7 +212,10 @@ static int manager_log(struct ast_cdr *cdr)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
if (customfields)
ast_free(customfields);
@@ -219,7 +224,12 @@ static int unload_module(void)
static int load_module(void)
{
+ if (ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
if (load_config(0)) {
+ ast_cdr_unregister(name);
return AST_MODULE_LOAD_DECLINE;
}
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index 022d75210..be07a8a56 100644
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -266,8 +266,10 @@ static int odbc_load_module(int reload)
} while (0);
if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
- ast_cdr_unregister(name);
+ ast_cdr_backend_suspend(name);
ast_clear_flag(&config, CONFIG_REGISTERED);
+ } else {
+ ast_cdr_backend_unsuspend(name);
}
if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
@@ -283,7 +285,9 @@ static int load_module(void)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
if (dsn) {
ast_verb(11, "cdr_odbc: free dsn\n");
diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c
index dc73de477..6ac389788 100644
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -436,7 +436,10 @@ static void empty_columns(void)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
PQfinish(conn);
diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c
index 2bf2002fe..1466808d5 100644
--- a/cdr/cdr_radius.c
+++ b/cdr/cdr_radius.c
@@ -230,7 +230,10 @@ return_cleanup:
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
if (rh) {
rc_destroy(rh);
rh = NULL;
diff --git a/cdr/cdr_sqlite.c b/cdr/cdr_sqlite.c
index 46aa42bb1..884837c16 100644
--- a/cdr/cdr_sqlite.c
+++ b/cdr/cdr_sqlite.c
@@ -191,7 +191,10 @@ static int sqlite_log(struct ast_cdr *cdr)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
if (db) {
sqlite_close(db);
}
diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c
index 601234604..83dac6a5d 100644
--- a/cdr/cdr_sqlite3_custom.c
+++ b/cdr/cdr_sqlite3_custom.c
@@ -289,7 +289,9 @@ static int write_cdr(struct ast_cdr *cdr)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
free_config(0);
diff --git a/cdr/cdr_syslog.c b/cdr/cdr_syslog.c
index dec4d65e9..de8cae4ec 100644
--- a/cdr/cdr_syslog.c
+++ b/cdr/cdr_syslog.c
@@ -235,7 +235,9 @@ static int load_config(int reload)
static int unload_module(void)
{
- ast_cdr_unregister(name);
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
if (AST_RWLIST_WRLOCK(&sinks)) {
ast_cdr_register(name, ast_module_info->description, syslog_log);
diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c
index aef57b55d..5a1312ecc 100644
--- a/cdr/cdr_tds.c
+++ b/cdr/cdr_tds.c
@@ -443,6 +443,10 @@ failed:
static int tds_unload_module(void)
{
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
if (settings) {
ast_mutex_lock(&tds_lock);
mssql_disconnect();
@@ -452,8 +456,6 @@ static int tds_unload_module(void)
ast_free(settings);
}
- ast_cdr_unregister(name);
-
dbexit();
return 0;
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 49acc61dd..801b1b498 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -503,8 +503,27 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
* \brief Unregister a CDR handling engine
* \param name name of CDR handler to unregister
* Unregisters a CDR by it's name
+ *
+ * \retval 0 The backend unregistered successfully
+ * \retval -1 The backend could not be unregistered at this time
+ */
+int ast_cdr_unregister(const char *name);
+
+/*!
+ * \brief Suspend a CDR backend temporarily
+ *
+ * \retval 0 The backend is suspdended
+ * \retval -1 The backend could not be suspended
+ */
+int ast_cdr_backend_suspend(const char *name);
+
+/*!
+ * \brief Unsuspend a CDR backend
+ *
+ * \retval 0 The backend was unsuspended
+ * \retval -1 The back could not be unsuspended
*/
-void ast_cdr_unregister(const char *name);
+int ast_cdr_backend_unsuspend(const char *name);
/*!
* \brief Disposition to a string
diff --git a/main/cdr.c b/main/cdr.c
index d4c2b96ab..02056ecc5 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -294,6 +294,7 @@ struct cdr_beitem {
char desc[80];
ast_cdrbe be;
AST_RWLIST_ENTRY(cdr_beitem) list;
+ int suspended:1;
};
/*! \brief List of registered backends */
@@ -2581,6 +2582,42 @@ int ast_cdr_is_enabled(void)
return ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED);
}
+int ast_cdr_backend_suspend(const char *name)
+{
+ int success = -1;
+ struct cdr_beitem *i = NULL;
+
+ AST_RWLIST_WRLOCK(&be_list);
+ AST_RWLIST_TRAVERSE(&be_list, i, list) {
+ if (!strcasecmp(name, i->name)) {
+ ast_debug(3, "Suspending CDR backend %s\n", i->name);
+ i->suspended = 1;
+ success = 0;
+ }
+ }
+ AST_RWLIST_UNLOCK(&be_list);
+
+ return success;
+}
+
+int ast_cdr_backend_unsuspend(const char *name)
+{
+ int success = -1;
+ struct cdr_beitem *i = NULL;
+
+ AST_RWLIST_WRLOCK(&be_list);
+ AST_RWLIST_TRAVERSE(&be_list, i, list) {
+ if (!strcasecmp(name, i->name)) {
+ ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
+ i->suspended = 0;
+ success = 0;
+ }
+ }
+ AST_RWLIST_UNLOCK(&be_list);
+
+ return success;
+}
+
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
{
struct cdr_beitem *i = NULL;
@@ -2615,24 +2652,39 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
return 0;
}
-void ast_cdr_unregister(const char *name)
+int ast_cdr_unregister(const char *name)
{
- struct cdr_beitem *i = NULL;
+ struct cdr_beitem *match = NULL;
+ int active_count;
AST_RWLIST_WRLOCK(&be_list);
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
- if (!strcasecmp(name, i->name)) {
- AST_RWLIST_REMOVE_CURRENT(list);
+ AST_RWLIST_TRAVERSE(&be_list, match, list) {
+ if (!strcasecmp(name, match->name)) {
break;
}
}
- AST_RWLIST_TRAVERSE_SAFE_END;
- AST_RWLIST_UNLOCK(&be_list);
- if (i) {
- ast_verb(2, "Unregistered '%s' CDR backend\n", name);
- ast_free(i);
+ if (!match) {
+ AST_RWLIST_UNLOCK(&be_list);
+ return 0;
+ }
+
+ active_count = ao2_container_count(active_cdrs_by_channel);
+
+ if (!match->suspended && active_count != 0) {
+ AST_RWLIST_UNLOCK(&be_list);
+ ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
+ name, active_count);
+ return -1;
}
+
+ AST_RWLIST_REMOVE(&be_list, match, list);
+ AST_RWLIST_UNLOCK(&be_list);
+
+ ast_verb(2, "Unregistered '%s' CDR backend\n", name);
+ ast_free(match);
+
+ return 0;
}
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
@@ -3159,7 +3211,9 @@ static void post_cdr(struct ast_cdr *cdr)
}
AST_RWLIST_RDLOCK(&be_list);
AST_RWLIST_TRAVERSE(&be_list, i, list) {
- i->be(cdr);
+ if (!i->suspended) {
+ i->be(cdr);
+ }
}
AST_RWLIST_UNLOCK(&be_list);
}
@@ -3772,7 +3826,7 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, " (none)\n");
} else {
AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
- ast_cli(a->fd, " %s\n", beitem->name);
+ ast_cli(a->fd, " %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
}
}
AST_RWLIST_UNLOCK(&be_list);