[Asterisk-code-review] res pjsip: Add AMI events for chan pjsip contact lifecycle c... (asterisk[master])

Mark Michelson asteriskteam at digium.com
Wed May 27 13:41:45 CDT 2015


Mark Michelson has submitted this change and it was merged.

Change subject: res_pjsip: Add AMI events for chan_pjsip contact lifecycle changes
......................................................................


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 at fairview5.com>
Tested-by: George Joseph <george.joseph at fairview5.com>
---
M CHANGES
M include/asterisk/res_pjsip.h
M include/asterisk/stasis_endpoints.h
M main/manager_endpoints.c
M main/stasis_endpoints.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip/pjsip_options.c
7 files changed, 173 insertions(+), 34 deletions(-)

Approvals:
  Mark Michelson: Looks good to me, approved; Verified
  Joshua Colp: Looks good to me, but someone else must approve



diff --git a/CHANGES b/CHANGES
index 12bbea4..281d059 100644
--- a/CHANGES
+++ b/CHANGES
@@ -177,6 +177,14 @@
    names. This setting is configurable for cdr_adaptive_odbc via the
    quoted_identifiers in configuration file cdr_adaptive_odbc.conf.
 
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.4.0 to Asterisk 13.5.0 ------------
+------------------------------------------------------------------------------
+
+AMI
+------------------
+ * A new ContactStatus event has been added that reflects res_pjsip contact
+   lifecycle changes:  Created, Removed, Reachable, Unreachable, Unknown.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.3.0 to Asterisk 13.4.0 ------------
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 4023014..bd56c19 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -178,7 +178,9 @@
 enum ast_sip_contact_status_type {
 	UNAVAILABLE,
 	AVAILABLE,
-	UNKNOWN
+	UNKNOWN,
+	CREATED,
+	REMOVED,
 };
 
 /*!
diff --git a/include/asterisk/stasis_endpoints.h b/include/asterisk/stasis_endpoints.h
index 1d56a8f..539f270 100644
--- a/include/asterisk/stasis_endpoints.h
+++ b/include/asterisk/stasis_endpoints.h
@@ -119,6 +119,12 @@
 struct stasis_message_type *ast_endpoint_state_type(void);
 
 /*!
+ * \brief Message type for endpoint contact state changes.
+ * \since 13.5
+ */
+struct stasis_message_type *ast_endpoint_contact_state_type(void);
+
+/*!
  * \brief Message type for \ref ast_endpoint_snapshot.
  * \since 12
  */
diff --git a/main/manager_endpoints.c b/main/manager_endpoints.c
index 424e321..ffcdef0 100644
--- a/main/manager_endpoints.c
+++ b/main/manager_endpoints.c
@@ -75,6 +75,7 @@
 	}
 
 	ret |= stasis_message_router_add(endpoint_router, ast_endpoint_state_type(), endpoint_state_cb, NULL);
+	ret |= stasis_message_router_add(endpoint_router, ast_endpoint_contact_state_type(), endpoint_state_cb, NULL);
 
 	/* If somehow we failed to add any routes, just shut down the whole
 	 * thing and fail it.
diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c
index f19bb91..da65053 100644
--- a/main/stasis_endpoints.c
+++ b/main/stasis_endpoints.c
@@ -71,6 +71,35 @@
 			</syntax>
 		</managerEventInstance>
 	</managerEvent>
+	<managerEvent language="en_US" name="ContactStatus">
+		<managerEventInstance class="EVENT_FLAG_SYSTEM">
+			<synopsis>Raised when the state of a contact changes.</synopsis>
+			<syntax>
+				<parameter name="URI">
+					<para>This contact's URI.</para>
+				</parameter>
+				<parameter name="ContactStatus">
+					<para>New status of the contact.</para>
+					<enumlist>
+						<enum name="Unknown"/>
+						<enum name="Unreachable"/>
+						<enum name="Reachable"/>
+						<enum name="Created"/>
+						<enum name="Removed"/>
+					</enumlist>
+				</parameter>
+				<parameter name="AOR">
+					<para>The name of the associated aor.</para>
+				</parameter>
+				<parameter name="EndpointName">
+					<para>The name of the associated endpoint.</para>
+				</parameter>
+				<parameter name="RoundtripUsec">
+					<para>The RTT measured during the last qualify.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
 ***/
 
 static struct stasis_cp_all *endpoint_cache_all;
