From 38622f3fdd9d6ad7b8b6856e31ba9b18f6e533bc Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthony.minessale@gmail.com>
Date: Sun, 1 Feb 2009 00:06:46 +0000
Subject: [PATCH] probably make nat work on sla

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11581 d0543943-73ff-0310-b7d9-9358b9ac24b2
---
 src/mod/endpoints/mod_sofia/mod_sofia.h      |  2 +-
 src/mod/endpoints/mod_sofia/sofia_glue.c     |  7 +-
 src/mod/endpoints/mod_sofia/sofia_presence.c | 27 ++++---
 src/mod/endpoints/mod_sofia/sofia_sla.c      | 74 ++++++++++++++++----
 4 files changed, 81 insertions(+), 29 deletions(-)

diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 98a6fc34ce..b8e54e80af 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -779,7 +779,7 @@ void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *
 
 void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip);
 void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
-void sofia_sla_handle_sip_i_subscribe(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
+void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
 void sofia_sla_handle_sip_r_subscribe(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
 void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
 
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index ab2817fb87..64b4e39cca 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -3047,7 +3047,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
 		"   call_id           VARCHAR(255),\n"
 		"   aor               VARCHAR(255),\n"
 		"   profile_name      VARCHAR(255),\n"
-		"   hostname          VARCHAR(255)\n"
+		"   hostname          VARCHAR(255),\n"
+		"   contact_str       VARCHAR(255)\n"
 		");\n";
 
 	if (profile->odbc_dsn) {
@@ -3105,7 +3106,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
 		free(test_sql);
 
 		if (profile->manage_shared_appearance) {
-			test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where hostname='%q'", mod_sofia_globals.hostname);
+			test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str='' or hostname='%q'", mod_sofia_globals.hostname);
 			if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
 				switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_shared_appearance_subscriptions", NULL);
 				switch_odbc_handle_exec(profile->master_odbc, shared_appearance_sql, NULL);
@@ -3145,7 +3146,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
 		free(test_sql);
 
 		if(profile->manage_shared_appearance) {
-			test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where hostname='%q'", mod_sofia_globals.hostname);
+			test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str = '' or hostname='%q'", mod_sofia_globals.hostname);
 			switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_shared_appearance_subscriptions", shared_appearance_sql);
 			free(test_sql);
 
diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c
index 5afe2670c2..c1cc3aea66 100644
--- a/src/mod/endpoints/mod_sofia/sofia_presence.c
+++ b/src/mod/endpoints/mod_sofia/sofia_presence.c
@@ -1423,17 +1423,6 @@ void sofia_presence_handle_sip_i_subscribe(int status,
 			return;
 		}
 
-		/* the following could be refactored back to the calling event handler in sofia.c XXX MTK */
-		if (profile->manage_shared_appearance) {
-			if (!strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
-				/* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */
-				if (status < 200) {
-					sofia_sla_handle_sip_i_subscribe(nua, profile, nh, sip, tags);
-				}
-				return;
-			}
-		}
-
 		get_addr(network_ip, sizeof(network_ip), my_addrinfo->ai_addr, my_addrinfo->ai_addrlen);
 		network_port = ntohs(((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_port);
 
@@ -1524,6 +1513,22 @@ void sofia_presence_handle_sip_i_subscribe(int status,
 										is_nat ?  ";nat" : "");
 		}
 
+
+
+		/* the following could be refactored back to the calling event handler in sofia.c XXX MTK */
+		if (profile->manage_shared_appearance) {
+			if (!strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
+				/* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */
+				if (status < 200) {
+					sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, tags);
+				}
+				switch_safe_free(contact_str);
+				return;
+			}
+		}
+
+
+
 		if (to) {
 			to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
 		}
diff --git a/src/mod/endpoints/mod_sofia/sofia_sla.c b/src/mod/endpoints/mod_sofia/sofia_sla.c
index 04128b6ce3..6311a8b3b1 100644
--- a/src/mod/endpoints/mod_sofia/sofia_sla.c
+++ b/src/mod/endpoints/mod_sofia/sofia_sla.c
@@ -78,12 +78,13 @@ void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_ha
 	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
 }
 
-void sofia_sla_handle_sip_i_subscribe(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[])
+void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[])
 {
 	char *aor = NULL;
 	char *subscriber = NULL;
 	char *sql = NULL;
-
+	char *route_uri = NULL;
+	
 	/*
 	 * XXX MTK FIXME - we don't look at the tag to see if NUTAG_SUBSTATE(nua_substate_terminated) or
 	 * a Subscription-State header with state "terminated" and/or expiration of 0. So we never forget
@@ -119,22 +120,43 @@ void sofia_sla_handle_sip_i_subscribe(nua_t *nua, sofia_profile_t *profile, nua_
 	}
 
 	if ((sql =
-		switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname) "
-		               "values ('%q','%q','%q','%q','%q')",
-		                subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname))) {
+		 switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str) "
+		               "values ('%q','%q','%q','%q','%q','%q')",
+		                subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str))) {
 		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 	}
 
 
+	if (strstr(contact_str, ";fs_nat")) {
+		char *p;
+		route_uri = strdup(contact_str);
+		if ((p = strstr(contact_str, ";fs_"))) {
+			*p = '\0';
+		}
+	}
+
+
+	if (route_uri) {
+		char *p;
+
+		while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
+			route_uri++;
+		}
+		if ((p = strchr(route_uri, '>'))) {
+			*p++ = '\0';
+		}
+	}
 
 	nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(profile->sla_contact), NUTAG_WITH_THIS(nua),
-        SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */
-        SIPTAG_EXPIRES_STR("300"), /* likewise, totally fake - FIXME XXX MTK */
+				TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
+				SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */
+				SIPTAG_EXPIRES_STR("300"), /* likewise, totally fake - FIXME XXX MTK */
 	/*  sofia_presence says something about needing TAG_IF(sticky, NUTAG_PROXY(sticky)) for NAT stuff? */
 	 TAG_END());
 
 	switch_safe_free(aor);
 	switch_safe_free(subscriber);
+	switch_safe_free(route_uri);
 	switch_safe_free(sql);
 }
 
@@ -199,7 +221,7 @@ void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_han
 	contact = switch_mprintf("sip:%s@%s",sip->sip_contact->m_url->url_user, sip->sip_contact->m_url->url_host);
 
 	if(sip->sip_payload && sip->sip_payload->pl_data) {
-		sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname from sip_shared_appearance_subscriptions where "
+		sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,route_uri from sip_shared_appearance_subscriptions where "
 		"aor='%q' and subscriber<>'%q' and profile_name='%q' and hostname='%q'",
 		aor, contact, profile->name, mod_sofia_globals.hostname); 
 
@@ -224,17 +246,41 @@ static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **colu
 	/* char *aor = argv[2]; */
 	/* char *profile_name = argv[3]; */
 	/* char *hostname = argv[4]; */
+	char *contact_str = argv[5];
 	nua_handle_t *nh;
+	char *route_uri = NULL;
+
 
 	nh = nua_handle_by_call_id(helper->profile->nua, call_id);  /* that's all you need to find the subscription's nh */
 
-	if(nh)
-	{
+	if(nh) {
+
+		if (strstr(contact_str, ";fs_nat")) {
+			char *p;
+			route_uri = strdup(contact_str);
+			if ((p = strstr(contact_str, ";fs_"))) {
+				*p = '\0';
+			}
+		}
+
+		if (route_uri) {
+			char *p;
+
+			while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
+				route_uri++;
+			}
+			if ((p = strchr(route_uri, '>'))) {
+				*p++ = '\0';
+			}
+		}
+
 		nua_notify(nh,
-			SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */
-			SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"),	/* could've just kept the type from the payload */
-			SIPTAG_PAYLOAD_STR(helper->payload),
-			TAG_END());
+				   SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */
+				   TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
+				   SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"),	/* could've just kept the type from the payload */
+				   SIPTAG_PAYLOAD_STR(helper->payload),
+				   TAG_END());
+		switch_safe_free(route_uri);
 	}
 	return 0;
 }