Index: doc/freediameter.conf.sample
===================================================================
--- doc/freediameter.conf.sample	(revision 1180)
+++ doc/freediameter.conf.sample	(revision 1181)
@@ -36,5 +36,6 @@
 # freeDiameter 1.2.0 introduces the support of DTLS over SCTP (RFC6083) instead of TLS over SCTP (RFC3436), 
 # as specified in RFC6733. If you need compatibility with older implementation that use TLS over SCTP, you 
-# can open an additional SCTP server port using this method:
+# can open an additional SCTP server port using TLS/SCTP by specifying the following parameter.
+# Note that no TCP server is started on the following port.
 # Default: 0 (disabled). Use 3869 for compatibility with freeDiameter < 1.2.0.
 #SctpSec3436 = 0;
Index: libfdcore/cnxctx.c
===================================================================
--- libfdcore/cnxctx.c	(revision 1180)
+++ libfdcore/cnxctx.c	(revision 1181)
@@ -96,4 +96,6 @@
 }
 
+#define CC_ID_HDR "{----} "
+
 /* Create and bind a server socket to the given endpoint and port */
 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep)
@@ -139,5 +141,5 @@
 		if (rc)
 			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
-		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
 	}
 
@@ -179,5 +181,5 @@
 
 	/* Generate the name for the connection object */
-	snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP srv :%hu (%d)", port, cnx->cc_socket);
+	snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP srv :%hu (%d)", port, cnx->cc_socket);
 
 	cnx->cc_proto = IPPROTO_SCTP;
@@ -249,5 +251,5 @@
 		
 		/* Numeric values for debug... */
-		snprintf(cli->cc_id, sizeof(cli->cc_id), "%s from [%s]:%s (%d<-%d)", 
+		snprintf(cli->cc_id, sizeof(cli->cc_id), CC_ID_HDR "%s from [%s]:%s (%d<-%d)", 
 				IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket);
 		
@@ -313,5 +315,5 @@
 		int  rc;
 		
-		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP,#%d->%s", cnx->cc_socket, sa_buf);
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP,#%d->%s", cnx->cc_socket, sa_buf);
 		
 		/* ...Name for log messages */
@@ -376,5 +378,5 @@
 		int  rc;
 		
-		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP,#%d->%s", cnx->cc_socket, sa_buf);
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP,#%d->%s", cnx->cc_socket, sa_buf);
 		
 		/* ...Name for log messages */
@@ -433,8 +435,30 @@
 	return st & flag;
 }
+void fd_cnx_update_id(struct cnxctx * conn) {
+	if (conn->cc_state & CC_STATUS_CLOSING)
+		conn->cc_id[1] = 'C';
+	else
+		conn->cc_id[1] = '-';
+	
+	if (conn->cc_state & CC_STATUS_ERROR)
+		conn->cc_id[2] = 'E';
+	else
+		conn->cc_id[2] = '-';
+	
+	if (conn->cc_state & CC_STATUS_SIGNALED)
+		conn->cc_id[3] = 'S';
+	else
+		conn->cc_id[3] = '-';
+	
+	if (conn->cc_state & CC_STATUS_TLS)
+		conn->cc_id[4] = 'T';
+	else
+		conn->cc_id[4] = '-';
+}
 void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate)
 {
 	CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
 	conn->cc_state |= orstate;
+	fd_cnx_update_id(conn);
 	CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
 }
@@ -443,4 +467,5 @@
 	CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
 	conn->cc_state = abstate;
+	fd_cnx_update_id(conn);
 	CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
 }
@@ -659,5 +684,5 @@
 }
 
-#ifndef DISABLE_SCTP
+#ifndef DISABLE_SCTP /* WE use this function only in SCTP code */
 static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl)
 {
@@ -853,10 +878,10 @@
 
 
-/* Returns 0 on error, received data size otherwise (always >= 0) */
+/* Returns 0 on error, received data size otherwise (always >= 0). This is not used for DTLS-protected associations. */
 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
 {
 	ssize_t ret;
 again:	
-	CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
+	CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), 
 		{
 			switch (ret) {
@@ -885,5 +910,9 @@
 				
 				default:
-					TRACE_DEBUG(INFO, "This GNU TLS error is not handled, assume unrecoverable error");
+					if (gnutls_error_is_fatal (ret) == 0) {
+						LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret));
+						goto again;
+					}
+					LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret));
 			}
 		} );
@@ -898,5 +927,5 @@
 }
 
-/* Wrapper around gnutls_record_send to handle some error codes */
+/* Wrapper around gnutls_record_send to handle some error codes. This is also used for DTLS-protected associations */
 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
 {
@@ -925,5 +954,9 @@
 
 				default:
-					TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
+					if (gnutls_error_is_fatal (ret) == 0) {
+						LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret));
+						goto again;
+					}
+					LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret));
 			}
 		} );
@@ -937,7 +970,13 @@
 
 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
