diff options
-rw-r--r-- | apps/app_skel.c | 2 | ||||
-rw-r--r-- | channels/chan_sip.c | 2 | ||||
-rw-r--r-- | doc/asterisk-ng-doxygen.in | 3 | ||||
-rw-r--r-- | include/asterisk/cli.h | 12 | ||||
-rw-r--r-- | main/asterisk.c | 7 | ||||
-rw-r--r-- | main/cli.c | 56 | ||||
-rw-r--r-- | main/config_options.c | 2 | ||||
-rw-r--r-- | main/logger.c | 3 | ||||
-rw-r--r-- | main/manager.c | 8 | ||||
-rw-r--r-- | main/utils.c | 1 | ||||
-rw-r--r-- | res/res_musiconhold.c | 29 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 6 |
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; } |