Index: /pjproject/trunk/pjlib/include/pj/ssl_sock.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/ssl_sock.h	(revision 6003)
+++ /pjproject/trunk/pjlib/include/pj/ssl_sock.h	(revision 6004)
@@ -299,4 +299,12 @@
 						 const char *error_strings[],
 						 unsigned *count);
+
+/** 
+ * Wipe out the keys in the SSL certificate. 
+ *
+ * @param cert		The SSL certificate. 
+ *
+ */
+PJ_DECL(void) pj_ssl_cert_wipe_keys(pj_ssl_cert_t *cert);
 
 
@@ -1050,4 +1058,38 @@
 
 /**
+ * The parameter for pj_ssl_sock_start_connect2().
+ */
+typedef struct pj_ssl_start_connect_param {
+    /**
+     * The pool to allocate some internal data for the operation.
+     */
+    pj_pool_t *pool;
+
+    /**
+     * Local address.
+     */
+    const pj_sockaddr_t *localaddr;
+
+    /**
+     * Port range for socket binding, relative to the start port number
+     * specified in \a localaddr. This is only applicable when the start port
+     * number is non zero.
+     */
+    pj_uint16_t local_port_range;
+
+    /**
+     * Remote address.
+     */
+    const pj_sockaddr_t *remaddr;
+
+    /**
+     * Length of buffer containing above addresses.
+     */
+    int addr_len;
+
+} pj_ssl_start_connect_param;
+
+
+/**
  * Initialize the secure socket parameters for its creation with 
  * the default values.
@@ -1369,4 +1411,22 @@
 					       int addr_len);
 
+/**
+ * Same as #pj_ssl_sock_start_connect(), but application can provide a 
+ * \a port_range parameter, which will be used to bind the socket to 
+ * random port.
+ *
+ * @param ssock		The secure socket.
+ *
+ * @param connect_param The parameter, refer to \a pj_ssl_start_connect_param.
+ *
+ * @return		PJ_SUCCESS if connection can be established immediately
+ *			or PJ_EPENDING if connection cannot be established 
+ *			immediately. In this case the \a on_connect_complete()
+ *			callback will be called when connection is complete. 
+ *			Any other return value indicates error condition.
+ */
+PJ_DECL(pj_status_t) pj_ssl_sock_start_connect2(
+			      pj_ssl_sock_t *ssock,
+			      pj_ssl_start_connect_param *connect_param);
 
 /**
@@ -1386,5 +1446,4 @@
 PJ_DECL(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock);
 
-
 /**
  * @}
Index: /pjproject/trunk/pjlib/src/pj/ssl_sock_imp_common.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ssl_sock_imp_common.c	(revision 6003)
+++ /pjproject/trunk/pjlib/src/pj/ssl_sock_imp_common.c	(revision 6004)
@@ -31,4 +31,6 @@
 #   define PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT	500
 #endif
+
+enum { MAX_BIND_RETRY = 100 };
 
 #ifdef SSL_SOCK_IMP_USE_CIRC_BUF
@@ -597,25 +599,4 @@
 }
 
-
-static void wipe_buf(pj_str_t *buf)
-{
-    volatile char *p = buf->ptr;
-    pj_ssize_t len = buf->slen;
-    while (len--) *p++ = 0;
-    buf->slen = 0;
-}
-
-static void wipe_cert_buffer(pj_ssl_cert_t *cert)
-{
-    wipe_buf(&cert->CA_file);
-    wipe_buf(&cert->CA_path);
-    wipe_buf(&cert->cert_file);
-    wipe_buf(&cert->privkey_file);
-    wipe_buf(&cert->privkey_pass);
-    wipe_buf(&cert->CA_buf);
-    wipe_buf(&cert->cert_buf);
-    wipe_buf(&cert->privkey_buf);
-}
-
 static void ssl_on_destroy(void *arg)
 {
@@ -633,11 +614,4 @@
 	ssock->circ_buf_output_mutex = NULL;
 	ssock->write_mutex = NULL;
-    }
-
-    /* Wipe out cert & key buffer, note that they may not be allocated
-     * using SSL socket memory pool.
-     */
-    if (ssock->cert) {
-	wipe_cert_buffer(ssock->cert);
     }
 
@@ -1363,4 +1337,11 @@
 
     ssl_reset_sock_state(ssock);
+
+    /* Wipe out cert & key buffer. */
+    if (ssock->cert) {
+	pj_ssl_cert_wipe_keys(ssock->cert);
+	ssock->cert = NULL;
+    }
+
     if (ssock->param.grp_lock) {
 	pj_grp_lock_dec_ref(ssock->param.grp_lock);
@@ -1883,13 +1864,33 @@
  * Starts asynchronous socket connect() operation.
  */
-PJ_DEF(pj_status_t) pj_ssl_sock_start_connect( pj_ssl_sock_t *ssock,
-					       pj_pool_t *pool,
-					       const pj_sockaddr_t *localaddr,
-					       const pj_sockaddr_t *remaddr,
-					       int addr_len)
+PJ_DEF(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
+					      pj_pool_t *pool,
+					      const pj_sockaddr_t *localaddr,
+					      const pj_sockaddr_t *remaddr,
+					      int addr_len)
+{
+    pj_ssl_start_connect_param param;    
+    param.pool = pool;
+    param.localaddr = localaddr;
+    param.local_port_range = 0;
+    param.remaddr = remaddr;
+    param.addr_len = addr_len;
+
+    return pj_ssl_sock_start_connect2(ssock, &param);
+}
+
+PJ_DEF(pj_status_t) pj_ssl_sock_start_connect2(
+			       pj_ssl_sock_t *ssock,
+			       pj_ssl_start_connect_param *connect_param)
 {
     pj_activesock_cb asock_cb;
     pj_activesock_cfg asock_cfg;
     pj_status_t status;
+    
+    pj_pool_t *pool = connect_param->pool;
+    const pj_sockaddr_t *localaddr = connect_param->localaddr;
+    pj_uint16_t port_range = connect_param->local_port_range;
+    const pj_sockaddr_t *remaddr = connect_param->remaddr;
+    int addr_len = connect_param->addr_len;
 
     PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
@@ -1919,5 +1920,16 @@
 
     /* Bind socket */
-    status = pj_sock_bind(ssock->sock, localaddr, addr_len);
+    if (port_range) {
+	pj_uint16_t max_bind_retry = MAX_BIND_RETRY;
+	if (port_range && port_range < max_bind_retry)
+	{
+	    max_bind_retry = port_range;
+	}
+	status = pj_sock_bind_random(ssock->sock, localaddr, port_range,
+				     max_bind_retry);
+    } else {
+	status = pj_sock_bind(ssock->sock, localaddr, addr_len);
+    }
+
     if (status != PJ_SUCCESS)
 	goto on_error;
@@ -2013,4 +2025,26 @@
 }
 
+static void wipe_buf(pj_str_t *buf)
+{
+    volatile char *p = buf->ptr;
+    pj_ssize_t len = buf->slen;
+    while (len--) *p++ = 0;
+    buf->slen = 0;
+}
+
+PJ_DEF(void) pj_ssl_cert_wipe_keys(pj_ssl_cert_t *cert)
+{    
+    if (cert) {
+	wipe_buf(&cert->CA_file);
+	wipe_buf(&cert->CA_path);
+	wipe_buf(&cert->cert_file);
+	wipe_buf(&cert->privkey_file);
+	wipe_buf(&cert->privkey_pass);
+	wipe_buf(&cert->CA_buf);
+	wipe_buf(&cert->cert_buf);
+	wipe_buf(&cert->privkey_buf);
+    }
+}
+
 /* Load credentials from files. */
 PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files (pj_pool_t *pool,
Index: /pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c	(revision 6003)
+++ /pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c	(revision 6004)
@@ -1057,5 +1057,5 @@
      */
     if (cert && (!ssock->is_server || ssock->parent)) {
-	wipe_cert_buffer(cert);
+	pj_ssl_cert_wipe_keys(cert);	
     }
 
Index: /pjproject/trunk/pjnath/include/pjnath/turn_session.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/turn_session.h	(revision 6003)
+++ /pjproject/trunk/pjnath/include/pjnath/turn_session.h	(revision 6004)
@@ -152,6 +152,7 @@
      * TLS transport. The TLS transport will only be used as the connection
      * type to reach the server and never as the allocation transport type.
-     */
-    PJ_TURN_TP_TLS = 255
+     * The value corresponds to IANA protocol number.
+     */
+    PJ_TURN_TP_TLS = 56
 
 } pj_turn_tp_type;
Index: /pjproject/trunk/pjnath/include/pjnath/turn_sock.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/turn_sock.h	(revision 6003)
+++ /pjproject/trunk/pjnath/include/pjnath/turn_sock.h	(revision 6004)
@@ -27,4 +27,5 @@
 #include <pjnath/turn_session.h>
 #include <pj/sock_qos.h>
+#include <pj/ssl_sock.h>
 
 
@@ -146,4 +147,111 @@
 
 /**
+ * The default enabled SSL proto to be used.
+ * Default is all protocol above TLSv1 (TLSv1 & TLS v1.1 & TLS v1.2).
+ */
+#ifndef PJ_TURN_TLS_DEFAULT_PROTO
+#   define PJ_TURN_TLS_DEFAULT_PROTO  (PJ_SSL_SOCK_PROTO_TLS1 | \
+				       PJ_SSL_SOCK_PROTO_TLS1_1 | \
+				       PJ_SSL_SOCK_PROTO_TLS1_2)
+#endif
+
+/**
+ * TLS transport settings.
+ */
+typedef struct pj_turn_sock_tls_cfg
+{
+    /**
+     * Certificate of Authority (CA) list file.
+     */
+    pj_str_t	ca_list_file;
+
+    /**
+     * Certificate of Authority (CA) list directory path.
+     */
+    pj_str_t	ca_list_path;
+
+    /**
+     * Public endpoint certificate file, which will be used as client-
+     * side  certificate for outgoing TLS connection.
+     */
+    pj_str_t	cert_file;
+
+    /**
+     * Optional private key of the endpoint certificate to be used.
+     */
+    pj_str_t	privkey_file;
+
+    /**
+     * Certificate of Authority (CA) buffer. If ca_list_file, ca_list_path,
+     * cert_file or privkey_file are set, this setting will be ignored.
+     */
+    pj_ssl_cert_buffer ca_buf;
+
+    /**
+     * Public endpoint certificate buffer, which will be used as client-
+     * side  certificate for outgoing TLS connection, and server-side
+     * certificate for incoming TLS connection. If ca_list_file, ca_list_path,
+     * cert_file or privkey_file are set, this setting will be ignored.
+     */
+    pj_ssl_cert_buffer cert_buf;
+
+    /**
+     * Optional private key buffer of the endpoint certificate to be used. 
+     * If ca_list_file, ca_list_path, cert_file or privkey_file are set, 
+     * this setting will be ignored.
+     */
+    pj_ssl_cert_buffer privkey_buf;
+
+    /**
+     * Password to open private key.
+     */
+    pj_str_t	password;
+
+    /**
+     * The ssl socket parameter.
+     * These fields are used by TURN TLS:
+     * - proto
+     * - ciphers_num
+     * - ciphers
+     * - curves_num
+     * - curves
+     * - sigalgs
+     * - entropy_type
+     * - entropy_path
+     * - timeout
+     * - sockopt_params
+     * - sockopt_ignore_error
+     */
+    pj_ssl_sock_param ssock_param;
+
+} pj_turn_sock_tls_cfg;
+
+/**
+ * Initialize TLS setting with default values.
+ *
+ * @param tls_cfg   The TLS setting to be initialized.
+ */
+ PJ_DECL(void) pj_turn_sock_tls_cfg_default(pj_turn_sock_tls_cfg *tls_cfg);
+
+/**
+ * Duplicate TLS setting.
+ *
+ * @param pool	    The pool to duplicate strings etc.
+ * @param dst	    Destination structure.
+ * @param src	    Source structure.
+ */
+ PJ_DECL(void) pj_turn_sock_tls_cfg_dup(pj_pool_t *pool,
+					pj_turn_sock_tls_cfg *dst,
+					const pj_turn_sock_tls_cfg *src);
+
+/**
+ * Wipe out certificates and keys in the TLS setting.
+ *
+ * @param tls_cfg   The TLS setting.
+ */
+PJ_DECL(void) pj_turn_sock_tls_cfg_wipe_keys(pj_turn_sock_tls_cfg *tls_cfg);
+
+
+/**
  * This structure describes options that can be specified when creating
  * the TURN socket. Application should call #pj_turn_sock_cfg_default()
@@ -229,4 +337,10 @@
      */
     unsigned so_sndbuf_size;
