diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/Makefile | 4 | ||||
-rw-r--r-- | main/acl.c | 61 | ||||
-rw-r--r-- | main/app.c | 13 | ||||
-rw-r--r-- | main/bridge_basic.c | 24 | ||||
-rw-r--r-- | main/ccss.c | 47 | ||||
-rw-r--r-- | main/cli.c | 124 | ||||
-rw-r--r-- | main/libasteriskssl.c | 2 | ||||
-rw-r--r-- | main/loader.c | 14 |
8 files changed, 195 insertions, 94 deletions
diff --git a/main/Makefile b/main/Makefile index 08d1f6558..c724e2012 100644 --- a/main/Makefile +++ b/main/Makefile @@ -273,7 +273,7 @@ endif $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(PJ_LDFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" -DAST_NOT_MODULE $(PJ_CFLAGS) -$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) $(OPENSSL_LIB) $(UUID_LIB) -lm -lpthread $(RT_LIB) ifeq ($(GNU_LD),1) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskpj.exports,--warn-common endif @@ -298,7 +298,7 @@ ASTPJ_LIB:=libasteriskpj.dylib # /lib or /usr/lib $(ASTPJ_LIB): _ASTLDFLAGS+=-dynamiclib -install_name $(ASTLIBDIR)/$(ASTPJ_LIB) $(PJ_LDFLAGS) $(ASTPJ_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) -DAST_NOT_MODULE -$(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB) +$(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) $(OPENSSL_LIB) $(UUID_LIB) -lm -lpthread $(RT_LIB) $(ASTPJ_LIB): SOLINK=$(DYLINK) # Special rules for building a shared library (not a dynamically loadable module) diff --git a/main/acl.c b/main/acl.c index 6868ea12e..bcb3f6391 100644 --- a/main/acl.c +++ b/main/acl.c @@ -281,6 +281,12 @@ struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original) while (start) { current = ast_duplicate_ha(start); /* Create copy of this object */ + if (!current) { + ast_free_ha(ret); + + return NULL; + } + if (prev) { prev->next = current; /* Link previous to this object */ } @@ -318,7 +324,7 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original) } if (!(clone = ast_calloc(1, sizeof(*clone)))) { - ast_log(LOG_WARNING, "Failed to allocate ast_acl_list struct while cloning an ACL\n"); + ast_log(LOG_ERROR, "Failed to allocate ast_acl_list struct while cloning an ACL\n"); return NULL; } AST_LIST_HEAD_INIT(clone); @@ -327,8 +333,10 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original) AST_LIST_TRAVERSE(original, current_cursor, list) { if ((acl_new(¤t_clone, current_cursor->name))) { - ast_log(LOG_WARNING, "Failed to allocate ast_acl struct while cloning an ACL."); - continue; + ast_log(LOG_ERROR, "Failed to allocate ast_acl struct while cloning an ACL.\n"); + ast_free_acl_list(clone); + clone = NULL; + break; } /* Copy data from original ACL to clone ACL */ @@ -338,6 +346,15 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original) current_clone->is_realtime = current_cursor->is_realtime; AST_LIST_INSERT_TAIL(clone, current_clone, list); + + if (current_cursor->acl && !current_clone->acl) { + /* Deal with failure after adding to clone so we don't have to free + * current_clone separately. */ + ast_log(LOG_ERROR, "Failed to duplicate HA list while cloning ACL.\n"); + ast_free_acl_list(clone); + clone = NULL; + break; + } } AST_LIST_UNLOCK(original); @@ -448,6 +465,8 @@ void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list ** if (error) { *error = 1; } + AST_LIST_UNLOCK(working_list); + return; } // Need to INSERT the ACL at the head here. AST_LIST_INSERT_HEAD(working_list, acl, list); @@ -477,7 +496,8 @@ void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list ** AST_LIST_TRAVERSE(working_list, current, list) { if (!strcasecmp(current->name, tmp)) { /* ACL= */ /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */ - ast_log(LOG_ERROR, "Named ACL '%s' occurs multiple times in ACL definition. Please update your ACL configuration.", tmp); + ast_log(LOG_ERROR, "Named ACL '%s' occurs multiple times in ACL definition. " + "Please update your ACL configuration.\n", tmp); if (error) { *error = 1; } @@ -536,6 +556,22 @@ int ast_acl_list_is_empty(struct ast_acl_list *acl_list) return 1; } +/*! + * \internal + * \brief Used by ast_append_ha to avoid ast_strdupa in a loop. + * + * \note This function is only called at debug level 3 and higher. + */ +static void debug_ha_sense_appended(struct ast_ha *ha) +{ + const char *parsed_mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask)); + + ast_log(LOG_DEBUG, "%s/%s sense %u appended to ACL\n", + ast_sockaddr_stringify(&ha->addr), + parsed_mask, + ha->sense); +} + struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error) { struct ast_ha *ha; @@ -545,7 +581,6 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha char *address = NULL, *mask = NULL; int addr_is_v4; int allowing = strncasecmp(sense, "p", 1) ? AST_SENSE_DENY : AST_SENSE_ALLOW; - const char *parsed_addr, *parsed_mask; ret = path; while (path) { @@ -653,10 +688,9 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha } prev = ha; - parsed_addr = ast_strdupa(ast_sockaddr_stringify(&ha->addr)); - parsed_mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask)); - - ast_debug(3, "%s/%s sense %u appended to ACL\n", parsed_addr, parsed_mask, ha->sense); + if (DEBUG_ATLEAST(3)) { + debug_ha_sense_appended(ha); + } } return ret; @@ -665,10 +699,11 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf) { for (; ha; ha = ha->next) { - const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr)); - ast_str_append(buf, 0, "%s%s/%s", - ha->sense == AST_SENSE_ALLOW ? "!" : "", - addr, ast_sockaddr_stringify_addr(&ha->netmask)); + ast_str_append(buf, 0, "%s%s/", + ha->sense == AST_SENSE_ALLOW ? "!" : "", + ast_sockaddr_stringify_addr(&ha->addr)); + /* Separated to avoid duplicating stringified addresses. */ + ast_str_append(buf, 0, "%s", ast_sockaddr_stringify_addr(&ha->netmask)); if (ha->next) { ast_str_append(buf, 0, ","); } diff --git a/main/app.c b/main/app.c index 69c96c06c..f35c4b7d2 100644 --- a/main/app.c +++ b/main/app.c @@ -3138,7 +3138,7 @@ struct stasis_topic *ast_mwi_topic(const char *uniqueid) struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) { - RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup); + struct ast_mwi_state *mwi_state; ast_assert(!ast_strlen_zero(mailbox)); @@ -3148,6 +3148,7 @@ struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) } if (ast_string_field_init(mwi_state, 256)) { + ao2_ref(mwi_state, -1); return NULL; } if (!ast_strlen_zero(context)) { @@ -3156,7 +3157,6 @@ struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) ast_string_field_set(mwi_state, uniqueid, mailbox); } - ao2_ref(mwi_state, +1); return mwi_state; } @@ -3329,8 +3329,8 @@ struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, struct stasis_message_type *message_type, struct ast_json *blob) { - RAII_VAR(struct ast_mwi_blob *, obj, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_mwi_blob *obj; + struct stasis_message *msg; ast_assert(blob != NULL); @@ -3349,11 +3349,8 @@ struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state, /* This is not a normal MWI event. Only used by the MinivmNotify app. */ msg = stasis_message_create(message_type, obj); - if (!msg) { - return NULL; - } + ao2_ref(obj, -1); - ao2_ref(msg, +1); return msg; } diff --git a/main/bridge_basic.c b/main/bridge_basic.c index e31f38561..fd6bac0c9 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -1547,6 +1547,23 @@ static void stimulate_attended_transfer(struct attended_transfer_properties *pro ao2_unlock(props); } +static void remove_attended_transfer_stimulus(struct attended_transfer_properties *props, + enum attended_transfer_stimulus stimulus) +{ + struct stimulus_list *list; + + ao2_lock(props); + AST_LIST_TRAVERSE_SAFE_BEGIN(&props->stimulus_queue, list, next) { + if (list->stimulus == stimulus) { + AST_LIST_REMOVE_CURRENT(next); + ast_free(list); + break; + } + } + AST_LIST_TRAVERSE_SAFE_END; + ao2_unlock(props); +} + /*! * \brief Get a desired transfer party for a bridge the transferer is not in. * @@ -2339,6 +2356,10 @@ static enum attended_transfer_state blond_nonfinal_exit(struct attended_transfer return TRANSFER_RESUME; case STIMULUS_TIMEOUT: ast_softhangup(props->recall_target, AST_SOFTHANGUP_EXPLICIT); + /* It is possible before we hung them up that they queued up a recall target answer + * so we remove it if present as it should not exist. + */ + remove_attended_transfer_stimulus(props, STIMULUS_RECALL_TARGET_ANSWER); case STIMULUS_RECALL_TARGET_HANGUP: props->recall_target = ast_channel_unref(props->recall_target); return TRANSFER_RECALLING; @@ -2803,7 +2824,8 @@ static struct ast_frame *transfer_target_framehook_cb(struct ast_channel *chan, if (event == AST_FRAMEHOOK_EVENT_READ && frame && frame->frametype == AST_FRAME_CONTROL && - frame->subclass.integer == AST_CONTROL_ANSWER) { + frame->subclass.integer == AST_CONTROL_ANSWER && + !ast_check_hangup(chan)) { ast_debug(1, "Detected an answer for recall attempt on attended transfer %p\n", props); if (props->superstate == SUPERSTATE_TRANSFER) { diff --git a/main/ccss.c b/main/ccss.c index a9d15b072..445de93e0 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -1022,9 +1022,9 @@ void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * c static int cc_publish(struct stasis_message_type *message_type, int core_id, struct ast_json *extras) { - RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); - RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); + struct ast_json *blob; + struct ast_json_payload *payload; + struct stasis_message *message; if (!message_type) { return -1; @@ -1040,121 +1040,138 @@ static int cc_publish(struct stasis_message_type *message_type, int core_id, str ast_json_object_update(blob, extras); } - if (!(payload = ast_json_payload_create(blob))) { + payload = ast_json_payload_create(blob); + ast_json_unref(blob); + + if (!payload) { return -1; } - if (!(message = stasis_message_create(message_type, payload))) { + message = stasis_message_create(message_type, payload); + ao2_ref(payload, -1); + + if (!message) { return -1; } stasis_publish(ast_system_topic(), message); + ao2_ref(message, -1); return 0; } static void cc_publish_available(int core_id, const char *callee, const char *service) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s, s: s}", "callee", callee, "service", service); cc_publish(ast_cc_available_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_offertimerstart(int core_id, const char *caller, unsigned int expires) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s, s: i}", "caller", caller, "expires", expires); cc_publish(ast_cc_offertimerstart_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_requested(int core_id, const char *caller, const char *callee) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s, s: s}", "caller", caller, "callee", callee); cc_publish(ast_cc_requested_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_requestacknowledged(int core_id, const char *caller) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "caller", caller); cc_publish(ast_cc_requestacknowledged_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_callerstopmonitoring(int core_id, const char *caller) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "caller", caller); cc_publish(ast_cc_callerstopmonitoring_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_callerstartmonitoring(int core_id, const char *caller) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "caller", caller); cc_publish(ast_cc_callerstartmonitoring_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_callerrecalling(int core_id, const char *caller) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "caller", caller); cc_publish(ast_cc_callerrecalling_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_recallcomplete(int core_id, const char *caller) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "caller", caller); cc_publish(ast_cc_recallcomplete_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_failure(int core_id, const char *caller, const char *reason) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s, s: s}", "caller", caller, "reason", reason); cc_publish(ast_cc_failure_type(), core_id, extras); + ast_json_unref(extras); } static void cc_publish_monitorfailed(int core_id, const char *callee) { - RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref); + struct ast_json *extras; extras = ast_json_pack("{s: s}", "callee", callee); cc_publish(ast_cc_monitorfailed_type(), core_id, extras); + ast_json_unref(extras); } struct cc_monitor_backend { diff --git a/main/cli.c b/main/cli.c index 5c16e8b7a..eae14adc4 100644 --- a/main/cli.c +++ b/main/cli.c @@ -959,7 +959,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar #define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n" #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n" - RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); + struct ao2_container *channels; struct ao2_iterator it_chans; struct stasis_message *msg; int numchans = 0, concise = 0, verbose = 0, count = 0; @@ -1073,6 +1073,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls())); } + ao2_ref(channels, -1); return CLI_SUCCESS; @@ -1685,7 +1686,7 @@ char *ast_cli_complete(const char *word, const char * const choices[], int state char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos) { int wordlen = strlen(word), which = 0; - RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup); + struct ao2_container *cached_channels; char *ret = NULL; struct ao2_iterator iter; struct stasis_message *msg; @@ -1709,6 +1710,7 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta } } ao2_iterator_destroy(&iter); + ao2_ref(cached_channels, -1); return ret; } @@ -2488,76 +2490,98 @@ int ast_cli_generatornummatches(const char *text, const char *word) return matches; } -static void destroy_match_list(char **match_list, int matches) +char **ast_cli_completion_matches(const char *text, const char *word) { - if (match_list) { - int idx; + struct ast_vector_string *vec = ast_cli_completion_vector(text, word); + char **match_list; - for (idx = 1; idx < matches; ++idx) { - ast_free(match_list[idx]); - } - ast_free(match_list); + if (!vec) { + return NULL; + } + + if (AST_VECTOR_APPEND(vec, NULL)) { + /* We failed to NULL terminate the elements */ + AST_VECTOR_CALLBACK_VOID(vec, ast_free); + AST_VECTOR_PTR_FREE(vec); + + return NULL; } + + match_list = AST_VECTOR_STEAL_ELEMENTS(vec); + AST_VECTOR_PTR_FREE(vec); + + return match_list; } -char **ast_cli_completion_matches(const char *text, const char *word) +struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word) { - char **match_list = NULL, *retstr, *prevstr; - char **new_list; - size_t match_list_len, max_equal, which, i; - int matches = 0; + char *retstr, *prevstr; + size_t max_equal; + size_t which = 0; + struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec)); - /* leave entry 0 free for the longest common substring */ - match_list_len = 1; - while ((retstr = ast_cli_generator(text, word, matches)) != NULL) { - if (matches + 1 >= match_list_len) { - match_list_len <<= 1; - new_list = ast_realloc(match_list, match_list_len * sizeof(*match_list)); - if (!new_list) { - destroy_match_list(match_list, matches); - return NULL; - } - match_list = new_list; + if (!vec) { + return NULL; + } + + while ((retstr = ast_cli_generator(text, word, which)) != NULL) { + if (AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) { + ast_free(retstr); + + goto vector_cleanup; } - match_list[++matches] = retstr; + + ++which; } - if (!match_list) { - return match_list; /* NULL */ + if (!AST_VECTOR_SIZE(vec)) { + AST_VECTOR_PTR_FREE(vec); + + return NULL; } + prevstr = AST_VECTOR_GET(vec, 0); + max_equal = strlen(prevstr); + which = 1; + /* Find the longest substring that is common to all results * (it is a candidate for completion), and store a copy in entry 0. */ - prevstr = match_list[1]; - max_equal = strlen(prevstr); - for (which = 2; which <= matches; which++) { - for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++) + while (which < AST_VECTOR_SIZE(vec)) { + size_t i = 0; + + retstr = AST_VECTOR_GET(vec, which); + /* Check for and remove duplicate strings. */ + if (!strcasecmp(prevstr, retstr)) { + AST_VECTOR_REMOVE(vec, which, 1); + ast_free(retstr); + continue; + } + + while (i < max_equal && toupper(prevstr[i]) == toupper(retstr[i])) { + i++; + } + max_equal = i; + prevstr = retstr; + ++which; } - retstr = ast_malloc(max_equal + 1); - if (!retstr) { - destroy_match_list(match_list, matches); - return NULL; + /* Insert longest match to position 0. */ + retstr = ast_strndup(AST_VECTOR_GET(vec, 0), max_equal); + if (!retstr || AST_VECTOR_INSERT_AT(vec, 0, retstr)) { + ast_free(retstr); + goto vector_cleanup; } - ast_copy_string(retstr, match_list[1], max_equal + 1); - match_list[0] = retstr; - /* ensure that the array is NULL terminated */ - if (matches + 1 >= match_list_len) { - new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list)); - if (!new_list) { - ast_free(retstr); - destroy_match_list(match_list, matches); - return NULL; - } - match_list = new_list; - } - match_list[matches + 1] = NULL; + return vec; - return match_list; +vector_cleanup: + AST_VECTOR_CALLBACK_VOID(vec, ast_free); + AST_VECTOR_PTR_FREE(vec); + + return NULL; } /*! \brief returns true if there are more words to match */ diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 8b19e247d..e2e256f8f 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -37,7 +37,7 @@ #endif #if defined(HAVE_OPENSSL) && \ - !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + (!defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)) #include <dlfcn.h> diff --git a/main/loader.c b/main/loader.c index fc3e9a374..19e30f835 100644 --- a/main/loader.c +++ b/main/loader.c @@ -117,14 +117,20 @@ static int modules_loaded; struct ast_module { const struct ast_module_info *info; - /* Used to get module references into refs log */ + /*! Used to get module references into refs log */ void *ref_debug; - void *lib; /* the shared lib, or NULL if embedded */ - int usecount; /* the number of 'users' currently in this module */ - struct module_user_list users; /* the list of users in the module */ + /*! The shared lib. */ + void *lib; + /*! Number of 'users' and other references currently holding the module. */ + int usecount; + /*! List of users holding the module. */ + struct module_user_list users; struct { + /*! The module running and ready to accept requests. */ unsigned int running:1; + /*! The module has declined to start. */ unsigned int declined:1; + /*! This module is being held open until it's time to shutdown. */ unsigned int keepuntilshutdown:1; } flags; AST_LIST_ENTRY(ast_module) list_entry; |