Ticket #61: Implement SRTP support in PJMEDIA and PJSUA-LIB, and updated applications because of the changes. This is a major modification back ported from SRTP branch. See ticket #61 for changelog detail of this commit

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1735 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 90f4202..8cc5772 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -120,6 +120,9 @@
     puts  ("");
     puts  ("SIP Account options:");
     puts  ("  --use-ims           Enable 3GPP/IMS related settings on this account");
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    puts  ("  --use-srtp=N        Use SRTP N= 0: disabled, 1: optional, 2: mandatory");
+#endif
     puts  ("  --registrar=url     Set the URL of registrar server");
     puts  ("  --id=url            Set the URL of local ID (used in From header)");
     puts  ("  --contact=url       Optionally override the Contact information");
@@ -382,7 +385,7 @@
 	   OPT_NAMESERVER, OPT_STUN_DOMAIN, OPT_STUN_SRV,
 	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
 	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
-	   OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_USE_ICE,
+	   OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_USE_ICE, OPT_USE_SRTP,
 	   OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC, 
 	   OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
 	   OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,
@@ -441,6 +444,9 @@
 	{ "rec-file",   1, 0, OPT_REC_FILE},
 	{ "rtp-port",	1, 0, OPT_RTP_PORT},
 	{ "use-ice",    0, 0, OPT_USE_ICE},
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	{ "use-srtp",   1, 0, OPT_USE_SRTP},
+#endif
 	{ "add-codec",  1, 0, OPT_ADD_CODEC},
 	{ "dis-codec",  1, 0, OPT_DIS_CODEC},
 	{ "complexity",	1, 0, OPT_COMPLEXITY},
@@ -796,6 +802,16 @@
 	    cfg->media_cfg.enable_ice = PJ_TRUE;
 	    break;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	case OPT_USE_SRTP:
+	    app_config.cfg.use_srtp = my_atoi(pj_optarg);
+	    if (!pj_isdigit(*pj_optarg) || app_config.cfg.use_srtp > 2) {
+		PJ_LOG(1,(THIS_FILE, "Invalid value for --use-srtp option"));
+		return -1;
+	    }
+	    break;
+#endif
+
 	case OPT_RTP_PORT:
 	    cfg->rtp_cfg.port = my_atoi(pj_optarg);
 	    if (cfg->rtp_cfg.port == 0) {
@@ -1111,6 +1127,15 @@
 	pj_strcat2(result, line);
     }
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP */
+    if (acc_cfg->use_srtp) {
+	pj_ansi_sprintf(line, "--use-srtp %i\n",
+			(int)acc_cfg->use_srtp);
+	pj_strcat2(result, line);
+    }
+#endif
+
     /* Proxy */
     for (i=0; i<acc_cfg->proxy_cnt; ++i) {
 	pj_ansi_sprintf(line, "--proxy %.*s\n",
diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c
index edf0b83..b288190 100644
--- a/pjsip-apps/src/samples/simpleua.c
+++ b/pjsip-apps/src/samples/simpleua.c
@@ -285,13 +285,7 @@
      * need this info to create SDP (i.e. the address and port info in
      * the SDP).
      */
-    {
-	pjmedia_transport_udp_info udp_info;
-
-	pjmedia_transport_udp_get_info(g_med_transport, &udp_info);
-	pj_memcpy(&g_med_skinfo, &udp_info.skinfo, 
-		  sizeof(pjmedia_sock_info));
-    }
+    pjmedia_transport_get_info(g_med_transport, &g_med_skinfo);
 
 
     /*
diff --git a/pjsip-apps/src/samples/siprtp.c b/pjsip-apps/src/samples/siprtp.c
index 47a97b2..9ab0b1f 100644
--- a/pjsip-apps/src/samples/siprtp.c
+++ b/pjsip-apps/src/samples/siprtp.c
@@ -1005,14 +1005,14 @@
     pjmedia_sdp_session *sdp;
     pjmedia_sdp_media *m;
     pjmedia_sdp_attr *attr;
-    pjmedia_transport_udp_info tpinfo;
+    pjmedia_sock_info tpinfo;
     struct media_stream *audio = &call->media[0];
 
     PJ_ASSERT_RETURN(pool && p_sdp, PJ_EINVAL);
 
 
     /* Get transport info */
-    pjmedia_transport_udp_get_info(audio->transport, &tpinfo);
+    pjmedia_transport_get_info(audio->transport, &tpinfo);
 
     /* Create and initialize basic SDP session */
     sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));
