diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index 25b55b35f6bd8b3813079fefab550e7c5d8b1e78..b00a3f34518c927cd58a4a85200c929ab134f1ed 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 0a9cfdbdd9a11e77c7d17e90ed57ec988b6311dd..4078b79ba7956d784adea453de29252586105471 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 a6f8a4dc0a33cb508fd96bb4b69e61b9f4a8f424..1cc1747c6757f7903a43de1ff5396bf4626b53ba 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 2a3b1a1dd06c23b2986bc5de6a5df7ccb4754017..51235db7fd57edf64e670fa526758bbd94487a33 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 e3ae7a57d215da46cce019925a4feaf294eb4193..90c5dbd2312babb80847a9db0b828e22970dc5f0 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 022d75210e5bbe59712d0a85e227cff936e012cf..be07a8a56b3024512ab88ec463c5f8932bcfa46f 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 dc73de4779385b069a569a19a490a83bc7282bba..6ac3897884e1f23348b910c4a3ccc7ee23217985 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 2bf2002feb52d9f42dc74e5b253c1063361b8f25..1466808d5be7b7dfc29e6c3db1166ffc8fd8d216 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 46aa42bb1a40b34033f89b882140a940a90a9946..884837c16216dacd283f98abb1ec02f13a40d654 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 601234604298ea884b8479e02dc4d1dc42d8707f..83dac6a5d68730888e5b6cbfbd7a42389c45d989 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 dec4d65e9d3225e560b89c6e0d1d3cb84097a965..de8cae4eca7e7658940e6e18a573370e8a52f4e6 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 aef57b55d15aa19d15632550fb6aebe2f4f59acd..5a1312eccd502680f25036fc793c8ff26ed307fb 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 49acc61dd22134e86a6d472a549866dcaf6fe7c4..801b1b4989d9800689877149d5b7a6d7f3ab9e7d 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 d4c2b96ab00cccc5a814a49ff23bd0521adae9a7..02056ecc510fcf16e346f74036434ad8b20724ff 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);