summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--UPGRADE.txt9
-rw-r--r--apps/app_queue.c20
-rw-r--r--include/asterisk/res_pjsip.h4
-rw-r--r--main/loader.c107
-rw-r--r--main/stasis_endpoints.c2
-rw-r--r--res/res_clialiases.c8
-rw-r--r--res/res_musiconhold.c4
-rw-r--r--res/res_pjsip.c1
-rw-r--r--res/res_pjsip/pjsip_options.c32
-rw-r--r--res/res_smdi.c44
-rw-r--r--rest-api/api-docs/events.json2
12 files changed, 151 insertions, 93 deletions
diff --git a/CHANGES b/CHANGES
index b2b740924..f367f46cf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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"
]
}