[Asterisk-code-review] res_pjsip_dialog_info_body_generator: Add LOCAL/REMOTE tags in dialog... (asterisk[18])

Joshua Colp asteriskteam at digium.com
Wed May 19 12:25:00 CDT 2021


Joshua Colp has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/15781 )

Change subject: res_pjsip_dialog_info_body_generator: Add LOCAL/REMOTE tags in dialog-info+xml
......................................................................

res_pjsip_dialog_info_body_generator: Add LOCAL/REMOTE tags in dialog-info+xml

RFC 4235 Section 4.1.6 describes XML elements that should be
sent to subscribed endpoints to identify the local and remote
participants in the dialog.

This patch adds this functionality to PJSIP by iterating through the
ringing channels causing the NOTIFY, and inserts the channel info
into the dialog so that information is properly passed to the endpoint
in dialog-info+xml.

ASTERISK-24601
Patch submitted: Joshua Elson
Modified by: Joseph Nadiv and Sean Bright
Tested by: Joseph Nadiv

Change-Id: I20c5cf5b45f34d7179df6573c5abf863eb72964b
---
A doc/CHANGES-staging/res_pjsip_dialog_info_body_generator.txt
M res/res_pjsip_dialog_info_body_generator.c
2 files changed, 123 insertions(+), 1 deletion(-)

Approvals:
  Joshua Colp: Looks good to me, but someone else must approve; Approved for Submit
  George Joseph: Looks good to me, approved



diff --git a/doc/CHANGES-staging/res_pjsip_dialog_info_body_generator.txt b/doc/CHANGES-staging/res_pjsip_dialog_info_body_generator.txt
new file mode 100644
index 0000000..0dd0a57
--- /dev/null
+++ b/doc/CHANGES-staging/res_pjsip_dialog_info_body_generator.txt
@@ -0,0 +1,5 @@
+Subject: res_pjsip_dialog_info_body_generator
+
+PJSIP now supports RFC 4235 Section 4.1.6 dialog-info+xml local and
+remote elements by iterating through ringing channels and inserting
+that info into NOTIFY packet sent to the endpoint.
diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c
index 3934a8a..88aa6c2 100644
--- a/res/res_pjsip_dialog_info_body_generator.c
+++ b/res/res_pjsip_dialog_info_body_generator.c
@@ -30,6 +30,7 @@
 #include <pjlib.h>
 
 #include "asterisk/module.h"
+#include "asterisk/callerid.h"
 #include "asterisk/res_pjsip.h"
 #include "asterisk/res_pjsip_pubsub.h"
 #include "asterisk/res_pjsip_presence_xml.h"
@@ -60,6 +61,35 @@
 	return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info");
 }
 