+
+    /**
+     * This specifies TLS settings for TLS transport. It is only be used
+     * when this TLS is used to connect to the TURN server.
+     */
+    pj_turn_sock_tls_cfg tls_cfg;
 
 } pj_turn_sock_cfg;
Index: /pjproject/trunk/pjnath/src/pjnath-test/server.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath-test/server.c	(revision 6003)
+++ /pjproject/trunk/pjnath/src/pjnath-test/server.c	(revision 6004)
@@ -24,4 +24,9 @@
 #define MAX_STUN_PKT	1500
 #define TURN_NONCE	"thenonce"
+#define CERT_DIR		    "../../pjlib/build/"
+#define CERT_CA_FILE		    CERT_DIR "cacert.pem"
+#define CERT_FILE		    CERT_DIR "cacert.pem"
+#define CERT_PRIVKEY_FILE	    CERT_DIR "privkey.pem"
+#define CERT_PRIVKEY_PASS	    ""
 
 static pj_bool_t stun_on_data_recvfrom(pj_activesock_t *asock,
@@ -31,10 +36,38 @@
 				       int addr_len,
 				       pj_status_t status);
-static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock,
+static pj_bool_t turn_tcp_on_data_read(pj_activesock_t *asock,
 				       void *data,
 				       pj_size_t size,
-				       const pj_sockaddr_t *src_addr,
-				       int addr_len,
-				       pj_status_t status);
+				       pj_status_t status,
+				       pj_size_t *remainder);
+static pj_bool_t turn_tls_on_data_read(pj_ssl_sock_t *ssock,
+				       void *data,
+				       pj_size_t size,
+				       pj_status_t status,
+				       pj_size_t *remainder);
+static pj_bool_t turn_udp_on_data_recvfrom(pj_activesock_t *asock,
+					   void *data,
+				           pj_size_t size,
+				           const pj_sockaddr_t *src_addr,
+				           int addr_len,
+				           pj_status_t status);
+static pj_bool_t turn_on_data_read(test_server *asock,
+				   void *data,
+				   pj_size_t size,
+				   const pj_sockaddr_t *src_addr,
+				   int addr_len,
+				   pj_status_t status);
+static pj_bool_t turn_tcp_on_accept_complete(pj_activesock_t *asock,
+					     pj_sock_t newsock,
+					     const pj_sockaddr_t *src_addr,
+					     int src_addr_len,
+					     pj_status_t status);
+#if USE_TLS
+static pj_bool_t turn_tls_on_accept_complete2(pj_ssl_sock_t *ssock,
+					      pj_ssl_sock_t *newsock,
+					      const pj_sockaddr_t *src_addr,
+					      int src_addr_len,
+					      pj_status_t status);
+#endif
 static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
 				       void *data,
@@ -53,5 +86,5 @@
     pj_sockaddr hostip;
     char strbuf[100];
-    pj_status_t status;
+    pj_status_t status = PJ_EINVAL;
     pj_bool_t use_ipv6 = flags & SERVER_IPV6;
 
@@ -169,23 +202,108 @@
 
     if (flags & CREATE_TURN_SERVER) {
-	pj_activesock_cb turn_sock_cb;
+	
 	pj_sockaddr bound_addr;
-
-	pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
-	turn_sock_cb.on_data_recvfrom = &turn_on_data_recvfrom;
-
+	pj_turn_tp_type tp_type = get_turn_tp_type(flags);
+	
 	pj_sockaddr_init(GET_AF(use_ipv6), &bound_addr, NULL, TURN_SERVER_PORT);
 
-	status = pj_activesock_create_udp(pool, &bound_addr, NULL, 
-					  test_srv->stun_cfg->ioqueue,
-					  &turn_sock_cb, test_srv,
-					  &test_srv->turn_sock, NULL);
-	if (status != PJ_SUCCESS) {
-	    destroy_test_server(test_srv);
-	    return status;
-	}
-
-	status = pj_activesock_start_recvfrom(test_srv->turn_sock, pool,
-					      MAX_STUN_PKT, 0);
+	if (tp_type == PJ_TURN_TP_UDP) {
+	    pj_activesock_cb turn_sock_cb;
+
+	    pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
+	    turn_sock_cb.on_data_recvfrom = &turn_udp_on_data_recvfrom;
+
+	    status = pj_activesock_create_udp(pool, &bound_addr, NULL,
+					      test_srv->stun_cfg->ioqueue,
+					      &turn_sock_cb, test_srv,
+					      &test_srv->turn_sock, NULL);
+
+	    if (status != PJ_SUCCESS) {
+		destroy_test_server(test_srv);
+		return status;
+	    }
+
+	    status = pj_activesock_start_recvfrom(test_srv->turn_sock, pool,
+						  MAX_STUN_PKT, 0);
+	} else if (tp_type == PJ_TURN_TP_TCP) {
+	    pj_sock_t sock_fd;
+	    pj_activesock_cb turn_sock_cb;
+
+	    pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
+	    turn_sock_cb.on_accept_complete2 = &turn_tcp_on_accept_complete;
+	    status = pj_sock_socket(GET_AF(use_ipv6), pj_SOCK_STREAM(), 0,
+				    &sock_fd);
+	    if (status != PJ_SUCCESS) {
+		return status;
+	    }
+
+	    status = pj_sock_bind(sock_fd, &bound_addr, 
+				  pj_sockaddr_get_len(&bound_addr));
+	    if (status != PJ_SUCCESS) {
+		pj_sock_close(sock_fd);
+		return status;
+	    }
+
+	    status = pj_sock_listen(sock_fd, 4);
+	    if (status != PJ_SUCCESS) {
+		pj_sock_close(sock_fd);
+		return status;
+	    }
+
+	    status = pj_activesock_create(pool, sock_fd, pj_SOCK_STREAM(), 
+					  NULL,
+					  test_srv->stun_cfg->ioqueue, 
+					  &turn_sock_cb, test_srv, 
+					  &test_srv->turn_sock);
+	    if (status != PJ_SUCCESS) {
+		pj_sock_close(sock_fd);
+		return status;
+	    }
+
+	    status = pj_activesock_start_accept(test_srv->turn_sock,
+						pool);
+	} 
+#if USE_TLS	
+	else if (tp_type == PJ_TURN_TP_TLS) {
+	    pj_ssl_sock_t *ssock_serv = NULL;
+	    pj_ssl_sock_param ssl_param;
+	    pj_ssl_cert_t *cert = NULL;
+	    pj_str_t ca_file = pj_str(CERT_CA_FILE);
+	    pj_str_t cert_file = pj_str(CERT_FILE);
+	    pj_str_t privkey_file = pj_str(CERT_PRIVKEY_FILE);
+	    pj_str_t privkey_pass = pj_str(CERT_PRIVKEY_PASS);
+
+	    pj_ssl_sock_param_default(&ssl_param);
+	    ssl_param.cb.on_accept_complete2 = &turn_tls_on_accept_complete2;
+	    ssl_param.cb.on_data_read = &turn_tls_on_data_read;
+	    ssl_param.ioqueue = test_srv->stun_cfg->ioqueue;
+	    ssl_param.timer_heap = test_srv->stun_cfg->timer_heap;
+	    ssl_param.user_data = test_srv;
+	    ssl_param.sock_af = GET_AF(use_ipv6);
+
+	    status = pj_ssl_sock_create(pool, &ssl_param, &ssock_serv);
+	    if (status != PJ_SUCCESS) {
+		if (ssock_serv)
+		    pj_ssl_sock_close(ssock_serv);
+	    }
+
+	    status = pj_ssl_cert_load_from_files(pool, &ca_file, &cert_file, 
+						 &privkey_file, &privkey_pass,
+						 &cert);
+	    if (status != PJ_SUCCESS) {
+		if (ssock_serv)
+		    pj_ssl_sock_close(ssock_serv);
+	    }
+
+	    status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
+	    if (status != PJ_SUCCESS) {
+		if (ssock_serv)
+		    pj_ssl_sock_close(ssock_serv);
+	    }
+	    test_srv->ssl_srv_sock = ssock_serv;
+	    status = pj_ssl_sock_start_accept(ssock_serv, pool, &bound_addr, 
+					     pj_sockaddr_get_len(&bound_addr));
+	}
+#endif
 	if (status != PJ_SUCCESS) {
 	    destroy_test_server(test_srv);
@@ -201,6 +319,18 @@
 	     *  turn.domain IN A 127.0.0.1
 	     */
-	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
-			     "_turn._udp.%s", domain);
+	    switch (tp_type) {
+	    case PJ_TURN_TP_TCP:
+		pj_ansi_snprintf(strbuf, sizeof(strbuf),
+				 "_turn._tcp.%s", domain);
+		break;
+	    case PJ_TURN_TP_TLS:
+		pj_ansi_snprintf(strbuf, sizeof(strbuf),
+				 "_turns._tcp.%s", domain);
+		break;
+	    default:
+		pj_ansi_snprintf(strbuf, sizeof(strbuf),
+				 "_turn._udp.%s", domain);
+		
+	    }
 	    pj_strdup2(pool, &res_name, strbuf);
 	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
@@ -244,4 +374,20 @@
 	test_srv->turn_sock = NULL;
     }