+/* 	   For the case of DTLS, since we are not using SCTP_UNORDERED, the messages over a single stream are ordered.
+	   Furthermore, as long as messages are shorter than the MTU [2^14 = 16384 bytes], they are delivered in a single
+	   record, as far as I understand. 
+	   For larger messages, however, it is possible that pieces of messages coming from different streams can get interleaved. 
+	   As a result, we do not use the following function for DTLS reception, because we use the sequence number to rebuild the
+	   messages. */
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
 {
-	/* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
+	/* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP. */
 	do {
 		uint8_t header[4];
@@ -1025,6 +1064,11 @@
 
 /* Prepare a gnutls session object for handshake */
-int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds)
-{
+int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds)
+{
+	if (dtls) {
+		LOG_E("DTLS sessions not yet supported");
+		return ENOTSUP;
+	}
+
 	/* Create the session context */
 	CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM );
@@ -1066,15 +1110,16 @@
 	
 	/* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
-	if (verbose && TRACE_BOOL(FULL)) {
+	#ifdef DEBUG
+	if (verbose) {
 		const char *tmp;
 		gnutls_kx_algorithm_t kx;
   		gnutls_credentials_type_t cred;
 		
-		fd_log_debug("TLS Session information for connection '%s':", conn->cc_id);
+		LOG_A("TLS Session information for connection '%s':", conn->cc_id);
 
 		/* print the key exchange's algorithm name */
 		GNUTLS_TRACE( kx = gnutls_kx_get (session) );
 		GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) );
-		fd_log_debug("\t - Key Exchange: %s", tmp);
+		LOG_A("\t - Key Exchange: %s", tmp);
 
 		/* Check the authentication type used and switch
@@ -1084,5 +1129,5 @@
 		{
 			case GNUTLS_CRD_IA:
-				fd_log_debug("\t - TLS/IA session");
+				LOG_A("\t - TLS/IA session");
 				break;
 
@@ -1090,14 +1135,14 @@
 				/* This returns NULL in server side. */
 				if (gnutls_psk_client_get_hint (session) != NULL)
-					fd_log_debug("\t - PSK authentication. PSK hint '%s'",
+					LOG_A("\t - PSK authentication. PSK hint '%s'",
 						gnutls_psk_client_get_hint (session));
 				/* This returns NULL in client side. */
 				if (gnutls_psk_server_get_username (session) != NULL)
-					fd_log_debug("\t - PSK authentication. Connected as '%s'",
+					LOG_A("\t - PSK authentication. Connected as '%s'",
 						gnutls_psk_server_get_username (session));
 				break;
 
 			case GNUTLS_CRD_ANON:	/* anonymous authentication */
-				fd_log_debug("\t - Anonymous DH using prime of %d bits",
+				LOG_A("\t - Anonymous DH using prime of %d bits",
 					gnutls_dh_get_prime_bits (session));
 				break;
@@ -1106,5 +1151,5 @@
 				/* Check if we have been using ephemeral Diffie-Hellman. */
 				if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) {
-					fd_log_debug("\t - Ephemeral DH using prime of %d bits",
+					LOG_A("\t - Ephemeral DH using prime of %d bits",
 						gnutls_dh_get_prime_bits (session));
 				}
@@ -1112,5 +1157,5 @@
 #ifdef ENABLE_SRP				
 			case GNUTLS_CRD_SRP:
-				fd_log_debug("\t - SRP session with username %s",
+				LOG_A("\t - SRP session with username %s",
 					gnutls_srp_server_get_username (session));
 				break;
@@ -1125,22 +1170,23 @@
 		/* print the protocol's name (ie TLS 1.0) */
 		tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
-		fd_log_debug("\t - Protocol: %s", tmp);
+		LOG_A("\t - Protocol: %s", tmp);
 
 		/* print the certificate type of the peer. ie X.509 */
 		tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
-		fd_log_debug("\t - Certificate Type: %s", tmp);
+		LOG_A("\t - Certificate Type: %s", tmp);
 
 		/* print the compression algorithm (if any) */
 		tmp = gnutls_compression_get_name (gnutls_compression_get (session));
-		fd_log_debug("\t - Compression: %s", tmp);
+		LOG_A("\t - Compression: %s", tmp);
 
 		/* print the name of the cipher used. ie 3DES. */
 		tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
-		fd_log_debug("\t - Cipher: %s", tmp);
+		LOG_A("\t - Cipher: %s", tmp);
 
 		/* Print the MAC algorithms name. ie SHA1 */
 		tmp = gnutls_mac_get_name (gnutls_mac_get (session));
-		fd_log_debug("\t - MAC: %s", tmp);
-	}
+		LOG_A("\t - MAC: %s", tmp);
+	}
+	#endif /* DEBUG */
 	
 	/* First, use built-in verification */
@@ -1173,5 +1219,5 @@
 	now = time(NULL);
 	
-	if (verbose && TRACE_BOOL(FULL)) {
+	#ifdef DEBUG
 		char serial[40];
 		char dn[128];
@@ -1180,5 +1226,5 @@
 		time_t expiration_time, activation_time;
 		
-		fd_log_debug("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size);
+		LOG_D("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size);
 		for (i = 0; i < cert_list_size; i++)
 		{
@@ -1187,11 +1233,11 @@
 			CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL);
 		
-			fd_log_debug(" Certificate %d info:", i);
+			LOG_A(" Certificate %d info:", i);
 
 			GNUTLS_TRACE( expiration_time = gnutls_x509_crt_get_expiration_time (cert) );
 			GNUTLS_TRACE( activation_time = gnutls_x509_crt_get_activation_time (cert) );
 
-			fd_log_debug("\t - Certificate is valid since: %s", ctime (&activation_time));
-			fd_log_debug("\t - Certificate expires: %s", ctime (&expiration_time));
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate is valid since: %.24s", ctime (&activation_time));
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate expires: %.24s", ctime (&expiration_time));
 
 			/* Print the serial number of the certificate. */
@@ -1206,27 +1252,27 @@
 					snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%02hhx", serial[j]);
 				}
-				fd_log_debug("%s", buf);
+				LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "%s", buf);
 			}
 
 			/* Extract some of the public key algorithm's parameters */
 			GNUTLS_TRACE( algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits) );
-			fd_log_debug("\t - Certificate public key: %s",
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate public key: %s",
 			      gnutls_pk_algorithm_get_name (algo));
 
 			/* Print the version of the X.509 certificate. */
-			fd_log_debug("\t - Certificate version: #%d",
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate version: #%d",
 			      gnutls_x509_crt_get_version (cert));
 
 			size = sizeof (dn);
 			GNUTLS_TRACE( gnutls_x509_crt_get_dn (cert, dn, &size) );
-			fd_log_debug("\t - DN: %s", dn);
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - DN: %s", dn);
 
 			size = sizeof (dn);
 			GNUTLS_TRACE( gnutls_x509_crt_get_issuer_dn (cert, dn, &size) );
-			fd_log_debug("\t - Issuer's DN: %s", dn);
+			LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Issuer's DN: %s", dn);
 
 			GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) );
 		}
