From 7cb91467e0fee89fe8c810941582f1ef0a75954b Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthm@freeswitch.org>
Date: Thu, 6 Mar 2014 00:01:02 +0500
Subject: [PATCH] FS-5814 --resolve

---
 libs/sofia-sip/configure.ac                   |  6 +-
 libs/sofia-sip/libsofia-sip-ua/Makefile.am    |  6 +-
 libs/sofia-sip/libsofia-sip-ua/nta/nta.c      | 89 ++++++++++++++++++-
 .../sofia-sip/libsofia-sip-ua/nta/nta_check.c |  4 +-
 .../libsofia-sip-ua/tport/Makefile.am         |  1 +
 .../libsofia-sip-ua/tport/tport_logging.c     | 74 +++++++++------
 src/mod/endpoints/mod_sofia/sofia_glue.c      |  3 +
 7 files changed, 151 insertions(+), 32 deletions(-)

diff --git a/libs/sofia-sip/configure.ac b/libs/sofia-sip/configure.ac
index f882bc76b4..e20ddcb4c6 100644
--- a/libs/sofia-sip/configure.ac
+++ b/libs/sofia-sip/configure.ac
@@ -255,7 +255,11 @@ fi
 AC_CHECK_HEADERS([fnmatch.h])
 
 AC_CHECK_LIB(pthread, pthread_setschedparam, [AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM, 1, [Define if you have pthread_setschedparam()])])
-
+AC_CHECK_LIB(z, compress, [have_zlib=yes],[have_zlib=no])
+if test x"$have_zlib" = "xyes"; then
+   AC_DEFINE(HAVE_ZLIB_COMPRESS, 1, [Define if you have zlib compress])
+fi
+AM_CONDITIONAL([HAVE_ZLIB], [test "x$have_zlib" = xyes])
 
 dnl dl is currently used only in testing
 AC_CHECK_LIB([dl], [dlopen], [
diff --git a/libs/sofia-sip/libsofia-sip-ua/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/Makefile.am
index 78a8307392..d2855be4bf 100644
--- a/libs/sofia-sip/libsofia-sip-ua/Makefile.am
+++ b/libs/sofia-sip/libsofia-sip-ua/Makefile.am
@@ -58,7 +58,11 @@ libsofia_sip_ua_la_LIBADD = 	bnf/libbnf.la \
 # set the libtool version info version:revision:age for libsofia-sip-ua
 # - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
 libsofia_sip_ua_la_LDFLAGS = \
-	-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
+	-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE) 
+
+if HAVE_ZLIB
+libsofia_sip_ua_la_LDFLAGS += -lz
+endif
 
 PHONY = doxygen built-sources
 
diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
index 5c8a98df0b..358f52afed 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
+++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
@@ -47,7 +47,9 @@
  */
 
 #include "config.h"
-
+#ifdef HAVE_ZLIB_COMPRESS
+#include <zlib.h>
+#endif
 #include <sofia-sip/su_string.h>
 
 /** @internal SU message argument structure type */
@@ -379,6 +381,7 @@ struct nta_leg_s
 				 * Request missing @To tag matches
 				 * a tagged leg even after tagging.
 				 */
+  unsigned leg_compressed:1;
   unsigned:0;
   nta_request_f    *leg_callback;
   nta_leg_magic_t  *leg_magic;
@@ -450,6 +453,7 @@ struct nta_incoming_s
   unsigned irq_must_100rel:1;	/**< 100rel is required */
   unsigned irq_extra_100:1;	/**< 100 Trying should be sent */
   unsigned irq_tag_set:1;	/**< Tag is not from request */
+  unsigned irq_compressed:1;
   unsigned :0;
 
   tp_name_t             irq_tpn[1];
@@ -2788,6 +2792,66 @@ void agent_recv_message(nta_agent_t *agent,
   }
 }
 