@@ -1046,7 +1046,7 @@
 
     /* Standard media info: */
     m->desc.media = pj_str("audio");
-    m->desc.port = pj_ntohs(tpinfo.skinfo.rtp_addr_name.ipv4.sin_port);
+    m->desc.port = pj_ntohs(tpinfo.rtp_addr_name.ipv4.sin_port);
     m->desc.port_count = 1;
     m->desc.transport = pj_str("RTP/AVP");
 
diff --git a/pjsip-apps/src/samples/streamutil.c b/pjsip-apps/src/samples/streamutil.c
index a9dae3a..c9d2802 100644
--- a/pjsip-apps/src/samples/streamutil.c
+++ b/pjsip-apps/src/samples/streamutil.c
@@ -55,6 +55,17 @@
  "  --send-recv           Set stream direction to bidirectional.        \n"
  "  --send-only           Set stream direction to send only		\n"
  "  --recv-only           Set stream direction to recv only (default)   \n"
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ "  --use-srtp[=NAME]     Enable SRTP with crypto suite NAME            \n"
+ "                        e.g: AES_CM_128_HMAC_SHA1_80 (default),       \n"
+ "                             AES_CM_128_HMAC_SHA1_32                  \n"
+ "                        Use this option along with the TX & RX keys,  \n"
+ "                        formated of 60 hex digits (e.g: E148DA..)      \n"
+ "  --srtp-tx-key         SRTP key for transmiting                      \n"
+ "  --srtp-rx-key         SRTP key for receiving                        \n"
+#endif
+
  "\n"
 ;
 
@@ -64,6 +75,7 @@
 #include <pjlib-util.h>
 #include <pjmedia.h>
 #include <pjmedia-codec.h>
+#include <pjmedia/transport_srtp.h>
 
 #include <stdlib.h>	/* atoi() */
 #include <stdio.h>
@@ -78,6 +90,8 @@
 /* Prototype */
 static void print_stream_stat(pjmedia_stream *stream);
 
+/* Prototype for LIBSRTP utility in file datatypes.c */
+int hex_string_to_octet_string(char *raw, char *hex, int len);
 
 /* 
  * Register all codecs. 
@@ -122,11 +136,20 @@
 				  pjmedia_dir dir,
 				  pj_uint16_t local_port,
 				  const pj_sockaddr_in *rem_addr,
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+				  pj_bool_t use_srtp,
+				  const pj_str_t *crypto_suite,
+				  const pj_str_t *srtp_tx_key,
+				  const pj_str_t *srtp_rx_key,
+#endif
 				  pjmedia_stream **p_stream )
 {
     pjmedia_stream_info info;
-    pjmedia_transport *transport;
+    pjmedia_transport *transport = NULL;
     pj_status_t status;
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    pjmedia_transport *srtp_tp = NULL;
+#endif
 
 
     /* Reset stream info. */
@@ -158,17 +181,43 @@
     if (status != PJ_SUCCESS)
 	return status;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* Check if SRTP enabled */