-	}
+	#endif /* DEBUG */
 
 	/* Check validity of all the certificates */
@@ -1291,5 +1337,5 @@
 	
 	/* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
-	if (TRACE_BOOL(FULL)) {
+#ifdef DEBUG
 		const char *tmp;
 		gnutls_credentials_type_t cred;
@@ -1299,5 +1345,5 @@
 		dhe = ecdh = 0;
 
-		fd_log_debug("TLS Session information for connection '%s':", conn->cc_id);
+		LOG_A("TLS Session information for connection '%s':", conn->cc_id);
 		
 		/* print the key exchange's algorithm name
@@ -1305,5 +1351,5 @@
 		GNUTLS_TRACE( kx = gnutls_kx_get (session) );
 		GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) );
-		fd_log_debug("\t- Key Exchange: %s", tmp);
+		LOG_A("\t- Key Exchange: %s", tmp);
 
 		/* Check the authentication type used and switch
@@ -1314,5 +1360,5 @@
 		{
 			case GNUTLS_CRD_IA:
-				fd_log_debug("\t - TLS/IA session");
+				LOG_A("\t - TLS/IA session");
 				break;
 
@@ -1320,5 +1366,5 @@
 			#ifdef ENABLE_SRP
 			case GNUTLS_CRD_SRP:
-				fd_log_debug("\t - SRP session with username %s",
+				LOG_A("\t - SRP session with username %s",
 					gnutls_srp_server_get_username (session));
 				break;
@@ -1329,10 +1375,10 @@
 				*/
 				if (gnutls_psk_client_get_hint (session) != NULL)
