summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/app_skel.c2
-rw-r--r--channels/chan_sip.c2
-rw-r--r--doc/asterisk-ng-doxygen.in3
-rw-r--r--include/asterisk/cli.h12
-rw-r--r--main/asterisk.c7
-rw-r--r--main/cli.c56
-rw-r--r--main/config_options.c2
-rw-r--r--main/logger.c3
-rw-r--r--main/manager.c8
-rw-r--r--main/utils.c1
-rw-r--r--res/res_musiconhold.c29
-rw-r--r--res/res_pjsip/pjsip_options.c6
12 files changed, 111 insertions, 20 deletions
diff --git a/apps/app_skel.c b/apps/app_skel.c
index 337539efe..3da3db0fc 100644
--- a/apps/app_skel.c
+++ b/apps/app_skel.c
@@ -739,7 +739,7 @@ static int load_module(void)
/* Level options */
aco_option_register(&cfg_info, "max_number", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_num));
- aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 1, FLDSET(struct skel_level, max_guesses));
+ aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_guesses));
if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
goto error;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 9e7872b20..83d3ea0eb 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -18815,7 +18815,7 @@ static void check_via(struct sip_pvt *p, const struct sip_request *req)
c = strchr(via, ' ');
if (c) {
*c = '\0';
- c = ast_skip_blanks(c+1);
+ c = ast_strip(c+1);
if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIP/2.0/TLS")) {
ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
return;
diff --git a/doc/asterisk-ng-doxygen.in b/doc/asterisk-ng-doxygen.in
index 51a3f5d58..2a7002c54 100644
--- a/doc/asterisk-ng-doxygen.in
+++ b/doc/asterisk-ng-doxygen.in
@@ -616,7 +616,8 @@ RECURSIVE = yes
EXCLUDE = doc/api \
menuselect \
res/pjproject \
- addons/ooh323c/src
+ addons/ooh323c/src \
+ third-party
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h
index 458ebc8aa..c51d89eb8 100644
--- a/include/asterisk/cli.h
+++ b/include/asterisk/cli.h
@@ -310,6 +310,18 @@ char **ast_cli_completion_matches(const char *, const char *);
*/
char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos);
+/*!
+ * \brief Allow a CLI command to be executed while Asterisk is shutting down.
+ *
+ * CLI commands by defeault are disabled when Asterisk is shutting down. This is
+ * to ensure the safety of the shutdown since CLI commands may attempt to access
+ * resources that have been freed as a result of the shutdown.
+ *
+ * If a CLI command should be allowed at shutdown, then the best way to enable this
+ * is to call ast_cli_allow_at_shutdown during the CLI_INIT state of the CLI handler.
+ */
+int ast_cli_allow_at_shutdown(struct ast_cli_entry *e);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/main/asterisk.c b/main/asterisk.c
index 3985149f7..5901d579c 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -2441,6 +2441,7 @@ static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
e->usage =
"Usage: core stop now\n"
" Shuts down a running Asterisk immediately, hanging up all active calls .\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2461,6 +2462,7 @@ static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast
"Usage: core stop gracefully\n"
" Causes Asterisk to not accept new calls, and exit when all\n"
" active calls have terminated normally.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2480,6 +2482,7 @@ static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struc
e->usage =
"Usage: core stop when convenient\n"
" Causes Asterisk to perform a shutdown when all active calls have ended.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2501,6 +2504,7 @@ static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli
"Usage: core restart now\n"
" Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
" restart.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2521,6 +2525,7 @@ static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct
"Usage: core restart gracefully\n"
" Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
" restart when all active calls have ended.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2540,6 +2545,7 @@ static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, st
e->usage =
"Usage: core restart when convenient\n"
" Causes Asterisk to perform a cold restart when all active calls have ended.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2561,6 +2567,7 @@ static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_
"Usage: core abort shutdown\n"
" Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
" call operations.\n";
+ ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
diff --git a/main/cli.c b/main/cli.c
index 7f86eab3a..852b32d40 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/bridge.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
+#include "asterisk/vector.h"
/*!
* \brief List of restrictions per user.
@@ -109,6 +110,9 @@ static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
AST_THREADSTORAGE(ast_cli_buf);
+AST_RWLOCK_DEFINE_STATIC(shutdown_commands_lock);
+static AST_VECTOR(, struct ast_cli_entry *) shutdown_commands;
+
/*! \brief Initial buffer size for resulting strings in ast_cli() */
#define AST_CLI_INITLEN 256
@@ -2030,6 +2034,7 @@ static void cli_shutdown(void)
/*! \brief initialize the _full_cmd string in * each of the builtins. */
void ast_builtins_init(void)
{
+ AST_VECTOR_INIT(&shutdown_commands, 0);
ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
ast_register_cleanup(cli_shutdown);
}
@@ -2208,6 +2213,13 @@ static int cli_is_registered(struct ast_cli_entry *e)
return 0;
}
+static void remove_shutdown_command(struct ast_cli_entry *e)
+{
+ ast_rwlock_wrlock(&shutdown_commands_lock);
+ AST_VECTOR_REMOVE_ELEM_UNORDERED(&shutdown_commands, e, AST_VECTOR_ELEM_CLEANUP_NOOP);
+ ast_rwlock_unlock(&shutdown_commands_lock);
+}
+
static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
{
if (e->inuse) {
@@ -2216,6 +2228,7 @@ static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *e
AST_RWLIST_WRLOCK(&helpers);
AST_RWLIST_REMOVE(&helpers, e, list);
AST_RWLIST_UNLOCK(&helpers);
+ remove_shutdown_command(e);
ast_free(e->_full_cmd);
e->_full_cmd = NULL;
if (e->handler) {
@@ -2679,10 +2692,27 @@ char *ast_cli_generator(const char *text, const char *word, int state)
return __ast_cli_generator(text, word, state, 1);
}
+static int allowed_on_shutdown(struct ast_cli_entry *e)
+{
+ int found = 0;
+ int i;
+
+ ast_rwlock_rdlock(&shutdown_commands_lock);
+ for (i = 0; i < AST_VECTOR_SIZE(&shutdown_commands); ++i) {
+ if (e == AST_VECTOR_GET(&shutdown_commands, i)) {
+ found = 1;
+ break;
+ }
+ }
+ ast_rwlock_unlock(&shutdown_commands_lock);
+
+ return found;
+}
+
int ast_cli_command_full(int uid, int gid, int fd, const char *s)
{
const char *args[AST_MAX_ARGS + 1];
- struct ast_cli_entry *e;
+ struct ast_cli_entry *e = NULL;
int x;
char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
char tmp[AST_MAX_ARGS + 1];
@@ -2706,12 +2736,16 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
goto done;
}
+ if (ast_shutting_down() && !allowed_on_shutdown(e)) {
+ ast_cli(fd, "Command '%s' cannot be run during shutdown\n", s);
+ goto done;
+ }
+
ast_join(tmp, sizeof(tmp), args + 1);
/* Check if the user has rights to run this command. */
if (!cli_has_permissions(uid, gid, tmp)) {
ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
- ast_free(duplicate);
- return 0;
+ goto done;
}
/*
@@ -2728,8 +2762,11 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
if (retval == CLI_FAILURE)
ast_cli(fd, "Command '%s' failed.\n", s);
}
- ast_atomic_fetchadd_int(&e->inuse, -1);
+
done:
+ if (e) {
+ ast_atomic_fetchadd_int(&e->inuse, -1);
+ }
ast_free(duplicate);
return 0;
}
@@ -2750,3 +2787,14 @@ int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const c
}
return count;
}
+
+int ast_cli_allow_at_shutdown(struct ast_cli_entry *e)
+{
+ int res;
+
+ ast_rwlock_wrlock(&shutdown_commands_lock);
+ res = AST_VECTOR_APPEND(&shutdown_commands, e);
+ ast_rwlock_unlock(&shutdown_commands_lock);
+
+ return res;
+}
diff --git a/main/config_options.c b/main/config_options.c
index 5da310fd8..db99a441d 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -1346,7 +1346,7 @@ static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var
*/
static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
unsigned int *field = (unsigned int *)(obj + opt->args[0]);
- unsigned int flags = PARSE_INT32 | opt->flags;
+ unsigned int flags = PARSE_UINT32 | opt->flags;
int res = 0;
if (opt->flags & PARSE_IN_RANGE) {
res = opt->flags & PARSE_DEFAULT ?
diff --git a/main/logger.c b/main/logger.c
index 46d9cbb57..9db33c954 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -1322,7 +1322,8 @@ static void ast_log_vsyslog(struct logmsg *msg, int facility)
return;
}
- syslog_level = LOG_MAKEPRI(facility, syslog_level);
+ /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */
+ syslog_level = facility | syslog_level; /* LOG_MAKEPRI(facility, syslog_level); */
snprintf(buf, sizeof(buf), "%s[%d]%s: %s:%d in %s: %s",
levels[msg->level], msg->lwp, call_identifier_str, msg->file, msg->line, msg->function, msg->message);
diff --git a/main/manager.c b/main/manager.c
index de003813c..7c2155015 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -6114,6 +6114,14 @@ static int process_message(struct mansession *s, const struct message *m)
return 0;
}
+ if (ast_shutting_down()) {
+ ast_log(LOG_ERROR, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action);
+ mansession_lock(s);
+ astman_send_error(s, m, "Asterisk is shutting down");
+ mansession_unlock(s);
+ return 0;
+ }
+
if (!s->session->authenticated
&& strcasecmp(action, "Login")
&& strcasecmp(action, "Logoff")
diff --git a/main/utils.c b/main/utils.c
index 0b527f0bd..686af6b2f 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1158,6 +1158,7 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_
"Usage: core show locks\n"
" This command is for lock debugging. It prints out which locks\n"
"are owned by each active thread.\n";
+ ast_cli_allow_on_shutdown(e);
return NULL;
case CLI_GENERATE:
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 669fb9bc9..6f5182072 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -1349,6 +1349,18 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char
return class;
}
+static struct ast_variable *load_realtime_musiconhold(const char *name)
+{
+ struct ast_variable *var = ast_load_realtime("musiconhold", "name", name, SENTINEL);
+ if (!var) {
+ ast_log(LOG_WARNING,
+ "Music on Hold class '%s' not found in memory/database. "
+ "Verify your configuration.\n",
+ name);
+ }
+ return var;
+}
+
static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
{
struct mohclass *mohclass = NULL;
@@ -1356,6 +1368,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
struct ast_variable *var = NULL;
int res = 0;
int realtime_possible = ast_check_realtime("musiconhold");
+ int warn_if_not_in_memory = !realtime_possible;
/* The following is the order of preference for which class to use:
* 1) The channels explicitly set musicclass, which should *only* be
@@ -1369,28 +1382,28 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
* 4) The default class.
*/
if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
- mohclass = get_mohbyname(ast_channel_musicclass(chan), 1, 0);
+ mohclass = get_mohbyname(ast_channel_musicclass(chan), warn_if_not_in_memory, 0);
if (!mohclass && realtime_possible) {
- var = ast_load_realtime("musiconhold", "name", ast_channel_musicclass(chan), SENTINEL);
+ var = load_realtime_musiconhold(ast_channel_musicclass(chan));
}
}
if (!mohclass && !var && !ast_strlen_zero(mclass)) {
- mohclass = get_mohbyname(mclass, 1, 0);
+ mohclass = get_mohbyname(mclass, warn_if_not_in_memory, 0);
if (!mohclass && realtime_possible) {
- var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
+ var = load_realtime_musiconhold(mclass);
}
}
if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
- mohclass = get_mohbyname(interpclass, 1, 0);
+ mohclass = get_mohbyname(interpclass, warn_if_not_in_memory, 0);
if (!mohclass && realtime_possible) {
- var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
+ var = load_realtime_musiconhold(interpclass);
}
}
if (!mohclass && !var) {
- mohclass = get_mohbyname("default", 1, 0);
+ mohclass = get_mohbyname("default", warn_if_not_in_memory, 0);
if (!mohclass && realtime_possible) {
- var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
+ var = load_realtime_musiconhold("default");
}
}
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index de551dc0a..157a07741 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -1038,14 +1038,14 @@ int ast_sip_initialize_sorcery_qualify(void)
snprintf(status_value_unknown, sizeof(status_value_unknown), "%u", UNKNOWN);
ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "last_status",
- status_value_unknown, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, last_status));
+ status_value_unknown, OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, last_status));
snprintf(status_value_created, sizeof(status_value_created), "%u", CREATED);
ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "status",
- status_value_created, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, status));
+ status_value_created, OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, status));
ast_sorcery_object_field_register_custom_nodoc(sorcery, CONTACT_STATUS, "rtt_start",
"0.0", rtt_start_handler, rtt_start_to_str, NULL, 0, 0);
ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt",
- "0", OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, rtt));
+ "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, rtt));
return 0;
}