+
+    if (test_srv->cl_turn_sock) {
+	pj_activesock_close(test_srv->cl_turn_sock);
+	test_srv->cl_turn_sock = NULL;
+    }
+
+#if USE_TLS
+    if (test_srv->ssl_srv_sock) {
+	pj_ssl_sock_close(test_srv->ssl_srv_sock);
+	test_srv->ssl_srv_sock = NULL;
+    }
+    if (test_srv->ssl_cl_sock) {
+	pj_ssl_sock_close(test_srv->ssl_cl_sock);
+	test_srv->ssl_cl_sock = NULL;
+    }
+#endif
 
     if (test_srv->stun_sock) {
@@ -350,13 +496,52 @@
 }
 
-
-static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock,
+static pj_bool_t turn_tcp_on_data_read(pj_activesock_t *asock,
 				       void *data,
 				       pj_size_t size,
-				       const pj_sockaddr_t *src_addr,
-				       int addr_len,
-				       pj_status_t status)
+				       pj_status_t status,
+				       pj_size_t *remainder)
+{
+    test_server *test_srv = (test_server *)pj_activesock_get_user_data(asock);
+
+    PJ_UNUSED_ARG(remainder);
+    return turn_on_data_read(test_srv, data, size, &test_srv->remote_addr, 
+			    sizeof(test_srv->remote_addr), status);
+}
+
+static pj_bool_t turn_tls_on_data_read(pj_ssl_sock_t *ssl_sock,
+				       void *data,
+				       pj_size_t size,
+				       pj_status_t status,
+				       pj_size_t *remainder)
+{
+    test_server *test_srv = (test_server *)pj_ssl_sock_get_user_data(ssl_sock);
+
+    PJ_UNUSED_ARG(remainder);
+    return turn_on_data_read(test_srv, data, size, 
+			     &test_srv->remote_addr, 
+			     sizeof(test_srv->remote_addr), 
+			     status);
+}
+
+static pj_bool_t turn_udp_on_data_recvfrom(pj_activesock_t *asock,
+					   void *data,
+					   pj_size_t size,
+					   const pj_sockaddr_t *src_addr,
+					   int addr_len,
+					   pj_status_t status)
 {
     test_server *test_srv;
+    test_srv = (test_server*) pj_activesock_get_user_data(asock);
+    return turn_on_data_read(test_srv, data, size, src_addr, addr_len, status);
+}
+
+static pj_bool_t turn_on_data_read(test_server *test_srv,
+				   void *data,
+				   pj_size_t size,
+				   const pj_sockaddr_t *src_addr,
+				   int addr_len,
+				   pj_status_t status)
+{
+    
     pj_pool_t *pool;
     turn_allocation *alloc;
@@ -372,6 +557,5 @@
 
     pj_sockaddr_print(src_addr, client_info, sizeof(client_info), 3);
-
-    test_srv = (test_server*) pj_activesock_get_user_data(asock);
+    
     use_ipv6 = test_srv->flags & SERVER_IPV6;
     pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);
@@ -383,6 +567,7 @@
     }
 
-
-    if (pj_stun_msg_check((pj_uint8_t*)data, size, PJ_STUN_NO_FINGERPRINT_CHECK)!=PJ_SUCCESS)  {
+    if (pj_stun_msg_check((pj_uint8_t*)data, size, 
+			  PJ_STUN_NO_FINGERPRINT_CHECK)!=PJ_SUCCESS)  
+{
 	/* Not STUN message, this probably is a ChannelData */
 	pj_turn_channel_data cd;
@@ -703,4 +888,6 @@
 send_pkt:
     if (resp) {
+	pj_turn_tp_type tp_type = get_turn_tp_type(test_srv->flags);
+
 	status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT, 
 				    0, &auth_key, &size);
@@ -709,6 +896,20 @@
 
 	len = size;
-	status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len,
-				      0, src_addr, addr_len);
+	switch (tp_type) {
+	case PJ_TURN_TP_TCP:
+	    status = pj_activesock_send(test_srv->cl_turn_sock, 
+					&test_srv->send_key, data, &len, 0);
+	    break;
+#if USE_TLS
+	case PJ_TURN_TP_TLS:
+	    status = pj_ssl_sock_send(test_srv->ssl_cl_sock, 
+				      &test_srv->send_key, data, &len, 0);
+	    break;
+#endif
+	default:
+	    status = pj_activesock_sendto(test_srv->turn_sock, 
+					  &test_srv->send_key, data, 
+					  &len, 0, src_addr, addr_len);	    
+	}
     }
 
@@ -717,4 +918,82 @@
     return PJ_TRUE;
 }
+
+static pj_bool_t turn_tcp_on_accept_complete(pj_activesock_t *asock,
+					     pj_sock_t newsock,
+					     const pj_sockaddr_t *src_addr,
+					     int src_addr_len,
+					     pj_status_t status)
+{
+    pj_status_t sstatus;
+    pj_activesock_cb asock_cb;
+    test_server *test_srv = (test_server *) pj_activesock_get_user_data(asock);
+    
+    PJ_UNUSED_ARG(src_addr_len);
+
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+        return PJ_FALSE;
+    }
+
+    pj_sockaddr_cp(&test_srv->remote_addr, src_addr);
+    pj_bzero(&asock_cb, sizeof(asock_cb));
+    asock_cb.on_data_read = &turn_tcp_on_data_read;
+
+    sstatus = pj_activesock_create(test_srv->pool, newsock, pj_SOCK_STREAM(),
+                                   NULL, test_srv->stun_cfg->ioqueue,
+			           &asock_cb, test_srv, 
+				   &test_srv->cl_turn_sock);
+    if (sstatus != PJ_SUCCESS) {        
+        goto on_exit;
+    }
+
+    sstatus = pj_activesock_start_read(test_srv->cl_turn_sock, 
+				       test_srv->pool, MAX_STUN_PKT, 0);
+    if (sstatus != PJ_SUCCESS) {
+        goto on_exit;
+    }
+
+    pj_ioqueue_op_key_init(&test_srv->send_key, sizeof(test_srv->send_key));
+
+    return PJ_TRUE;
+
+on_exit:
+    if (test_srv->cl_turn_sock)
+        pj_activesock_close(test_srv->turn_sock);
+    else    
+	pj_sock_close(newsock);
+
+    return PJ_FALSE;
+
+}
+
+#if USE_TLS
+static pj_bool_t turn_tls_on_accept_complete2(pj_ssl_sock_t *ssock,
+					      pj_ssl_sock_t *newsock,
+					      const pj_sockaddr_t *src_addr,
+					      int src_addr_len,
+					      pj_status_t status)
+{
+    pj_status_t sstatus;
+    test_server *test_srv = (test_server *) pj_ssl_sock_get_user_data(ssock);
+
+    PJ_UNUSED_ARG(src_addr_len);
+
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+        return PJ_FALSE;
+    }
+
+    pj_ssl_sock_set_user_data(newsock, test_srv);
+    pj_sockaddr_cp(&test_srv->remote_addr, src_addr);
+    test_srv->ssl_cl_sock = newsock;
+
+    sstatus = pj_ssl_sock_start_read(newsock, test_srv->pool, MAX_STUN_PKT, 0);
+    if (sstatus != PJ_SUCCESS) {
+	pj_ssl_sock_close(newsock);
+	test_srv->ssl_cl_sock = NULL;
+
+    }
+    return PJ_TRUE;
+}
+#endif
 
 /* On received data from peer */