-					fd_log_debug("\t - PSK authentication. PSK hint '%s'",
+					LOG_A("\t - PSK authentication. PSK hint '%s'",
 						gnutls_psk_client_get_hint (session));
 				/* This returns NULL in client side.
 				*/
 				if (gnutls_psk_server_get_username (session) != NULL)
-					fd_log_debug("\t - PSK authentication. Connected as '%s'",
+					LOG_A("\t - PSK authentication. Connected as '%s'",
 						gnutls_psk_server_get_username (session));
 
@@ -1344,5 +1390,5 @@
 
 			case GNUTLS_CRD_ANON:      /* anonymous authentication */
-				fd_log_debug("\t - Anonymous DH using prime of %d bits",
+				LOG_A("\t - Anonymous DH using prime of %d bits",
 					gnutls_dh_get_prime_bits (session));
 				if (kx == GNUTLS_KX_ANON_ECDH)
@@ -1367,5 +1413,5 @@
 					cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
 
-					fd_log_debug("\t Peer provided %d certificates.", cert_list_size);
+					LOG_A("\t Peer provided %d certificates.", cert_list_size);
 
 					if (cert_list_size > 0)
@@ -1379,5 +1425,5 @@
 						gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
 
-						fd_log_debug("\t Certificate info:");
+												LOG_A("\t Certificate info:");
 
 						/* This is the preferred way of printing short information about
@@ -1387,5 +1433,5 @@
 						if (ret == 0)
 						{
-						  fd_log_debug("\t\t%s", cinfo.data);
+						  LOG_A("\t\t%s", cinfo.data);
 						  gnutls_free (cinfo.data);
 						}
@@ -1410,13 +1456,13 @@
 
 			default:
-				fd_log_debug("\t - unknown session type (%d)", cred);
+				LOG_A("\t - unknown session type (%d)", cred);
 
 		}                           /* switch */
 
 		if (ecdh != 0)
-			fd_log_debug("\t - Ephemeral ECDH using curve %s",
+			LOG_A("\t - Ephemeral ECDH using curve %s",
 				gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session)));
 		else if (dhe != 0)
-			fd_log_debug("\t - Ephemeral DH using prime of %d bits",
+			LOG_A("\t - Ephemeral DH using prime of %d bits",
 				gnutls_dh_get_prime_bits (session));
 
@@ -1424,5 +1470,5 @@
 		*/
 		tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
-		fd_log_debug("\t - Protocol: %s", tmp);
+		LOG_A("\t - Protocol: %s", tmp);
 
 		/* print the certificate type of the peer.
@@ -1430,10 +1476,10 @@
 		*/
 		tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
-		fd_log_debug("\t - Certificate Type: %s", tmp);
+		LOG_A("\t - Certificate Type: %s", tmp);
 
 		/* print the compression algorithm (if any)
 		*/
 		tmp = gnutls_compression_get_name (gnutls_compression_get (session));
-		fd_log_debug("\t - Compression: %s", tmp);
+		LOG_A("\t - Compression: %s", tmp);
 
 		/* print the name of the cipher used.
@@ -1441,5 +1487,5 @@
 		*/
 		tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
-		fd_log_debug("\t - Cipher: %s", tmp);
+		LOG_A("\t - Cipher: %s", tmp);
 
 		/* Print the MAC algorithms name.
@@ -1447,7 +1493,7 @@
 		*/
 		tmp = gnutls_mac_get_name (gnutls_mac_get (session));
-		fd_log_debug("\t - MAC: %s", tmp);
-	
-	}
+		LOG_A("\t - MAC: %s", tmp);
+	
+#endif /* DEBUG */		
 
 	/* This verification function uses the trusted CAs in the credentials
@@ -1509,12 +1555,27 @@
 #endif /* GNUTLS_VERSION_300 */
 
+static int fd_cnx_may_dtls(struct cnxctx * conn) {
+#ifndef DISABLE_SCTP
+	if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_tls_para.algo == ALGO_HANDSHAKE_DEFAULT))
+		return 1;
+#endif /* DISABLE_SCTP */
+	return 0;
+}
+
+static int fd_cnx_uses_dtls(struct cnxctx * conn) {
+	return fd_cnx_may_dtls(conn) && (fd_cnx_teststate(conn, CC_STATUS_TLS));
+}
+
 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
-int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
-{
-	TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds);
+int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds)
+{
+	int dtls = 0;
+	
+	TRACE_ENTRY( "%p %d %d %p %p", conn, mode, algo, priority, alt_creds);
 	CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
 
 	/* Save the mode */
 	conn->cc_tls_para.mode = mode;
+	conn->cc_tls_para.algo = algo;
 	
 	/* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */
@@ -1524,9 +1585,11 @@
 	conn->cc_loop = 1;
 	
+	dtls = fd_cnx_may_dtls(conn);
+	
 	/* Prepare the master session credentials and priority */
-	CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) );
+	CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, dtls, priority, alt_creds) );
 
 	/* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
-	if (conn->cc_sctp_para.pairs > 1) {
+	if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
 #ifdef DISABLE_SCTP
 		ASSERT(0);
@@ -1541,6 +1604,11 @@
 
 		/* Set the push and pull callbacks */
-		GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) );
-		GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) );
+		if (!dtls) {
+			GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) );
+			GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) );
+		} else {
+			TODO("DTLS push/pull functions");
+			return ENOTSUP;
+		}
 	}
 	
@@ -1589,7 +1657,7 @@
 		#endif /* GNUTLS_VERSION_300 */
 	}
-
+	
 	/* Multi-stream TLS: handshake other streams as well */
-	if (conn->cc_sctp_para.pairs > 1) {
+	if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
 #ifndef DISABLE_SCTP
 		/* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */
@@ -1604,5 +1672,11 @@
 	} else {
 		/* Start decrypting the data */
-		CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
+		if (!dtls) {
+			CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
+		} else {
+			TODO("Signal the dtls_push function that multiple streams can be used from this point.");
+			TODO("Create DTLS rcvthr (must reassembly based on seq numbers & stream id ?)");
+			return ENOTSUP;
+		}
 	}
 	
