mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
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/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@402081 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -337,6 +337,9 @@ CDR (Call Detail Records)
|
|||||||
associated with the current CDR for the channel, as opposed to a cumulative
|
associated with the current CDR for the channel, as opposed to a cumulative
|
||||||
measurement of all CDRs for that channel.
|
measurement of all CDRs for that channel.
|
||||||
|
|
||||||
|
- CDR backends can no longer be unloaded while billing data is in flight. This
|
||||||
|
helps to prevent loss of billing data during restarts and shutdowns.
|
||||||
|
|
||||||
CEL:
|
CEL:
|
||||||
- The Uniqueid field for a channel is now a stable identifier, and will not
|
- The Uniqueid field for a channel is now a stable identifier, and will not
|
||||||
change due to transfers, parking, etc.
|
change due to transfers, parking, etc.
|
||||||
|
@@ -384,9 +384,11 @@ static int my_unload_module(int reload)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbport = 0;
|
dbport = 0;
|
||||||
ast_cdr_unregister(name);
|
if (reload) {
|
||||||
|
return ast_cdr_backend_suspend(name);
|
||||||
return 0;
|
} 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)
|
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;
|
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) {
|
if (res) {
|
||||||
ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
|
ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
|
||||||
} else {
|
} else {
|
||||||
|
@@ -767,7 +767,10 @@ early_release:
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
|
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
|
||||||
ast_cdr_register(name, ast_module_info->description, odbc_log);
|
ast_cdr_register(name, ast_module_info->description, odbc_log);
|
||||||
ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
|
ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
|
||||||
|
@@ -315,7 +315,10 @@ static int csv_log(struct ast_cdr *cdr)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
loaded = 0;
|
loaded = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -184,7 +184,9 @@ static int custom_log(struct ast_cdr *cdr)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (AST_RWLIST_WRLOCK(&sinks)) {
|
if (AST_RWLIST_WRLOCK(&sinks)) {
|
||||||
ast_cdr_register(name, ast_module_info->description, custom_log);
|
ast_cdr_register(name, ast_module_info->description, custom_log);
|
||||||
|
@@ -86,8 +86,9 @@ static int load_config(int reload)
|
|||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
/* Standard configuration */
|
/* Standard configuration */
|
||||||
ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
|
ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
|
||||||
if (enablecdr)
|
if (enablecdr) {
|
||||||
ast_cdr_unregister(name);
|
ast_cdr_backend_suspend(name);
|
||||||
|
}
|
||||||
enablecdr = 0;
|
enablecdr = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -135,10 +136,11 @@ static int load_config(int reload)
|
|||||||
|
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
|
|
||||||
if (enablecdr && !newenablecdr)
|
if (!newenablecdr) {
|
||||||
ast_cdr_unregister(name);
|
ast_cdr_backend_suspend(name);
|
||||||
else if (!enablecdr && newenablecdr)
|
} else if (newenablecdr) {
|
||||||
ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
|
ast_cdr_backend_unsuspend(name);
|
||||||
|
}
|
||||||
enablecdr = newenablecdr;
|
enablecdr = newenablecdr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -210,7 +212,10 @@ static int manager_log(struct ast_cdr *cdr)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (customfields)
|
if (customfields)
|
||||||
ast_free(customfields);
|
ast_free(customfields);
|
||||||
|
|
||||||
@@ -219,7 +224,12 @@ static int unload_module(void)
|
|||||||
|
|
||||||
static int load_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)) {
|
if (load_config(0)) {
|
||||||
|
ast_cdr_unregister(name);
|
||||||
return AST_MODULE_LOAD_DECLINE;
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -266,8 +266,10 @@ static int odbc_load_module(int reload)
|
|||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
|
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);
|
ast_clear_flag(&config, CONFIG_REGISTERED);
|
||||||
|
} else {
|
||||||
|
ast_cdr_backend_unsuspend(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
|
if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
|
||||||
@@ -283,7 +285,9 @@ static int load_module(void)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (dsn) {
|
if (dsn) {
|
||||||
ast_verb(11, "cdr_odbc: free dsn\n");
|
ast_verb(11, "cdr_odbc: free dsn\n");
|
||||||
|
@@ -436,7 +436,10 @@ static void empty_columns(void)
|
|||||||
|
|
||||||
static int unload_module(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));
|
ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
|
||||||
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
|
@@ -230,7 +230,10 @@ return_cleanup:
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (rh) {
|
if (rh) {
|
||||||
rc_destroy(rh);
|
rc_destroy(rh);
|
||||||
rh = NULL;
|
rh = NULL;
|
||||||
|
@@ -191,7 +191,10 @@ static int sqlite_log(struct ast_cdr *cdr)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
sqlite_close(db);
|
sqlite_close(db);
|
||||||
}
|
}
|
||||||
|
@@ -289,7 +289,9 @@ static int write_cdr(struct ast_cdr *cdr)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
free_config(0);
|
free_config(0);
|
||||||
|
|
||||||
|
@@ -235,7 +235,9 @@ static int load_config(int reload)
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
ast_cdr_unregister(name);
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (AST_RWLIST_WRLOCK(&sinks)) {
|
if (AST_RWLIST_WRLOCK(&sinks)) {
|
||||||
ast_cdr_register(name, ast_module_info->description, syslog_log);
|
ast_cdr_register(name, ast_module_info->description, syslog_log);
|
||||||
|
@@ -443,6 +443,10 @@ failed:
|
|||||||
|
|
||||||
static int tds_unload_module(void)
|
static int tds_unload_module(void)
|
||||||
{
|
{
|
||||||
|
if (ast_cdr_unregister(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (settings) {
|
if (settings) {
|
||||||
ast_mutex_lock(&tds_lock);
|
ast_mutex_lock(&tds_lock);
|
||||||
mssql_disconnect();
|
mssql_disconnect();
|
||||||
@@ -452,8 +456,6 @@ static int tds_unload_module(void)
|
|||||||
ast_free(settings);
|
ast_free(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_cdr_unregister(name);
|
|
||||||
|
|
||||||
dbexit();
|
dbexit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -503,8 +503,27 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
|
|||||||
* \brief Unregister a CDR handling engine
|
* \brief Unregister a CDR handling engine
|
||||||
* \param name name of CDR handler to unregister
|
* \param name name of CDR handler to unregister
|
||||||
* Unregisters a CDR by it's name
|
* Unregisters a CDR by it's name
|
||||||
|
*
|
||||||
|
* \retval 0 The backend unregistered successfully
|
||||||
|
* \retval -1 The backend could not be unregistered at this time
|
||||||
*/
|
*/
|
||||||
void ast_cdr_unregister(const char *name);
|
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
|
||||||
|
*/
|
||||||
|
int ast_cdr_backend_unsuspend(const char *name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Disposition to a string
|
* \brief Disposition to a string
|
||||||
|
78
main/cdr.c
78
main/cdr.c
@@ -294,6 +294,7 @@ struct cdr_beitem {
|
|||||||
char desc[80];
|
char desc[80];
|
||||||
ast_cdrbe be;
|
ast_cdrbe be;
|
||||||
AST_RWLIST_ENTRY(cdr_beitem) list;
|
AST_RWLIST_ENTRY(cdr_beitem) list;
|
||||||
|
int suspended:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief List of registered backends */
|
/*! \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);
|
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)
|
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
|
||||||
{
|
{
|
||||||
struct cdr_beitem *i = NULL;
|
struct cdr_beitem *i = NULL;
|
||||||
@@ -2615,24 +2652,39 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
|
|||||||
return 0;
|
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_WRLOCK(&be_list);
|
||||||
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
|
AST_RWLIST_TRAVERSE(&be_list, match, list) {
|
||||||
if (!strcasecmp(name, i->name)) {
|
if (!strcasecmp(name, match->name)) {
|
||||||
AST_RWLIST_REMOVE_CURRENT(list);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AST_RWLIST_TRAVERSE_SAFE_END;
|
|
||||||
|
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_RWLIST_UNLOCK(&be_list);
|
||||||
|
|
||||||
if (i) {
|
ast_verb(2, "Unregistered '%s' CDR backend\n", name);
|
||||||
ast_verb(2, "Unregistered '%s' CDR backend\n", name);
|
ast_free(match);
|
||||||
ast_free(i);
|
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
|
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_RDLOCK(&be_list);
|
||||||
AST_RWLIST_TRAVERSE(&be_list, i, list) {
|
AST_RWLIST_TRAVERSE(&be_list, i, list) {
|
||||||
i->be(cdr);
|
if (!i->suspended) {
|
||||||
|
i->be(cdr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AST_RWLIST_UNLOCK(&be_list);
|
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");
|
ast_cli(a->fd, " (none)\n");
|
||||||
} else {
|
} else {
|
||||||
AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
|
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);
|
AST_RWLIST_UNLOCK(&be_list);
|
||||||
|
Reference in New Issue
Block a user