Index: /pjproject/trunk/pjnath/src/pjnath-test/server.h
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath-test/server.h	(revision 6003)
+++ /pjproject/trunk/pjnath/src/pjnath-test/server.h	(revision 6004)
@@ -47,5 +47,9 @@
 
     SERVER_IPV4			= (1 << 12),
-    SERVER_IPV6			= (1 << 13)
+    SERVER_IPV6			= (1 << 13),
+
+    TURN_UDP			= (1 << 16),
+    TURN_TCP			= (1 << 17),
+    TURN_TLS			= (1 << 18)
 };
 
@@ -83,4 +87,12 @@
 
     pj_activesock_t	*turn_sock;
+
+    pj_ssl_sock_t	*ssl_srv_sock;
+
+    pj_ssl_sock_t	*ssl_cl_sock;
+
+    pj_activesock_t	*cl_turn_sock;
+
+    pj_sockaddr		 remote_addr;
     unsigned		 turn_alloc_cnt;
     turn_allocation	 turn_alloc[MAX_TURN_ALLOC];
Index: /pjproject/trunk/pjnath/src/pjnath-test/test.h
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath-test/test.h	(revision 6003)
+++ /pjproject/trunk/pjnath/src/pjnath-test/test.h	(revision 6004)
@@ -36,4 +36,10 @@
 #endif
 
+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK
+#   define USE_TLS	1
+#else
+#   define USE_TLS	0
+#endif
+
 int stun_test(void);
 int sess_auth_test(void);
@@ -71,4 +77,5 @@
 		      const struct pjlib_state *initial_st);
 
+pj_turn_tp_type get_turn_tp_type(pj_uint32_t flag);
 
 #define ERR_MEMORY_LEAK	    1
Index: /pjproject/trunk/pjnath/src/pjnath-test/turn_sock_test.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath-test/turn_sock_test.c	(revision 6003)
+++ /pjproject/trunk/pjnath/src/pjnath-test/turn_sock_test.c	(revision 6004)
@@ -91,5 +91,12 @@
 }
 