@@ -1737,38 +1811,47 @@
 #ifndef DISABLE_SCTP
 		case IPPROTO_SCTP: {
-			if (flags & FD_CNX_ORDERED) {
-				/* We send over stream #0 */
-				CHECK_FCT( send_simple(conn, buf, len) );
-			} else {
-				/* Default case : no flag specified */
-			
-				int another_str = 0; /* do we send over stream #0 ? */
-				
-				if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
-					/* Update the id of the stream we will send this message over */
-					conn->cc_sctp_para.next += 1;
-					conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
-					another_str = (conn->cc_sctp_para.next ? 1 : 0);
-				}
-
-				if ( ! another_str ) {
+			int dtls = fd_cnx_uses_dtls(conn);
+
+			if (!dtls) {
+				if (flags & FD_CNX_ORDERED) {
+					/* We send over stream #0 */
 					CHECK_FCT( send_simple(conn, buf, len) );
 				} else {
-					if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) {
-						CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } );
+					/* Default case : no flag specified */
+			
+					int another_str = 0; /* do we send over stream #0 ? */
+
+					if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
+						/* Update the id of the stream we will send this message over */
+						conn->cc_sctp_para.next += 1;
+						conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
+						another_str = (conn->cc_sctp_para.next ? 1 : 0);
+					}
+
+					if ( ! another_str ) {
+						CHECK_FCT( send_simple(conn, buf, len) );
 					} else {
-						/* push the record to the appropriate session */
-						ssize_t ret;
-						size_t sent = 0;
-						ASSERT(conn->cc_sctp3436_data.array != NULL);
-						do {
-							CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), );
-							if (ret <= 0)
-								return ENOTCONN;
-
-							sent += ret;
-						} while ( sent < len );
+						if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) {
+							CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } );
+						} else {
+							/* push the record to the appropriate session */
+							ssize_t ret;
+							size_t sent = 0;
+							ASSERT(conn->cc_sctp3436_data.array != NULL);
+							do {
+								CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), );
+								if (ret <= 0)
+									return ENOTCONN;
+
+								sent += ret;
+							} while ( sent < len );
+						}
 					}
 				}
+			} else {
+				/* DTLS */
+				/* We signal the push function directly to tell if using stream 0 or round-robin */
+				TODO("DTLS send");
+				return ENOTSUP;
 			}
 		}
@@ -1802,5 +1885,6 @@
 	if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
 #ifndef DISABLE_SCTP
-		if (conn->cc_sctp_para.pairs > 1) {
+		int dtls = fd_cnx_uses_dtls(conn);
+		if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
 			if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) {
 				/* Bye on master session */
Index: libfdcore/cnxctx.h
===================================================================
--- libfdcore/cnxctx.h	(revision 1180)
+++ libfdcore/cnxctx.h	(revision 1181)
@@ -41,5 +41,5 @@
 /* The connection context structure */
 struct cnxctx {
-	char		cc_id[60];	/* The name of this connection */
+	char		cc_id[60];	/* The name of this connection. the first 5 chars are reserved for flags display (cc_state). */
 	char		cc_remid[60];	/* Id of remote peer */
 	
@@ -65,4 +65,5 @@
 		DiamId_t 			 cn;		/* If not NULL, remote certif will be checked to match this Common Name */
 		int				 mode; 		/* GNUTLS_CLIENT / GNUTLS_SERVER */
+		int				 algo;		/* ALGO_HANDSHAKE_DEFAULT / ALGO_HANDSHAKE_3436 */
 		gnutls_session_t 		 session;	/* Session object (stream #0 in case of SCTP) */
 	}		cc_tls_para;
@@ -97,5 +98,5 @@
 /* TLS */
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
-int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds);
+int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds);
 #ifndef GNUTLS_VERSION_300
 int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn, int verbose);
Index: libfdcore/config.c
===================================================================
--- libfdcore/config.c	(revision 1155)
+++ libfdcore/config.c	(revision 1181)
@@ -94,4 +94,7 @@
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
+	if (fd_g_config->cnf_port_3436) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local SCTP TLS port .... : %hu\n", fd_g_config->cnf_port_3436), return NULL);
+	}
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of server threads : %hu\n", fd_g_config->cnf_dispthr), return NULL);
Index: libfdcore/fdcore-internal.h
===================================================================
--- libfdcore/fdcore-internal.h	(revision 1102)
+++ libfdcore/fdcore-internal.h	(revision 1181)
@@ -342,5 +342,7 @@
 int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
 void		fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
-int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
+#define ALGO_HANDSHAKE_DEFAULT	0 /* TLS for TCP, DTLS for SCTP */
+#define ALGO_HANDSHAKE_3436	1 /* For TLS for SCTP also */
+int             fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds);
 char *          fd_cnx_getid(struct cnxctx * conn);
 int		fd_cnx_getproto(struct cnxctx * conn);
