res_pjsip: Add AMI events for chan_pjsip contact lifecycle changes

Add a new ContactStatus AMI event.
Publish the following status/state changes:
Created
Removed
Reachable
Unreachable
Unknown

Contact URI, new status/state, aor and endpoint names, and the
last qualify rtt result are included in the event.

ASTERISK-25114 #close

Change-Id: Id25aae5f7122facba183273efb3e8f36c20fb61e
Reported-by: George Joseph <george.joseph@fairview5.com>
Tested-by: George Joseph <george.joseph@fairview5.com>
This commit is contained in:
George Joseph
2015-05-21 16:21:01 -06:00
parent 3a8eb3c476
commit b8ac683822
7 changed files with 173 additions and 34 deletions

View File

@@ -56,22 +56,47 @@ static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
}
/*! \brief Structure for communicating contact status to
* persistent_endpoint_update_state from the contact/contact_status
* observers.
*/
struct sip_contact_status {
char *uri;
enum ast_sip_contact_status_type status;
int64_t rtt;
};
/*! \brief Callback function for changing the state of an endpoint */
static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
static int persistent_endpoint_update_state(void *obj, void *arg, void *data, int flags)
{
struct sip_persistent_endpoint *persistent = obj;
struct ast_endpoint *endpoint = persistent->endpoint;
char *aor = arg;
struct sip_contact_status *status = data;
struct ao2_container *contacts;
struct ast_json *blob;
struct ao2_iterator i;
struct ast_sip_contact *contact;
enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
if (!ast_strlen_zero(aor) && !strstr(persistent->aors, aor)) {
return 0;
}
if (!ast_strlen_zero(aor)) {
if (!strstr(persistent->aors, aor)) {
return 0;
}
if (status) {
char rtt[32];
snprintf(rtt, 31, "%" PRId64, status->rtt);
blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
"contact_status", ast_sip_get_contact_status_label(status->status),
"aor", aor,
"uri", status->uri,
"roundtrip_usec", rtt,
"endpoint_name", ast_endpoint_get_resource(endpoint));
ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
ast_json_unref(blob);
}
}
/* Find all the contacts for this endpoint. If ANY are available,
* mark the endpoint as ONLINE.
*/
@@ -121,22 +146,28 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
/*! \brief Function called when stuff relating to a contact happens (created/deleted) */
static void persistent_endpoint_contact_created_observer(const void *object)
{
char *id = ast_strdupa(ast_sorcery_object_get_id(object));
const struct ast_sip_contact *contact = object;
char *id = ast_strdupa(ast_sorcery_object_get_id(contact));
char *aor = NULL;
char *contact = NULL;
char *contact_uri = NULL;
struct sip_contact_status status;
aor = id;
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
if ((contact = strstr(id, ";@")) || (contact = strstr(id, "@@"))) {
*contact = '\0';
contact += 2;
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
*contact_uri = '\0';
contact_uri += 2;
} else {
contact = id;
contact_uri = id;
}
ast_verb(1, "Contact %s/%s has been created\n", aor, contact);
status.uri = contact_uri;
status.status = CREATED;
status.rtt = 0;
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor);
ast_verb(1, "Contact %s/%s has been created\n", aor, contact_uri);
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
}
/*! \brief Function called when stuff relating to a contact happens (created/deleted) */
@@ -144,20 +175,25 @@ static void persistent_endpoint_contact_deleted_observer(const void *object)
{
char *id = ast_strdupa(ast_sorcery_object_get_id(object));
char *aor = NULL;
char *contact = NULL;
char *contact_uri = NULL;
struct sip_contact_status status;
aor = id;
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
if ((contact = strstr(id, ";@")) || (contact = strstr(id, "@@"))) {
*contact = '\0';
contact += 2;
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
*contact_uri = '\0';
contact_uri += 2;
} else {
contact = id;
contact_uri = id;
}
ast_verb(1, "Contact %s/%s has been deleted\n", aor, contact);
ast_verb(1, "Contact %s/%s has been deleted\n", aor, contact_uri);
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor);
status.uri = contact_uri;
status.status = REMOVED;
status.rtt = 0;
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
}
/*! \brief Observer for contacts so state can be updated on respective endpoints */
@@ -172,23 +208,32 @@ static void persistent_endpoint_contact_status_observer(const void *object)
const struct ast_sip_contact_status *contact_status = object;
char *id = ast_strdupa(ast_sorcery_object_get_id(object));
char *aor = NULL;
char *contact = NULL;
char *contact_uri = NULL;
struct sip_contact_status status;
/* If rtt_start is set (this is the outgoing OPTIONS) or
* there's no status change, ignore.
*/
if (contact_status->rtt_start.tv_sec > 0
|| contact_status->status == contact_status->last_status) {
/* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
if (contact_status->rtt_start.tv_sec > 0) {
return;
}
aor = id;
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
if ((contact = strstr(id, ";@")) || (contact = strstr(id, "@@"))) {
*contact = '\0';
contact += 2;
if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
*contact_uri = '\0';
contact_uri += 2;
} else {
contact = id;
contact_uri = id;
}
if (contact_status->status == contact_status->last_status) {
ast_debug(3, "Contact %s status didn't change: %s, RTT: %.3f msec\n",
contact_uri, ast_sip_get_contact_status_label(contact_status->status),
contact_status->rtt / 1000.0);
return;
} else {
ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", aor, contact_uri,
ast_sip_get_contact_status_label(contact_status->status),
contact_status->rtt / 1000.0);
}
ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
@@ -197,10 +242,11 @@ static void persistent_endpoint_contact_status_observer(const void *object)
ast_sorcery_object_get_id(contact_status),
ast_sip_get_contact_status_label(contact_status->status));
ast_verb(1, "Contact %s/%s is now %s\n", aor, contact,
ast_sip_get_contact_status_label(contact_status->status));
status.uri = contact_uri;
status.status = contact_status->status;
status.rtt = contact_status->rtt;
ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor);
ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
}
/*! \brief Observer for contacts so state can be updated on respective endpoints */
@@ -1025,7 +1071,7 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_
if (ast_strlen_zero(persistent->aors)) {
ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
} else {
persistent_endpoint_update_state(persistent, NULL, 0);
persistent_endpoint_update_state(persistent, NULL, NULL, 0);
}
ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);