diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | UPGRADE.txt | 9 | ||||
-rw-r--r-- | apps/app_queue.c | 20 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 4 | ||||
-rw-r--r-- | main/loader.c | 107 | ||||
-rw-r--r-- | main/stasis_endpoints.c | 2 | ||||
-rw-r--r-- | res/res_clialiases.c | 8 | ||||
-rw-r--r-- | res/res_musiconhold.c | 4 | ||||
-rw-r--r-- | res/res_pjsip.c | 1 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 32 | ||||
-rw-r--r-- | res/res_smdi.c | 44 | ||||
-rw-r--r-- | rest-api/api-docs/events.json | 2 |
12 files changed, 151 insertions, 93 deletions
@@ -26,6 +26,17 @@ chan_sip headers be retrieved from the REFER message and made accessible to the dialplan in the hash TRANSFER_DATA. +AMI +------------------ + * The ContactStatus and Status fields for the manager events ContactStatus + and ContactStatusDetail are now set to "NonQualified" when a contact exists + but has not been qualified. + +ARI +------------------ + * The ContactInfo event's contact_status field is now set to "NonQualified" + when a contact exists but has not been qualified. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 15.1.0 to Asterisk 15.2.0 ------------ ------------------------------------------------------------------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index 39c0f8cec..dd37b259d 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -31,6 +31,15 @@ app_macro: built. Users should migrate to app_stack (Gosub). A warning is logged the first time any Macro is used. +AMI: + - The ContactStatus and Status fields for the manager events ContactStatus + and ContactStatusDetail are now set to "NonQualified" when a contact exists + but has not been qualified. + +ARI: + - The ContactInfo event's contact_status field is now set to "NonQualified" + when a contact exists but has not been qualified. + New in 15.0.0: Build System: diff --git a/apps/app_queue.c b/apps/app_queue.c index 801695fff..a140847c6 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1575,6 +1575,7 @@ struct member { char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */ char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */ char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */ + int state_id; /*!< Extension state callback id (if using hint) */ char membername[80]; /*!< Member name to use in queue logs */ int penalty; /*!< Are we a last resort? */ int calls; /*!< Number of calls serviced by this member */ @@ -2632,12 +2633,21 @@ static int get_queue_member_status(struct member *cur) return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); } +static void destroy_queue_member_cb(void *obj) +{ + struct member *mem = obj; + + if (mem->state_id != -1) { + ast_extension_state_del(mem->state_id, extension_state_cb); + } +} + /*! \brief allocate space for new queue member and set fields based on parameters passed */ static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse) { struct member *cur; - if ((cur = ao2_alloc(sizeof(*cur), NULL))) { + if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) { cur->ringinuse = ringinuse; cur->penalty = penalty; cur->paused = paused; @@ -2664,6 +2674,10 @@ static struct member *create_queue_member(const char *interface, const char *mem ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); + + cur->state_id = ast_extension_state_add(cur->state_context, cur->state_exten, extension_state_cb, NULL); + } else { + cur->state_id = -1; } cur->status = get_queue_member_status(cur); } @@ -11084,8 +11098,6 @@ static int unload_module(void) device_state_sub = stasis_unsubscribe_and_join(device_state_sub); - ast_extension_state_del(0, extension_state_cb); - ast_unload_realtime("queue_members"); ao2_cleanup(queues); ao2_cleanup(pending_members); @@ -11243,8 +11255,6 @@ static int load_module(void) err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type); err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type); - ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); - if (err) { unload_module(); return AST_MODULE_LOAD_DECLINE; diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index e71eb98d7..6c48d2e84 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -289,9 +289,13 @@ struct ast_sip_contact { * \brief Status type for a contact. */ enum ast_sip_contact_status_type { + /*! Frequency > 0, but no response from remote uri */ UNAVAILABLE, + /*! Frequency > 0, and got response from remote uri */ AVAILABLE, + /*! Default last status, and when a contact status object is not found */ UNKNOWN, + /*! Frequency == 0, has a contact, but don't know status (non-qualified) */ CREATED, REMOVED, }; diff --git a/main/loader.c b/main/loader.c index 49151ccb9..e0733651f 100644 --- a/main/loader.c +++ b/main/loader.c @@ -167,38 +167,51 @@ static int do_full_reload = 0; static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item); -/* when dynamic modules are being loaded, ast_module_register() will - need to know what filename the module was loaded from while it - is being registered -*/ +/*! + * \internal + * + * This variable is set by load_dynamic_module so ast_module_register + * can know what pointer is being registered. + * + * This is protected by the module_list lock. + */ static struct ast_module *resource_being_loaded; -/* XXX: should we check for duplicate resource names here? */ - +/*! + * \internal + * \brief Used by AST_MODULE_INFO to register with the module loader. + * + * This function is automatically called when each module is opened. + * It must never be used from outside AST_MODULE_INFO. + */ void ast_module_register(const struct ast_module_info *info) { - struct ast_module *mod = resource_being_loaded; + struct ast_module *mod; + + /* + * This lock protects resource_being_loaded as well as the module + * list. Normally we already have a lock on module_list when we + * begin the load but locking again from here prevents corruption + * if an asterisk module is dlopen'ed from outside the module loader. + */ + AST_DLLIST_LOCK(&module_list); + mod = resource_being_loaded; + if (!mod) { + AST_DLLIST_UNLOCK(&module_list); + return; + } ast_debug(5, "Registering module %s\n", info->name); + /* This tells load_dynamic_module that we're registered. */ + resource_being_loaded = NULL; + mod->info = info; if (ast_opt_ref_debug) { mod->ref_debug = ao2_t_alloc(0, NULL, info->name); } AST_LIST_HEAD_INIT(&mod->users); - /* during startup, before the loader has been initialized, - there are no threads, so there is no need to take the lock - on this list to manipulate it. it is also possible that it - might be unsafe to use the list lock at that point... so - let's avoid it altogether - */ - AST_DLLIST_LOCK(&module_list); - /* it is paramount that the new entry be placed at the tail of - the list, otherwise the code that uses dlopen() to load - dynamic modules won't be able to find out if the module it - just opened was registered or failed to load - */ AST_DLLIST_INSERT_TAIL(&module_list, mod, entry); AST_DLLIST_UNLOCK(&module_list); @@ -206,6 +219,13 @@ void ast_module_register(const struct ast_module_info *info) *((struct ast_module **) &(info->self)) = mod; } +static void module_destroy(struct ast_module *mod) +{ + AST_LIST_HEAD_DESTROY(&mod->users); + ao2_cleanup(mod->ref_debug); + ast_free(mod); +} + void ast_module_unregister(const struct ast_module_info *info) { struct ast_module *mod = NULL; @@ -226,9 +246,7 @@ void ast_module_unregister(const struct ast_module_info *info) if (mod) { ast_debug(5, "Unregistering module %s\n", info->name); - AST_LIST_HEAD_DESTROY(&mod->users); - ao2_cleanup(mod->ref_debug); - ast_free(mod); + module_destroy(mod); } } @@ -511,6 +529,8 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int space; /* room needed for the descriptor */ int missing_so = 0; + ast_assert(!resource_being_loaded); + space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1; if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) { missing_so = 1; @@ -523,34 +543,23 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned any symbols, and don't export any symbols. this will allow us to peek into the module's info block (if available) to see what flags it has set */ - resource_being_loaded = ast_calloc(1, space); + mod = resource_being_loaded = ast_calloc(1, space); if (!resource_being_loaded) return NULL; strcpy(resource_being_loaded->resource, resource_in); if (missing_so) strcat(resource_being_loaded->resource, ".so"); - if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) { - if (!suppress_logging) { + lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL); + if (resource_being_loaded) { + resource_being_loaded = NULL; + if (lib) { + ast_log(LOG_ERROR, "Module '%s' did not register itself during load\n", resource_in); + logged_dlclose(resource_in, lib); + } else if (!suppress_logging) { ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); } - ast_free(resource_being_loaded); - return NULL; - } - - /* the dlopen() succeeded, let's find out if the module - registered itself */ - /* note that this will only work properly as long as - ast_module_register() (which is called by the module's - constructor) places the new module at the tail of the - module_list - */ - if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) { - ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); - /* no, it did not, so close it and return */ - logged_dlclose(resource_in, lib); - /* note that the module's destructor will call ast_module_unregister(), - which will free the structure we allocated in resource_being_loaded */ + ast_free(mod); return NULL; } @@ -564,19 +573,20 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned } logged_dlclose(resource_in, lib); - resource_being_loaded = NULL; /* start the load process again */ - resource_being_loaded = ast_calloc(1, space); + mod = resource_being_loaded = ast_calloc(1, space); if (!resource_being_loaded) return NULL; strcpy(resource_being_loaded->resource, resource_in); if (missing_so) strcat(resource_being_loaded->resource, ".so"); - if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { + lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL); + resource_being_loaded = NULL; + if (!lib) { ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); - ast_free(resource_being_loaded); + ast_free(mod); return NULL; } @@ -585,7 +595,6 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned time too :) */ AST_DLLIST_LAST(&module_list)->lib = lib; - resource_being_loaded = NULL; return AST_DLLIST_LAST(&module_list); } @@ -621,9 +630,7 @@ int modules_shutdown(void) ast_verb(1, "Unloading %s\n", mod->resource); mod->info->unload(); } - AST_LIST_HEAD_DESTROY(&mod->users); - ao2_cleanup(mod->ref_debug); - ast_free(mod); + module_destroy(mod); somethingchanged = 1; } AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END; diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 161fdfa44..5cee22eba 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -82,7 +82,7 @@ <enum name="Unknown"/> <enum name="Unreachable"/> <enum name="Reachable"/> - <enum name="Created"/> + <enum name="Unqualified"/> <enum name="Removed"/> <enum name="Updated"/> </enumlist> diff --git a/res/res_clialiases.c b/res/res_clialiases.c index 1a2fc6939..337c31c97 100644 --- a/res/res_clialiases.c +++ b/res/res_clialiases.c @@ -103,7 +103,7 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_ struct cli_alias tmp = { .cli_entry.command = e->command, }; - char *generator; + char *generator = NULL; const char *line; /* Try to find the alias based on the CLI entry */ @@ -118,14 +118,10 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_ case CLI_GENERATE: line = a->line; line += (strlen(alias->alias)); - if (!strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) { - generator = NULL; - } else if (!ast_strlen_zero(a->word)) { + if (strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) { struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1); ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line); generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n); - } else { - generator = ast_cli_generator(alias->real_cmd, a->word, a->n); } ao2_ref(alias, -1); return generator; diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index ef1b81c2a..17e91b70c 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -333,6 +333,7 @@ static int ast_moh_files_next(struct ast_channel *chan) } } else { state->announcement = 0; + state->samples = 0; } if (!state->class->total_files) { @@ -1934,6 +1935,9 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "Class: %s\n", class->name); ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); + if (ast_test_flag(class, MOH_ANNOUNCEMENT)) { + ast_cli(a->fd, "\tAnnouncement: %s\n", S_OR(class->announcement, "<none>")); + } if (ast_test_flag(class, MOH_CUSTOM)) { ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->kill_delay / 1000); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 21e43f073..b50ee5fc7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2282,6 +2282,7 @@ <enumlist> <enum name="Reachable"/> <enum name="Unreachable"/> + <enum name="NonQualified"/> </enumlist> </parameter> <parameter name="RoundtripUsec"> diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index fbe07d53d..f9df2f0a5 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -41,7 +41,7 @@ static const char *status_map [] = { [UNAVAILABLE] = "Unreachable", [AVAILABLE] = "Reachable", [UNKNOWN] = "Unknown", - [CREATED] = "Created", + [CREATED] = "NonQualified", [REMOVED] = "Removed", }; @@ -49,7 +49,7 @@ static const char *short_status_map [] = { [UNAVAILABLE] = "Unavail", [AVAILABLE] = "Avail", [UNKNOWN] = "Unknown", - [CREATED] = "Created", + [CREATED] = "NonQual", [REMOVED] = "Removed", }; @@ -205,24 +205,12 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } - if (is_contact_refresh - && status->status == CREATED) { - /* - * The contact status hasn't been updated since creation - * and we don't want to re-send a created status. - */ - if (contact->qualify_frequency - || status->rtt_start.tv_sec > 0) { - /* Ignore, the status will change soon. */ - return; - } - - /* - * Convert to a regular contact status update - * because the status may never change. - */ - is_contact_refresh = 0; - value = UNKNOWN; + /* + * If the current status is CREATED, and it's a refresh or the given value is + * also CREATED then there is nothing to update as nothing needs to change. + */ + if (status->status == CREATED && (is_contact_refresh || status->status == value)) { + return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, @@ -595,7 +583,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) schedule_qualify(contact, contact->qualify_frequency * 1000); } else { - update_contact_status(contact, UNKNOWN, 0); + update_contact_status(contact, CREATED, 0); } } @@ -1127,7 +1115,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) if (contact->qualify_frequency) { schedule_qualify(contact, initial_interval); } else { - update_contact_status(contact, UNKNOWN, 0); + update_contact_status(contact, CREATED, 0); } } diff --git a/res/res_smdi.c b/res/res_smdi.c index 0edabb83c..054e6aab6 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -586,9 +586,8 @@ static void *smdi_read(void *iface_p) struct ast_smdi_interface *iface = iface_p; struct ast_smdi_md_message *md_msg; struct ast_smdi_mwi_message *mwi_msg; - char c = '\0'; char *cp = NULL; - int i; + int i, c; int start = 0; /* read an smdi message */ @@ -616,7 +615,14 @@ static void *smdi_read(void *iface_p) /* read the message desk number */ for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { - md_msg->mesg_desk_num[i] = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading MD message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->mesg_desk_num[i] = (char) c; ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]); } @@ -626,7 +632,14 @@ static void *smdi_read(void *iface_p) /* read the message desk terminal number */ for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { - md_msg->mesg_desk_term[i] = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->mesg_desk_term[i] = (char) c; ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]); } @@ -635,7 +648,14 @@ static void *smdi_read(void *iface_p) ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); /* read the message type */ - md_msg->type = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->type = (char) c; ast_debug(1, "Message type is '%c'\n", md_msg->type); @@ -717,7 +737,7 @@ static void *smdi_read(void *iface_p) /* discard the 'I' (from 'MWI') */ fgetc(iface->file); - + /* read the forwarding station number (may be blank) */ cp = &mwi_msg->fwd_st[0]; for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { @@ -740,8 +760,16 @@ static void *smdi_read(void *iface_p) ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); /* read the mwi failure cause */ - for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) - mwi_msg->cause[i] = fgetc(iface->file); + for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) { + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading MWI message\n"); + ao2_ref(mwi_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + mwi_msg->cause[i] = (char) c; + } mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index 9ebbac061..e1b31bb97 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -207,7 +207,7 @@ "Unreachable", "Reachable", "Unknown", - "Created", + "NonQualified", "Removed" ] } |