+    if (use_srtp) {
+	pjmedia_srtp_crypto tx_plc, rx_plc;
+
+	status = pjmedia_transport_srtp_create(med_endpt, transport, 
+					       NULL, &srtp_tp);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
+	pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
+
+	tx_plc.key = *srtp_tx_key;
+	tx_plc.name = *crypto_suite;
+	rx_plc.key = *srtp_rx_key;
+	rx_plc.name = *crypto_suite;
+	
+	status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	transport = srtp_tp;
+    }
+#endif
 
     /* Now that the stream info is initialized, we can create the 
      * stream.
      */
 
     status = pjmedia_stream_create( med_endpt, pool, &info, 
-				    transport, NULL, p_stream);
+				    transport, 
+				    NULL, p_stream);
 
     if (status != PJ_SUCCESS) {
 	app_perror(THIS_FILE, "Error creating stream", status);
-	pjmedia_transport_udp_close(transport);
+	pjmedia_transport_close(transport);
 	return status;
     }
 
@@ -201,6 +250,16 @@
     char tmp[10];
     pj_status_t status; 
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP variables */
+    pj_bool_t use_srtp = PJ_FALSE;
+    char tmp_tx_key[64];
+    char tmp_rx_key[64];
+    pj_str_t  srtp_tx_key = {NULL, 0};
+    pj_str_t  srtp_rx_key = {NULL, 0};
+    pj_str_t  srtp_crypto_suite = {NULL, 0};
+    int	tmp_key_len;
+#endif
 
     /* Default values */
     const pjmedia_codec_info *codec_info;
@@ -220,6 +279,11 @@
 	OPT_SEND_RECV	= 'b',
 	OPT_SEND_ONLY	= 's',
 	OPT_RECV_ONLY	= 'i',
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	OPT_USE_SRTP	= 'S',
+#endif
+	OPT_SRTP_TX_KEY	= 'x',
+	OPT_SRTP_RX_KEY	= 'y',
 	OPT_HELP	= 'h',
     };
 
@@ -232,6 +296,11 @@
 	{ "send-recv",      0, 0, OPT_SEND_RECV },
 	{ "send-only",      0, 0, OPT_SEND_ONLY },
 	{ "recv-only",      0, 0, OPT_RECV_ONLY },
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	{ "use-srtp",	    2, 0, OPT_USE_SRTP },
+	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
+	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
+#endif
 	{ "help",	    0, 0, OPT_HELP },
 	{ NULL, 0, 0, 0 },
     };
@@ -298,6 +367,27 @@
 	    dir = PJMEDIA_DIR_DECODING;
 	    break;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	case OPT_USE_SRTP:
+	    use_srtp = PJ_TRUE;
+	    if (pj_optarg) {
+		pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
+	    } else {
+		srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
+	    }
+	    break;
+
+	case OPT_SRTP_TX_KEY:
+	    tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, strlen(pj_optarg));
+	    pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
+	    break;
+
+	case OPT_SRTP_RX_KEY:
+	    tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg, strlen(pj_optarg));
+	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
+	    break;
+#endif
+
 	case OPT_HELP:
 	    usage();
 	    return 1;
@@ -323,6 +413,16 @@
 	dir = PJMEDIA_DIR_ENCODING;
     }
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP validation */
+    if (use_srtp) {
+	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
+	{
+	    printf("Error: Key for each SRTP stream direction must be set\n");
+	    return 1;
+	}
+    }
+#endif
 
     /* Must create a pool factory before we can allocate any memory. */
     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
@@ -368,7 +468,12 @@
 
     /* Create stream based on program arguments */
     status = create_stream(pool, med_endpt, codec_info, dir, local_port, 
-			   &remote_addr, &stream);
+			   &remote_addr, 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+			   use_srtp, &srtp_crypto_suite, 
+			   &srtp_tx_key, &srtp_rx_key,
+#endif
+			   &stream);
     if (status != PJ_SUCCESS)
 	goto on_exit;
 
@@ -537,7 +642,8 @@
 
 	tp = pjmedia_stream_get_transport(stream);
 	pjmedia_stream_destroy(stream);
-	pjmedia_transport_udp_close(tp);
+	
+	pjmedia_transport_close(tp);
     }
 
     /* Destroy file ports */