-
+pj_turn_tp_type get_turn_tp_type(pj_uint32_t flag) {
+    if (flag & TURN_TCP) {
+	return PJ_TURN_TP_TCP;
+    } else if (flag & TURN_TLS) {
+	return PJ_TURN_TP_TLS;
+    } 
+    return PJ_TURN_TP_UDP;
+}
 
 static int create_test_session(pj_stun_config  *stun_cfg,
@@ -104,4 +111,5 @@
     pj_status_t status;
     pj_bool_t use_ipv6 = cfg->srv.flags & SERVER_IPV6;
+    pj_turn_tp_type tp_type = get_turn_tp_type(cfg->srv.flags);
 
     /* Create client */
@@ -117,5 +125,5 @@
     status = pj_turn_sock_create(sess->stun_cfg,
 				 GET_AF(use_ipv6),
-				 PJ_TURN_TP_UDP, 
+				 tp_type, 
 				 &turn_sock_cb, 
 				 0, 
@@ -258,12 +266,23 @@
 
 static void set_server_flag(struct test_session_cfg *test_cfg, 
-			    pj_bool_t use_ipv6)
-{
-    test_cfg->srv.flags &= ~(SERVER_IPV4+SERVER_IPV6);
-    test_cfg->srv.flags |= (use_ipv6)?SERVER_IPV6:SERVER_IPV4;
+			    pj_bool_t use_ipv6,
+			    pj_turn_tp_type tp_type)
+{
+    pj_uint32_t flag = TURN_UDP;
+    test_cfg->srv.flags &= ~(SERVER_IPV4+SERVER_IPV6+
+			     TURN_UDP+TURN_TCP+TURN_TLS);    
+    switch (tp_type) {
+	case PJ_TURN_TP_TCP:
+	    flag = TURN_TCP;
+	    break;
+	case PJ_TURN_TP_TLS:
+	    flag = TURN_TLS;
+    }
+    test_cfg->srv.flags |= ((use_ipv6)?SERVER_IPV6:SERVER_IPV4)+flag;
 }
 
 static int state_progression_test(pj_stun_config  *stun_cfg, 
-				  pj_bool_t use_ipv6)
+				  pj_bool_t use_ipv6,
+				  pj_turn_tp_type tp_type)
 {
     struct test_session_cfg test_cfg = 
@@ -283,7 +302,10 @@
     int rc = 0;
 
-    PJ_LOG(3,("", "  state progression tests - (%s)",use_ipv6?"IPv6":"IPv4"));
+    PJ_LOG(3,("", "  state progression tests - (%s) (%s)",
+	      use_ipv6?"IPv6":"IPv4",
+	      (tp_type==PJ_TURN_TP_UDP)?"UDP":
+		(tp_type==PJ_TURN_TP_TCP)?"TCP":"TLS"));
     
-    set_server_flag(&test_cfg, use_ipv6);
+    set_server_flag(&test_cfg, use_ipv6, tp_type);
     for (i=0; i<=1; ++i) {
 	enum { TIMEOUT = 60 };
@@ -312,4 +334,7 @@
 
 	    poll_events(stun_cfg, 10, PJ_FALSE);
+	    if (sess->turn_sock == NULL) {
+		break;
+	    }
 	    rc = pj_turn_sock_get_info(sess->turn_sock, &info);
 	    if (rc!=PJ_SUCCESS)
@@ -389,5 +414,5 @@
 
     if (use_ipv6)
-	rc = state_progression_test(stun_cfg, 0);
+	rc = state_progression_test(stun_cfg, 0, tp_type);
 
     return rc;
@@ -400,5 +425,6 @@
 			pj_bool_t with_dns_srv,
 			pj_bool_t in_callback,
-			pj_bool_t use_ipv6)
+			pj_bool_t use_ipv6,
+			pj_turn_tp_type tp_type)
 {
     struct test_session_cfg test_cfg = 
@@ -418,11 +444,12 @@
     int rc;
 
-    PJ_LOG(3,("", "  destroy test %s %s",
+    PJ_LOG(3,("", "  destroy test %s %s (%s)",
 	          (in_callback? "in callback" : ""),
-		  (with_dns_srv? "with DNS srv" : "")
-		  ));
+		  (with_dns_srv? "with DNS srv" : ""),
+		  (tp_type==PJ_TURN_TP_UDP)?"UDP":
+		    (tp_type==PJ_TURN_TP_TCP)?"TCP":"TLS"));
 
     test_cfg.client.enable_dns_srv = with_dns_srv;
-    set_server_flag(&test_cfg, use_ipv6);    
+    set_server_flag(&test_cfg, use_ipv6, tp_type);    
 
     for (target_state=PJ_TURN_STATE_RESOLVING; target_state<=PJ_TURN_STATE_READY; ++target_state) {
@@ -507,5 +534,5 @@
     pj_pool_t *pool;
     pj_stun_config stun_cfg;
-    int i, rc = 0;
+    int n, i, rc = 0;
 
     pool = pj_pool_create(mem, "turntest", 512, 512, NULL);
@@ -516,14 +543,29 @@
     }
 
-    rc = state_progression_test(&stun_cfg, USE_IPV6);
-    if (rc != 0) 
-	goto on_return;
-
-    for (i=0; i<=1; ++i) {
-	int j;
-	for (j=0; j<=1; ++j) {
-	    rc = destroy_test(&stun_cfg, i, j, USE_IPV6);
-	    if (rc != 0)
-		goto on_return;
+    for (n = 0; n <= 2; ++n) {
+	pj_turn_tp_type tp_type = PJ_TURN_TP_UDP;
+
+	if ((n == 2) && !USE_TLS)
+	    break;
+
+	switch (n) {
+	case 1:
+	    tp_type = PJ_TURN_TP_TCP;
+	    break;
+	case 2:
+	    tp_type = PJ_TURN_TP_TLS;
+	}
+
+	rc = state_progression_test(&stun_cfg, USE_IPV6, tp_type);
+	if (rc != 0) 
+	    goto on_return;
+
+	for (i=0; i<=1; ++i) {
+	    int j;
+	    for (j=0; j<=1; ++j) {
+		rc = destroy_test(&stun_cfg, i, j, USE_IPV6, tp_type);
+		if (rc != 0)
+		    goto on_return;
+	    }
 	}
     }
Index: /pjproject/trunk/pjnath/src/pjnath/turn_sock.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/turn_sock.c	(revision 6003)
+++ /pjproject/trunk/pjnath/src/pjnath/turn_sock.c	(revision 6004)
@@ -20,4 +20,5 @@
 #include <pjnath/turn_sock.h>
 #include <pj/activesock.h>
+#include <pj/ssl_sock.h>
 #include <pj/assert.h>
 #include <pj/errno.h>
@@ -26,4 +27,5 @@
 #include <pj/pool.h>
 #include <pj/ioqueue.h>
+#include <pj/compat/socket.h>
 
 enum
@@ -85,4 +87,10 @@
     pj_turn_tp_type	 conn_type;
     pj_activesock_t	*active_sock;
+#if PJ_HAS_SSL_SOCK
+    pj_ssl_sock_t       *ssl_sock;
+    pj_ssl_cert_t       *cert;
+    pj_str_t             server_name;
+#endif
+
     pj_ioqueue_op_key_t	 send_key;
 
@@ -123,12 +131,34 @@
 					   unsigned addr_len);
 
-static pj_bool_t on_data_read(pj_activesock_t *asock,
+static pj_bool_t on_data_read(pj_turn_sock *turn_sock,
 			      void *data,
 			      pj_size_t size,
 			      pj_status_t status,
 			      pj_size_t *remainder);
-static pj_bool_t on_connect_complete(pj_activesock_t *asock,
+static pj_bool_t on_connect_complete(pj_turn_sock *turn_sock,
 				     pj_status_t status);
 
+/*
+ * Activesock callback
+ */
+static pj_bool_t on_connect_complete_asock(pj_activesock_t *asock,
+					   pj_status_t status);
+static pj_bool_t on_data_read_asock(pj_activesock_t *asock,
+				    void *data,
+				    pj_size_t size,
+				    pj_status_t status,
+				    pj_size_t *remainder);
+
+/*
+ * SSL sock callback
+ */
+static pj_bool_t on_connect_complete_ssl_sock(pj_ssl_sock_t *ssl_sock,
+					      pj_status_t status);
+static pj_bool_t on_data_read_ssl_sock(pj_ssl_sock_t *ssl_sock,
+				       void *data,
+				       pj_size_t size,
+				       pj_status_t status,
+				       pj_size_t *remainder);
+  
 static pj_bool_t dataconn_on_data_read(pj_activesock_t *asock,
 				       void *data,
@@ -152,6 +182,55 @@
     cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT;
     cfg->qos_ignore_error = PJ_TRUE;
-}
-
+
+#if PJ_HAS_SSL_SOCK
+    pj_turn_sock_tls_cfg_default(&cfg->tls_cfg);
+#endif
+}
+
+#if PJ_HAS_SSL_SOCK
+
+PJ_DEF(void) pj_turn_sock_tls_cfg_default(pj_turn_sock_tls_cfg *tls_cfg)
+{
+    pj_bzero(tls_cfg, sizeof(*tls_cfg));
+    pj_ssl_sock_param_default(&tls_cfg->ssock_param);
+    tls_cfg->ssock_param.proto = PJ_TURN_TLS_DEFAULT_PROTO;
+}
+
+PJ_DEF(void) pj_turn_sock_tls_cfg_dup(pj_pool_t *pool,
+				      pj_turn_sock_tls_cfg *dst,
+				      const pj_turn_sock_tls_cfg *src)
+{
+    pj_memcpy(dst, src, sizeof(*dst));
+    pj_strdup_with_null(pool, &dst->ca_list_file, &src->ca_list_file);
+    pj_strdup_with_null(pool, &dst->ca_list_path, &src->ca_list_path);
+    pj_strdup_with_null(pool, &dst->cert_file, &src->cert_file);
+    pj_strdup_with_null(pool, &dst->privkey_file, &src->privkey_file);
+    pj_strdup_with_null(pool, &dst->password, &src->password);
+    pj_strdup(pool, &dst->ca_buf, &src->ca_buf);
+    pj_strdup(pool, &dst->cert_buf, &src->cert_buf);
+    pj_strdup(pool, &dst->privkey_buf, &src->privkey_buf);
+    pj_ssl_sock_param_copy(pool, &dst->ssock_param, &src->ssock_param);
+}
+
+static void wipe_buf(pj_str_t *buf)
+{
+    volatile char *p = buf->ptr;
+    pj_ssize_t len = buf->slen;
+    while (len--) *p++ = 0;
+    buf->slen = 0;
+}
+
+PJ_DEF(void) pj_turn_sock_tls_cfg_wipe_keys(pj_turn_sock_tls_cfg *tls_cfg)
+{
+    wipe_buf(&tls_cfg->ca_list_file);
+    wipe_buf(&tls_cfg->ca_list_path);
+    wipe_buf(&tls_cfg->cert_file);
+    wipe_buf(&tls_cfg->privkey_file);
+    wipe_buf(&tls_cfg->password);
+    wipe_buf(&tls_cfg->ca_buf);
+    wipe_buf(&tls_cfg->cert_buf);
+    wipe_buf(&tls_cfg->privkey_buf); 
+}
+#endif
 
 /*
@@ -176,4 +255,5 @@
     PJ_ASSERT_RETURN(af==pj_AF_INET() || af==pj_AF_INET6(), PJ_EINVAL);
     PJ_ASSERT_RETURN(conn_type!=PJ_TURN_TP_TCP || PJ_HAS_TCP, PJ_EINVAL);
+    PJ_ASSERT_RETURN(conn_type!=PJ_TURN_TP_TLS || PJ_HAS_SSL_SOCK, PJ_EINVAL);
 
     if (!setting) {
@@ -189,4 +269,9 @@
 	name_tmpl = "tcprel%p";
 	break;
+#if PJ_HAS_SSL_SOCK
+    case PJ_TURN_TP_TLS:
+	name_tmpl = "tlsrel%p";
+	break;
+#endif
     default:
 	PJ_ASSERT_RETURN(!"Invalid TURN conn_type", PJ_EINVAL);
@@ -210,4 +295,8 @@
     /* Copy setting (QoS parameters etc */
     pj_memcpy(&turn_sock->setting, setting, sizeof(*setting));
+#if PJ_HAS_SSL_SOCK
+    pj_turn_sock_tls_cfg_dup(turn_sock->pool, &turn_sock->setting.tls_cfg,
+			     &setting->tls_cfg);
+#endif
 
     /* Set callback */
@@ -289,4 +378,8 @@
     if (turn_sock->active_sock)
 	pj_activesock_close(turn_sock->active_sock);
+#if PJ_HAS_SSL_SOCK
+    if (turn_sock->ssl_sock)
+	pj_ssl_sock_close(turn_sock->ssl_sock);
+#endif
 
     for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) {
@@ -475,4 +568,9 @@
 	}
     }
+#if PJ_HAS_SSL_SOCK
+    if (turn_sock->conn_type == PJ_TURN_TP_TLS) {
+	pj_strdup_with_null(turn_sock->pool, &turn_sock->server_name, domain);
+    }
+#endif
 
     /* Resolve server */
@@ -549,13 +647,7 @@
  * Notification when outgoing TCP socket has been connected.
  */
-static pj_bool_t on_connect_complete(pj_activesock_t *asock,
+static pj_bool_t on_connect_complete(pj_turn_sock *turn_sock,
 				     pj_status_t status)
 {
-    pj_turn_sock *turn_sock;
-
-    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
-    if (!turn_sock)
-        return PJ_FALSE;
-
     pj_grp_lock_acquire(turn_sock->grp_lock);
 
@@ -570,5 +662,11 @@
 
     if (status != PJ_SUCCESS) {
-	sess_fail(turn_sock, "TCP connect() error", status);
+	if (turn_sock->conn_type == PJ_TURN_TP_UDP)
+	    sess_fail(turn_sock, "UDP connect() error", status);
+	else if (turn_sock->conn_type == PJ_TURN_TP_TCP)
+	    sess_fail(turn_sock, "TCP connect() error", status);
+	else if (turn_sock->conn_type == PJ_TURN_TP_TLS)
+	    sess_fail(turn_sock, "TLS connect() error", status);
+
 	pj_grp_lock_release(turn_sock->grp_lock);
 	return PJ_FALSE;
@@ -576,10 +674,19 @@
 
     if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
-	PJ_LOG(5,(turn_sock->obj_name, "TCP connected"));
+	PJ_LOG(5, (turn_sock->obj_name, "%s connected",
+		   turn_sock->conn_type == PJ_TURN_TP_TCP ? "TCP" : "TLS"));
     }
 
     /* Kick start pending read operation */
-    status = pj_activesock_start_read(asock, turn_sock->pool, 
-				      turn_sock->setting.max_pkt_size, 0);
+    if (turn_sock->conn_type != PJ_TURN_TP_TLS) 
+	status = pj_activesock_start_read(turn_sock->active_sock, 
+					  turn_sock->pool,
+					  turn_sock->setting.max_pkt_size, 
+					  0);
+#if PJ_HAS_SSL_SOCK
+    else
+	status = pj_ssl_sock_start_read(turn_sock->ssl_sock, turn_sock->pool,
+					turn_sock->setting.max_pkt_size, 0);
+#endif
 
     /* Init send_key */
@@ -598,4 +705,28 @@
 }
 
+static pj_bool_t on_connect_complete_asock(pj_activesock_t *asock,
+					   pj_status_t status)
+{
+    pj_turn_sock *turn_sock;
+
+    turn_sock = (pj_turn_sock*)pj_activesock_get_user_data(asock);
+    if (!turn_sock)
+	return PJ_FALSE;
+
+    return on_connect_complete(turn_sock, status);
+}
+
+static pj_bool_t on_connect_complete_ssl_sock(pj_ssl_sock_t *ssl_sock,
+					      pj_status_t status)
+{
+    pj_turn_sock *turn_sock;
+
+    turn_sock = (pj_turn_sock*)pj_ssl_sock_get_user_data(ssl_sock);
+    if (!turn_sock)
+	return PJ_FALSE;
+
+    return on_connect_complete(turn_sock, status);
+}
+
 static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
 {
@@ -644,5 +775,5 @@
  * Notification from ioqueue when incoming UDP packet is received.
  */
-static pj_bool_t on_data_read(pj_activesock_t *asock,
+static pj_bool_t on_data_read(pj_turn_sock *turn_sock,
 			      void *data,
 			      pj_size_t size,
@@ -650,8 +781,6 @@
 			      pj_size_t *remainder)
 {
-    pj_turn_sock *turn_sock;
     pj_bool_t ret = PJ_TRUE;
 
-    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
     pj_grp_lock_acquire(turn_sock->grp_lock);
 
@@ -697,8 +826,12 @@
 	    //	      "Buffer size now %lu bytes", size));
 	}
-    } else if (status != PJ_SUCCESS && 
-	       turn_sock->conn_type != PJ_TURN_TP_UDP) 
-    {
-	sess_fail(turn_sock, "TCP connection closed", status);
+    } else if (status != PJ_SUCCESS) {
+	if (turn_sock->conn_type == PJ_TURN_TP_UDP)
+	    sess_fail(turn_sock, "UDP connection closed", status);
+	else if (turn_sock->conn_type == PJ_TURN_TP_TCP)
+	    sess_fail(turn_sock, "TCP connection closed", status);
+	else if (turn_sock->conn_type == PJ_TURN_TP_TLS)
+	    sess_fail(turn_sock, "TLS connection closed", status);
+
 	ret = PJ_FALSE;
 	goto on_return;
@@ -711,4 +844,54 @@
 }
 
+static pj_bool_t on_data_read_asock(pj_activesock_t *asock,
+				    void *data,
+				    pj_size_t size,
+				    pj_status_t status,
+				    pj_size_t *remainder)
+{
+    pj_turn_sock *turn_sock;
+
+    turn_sock = (pj_turn_sock*)pj_activesock_get_user_data(asock);
+
+    return on_data_read(turn_sock, data, size, status, remainder);
+}
+
+static pj_bool_t on_data_read_ssl_sock(pj_ssl_sock_t *ssl_sock,
+				       void *data,
+				       pj_size_t size,
+				       pj_status_t status,
+				       pj_size_t *remainder)
+{
+    pj_turn_sock *turn_sock;
+
+    turn_sock = (pj_turn_sock*)pj_ssl_sock_get_user_data(ssl_sock);
+
+    return on_data_read(turn_sock, data, size, status, remainder);
+}
+
+static pj_bool_t on_data_sent_ssl_sock(pj_ssl_sock_t *ssl_sock,
+				       pj_ioqueue_op_key_t *op_key,
+				       pj_ssize_t bytes_sent)
+{
+    pj_turn_sock *turn_sock;
+
+    PJ_UNUSED_ARG(op_key);
+
+    turn_sock = (pj_turn_sock*)pj_ssl_sock_get_user_data(ssl_sock);
+
+    /* Check for error/closure */
+    if (bytes_sent <= 0) {
+	pj_status_t status;
+
+	status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) :
+	    (pj_status_t)-bytes_sent;
+
+	sess_fail(turn_sock, "TLS send() error", status);
+
+	return PJ_FALSE;
+    }
+
+    return PJ_TRUE;
+}
 
 /*
@@ -761,7 +944,16 @@
 	    }
 	}
-    } else {
+    } else  if (turn_sock->conn_type == PJ_TURN_TP_TCP) {
 	status = pj_activesock_send(turn_sock->active_sock,
 				    &turn_sock->send_key, pkt, &len, 0);
+    }
+#if PJ_HAS_SSL_SOCK
+    else if (turn_sock->conn_type == PJ_TURN_TP_TLS) {
+	status = pj_ssl_sock_send(turn_sock->ssl_sock,
+				  &turn_sock->send_key, pkt, &len, 0);
+    }
+#endif
+    else {
+	PJ_ASSERT_RETURN(!"Invalid TURN conn_type", PJ_EINVAL);
     }
 
@@ -826,5 +1018,5 @@
     pj_turn_sock *turn_sock = (pj_turn_sock*) 
 			   pj_turn_session_get_user_data(sess);
-    pj_status_t status;
+    pj_status_t status = PJ_SUCCESS;
 
     if (turn_sock == NULL) {
@@ -863,9 +1055,18 @@
 	 * connection or ALLOCATE request failed.
 	 */
-	if (turn_sock->active_sock) {
+	if ((turn_sock->conn_type != PJ_TURN_TP_TLS) && 
+	    (turn_sock->active_sock)) 
+	{
 	    pj_activesock_close(turn_sock->active_sock);
 	    turn_sock->active_sock = NULL;
 	}
-
+#if PJ_HAS_SSL_SOCK
+	else if ((turn_sock->conn_type == PJ_TURN_TP_TLS) &&
+	    (turn_sock->ssl_sock))
+	{
+	    pj_ssl_sock_close(turn_sock->ssl_sock);
+	    turn_sock->ssl_sock = NULL;
+	}
+#endif
 	/* Get server address from session info */
 	pj_turn_session_get_info(sess, &info);
@@ -876,12 +1077,4 @@
 	    sock_type = pj_SOCK_STREAM();
 
-	/* Init socket */
-	status = pj_sock_socket(turn_sock->af, sock_type, 0, &sock);
-	if (status != PJ_SUCCESS) {
-	    pj_turn_sock_destroy(turn_sock);
-	    return;
-	}
-
-	/* Bind socket */
 	cfg_bind_addr = &turn_sock->setting.bound_addr;
 	max_bind_retry = MAX_BIND_RETRY;
@@ -897,74 +1090,168 @@
 	    pj_sockaddr_cp(&bound_addr, cfg_bind_addr);
 	}
-	status = pj_sock_bind_random(sock, &bound_addr,
-				     turn_sock->setting.port_range,
-				     max_bind_retry);
-	if (status != PJ_SUCCESS) {
-	    pj_turn_sock_destroy(turn_sock);
-	    return;
-	}
-
-	/* Apply QoS, if specified */
-	status = pj_sock_apply_qos2(sock, turn_sock->setting.qos_type,
-				    &turn_sock->setting.qos_params, 
+
+	if (turn_sock->conn_type != PJ_TURN_TP_TLS) {
+	    /* Init socket */
+	    status = pj_sock_socket(turn_sock->af, sock_type, 0, &sock);
+	    if (status != PJ_SUCCESS) {
+		pj_turn_sock_destroy(turn_sock);
+		return;
+	    }
+
+	    /* Bind socket */
+	    status = pj_sock_bind_random(sock, &bound_addr,
+					 turn_sock->setting.port_range,
+					 max_bind_retry);
+	    if (status != PJ_SUCCESS) {
+		pj_turn_sock_destroy(turn_sock);
+		return;
+	    }
+	    /* Apply QoS, if specified */
+	    status = pj_sock_apply_qos2(sock, turn_sock->setting.qos_type,
+				    &turn_sock->setting.qos_params,
 				    (turn_sock->setting.qos_ignore_error?2:1),
 				    turn_sock->pool->obj_name, NULL);
-	if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) {
-	    pj_turn_sock_destroy(turn_sock);
-	    return;
-	}
-
-	/* Apply socket buffer size */
-	if (turn_sock->setting.so_rcvbuf_size > 0) {
-	    unsigned sobuf_size = turn_sock->setting.so_rcvbuf_size;
-	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_RCVBUF(),
-					      PJ_TRUE, &sobuf_size);
-	    if (status != PJ_SUCCESS) {
-		PJ_PERROR(3, (turn_sock->obj_name, status,
-			      "Failed setting SO_RCVBUF"));
-	    } else {
-		if (sobuf_size < turn_sock->setting.so_rcvbuf_size) {
-		    PJ_LOG(4, (turn_sock->obj_name, 
-			       "Warning! Cannot set SO_RCVBUF as configured,"
-			       " now=%d, configured=%d", sobuf_size,
-			       turn_sock->setting.so_rcvbuf_size));
+	    if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) 
+	    {
+		pj_turn_sock_destroy(turn_sock);
+		return;
+	    }
+
+	    /* Apply socket buffer size */
+	    if (turn_sock->setting.so_rcvbuf_size > 0) {
+		unsigned sobuf_size = turn_sock->setting.so_rcvbuf_size;
+		status = pj_sock_setsockopt_sobuf(sock, pj_SO_RCVBUF(),
+						  PJ_TRUE, &sobuf_size);
+		if (status != PJ_SUCCESS) {
+		    pj_perror(3, turn_sock->obj_name, status,
+			      "Failed setting SO_RCVBUF");
 		} else {
-		    PJ_LOG(5, (turn_sock->obj_name, "SO_RCVBUF set to %d",
-			       sobuf_size));
+		    if (sobuf_size < turn_sock->setting.so_rcvbuf_size) {
+			PJ_LOG(4, (turn_sock->obj_name,
+				"Warning! Cannot set SO_RCVBUF as configured,"
+				" now=%d, configured=%d", sobuf_size,
+				turn_sock->setting.so_rcvbuf_size));
+		    } else {
+			PJ_LOG(5, (turn_sock->obj_name, "SO_RCVBUF set to %d",
+				   sobuf_size));
+		    }
 		}
 	    }
-	}
-	if (turn_sock->setting.so_sndbuf_size > 0) {
-	    unsigned sobuf_size = turn_sock->setting.so_sndbuf_size;
-	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_SNDBUF(),
-					      PJ_TRUE, &sobuf_size);
-	    if (status != PJ_SUCCESS) {
-		PJ_PERROR(3, (turn_sock->obj_name, status,
-			      "Failed setting SO_SNDBUF"));
-	    } else {
-		if (sobuf_size < turn_sock->setting.so_sndbuf_size) {
-		    PJ_LOG(4, (turn_sock->obj_name, 
-			       "Warning! Cannot set SO_SNDBUF as configured,"
-			       " now=%d, configured=%d", sobuf_size,
-			       turn_sock->setting.so_sndbuf_size));
+	    if (turn_sock->setting.so_sndbuf_size > 0) {
+		unsigned sobuf_size = turn_sock->setting.so_sndbuf_size;
+		status = pj_sock_setsockopt_sobuf(sock, pj_SO_SNDBUF(),
+						  PJ_TRUE, &sobuf_size);
+		if (status != PJ_SUCCESS) {
+		    pj_perror(3, turn_sock->obj_name, status,
+			      "Failed setting SO_SNDBUF");
 		} else {
-		    PJ_LOG(5, (turn_sock->obj_name, "SO_SNDBUF set to %d",
-			       sobuf_size));
+		    if (sobuf_size < turn_sock->setting.so_sndbuf_size) {
+			PJ_LOG(4, (turn_sock->obj_name,
+				"Warning! Cannot set SO_SNDBUF as configured,"
+				" now=%d, configured=%d", sobuf_size,
+				turn_sock->setting.so_sndbuf_size));
+		    } else {
+			PJ_LOG(5, (turn_sock->obj_name, "SO_SNDBUF set to %d",
+				   sobuf_size));
+		    }
 		}
 	    }
-	}
-
-	/* Create active socket */
-	pj_activesock_cfg_default(&asock_cfg);
-	asock_cfg.grp_lock = turn_sock->grp_lock;
-
-	pj_bzero(&asock_cb, sizeof(asock_cb));
-	asock_cb.on_data_read = &on_data_read;
-	asock_cb.on_connect_complete = &on_connect_complete;
-	status = pj_activesock_create(turn_sock->pool, sock,
-				      sock_type, &asock_cfg,
-				      turn_sock->cfg.ioqueue, &asock_cb, 
-				      turn_sock,
-				      &turn_sock->active_sock);
+
+	    /* Create active socket */
+	    pj_activesock_cfg_default(&asock_cfg);
+	    asock_cfg.grp_lock = turn_sock->grp_lock;
+
+	    pj_bzero(&asock_cb, sizeof(asock_cb));
+	    asock_cb.on_data_read = &on_data_read_asock;
+	    asock_cb.on_connect_complete = &on_connect_complete_asock;
+	    status = pj_activesock_create(turn_sock->pool, sock,
+					  sock_type, &asock_cfg,
+					  turn_sock->cfg.ioqueue, &asock_cb,
+					  turn_sock,
+					  &turn_sock->active_sock);
+	}
+#if PJ_HAS_SSL_SOCK
+	else {
+	    //TURN TLS
+	    pj_ssl_sock_param param, *ssock_param;
+
+	    ssock_param = &turn_sock->setting.tls_cfg.ssock_param;
+	    pj_ssl_sock_param_default(&param);
+
+	    pj_ssl_sock_param_copy(turn_sock->pool, &param, ssock_param);
+	    param.cb.on_connect_complete = &on_connect_complete_ssl_sock;
+	    param.cb.on_data_read = &on_data_read_ssl_sock;
+	    param.cb.on_data_sent = &on_data_sent_ssl_sock;
+	    param.ioqueue = turn_sock->cfg.ioqueue;
+	    param.timer_heap = turn_sock->cfg.timer_heap;
+	    param.grp_lock = turn_sock->grp_lock;
+	    param.server_name = turn_sock->server_name;
+	    param.user_data = turn_sock;
+	    param.sock_type = sock_type;
+	    param.sock_af = turn_sock->af;
+	    if (param.send_buffer_size < PJ_TURN_MAX_PKT_LEN)
+		param.send_buffer_size = PJ_TURN_MAX_PKT_LEN;
+	    if (param.read_buffer_size < PJ_TURN_MAX_PKT_LEN)
+		param.read_buffer_size = PJ_TURN_MAX_PKT_LEN;
+
+	    param.qos_type = turn_sock->setting.qos_type;
+	    param.qos_ignore_error = turn_sock->setting.qos_ignore_error;
+	    pj_memcpy(&param.qos_params, &turn_sock->setting.qos_params,
+		      sizeof(param.qos_params));
+
+	    if (turn_sock->setting.tls_cfg.cert_file.slen ||
+		turn_sock->setting.tls_cfg.ca_list_file.slen ||
+		turn_sock->setting.tls_cfg.ca_list_path.slen ||
+		turn_sock->setting.tls_cfg.privkey_file.slen)
+	    {
+		status = pj_ssl_cert_load_from_files2(
+		    turn_sock->pool,
+		    &turn_sock->setting.tls_cfg.ca_list_file,
+		    &turn_sock->setting.tls_cfg.ca_list_path,
+		    &turn_sock->setting.tls_cfg.cert_file,
+		    &turn_sock->setting.tls_cfg.privkey_file,
+		    &turn_sock->setting.tls_cfg.password,
+		    &turn_sock->cert);
+
+	    } else if (turn_sock->setting.tls_cfg.ca_buf.slen ||
+		       turn_sock->setting.tls_cfg.cert_buf.slen ||
+		       turn_sock->setting.tls_cfg.privkey_buf.slen)
+	    {
+		status = pj_ssl_cert_load_from_buffer(
+		    turn_sock->pool,
+		    &turn_sock->setting.tls_cfg.ca_buf,
+		    &turn_sock->setting.tls_cfg.cert_buf,
+		    &turn_sock->setting.tls_cfg.privkey_buf,
+		    &turn_sock->setting.tls_cfg.password,
+		    &turn_sock->cert);
+	    }
+	    if (status != PJ_SUCCESS) {
+		pj_turn_sock_destroy(turn_sock);
+		return;
+	    }
+	    if (turn_sock->cert) {
+		pj_turn_sock_tls_cfg_wipe_keys(&turn_sock->setting.tls_cfg);
+	    }
+
+	    status = pj_ssl_sock_create(turn_sock->pool, &param,
+					&turn_sock->ssl_sock);
+
+	    if (status != PJ_SUCCESS) {
+		pj_turn_sock_destroy(turn_sock);
+		return;
+	    }
+
+	    if (turn_sock->cert) {
+		status = pj_ssl_sock_set_certificate(turn_sock->ssl_sock,
+						     turn_sock->pool,
+						     turn_sock->cert);
+
+		pj_ssl_cert_wipe_keys(turn_sock->cert);
+		turn_sock->cert = NULL;
+	    }
+
+	}
+#endif
+
 	if (status != PJ_SUCCESS) {
 	    pj_turn_sock_destroy(turn_sock);
@@ -978,6 +1265,9 @@
 
 	/* Initiate non-blocking connect */
+	if (turn_sock->conn_type == PJ_TURN_TP_UDP) {
+	    status = PJ_SUCCESS;
+	}
 #if PJ_HAS_TCP
-	if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
+	else if (turn_sock->conn_type == PJ_TURN_TP_TCP) {
 	    status=pj_activesock_start_connect(
 					turn_sock->active_sock, 
@@ -985,9 +1275,21 @@
 					&info.server, 
 					pj_sockaddr_get_len(&info.server));
-	} else {
-	    status = PJ_SUCCESS;
-	}
+	} 
+#endif	
+#if PJ_HAS_SSL_SOCK
+	else if (turn_sock->conn_type == PJ_TURN_TP_TLS) {
+	    pj_ssl_start_connect_param connect_param;
+	    connect_param.pool = turn_sock->pool;
+	    connect_param.localaddr = &bound_addr;
+	    connect_param.local_port_range = turn_sock->setting.port_range;
+	    connect_param.remaddr = &info.server;
+	    connect_param.addr_len = pj_sockaddr_get_len(&info.server);
+
+	    status = pj_ssl_sock_start_connect2(turn_sock->ssl_sock,
+						&connect_param);
+	}
+#endif
 	if (status == PJ_SUCCESS) {
-	    on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
+	    on_connect_complete(turn_sock, PJ_SUCCESS);
 	} else if (status != PJ_EPENDING) {
             PJ_PERROR(3, (turn_sock->pool->obj_name, status,
@@ -998,7 +1300,4 @@
 	    return;
 	}
-#else
-	on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
-#endif
 
 	/* Done for now. Subsequent work will be done in 
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 6003)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 6004)
@@ -197,5 +197,16 @@
     puts  ("                      0=SDES (default), 1=DTLS");
 #endif
-
+#if PJ_HAS_SSL_SOCK
+    puts  ("");
+    puts  ("TURN TLS Options:");
+    puts  ("  --turn-tls          Use TLS connection to TURN server (default no)");
+    puts  ("  --turn-tls-ca-file  Specify TURN TLS CA file (default=none)");
+    puts  ("  --turn-tls-cert-file  Specify TURN TLS certificate file (default=none)");
+    puts  ("  --turn-tls-privkey-file  Specify TURN TLS private key file (default=none)");
+    puts  ("  --turn-tls-privkey-pwd Specify TURN TLS password to private key file (default=none)");
+    puts  ("  --turn-tls-neg-timeout Specify TURN TLS negotiation timeout (default=no)");
+    puts  ("  --turn-tls-cipher   Specify prefered TURN TLS cipher (optional).");
+    puts  ("                      May be specified multiple times");
+#endif
     puts  ("");
     puts  ("Buddy List (can be more than one):");
@@ -361,6 +372,9 @@
 	   OPT_USE_ICE, OPT_ICE_REGULAR, OPT_USE_SRTP, OPT_SRTP_SECURE,
 	   OPT_USE_TURN, OPT_ICE_MAX_HOSTS, OPT_ICE_NO_RTCP, OPT_TURN_SRV,
-	   OPT_TURN_TCP, OPT_TURN_USER, OPT_TURN_PASSWD, OPT_RTCP_MUX,
-	   OPT_SRTP_KEYING,
+	   OPT_TURN_TCP, OPT_TURN_USER, OPT_TURN_PASSWD, OPT_TURN_TLS, 
+	   OPT_TURN_TLS_CA_FILE, OPT_TURN_TLS_CERT_FILE, 
+	   OPT_TURN_TLS_NEG_TIMEOUT, OPT_TURN_TLS_CIPHER,
+	   OPT_TURN_TLS_PRIV_FILE, OPT_TURN_TLS_PASSWORD,
+	   OPT_RTCP_MUX, OPT_SRTP_KEYING,
 	   OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,
 	   OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
@@ -453,4 +467,13 @@
 	{ "turn-srv",	1, 0, OPT_TURN_SRV},
 	{ "turn-tcp",	0, 0, OPT_TURN_TCP},
+#if PJ_HAS_SSL_SOCK
+	{ "turn-tls",	0, 0, OPT_TURN_TLS},
+	{ "turn-tls-ca-file",1, 0, OPT_TURN_TLS_CA_FILE},
+	{ "turn-tls-cert-file",1,0, OPT_TURN_TLS_CERT_FILE},
+	{ "turn-tls-privkey-file",1,0, OPT_TURN_TLS_PRIV_FILE},
+	{ "turn-tls-privkey-pwd",1,0, OPT_TURN_TLS_PASSWORD},
+	{ "turn-tls-neg-timeout", 1, 0, OPT_TURN_TLS_NEG_TIMEOUT},
+	{ "turn-tls-cipher", 1, 0, OPT_TURN_TLS_CIPHER},
+#endif
 	{ "turn-user",	1, 0, OPT_TURN_USER},
 	{ "turn-passwd",1, 0, OPT_TURN_PASSWD},
@@ -1009,4 +1032,78 @@
 	    break;
 
+#if PJ_HAS_SSL_SOCK
+	case OPT_TURN_TLS:
+	    cfg->media_cfg.turn_conn_type =
+		    cur_acc->turn_cfg.turn_conn_type = PJ_TURN_TP_TLS;
+	    break;
+	case OPT_TURN_TLS_CA_FILE:
+	    cfg->media_cfg.turn_tls_setting.ca_list_file =
+		cur_acc->turn_cfg.turn_tls_setting.ca_list_file =
+		    pj_str(pj_optarg);
+	    break;
+
+	case OPT_TURN_TLS_CERT_FILE:
+	    cfg->media_cfg.turn_tls_setting.cert_file =
+		cur_acc->turn_cfg.turn_tls_setting.cert_file =
+		    pj_str(pj_optarg);
+	    break;
+
+	case OPT_TURN_TLS_PRIV_FILE:
+	    cfg->media_cfg.turn_tls_setting.privkey_file =
+		cur_acc->turn_cfg.turn_tls_setting.privkey_file =
+		    pj_str(pj_optarg);
+	    break;
+
+	case OPT_TURN_TLS_PASSWORD:
+	    cfg->media_cfg.turn_tls_setting.password =
+		cur_acc->turn_cfg.turn_tls_setting.password =
+		    pj_str(pj_optarg);
+	    break;
+
+	case OPT_TURN_TLS_NEG_TIMEOUT:
+	    cfg->media_cfg.turn_tls_setting.ssock_param.timeout.sec =
+		cur_acc->turn_cfg.turn_tls_setting.ssock_param.timeout.sec =
+		    atoi(pj_optarg);
+	    break;
+
+	case OPT_TURN_TLS_CIPHER:
+	    {
+		pj_ssl_cipher cipher;
+
+		if (pj_ansi_strnicmp(pj_optarg, "0x", 2) == 0) {
+		    pj_str_t cipher_st = pj_str(pj_optarg + 2);
+		    cipher = pj_strtoul2(&cipher_st, NULL, 16);
+		} else {
+		    cipher = atoi(pj_optarg);
+		}
+
+		if (pj_ssl_cipher_is_supported(cipher)) {
+		    static pj_ssl_cipher tls_ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
+		    pj_ssl_sock_param *ssock_param =
+				  &cfg->media_cfg.turn_tls_setting.ssock_param;
+
+		    tls_ciphers[ssock_param->ciphers_num++] = cipher;
+		    ssock_param->ciphers =
+		       cur_acc->turn_cfg.turn_tls_setting.ssock_param.ciphers =
+			    tls_ciphers;
+		} else {
+		    pj_ssl_cipher ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
+		    unsigned j, ciphers_cnt;
+
+		    ciphers_cnt = PJ_ARRAY_SIZE(ciphers);
+		    pj_ssl_cipher_get_availables(ciphers, &ciphers_cnt);
+
+		    PJ_LOG(1,(THIS_FILE, "Cipher \"%s\" is not supported by "
+					 "TLS/SSL backend.", pj_optarg));
+		    printf("Available TLS/SSL ciphers (%d):\n", ciphers_cnt);
+		    for (j=0; j<ciphers_cnt; ++j)
+			printf("- 0x%06X: %s\n", ciphers[j], 
+			       pj_ssl_cipher_name(ciphers[j]));
+		    return -1;
+		}
+	    }
+ 	    break;
+#endif
+
 	case OPT_TURN_USER:
 	    cfg->media_cfg.turn_auth_cred.type =
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 6003)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 6004)
@@ -3347,5 +3347,5 @@
     /**
      * Specify the connection type to be used to the TURN server. Valid
-     * values are PJ_TURN_TP_UDP or PJ_TURN_TP_TCP.
+     * values are PJ_TURN_TP_UDP, PJ_TURN_TP_TCP or PJ_TURN_TP_TLS.
      *
      * Default: PJ_TURN_TP_UDP
@@ -3357,4 +3357,10 @@
      */
     pj_stun_auth_cred	turn_auth_cred;
+
+    /**
+     * This specifies TLS settings for TURN TLS. It is only be used
+     * when this TLS is used to connect to the TURN server.
+     */
+    pj_turn_sock_tls_cfg turn_tls_setting;
 
 } pjsua_turn_config;
@@ -6643,5 +6649,5 @@
     /**
      * Specify the connection type to be used to the TURN server. Valid
-     * values are PJ_TURN_TP_UDP or PJ_TURN_TP_TCP.
+     * values are PJ_TURN_TP_UDP, PJ_TURN_TP_TCP or PJ_TURN_TP_TLS.
      *
      * Default: PJ_TURN_TP_UDP
@@ -6653,4 +6659,10 @@
      */
     pj_stun_auth_cred	turn_auth_cred;
+
+    /**
+     * This specifies TLS settings for TLS transport. It is only be used
+     * when this TLS is used to connect to the TURN server.
+     */
+    pj_turn_sock_tls_cfg turn_tls_setting;
 
     /**
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 6003)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 6004)
@@ -169,4 +169,6 @@
 /* Clean up TLS resources */
 static void tls_on_destroy(void *arg);
+
+static void wipe_buf(pj_str_t *buf);
 
 
@@ -665,4 +667,9 @@
 {
     struct tls_listener *listener = (struct tls_listener*)arg;
+
+    if (listener->cert) {
+	pj_ssl_cert_wipe_keys(listener->cert);
+	listener->cert = NULL;
+    }
 
     if (listener->factory.lock) {
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 6003)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 6004)
@@ -713,4 +713,8 @@
     if (pjsua_var.default_acc == acc_id)
 	pjsua_var.default_acc = 0;
+
+#if PJ_HAS_SSL_SOCK
+    pj_turn_sock_tls_cfg_wipe_keys(&acc->cfg.turn_cfg.turn_tls_setting);
+#endif
 
     PJSUA_UNLOCK();
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 6003)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 6004)
@@ -239,4 +239,9 @@
 	dst->turn_server = src->turn_server;
 	dst->turn_auth_cred = src->turn_auth_cred;
+
+#if PJ_HAS_SSL_SOCK
+	pj_memcpy(&dst->turn_tls_setting, &src->turn_tls_setting,
+		  sizeof(src->turn_tls_setting));
+#endif
     } else {
 	if (pj_stricmp(&dst->turn_server, &src->turn_server))
@@ -244,4 +249,9 @@
 	pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
 	                      &src->turn_auth_cred);
+
+#if PJ_HAS_SSL_SOCK
+	pj_turn_sock_tls_cfg_dup(pool, &dst->turn_tls_setting,
+				 &src->turn_tls_setting);
+#endif
     }
 }