Index: libfdcore/p_ce.c
===================================================================
--- libfdcore/p_ce.c	(revision 1155)
+++ libfdcore/p_ce.c	(revision 1181)
@@ -786,5 +786,5 @@
 		} else {
 			fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
-			CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
+			CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, ALGO_HANDSHAKE_3436, peer->p_hdr.info.config.pic_priority, NULL),
 				{
 					/* Handshake failed ...  */
@@ -955,5 +955,5 @@
 	if (isi & PI_SEC_TLS_OLD) {
 		fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
-		CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_SERVER, peer->p_hdr.info.config.pic_priority, NULL),
+		CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, peer->p_hdr.info.config.pic_priority, NULL),
 			{
 				/* Handshake failed ...  */
Index: libfdcore/p_cnx.c
===================================================================
--- libfdcore/p_cnx.c	(revision 1155)
+++ libfdcore/p_cnx.c	(revision 1181)
@@ -282,5 +282,7 @@
 	/* Handshake if needed (secure port) */
 	if (nc->dotls) {
-		CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
+		CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, 
+						(peer->p_hdr.info.config.pic_flags.sctpsec == PI_SCTPSEC_3436) ? ALGO_HANDSHAKE_3436 : ALGO_HANDSHAKE_DEFAULT,
+						peer->p_hdr.info.config.pic_priority, NULL),
 			{
 				/* Handshake failed ...  */
Index: libfdcore/p_psm.c
===================================================================
--- libfdcore/p_psm.c	(revision 1120)
+++ libfdcore/p_psm.c	(revision 1181)
@@ -785,5 +785,5 @@
 			case STATE_WAITCNXACK_ELEC:
 			case STATE_WAITCNXACK:
-				LOG_D("%s: Connection established", peer->p_hdr.info.pi_diamid);
+				LOG_D("%s: Connection established, %s", peer->p_hdr.info.pi_diamid, fd_cnx_getid(cnx));
 				fd_p_ce_handle_newcnx(peer, cnx);
 				break;
Index: libfdcore/peers.c
===================================================================
--- libfdcore/peers.c	(revision 1113)
+++ libfdcore/peers.c	(revision 1181)
@@ -430,5 +430,5 @@
 		}
 		if (details > 1) {
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [from:%s] flags:%s%s%s%s%s%s%s lft:%ds", 
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [from:%s] flags:%s%s%s%s%s%s%s%s lft:%ds", 
 				peer->p_dbgorig ?: "unset",
 				peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "-" :
@@ -439,4 +439,5 @@
 				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "N" :"-",
 				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "O" :"-",
+				peer->p_hdr.info.config.pic_flags.sctpsec & PI_SCTPSEC_3436 ? "3" :"-",
 				peer->p_hdr.info.config.pic_flags.exp ? "E" : "-",
 				peer->p_hdr.info.config.pic_flags.persist ? "P" : "-",
Index: libfdcore/sctp3436.c
===================================================================
--- libfdcore/sctp3436.c	(revision 1180)
+++ libfdcore/sctp3436.c	(revision 1181)
@@ -566,5 +566,5 @@
 	for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
 		/* Set credentials and priority */
-		CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, priority, alt_creds) );
+		CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, 0, priority, alt_creds) );
 		
 		/* additional initialization for gnutls 3.x */
Index: libfdcore/server.c
===================================================================
--- libfdcore/server.c	(revision 1136)
+++ libfdcore/server.c	(revision 1181)
@@ -54,5 +54,5 @@
 	struct cnxctx *	conn;		/* server connection context (listening socket) */
 	int 		proto;		/* IPPROTO_TCP or IPPROTO_SCTP */
-	int 		secur;		/* TLS is started immediatly after connection ? */
+	int 		secur;		/* TLS is started immediatly after connection ? 0: no; 1: yes (TLS/TCP or DTLS/SCTP); 2: yes (TLS/TCP or TLS/SCTP) */
 	
 	pthread_t	thr;		/* The thread listening for new connections */
@@ -105,7 +105,7 @@
 		
 		if (details) {
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s, %s", s, fd_cnx_getid(s->conn), 
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s(%d), %s", s, fd_cnx_getid(s->conn), 
 					IPPROTO_NAME( s->proto ),
-					s->secur ? "Secur" : "NotSecur",
+					s->secur ? "Secur" : "NotSecur", s->secur,
 					(st == NOT_CREATED) ? "Thread not created" :
 					((st == RUNNING) ? "Thread running" :
@@ -147,5 +147,8 @@
 	TRACE_ENTRY("%p", c);
 	
+	memset(&rcv_data, 0, sizeof(rcv_data));
+	
 	CHECK_PARAMS_DO(c && c->conn && c->chain.head, goto fatal_error );
+	
 	
 	s = c->chain.head->o;
@@ -156,5 +159,5 @@
 	/* Handshake if we are a secure server port, or start clear otherwise */
 	if (s->secur) {
-		int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL, NULL);
+		int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, (s->secur == 1) ? ALGO_HANDSHAKE_DEFAULT : ALGO_HANDSHAKE_3436, NULL, NULL);
 		if (ret != 0) {
 			char buf[1024];
@@ -360,4 +363,12 @@
 			CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
 			CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, empty_conf_ep ? NULL : &fd_g_config->cnf_endpoints) );