+/*!
+ * \internal
+ * \brief Find the channel that is causing the RINGING update, ref'd
+ */
+static struct ast_channel *find_ringing_channel(struct ao2_container *device_state_info)
+{
+	struct ao2_iterator citer;
+	struct ast_device_state_info *device_state;
+	struct ast_channel *c = NULL;
+	struct timeval tv = {0,};
+
+	/* iterate ringing devices and get the oldest of all causing channels */
+	citer = ao2_iterator_init(device_state_info, 0);
+	for (; (device_state = ao2_iterator_next(&citer)); ao2_ref(device_state, -1)) {
+		if (!device_state->causing_channel || (device_state->device_state != AST_DEVICE_RINGING &&
+				device_state->device_state != AST_DEVICE_RINGINUSE)) {
+			continue;
+		}
+		ast_channel_lock(device_state->causing_channel);
+		if (ast_tvzero(tv) || ast_tvcmp(ast_channel_creationtime(device_state->causing_channel), tv) < 0) {
+			c = device_state->causing_channel;
+			tv = ast_channel_creationtime(c);
+		}
+		ast_channel_unlock(device_state->causing_channel);
+	}
+	ao2_iterator_destroy(&citer);
+	return c ? ast_channel_ref(c) : NULL;
+}
+
 static int dialog_info_generate_body_content(void *body, void *data)
 {
 	pj_xml_node *dialog_info = body, *dialog, *state;
@@ -67,13 +97,14 @@
 	struct dialog_info_xml_state *datastore_state;
 	struct ast_sip_exten_state_data *state_data = data;
 	char *local = ast_strdupa(state_data->local), *stripped, *statestring = NULL;
+	char *remote = ast_strdupa(state_data->remote);
 	char *pidfstate = NULL, *pidfnote = NULL;
 	enum ast_sip_pidf_state local_state;
 	char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
 	struct ast_sip_endpoint *endpoint = NULL;
 	unsigned int notify_early_inuse_ringing = 0;
 
-	if (!local || !state_data->datastores) {
+	if (!local || !remote || !state_data->datastores) {
 		return -1;
 	}
 
@@ -133,7 +164,93 @@
 	dialog = ast_sip_presence_xml_create_node(state_data->pool, dialog_info, "dialog");
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog, "id", state_data->exten);
 	if (!ast_strlen_zero(statestring) && !strcmp(statestring, "early")) {
+		struct ast_channel *callee = NULL;
+		char local_target[PJSIP_MAX_URL_SIZE + 32] = "";
+		char *local_cid_name = NULL;
+		pj_xml_node *local_node, *local_identity_node, *local_target_node;
+
 		ast_sip_presence_xml_create_attr(state_data->pool, dialog, "direction", "recipient");
+
+		if (state_data->device_state_info) {
+			callee = find_ringing_channel(state_data->device_state_info);
+		}
+
+		if (callee) {
+			static char *anonymous = "anonymous";
+			static char *invalid = "anonymous.invalid";
+			char *remote_cid_name;
+			char *remote_connected_num;
+			int remote_connected_num_restricted;
+			char *local_caller_num;
+			pjsip_dialog *dlg = ast_sip_subscription_get_dialog(state_data->sub);
+			pjsip_sip_uri *dlg_remote_fromhdr = pjsip_uri_get_uri(dlg->local.info->uri);
+			char remote_target[PJSIP_MAX_URL_SIZE + 32];
+			char dlg_remote_uri[PJSIP_MAX_URL_SIZE];
+			char *from_domain_stripped;
+			char from_domain_sanitized[PJSIP_MAX_URL_SIZE];
+			pj_xml_node *remote_node, *remote_identity_node, *remote_target_node;
+
+			/* We use the local dialog URI to determine the domain to use in the XML itself */
+			ast_copy_pj_str(dlg_remote_uri, &dlg_remote_fromhdr->host, sizeof(dlg_remote_uri));
+			from_domain_stripped = ast_strip_quoted(dlg_remote_uri, "<", ">");
+			ast_sip_sanitize_xml(from_domain_stripped, from_domain_sanitized, sizeof(from_domain_sanitized));
+
+			ast_channel_lock(callee);
+
+			/* The remote node uses the connected line information, so who is calling the
+			 * monitored endpoint.
+			 */
+			remote_cid_name = S_COR(ast_channel_connected(callee)->id.name.valid,
+				S_COR((ast_channel_connected(callee)->id.name.presentation &
+						AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED, anonymous,
+					ast_channel_connected(callee)->id.name.str), "");
+
+			remote_connected_num_restricted = (ast_channel_connected(callee)->id.number.presentation &
+				AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED;
+			remote_connected_num = S_COR(ast_channel_connected(callee)->id.number.valid,
+				S_COR(remote_connected_num_restricted, anonymous,
+					ast_channel_connected(callee)->id.number.str), "invalid");
+
+			snprintf(remote_target, sizeof(remote_target), "sip:%s@%s", remote_connected_num,
+				remote_connected_num_restricted ? invalid : from_domain_sanitized);
+
+			/* The local node uses the callerid information, so what the callerid would be
+			 * if the monitored endpoint was calling.
+			 */
+			local_cid_name = S_COR(ast_channel_caller(callee)->id.name.valid,
+				ast_channel_caller(callee)->id.name.str, "");
+			local_caller_num = S_COR(ast_channel_caller(callee)->id.number.valid,
+				ast_channel_caller(callee)->id.number.str, "invalid");
+
+			snprintf(local_target, sizeof(local_target), "sip:%s@%s", local_caller_num,
+				from_domain_sanitized);
+
+			ast_channel_unlock(callee);
+			callee = ast_channel_unref(callee);
+
+			remote_node = ast_sip_presence_xml_create_node(state_data->pool, dialog, "remote");
+			remote_identity_node = ast_sip_presence_xml_create_node(state_data->pool, remote_node, "identity");
+			remote_target_node = ast_sip_presence_xml_create_node(state_data->pool, remote_node, "target");
+
+			pj_strdup2(state_data->pool, &remote_identity_node->content, remote_target);
+			if (!ast_strlen_zero(remote_cid_name)) {
+				ast_sip_presence_xml_create_attr(state_data->pool, remote_identity_node, "display", remote_cid_name);
+			}
+			ast_sip_presence_xml_create_attr(state_data->pool, remote_target_node, "uri", remote_target);
+		}
+
+		if (state_data->device_state_info) {
+			local_node = ast_sip_presence_xml_create_node(state_data->pool, dialog, "local");
+			local_identity_node = ast_sip_presence_xml_create_node(state_data->pool, local_node, "identity");
+			local_target_node = ast_sip_presence_xml_create_node(state_data->pool, local_node, "target");
+
+			/* If a channel is not available we fall back to the sanitized local URI instead */
+			pj_strdup2(state_data->pool, &local_identity_node->content, S_OR(local_target, sanitized));
+			if (!ast_strlen_zero(local_cid_name)) {
+				ast_sip_presence_xml_create_attr(state_data->pool, local_identity_node, "display", local_cid_name);
+			}
+			ast_sip_presence_xml_create_attr(state_data->pool, local_target_node, "uri", S_OR(local_target, sanitized));
+		}
 	}
 
 	state = ast_sip_presence_xml_create_node(state_data->pool, dialog, "state");

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/15781
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 18
Gerrit-Change-Id: I20c5cf5b45f34d7179df6573c5abf863eb72964b
Gerrit-Change-Number: 15781
Gerrit-PatchSet: 9
Gerrit-Owner: Joe <ynadiv at corpit.xyz>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at sangoma.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20210519/8b614ff2/attachment-0001.html>


More information about the asterisk-code-review mailing list