@@ -256,4 +266,9 @@
 	pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
 	                      &src->turn_auth_cred);
+
+#if PJ_HAS_SSL_SOCK
+	pj_turn_sock_tls_cfg_dup(pool, &dst->turn_tls_setting,
+				 &src->turn_tls_setting);
+#endif
     }
 }
@@ -408,4 +423,7 @@
 
     cfg->turn_conn_type = PJ_TURN_TP_UDP;
+#if PJ_HAS_SSL_SOCK
+    pj_turn_sock_tls_cfg_default(&cfg->turn_tls_setting);
+#endif
     cfg->vid_preview_enable_native = PJ_TRUE;
 }
@@ -1928,4 +1946,8 @@
 		pjsua_acc_set_registration(i, PJ_FALSE);
 	    }
+#if PJ_HAS_SSL_SOCK
+	    pj_turn_sock_tls_cfg_wipe_keys(
+			      &pjsua_var.acc[i].cfg.turn_cfg.turn_tls_setting);
+#endif
 	}
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 6003)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 6004)
@@ -37,4 +37,8 @@
     pj_strdup(pool, &dst->turn_server, &src->turn_server);
     pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred, &src->turn_auth_cred);
+#if PJ_HAS_SSL_SOCK
+    pj_turn_sock_tls_cfg_dup(pool, &dst->turn_tls_setting,
+			     &src->turn_tls_setting);
+#endif
 }
 
@@ -1075,4 +1079,12 @@
 	    /* Configure max packet size */
 	    ice_cfg.turn_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+
+#if PJ_HAS_SSL_SOCK
+	    if (ice_cfg.turn_tp[i].conn_type == PJ_TURN_TP_TLS) {
+		pj_memcpy(&ice_cfg.turn_tp[i].cfg.tls_cfg, 
+			  &acc_cfg->turn_cfg.turn_tls_setting,
+			  sizeof(ice_cfg.turn_tp[i].cfg.tls_cfg));
+	    }
+#endif
 	}
     }