+			fd_list_insert_before( &FD_SERVERS, &s->chain );
+			CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
+		}
+		
+		/* Create the other server on 3436 secure port */
+		if (fd_g_config->cnf_port_3436) {
+			CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 2) );
+			CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_3436, empty_conf_ep ? NULL : &fd_g_config->cnf_endpoints) );
 			fd_list_insert_before( &FD_SERVERS, &s->chain );
 			CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
Index: tests/testcnx.c
===================================================================
--- tests/testcnx.c	(revision 1127)
+++ tests/testcnx.c	(revision 1181)
@@ -549,4 +549,5 @@
 	struct cnxctx * cnx;
 	gnutls_certificate_credentials_t	creds;
+	int algo;
 	int ret;
 };
@@ -557,5 +558,5 @@
 	struct handshake_flags * hf = arg;
 	fd_log_threadname ( "testcnx:handshake" );
-	hf->ret = fd_cnx_handshake(hf->cnx, GNUTLS_CLIENT, NULL, hf->creds);
+	hf->ret = fd_cnx_handshake(hf->cnx, GNUTLS_CLIENT, hf->algo, NULL, hf->creds);
 	return NULL;
 }
@@ -864,5 +865,5 @@
 		/* At this point in legacy Diameter we start the handshake */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT /* No impact on TCP */, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -905,4 +906,5 @@
 		
 		memset(&hf, 0, sizeof(hf));
+		hf.algo = ALGO_HANDSHAKE_3436; /* this is mandatory for old TLS mechanism */
 		
 		/* Initialize remote certificate */
@@ -949,5 +951,5 @@
 		/* At this point in legacy Diameter we start the handshake */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1015,5 +1017,5 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1046,5 +1048,9 @@
 	
 #ifndef DISABLE_SCTP
-	/* SCTP Client / server emulating new Diameter behavior (handshake at connection directly) */
+	
+	
+	/* SCTP Client / server emulating new Diameter behavior (DTLS handshake at connection directly) */
+	TODO("Enabled after DTLS implementation");
+	if (0)
 	{
 		struct connect_flags cf;
@@ -1080,5 +1086,5 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1110,8 +1116,6 @@
 		gnutls_certificate_free_credentials(hf.creds);
 	}
-#endif /* DISABLE_SCTP */
-	
-	/* Test with different number of streams between server and client */
-#ifndef DISABLE_SCTP
+	
+	/* SCTP Client / server emulating old intermediary Diameter behavior (TLS handshake at connection directly) */
 	{
 		struct connect_flags cf;
@@ -1122,4 +1126,5 @@
 		
 		memset(&hf, 0, sizeof(hf));
+		hf.algo = ALGO_HANDSHAKE_3436; /* this is mandatory for old TLS mechanism */
 		
 		/* Initialize remote certificate */
@@ -1133,6 +1138,5 @@
 		CHECK( GNUTLS_E_SUCCESS, ret );
 		
-		/* Start the client thread with more streams than the server */
-		fd_g_config->cnf_sctp_str = 2 * NB_STREAMS;
+		/* Start the client thread */
 		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
 
@@ -1148,5 +1152,76 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a few TLS protected messages, and replies */
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
+			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+
+			CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(server_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+		}
+		
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, NULL, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+#endif /* DISABLE_SCTP */
+	
+	/* Test with different number of streams between server and client */
+#ifndef DISABLE_SCTP
+	/* DTLS / SCTP style */
+	TODO("Enabled after DTLS implementation");
+	if (0)
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &client_cert, &client_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread with more streams than the server */
+		fd_g_config->cnf_sctp_str = 2 * NB_STREAMS;
+		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1187,5 +1262,5 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1217,4 +1292,111 @@
 		gnutls_certificate_free_credentials(hf.creds);
 	}
+	
+	/* TLS / SCTP style */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		hf.algo = ALGO_HANDSHAKE_3436;
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &client_cert, &client_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread with more streams than the server */
+		fd_g_config->cnf_sctp_str = 2 * NB_STREAMS;
+		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a few TLS protected message, and replies */
+		for (i = 0; i < 4 * NB_STREAMS; i++) {
+			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+
+			CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(server_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+		}
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, NULL, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Do the same test but with more streams on the server this time */
+		fd_g_config->cnf_sctp_str = NB_STREAMS / 2;
+		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a few TLS protected message, and replies */
+		for (i = 0; i < 2 * NB_STREAMS; i++) {
+			CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+
+			CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz, 0));
+			CHECK( 0, fd_cnx_receive(server_side, NULL, &rcv_buf, &rcv_sz));
+			CHECK( cer_sz, rcv_sz );
+			CHECK( 0, memcmp( rcv_buf, cer_buf, cer_sz ) );
+			free(rcv_buf);
+		}
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, NULL, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+	
 #endif /* DISABLE_SCTP */
 	