+#ifdef HAVE_ZLIB_COMPRESS
+int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check)
+{
+	char const *method_name;
+	unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
+	int ok = !check;
+
+	if (sip->sip_request) {
+		method_name = sip->sip_request->rq_method_name;
+	} else if (sip->sip_cseq) {
+		method_name = sip->sip_cseq->cs_method_name;
+	} else {
+		method_name = "Unknown";
+	}
+
+	if (!ok) {
+		if (sip->sip_content_encoding && sip->sip_content_encoding->k_items && sip->sip_payload) {
+			const char *val = sip->sip_content_encoding->k_items[0];
+			if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) {
+				ok = 1;
+			}
+		}
+	}
+
+	if (ok) {
+		unsigned long n = 0;
+		void *decoded = NULL;
+		const char *id = "N/A";
+		const char *orig_payload = sip->sip_payload->pl_data;
+
+		n = sip->sip_payload->pl_len * 10;
+		  
+		decoded = su_alloc(msg_home(msg), n);
+		assert(decoded);
+
+		if (inflate) {
+			uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
+		} else {
+			compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
+		}
+		  
+		sip->sip_payload = sip_payload_create(msg_home(msg), decoded, n);
+
+		if (sip->sip_call_id) {
+			id = sip->sip_call_id->i_id;
+		}
+
+		if (inflate) {
+			SU_DEBUG_1(("nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded));
+		} else {
+			SU_DEBUG_1(("nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload));
+		}
+
+		return 1;
+	}
+ 
+  return 0;
+}
+#endif
+
 /** @internal Handle incoming requests. */
 static
 void agent_recv_request(nta_agent_t *agent,
@@ -2802,6 +2866,7 @@ void agent_recv_request(nta_agent_t *agent,
   url_t url[1];
   unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
   int insane, errors, stream;
+  unsigned compressed = 0;
 
   agent->sa_stats->as_recv_msg++;
   agent->sa_stats->as_recv_request++;
@@ -2924,6 +2989,10 @@ void agent_recv_request(nta_agent_t *agent,
     return;
   }
 
+#ifdef HAVE_ZLIB_COMPRESS
+  compressed = sip_content_encoding_Xflate(msg, sip, 1, 1);
+#endif
+
   /* First, try existing incoming requests */
   irq = incoming_find(agent, sip, sip->sip_via,
 		      agent->sa_merge_482 &&
@@ -2986,6 +3055,7 @@ void agent_recv_request(nta_agent_t *agent,
     /* Try existing dialog */
     SU_DEBUG_5(("nta: %s (%u) %s\n",
 		method_name, cseq, "going to existing leg"));
+	leg->leg_compressed = compressed;
     leg_recv(leg, msg, sip, tport);
     return;
   }
@@ -2994,6 +3064,7 @@ void agent_recv_request(nta_agent_t *agent,
     /* Dialogless legs - let application process transactions statefully */
     SU_DEBUG_5(("nta: %s (%u) %s\n",
 		method_name, cseq, "going to a dialogless leg"));
+	leg->leg_compressed = compressed;
     leg_recv(leg, msg, sip, tport);
   }
   else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
@@ -3009,6 +3080,7 @@ void agent_recv_request(nta_agent_t *agent,
     else {
       SU_DEBUG_5(("nta: %s (%u) %s\n",
 		  method_name, cseq, "going to a default leg"));
+	  leg->leg_compressed = compressed;
       leg_recv(leg, msg, sip, tport);
     }
   }
@@ -3280,6 +3352,10 @@ void agent_recv_response(nta_agent_t *agent,
 
   /* XXX - should check if msg should be discarded based on via? */
 
+#ifdef HAVE_ZLIB_COMPRESS
+  sip_content_encoding_Xflate(msg, sip, 1, 1);
+#endif
+
   if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
     SU_DEBUG_5(("nta: %03d %s %s\n",
 		status, phrase, "is going to a transaction"));
@@ -4767,6 +4843,7 @@ void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
     return;
   }
 
+  irq->irq_compressed = leg->leg_compressed;
   irq->irq_in_callback = 1;
   status = incoming_callback(leg, irq, sip);
   irq->irq_in_callback = 0;
@@ -6566,6 +6643,12 @@ int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg)
     return -1;
   }
 
+#ifdef HAVE_ZLIB_COMPRESS
+  if (irq->irq_compressed) {
+	  sip_content_encoding_Xflate(msg, sip, 0, 0);
+  }
+#endif
+
   if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
     /* This nta_reliable_t object will be destroyed by PRACK or timeout */
     if (nta_reliable_mreply(irq, NULL, NULL, msg))
@@ -7738,6 +7821,10 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
   sip = sip_object(msg);
   home = msg_home(msg);
 
+#ifdef HAVE_ZLIB_COMPRESS
+  sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1);
+#endif
+
   if (!sip->sip_request || sip_complete_message(msg) < 0) {
     SU_DEBUG_3(("nta: outgoing_create: incomplete request\n" VA_NONE));
     return NULL;
diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
index 8d1d4d490c..d3c8094821 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
+++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
@@ -248,7 +248,9 @@ int nta_check_session_content(nta_incoming_t *irq,
   if (!sip->sip_content_encoding ||
       !sip->sip_content_encoding->k_items ||
       !sip->sip_content_encoding->k_items[0] ||
-      !sip->sip_content_encoding->k_items[0][0])
+      !sip->sip_content_encoding->k_items[0][0] ||
+	  !strcasecmp(sip->sip_content_encoding->k_items[0], "gzip") ||
+	  !strcasecmp(sip->sip_content_encoding->k_items[0], "deflate"))
     acceptable_encoding = 1;
 
   if (acceptable_type && acceptable_encoding)
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
index e9aec1c997..73cc4bd7a7 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
@@ -14,6 +14,7 @@ INCLUDES = 		-I$(srcdir)/../bnf -I../bnf \
 			-I$(srcdir)/../msg -I../msg \
 			-I$(srcdir)/../http -I../http \
 			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../sip -I../sip \
 			-I$(srcdir)/../su -I../su
 
 # ----------------------------------------------------------------------
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
index acb8e186dc..6931ba13f3 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
@@ -478,7 +478,7 @@ void tport_log_msg(tport_t *self, msg_t *msg,
   size_t i, iovlen = msg_iovec(msg, iov, 80);
   size_t linelen = 0, n, logged = 0, truncated = 0;
   int skip_lf = 0;
-
+  int j, unprintable = 0;
 
 #define MSG_SEPARATOR \
   "------------------------------------------------------------------------\n"
@@ -496,39 +496,57 @@ void tport_log_msg(tport_t *self, msg_t *msg,
     if (skip_lf && s < end && s[0] == '\n') { s++; logged++; skip_lf = 0; }
 
     while (s < end) {
-      if (s[0] == '\0') {
-	truncated = logged;
-	break;
-      }
+		if (s[0] == '\0') {
+			truncated = logged;
+			break;
+		}
 
-      n = su_strncspn(s, end - s, "\r\n");
+		n = su_strncspn(s, end - s, "\r\n");
 
-      if (linelen + n > MAX_LINELEN) {
-	n = MAX_LINELEN - linelen;
-	truncated = logged + n;
-      }
+		if (linelen + n > MAX_LINELEN) {
+			n = MAX_LINELEN - linelen;
+			truncated = logged + n;
+		}
+		
+		if (!unprintable) {
+			for (j = 0; j < 4; j++) {
+				if (s[j] == 0) break;
+				if (s[j] != 9 && s[j] != 10 && s[j] != 13 && (s[j] < 32 || s[j] > 126)) {
+					unprintable++;
+				}
+			}
+		}
 
-      su_log("%s%.*s", linelen > 0 ? "" : "   ", (int)n, s);
-      s += n, linelen += n, logged += n;
+		if (unprintable) {
+			if (unprintable == 1)
+				su_log("\n   <ENCODED DATA>");
+			unprintable++;
+		} else {
+			su_log("%s%.*s", linelen > 0 ? "" : "   ", (int)n, s);
+		}
 
-      if (truncated)
-	break;
-      if (s == end)
-	break;
+		s += n, linelen += n, logged += n;
 
-      linelen = 0;
-      su_log("\n");
+		if (truncated)
+			break;
+		if (s == end)
+			break;
+		
+		linelen = 0;
+		su_log("\n");
+		
+		/* Skip eol */
+		if (s[0] == '\r') {
+			s++, logged++;
+			if (s == end) {
+				skip_lf = 1;
+				continue;
+			}
+		}
 
-      /* Skip eol */
-      if (s[0] == '\r') {
-	s++, logged++;
-	if (s == end) {
-	  skip_lf = 1;
-	  continue;
-	}
-      }
-      if (s[0] == '\n')
-	s++, logged++;
+		if (s[0] == '\n') {
+			s++, logged++;
+		}
     }
   }
 
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index f2cbba1173..450b7e71d6 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -691,6 +691,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 	const char *handle_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_handle_full_to");
 	const char *force_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_force_full_from");
 	const char *force_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_force_full_to");
+	const char *content_encoding = switch_channel_get_variable(tech_pvt->channel, "sip_content_encoding");
 	char *mp = NULL, *mp_type = NULL;
 	char *record_route = NULL;
 	const char *recover_via = NULL;
@@ -1255,6 +1256,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 				   TAG_IF(!zstr(route), SIPTAG_ROUTE_STR(route)),
 				   TAG_IF(tech_pvt->profile->minimum_session_expires, NUTAG_MIN_SE(tech_pvt->profile->minimum_session_expires)),
 				   TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
+				   TAG_IF(content_encoding, SIPTAG_CONTENT_ENCODING_STR(content_encoding)),
 				   TAG_IF(zstr(tech_pvt->mparams.local_sdp_str), SIPTAG_PAYLOAD_STR("")),
 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip)),
 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str)),
@@ -1291,6 +1293,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 				   TAG_IF(tech_pvt->profile->minimum_session_expires, NUTAG_MIN_SE(tech_pvt->profile->minimum_session_expires)),
 				   TAG_IF(!require_timer, NUTAG_TIMER_AUTOREQUIRE(0)),
 				   TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
+				   TAG_IF(content_encoding, SIPTAG_CONTENT_ENCODING_STR(content_encoding)),
 				   NUTAG_MEDIA_ENABLE(0),
 				   SIPTAG_CONTENT_TYPE_STR(mp_type ? mp_type : "application/sdp"),
 				   SIPTAG_PAYLOAD_STR(mp ? mp : tech_pvt->mparams.local_sdp_str), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END());