@@ -135,6 +164,46 @@
 		obj->snapshot->tech,
 		obj->snapshot->resource,
 		ast_str_buffer(peerstatus_event_string));
+}
+
+static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg);
+
+STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_contact_state_type,
+	.to_ami = contactstatus_to_ami,
+);
+
+static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg)
+{
+	struct ast_endpoint_blob *obj = stasis_message_data(msg);
+	RAII_VAR(struct ast_str *, contactstatus_event_string, ast_str_create(64), ast_free);
+	const char *value;
+
+	if (!(value = ast_json_string_get(ast_json_object_get(obj->blob, "uri")))) {
+		return NULL;
+	}
+	ast_str_append(&contactstatus_event_string, 0, "URI: %s\r\n", value);
+
+	if (!(value = ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")))) {
+		return NULL;
+	}
+	ast_str_append(&contactstatus_event_string, 0, "ContactStatus: %s\r\n", value);
+
+	if (!(value = ast_json_string_get(ast_json_object_get(obj->blob, "aor")))) {
+		return NULL;
+	}
+	ast_str_append(&contactstatus_event_string, 0, "AOR: %s\r\n", value);
+
+	if (!(value = ast_json_string_get(ast_json_object_get(obj->blob, "endpoint_name")))) {
+		return NULL;
+	}
+	ast_str_append(&contactstatus_event_string, 0, "EndpointName: %s\r\n", value);
+
+	if ((value = ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec")))) {
+		ast_str_append(&contactstatus_event_string, 0, "RoundtripUsec: %s\r\n", value);
+	}
+
+	return ast_manager_event_blob_create(EVENT_FLAG_SYSTEM, "ContactStatus",
+		"%s", ast_str_buffer(contactstatus_event_string));
 }
 
 static void endpoint_blob_dtor(void *obj)
@@ -294,6 +363,7 @@
 {
 	STASIS_MESSAGE_TYPE_CLEANUP(ast_endpoint_snapshot_type);
 	STASIS_MESSAGE_TYPE_CLEANUP(ast_endpoint_state_type);
+	STASIS_MESSAGE_TYPE_CLEANUP(ast_endpoint_contact_state_type);
 
 	ao2_cleanup(endpoint_cache_all);
 	endpoint_cache_all = NULL;
@@ -312,6 +382,7 @@
 
 	res |= STASIS_MESSAGE_TYPE_INIT(ast_endpoint_snapshot_type);
 	res |= STASIS_MESSAGE_TYPE_INIT(ast_endpoint_state_type);
+	res |= STASIS_MESSAGE_TYPE_INIT(ast_endpoint_contact_state_type);
 
 	return res;
 }
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 9fa18c7..59598ec 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -56,22 +56,47 @@
 	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 @@
 /*! \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 @@
 {
 	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 @@
 	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 @@
 		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 @@
 		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);
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index 87c67fa..e3e8f18 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -39,12 +39,17 @@
 	[UNAVAILABLE] = "Unreachable",
 	[AVAILABLE] = "Reachable",
 	[UNKNOWN] = "Unknown",
+	[CREATED] = "Created",
+	[REMOVED] = "Removed",
+
 };
 
 static const char *short_status_map [] = {
 	[UNAVAILABLE] = "Unavail",
 	[AVAILABLE] = "Avail",
 	[UNKNOWN] = "Unknown",
+	[CREATED] = "Created",
+	[REMOVED] = "Removed",
 };
 
 const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)

-- 
To view, visit https://gerrit.asterisk.org/519
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id25aae5f7122facba183273efb3e8f36c20fb61e
Gerrit-PatchSet: 4
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: George Joseph <george.joseph at fairview5.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>



More information about the asterisk-code-review mailing list