@@ -1257,5 +1439,5 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		fd_cnx_destroy(server_side);
 		
@@ -1274,4 +1456,7 @@
 	/* Same in SCTP */
 #ifndef DISABLE_SCTP
+	/* DTLS */
+	TODO("Enabled after DTLS implementation");
+	if (0)
 	{
 		struct connect_flags cf;
@@ -1308,5 +1493,55 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, NULL, destroy_thr, client_side) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
+	
+	/* TLS */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		hf.algo = ALGO_HANDSHAKE_3436;
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &notrust_ca, GNUTLS_X509_FMT_PEM), );
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &notrust_cert, &notrust_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake directly */
+		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
 		fd_cnx_destroy(server_side);
 		CHECK( 0, pthread_join(thr, NULL) );
@@ -1357,5 +1592,5 @@
 		/* Start the handshake directly */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		fd_cnx_destroy(server_side);
 		CHECK( 0, pthread_join(thr, NULL) );
@@ -1409,5 +1644,5 @@
 		/* Start the handshake, check it is successful */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1435,5 +1670,5 @@
 		/* Start the handshake, check it is successful */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( EINVAL, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		fd_cnx_destroy(server_side);
 		CHECK( 0, pthread_join(thr, NULL) );
@@ -1489,5 +1724,5 @@
 		/* Start the handshake */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1543,4 +1778,6 @@
 #ifndef DISABLE_SCTP
 	/* And re-test with a SCTP connection */
+	TODO("Enabled after DTLS implementation");
+	if (0)
 	{
 		struct connect_flags cf;
@@ -1582,5 +1819,5 @@
 		/* Start the handshake */
 		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
-		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_DEFAULT, NULL, NULL) );
 		CHECK( 0, pthread_join(thr, NULL) );
 		CHECK( 0, hf.ret );
@@ -1633,4 +1870,97 @@
 		gnutls_certificate_free_credentials(hf.creds);
 	}
+	
+	/* TLS */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		char * str;
+		const gnutls_datum_t *cert_list;
+		unsigned int cert_list_size;
+		struct fifo * myfifo = NULL;
+		struct timespec now;
+		int ev_code;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		memset(&hf, 0, sizeof(hf));
+		hf.algo = ALGO_HANDSHAKE_3436;
+		
+		/* Initialize remote certificate */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_allocate_credentials (&hf.creds), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		/* Set the CA */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( hf.creds, &ca, GNUTLS_X509_FMT_PEM), );
+		CHECK( 1, ret );
+		/* Set the key */
+		CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( hf.creds, &client_cert, &client_priv, GNUTLS_X509_FMT_PEM), );
+		CHECK( GNUTLS_E_SUCCESS, ret );
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, NULL, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener_sctp);
+		CHECK( 1, server_side ? 1 : 0 );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		hf.cnx = client_side;
+		
+		/* Start the handshake */
+		CHECK( 0, pthread_create(&thr, NULL, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, ALGO_HANDSHAKE_3436, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Test some simple functions */
+		
+		/* fd_cnx_getid */
+		str = fd_cnx_getid(server_side);
+		CHECK( 1, str ? 1 : 0 );
+		CHECK( 1, (str[0] != '\0') ? 1 : 0 );
+		
+		/* fd_cnx_getproto */
+		i = fd_cnx_getproto(server_side);
+		CHECK( IPPROTO_SCTP, i);
+		
+		/* fd_cnx_getTLS */
+		i = fd_cnx_getTLS(server_side);
+		CHECK( 1, i ? 1 : 0 );
+		
+		/* fd_cnx_getcred */
+		CHECK( 0, fd_cnx_getcred(server_side, &cert_list, &cert_list_size) );
+		CHECK( 1, (cert_list_size > 0) ? 1 : 0 );
+		/* We could also verify that the cert_list really contains the client_cert and ca certificates */
+		
+		/* fd_cnx_getremoteid */
+		str = fd_cnx_getremoteid(server_side);
+		CHECK( 1, str ? 1 : 0 );
+		CHECK( 1, (str[0] != '\0') ? 1 : 0 );
+		
+		/* fd_cnx_recv_setaltfifo */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz, 0));
+		CHECK( 0, fd_fifo_new(&myfifo, 0) );
+		CHECK( 0, fd_cnx_recv_setaltfifo(server_side, myfifo) );
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &now) );
+		do {
+			CHECK( 0, fd_event_timedget(myfifo, &now, ETIMEDOUT, &ev_code, NULL, (void *)&rcv_buf) );
+			free(rcv_buf);
+		} while (ev_code != FDEVP_CNX_MSG_RECV);
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, NULL, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+		
+		fd_event_destroy(&myfifo, free);
+		
+		/* Free the credentials */
+		gnutls_certificate_free_keys(hf.creds);
+		gnutls_certificate_free_cas(hf.creds);
+		gnutls_certificate_free_credentials(hf.creds);
+	}
 #endif /* DISABLE_SCTP */
 	
