Index: contrib/ca_script/Makefile
===================================================================
--- contrib/ca_script/Makefile	(revision 19)
+++ contrib/ca_script/Makefile	(revision 29)
@@ -32,4 +32,7 @@
 O = WIDE
 OU = "AAA WG"
+
+#Default lifetime
+DAYS = 365
 
 #Values for the CA
@@ -130,4 +133,5 @@
 	@openssl ca $(CONFIG) -in $(DIR)/clients/csr/$(name).csr \
 		-out $(DIR)/clients/certs/$(name).cert \
+		-days $(DAYS) \
 		-batch
 	@ln -s $(DIR)/clients/certs/$(name).cert $(DIR)/certs/`openssl x509 -noout -hash < $(DIR)/clients/certs/$(name).cert`.0
Index: freeDiameter/cnxctx.c
===================================================================
--- freeDiameter/cnxctx.c	(revision 27)
+++ freeDiameter/cnxctx.c	(revision 29)
@@ -397,4 +397,18 @@
 }
 
+/* Return the protocol of a connection */
+int fd_cnx_getproto(struct cnxctx * conn)
+{
+	CHECK_PARAMS_DO( conn, return 0 );
+	return conn->cc_proto;
+}
+
+/* Return the TLS state of a connection */
+int fd_cnx_getTLS(struct cnxctx * conn)
+{
+	CHECK_PARAMS_DO( conn, return 0 );
+	return conn->cc_tls;
+}
+
 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
@@ -474,6 +488,13 @@
 	
 	TRACE_ENTRY("%p", arg);
-	
 	CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
 	ASSERT( conn->cc_proto == IPPROTO_TCP );
 	ASSERT( conn->cc_tls == 0 );
@@ -548,6 +569,13 @@
 	
 	TRACE_ENTRY("%p", arg);
-	
 	CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
 	ASSERT( conn->cc_proto == IPPROTO_SCTP );
 	ASSERT( conn->cc_tls == 0 );
@@ -607,5 +635,5 @@
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
 {
-	/* No guaranty 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];
@@ -616,5 +644,5 @@
 
 		do {
-			ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, &header[received], sizeof(header) - received);
+			ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);
 			if (ret == 0) {
 				/* The connection is closed */
@@ -640,5 +668,5 @@
 		while (received < length) {
 			pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
-			ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, newmsg + received, length - received);
+			ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);
 			pthread_cleanup_pop(0);
 
@@ -664,6 +692,13 @@
 	
 	TRACE_ENTRY("%p", arg);
-	
 	CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error);
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Receiver (%d) TLS/ single stream)", conn->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
 	ASSERT( conn->cc_tls == 1 );
 	ASSERT( Target_Queue(conn) );
@@ -709,5 +744,5 @@
 
 /* Prepare a gnutls session object for handshake */
-int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority)
+int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds)
 {
 	/* Create the master session context */
@@ -724,5 +759,5 @@
 
 	/* Set the credentials of this side of the connection */
-	CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
+	CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, alt_creds ?: fd_g_config->cnf_sec_data.credentials), return EINVAL );
 
 	/* Request the remote credentials as well */
@@ -735,5 +770,5 @@
 
 /* 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)
+int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
 {
 	TRACE_ENTRY( "%p %d", conn, mode);
@@ -750,5 +785,5 @@
 	
 	/* Prepare the master session credentials and priority */
-	CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority) );
+	CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) );
 
 	/* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
@@ -801,14 +836,20 @@
 #ifndef DISABLE_SCTP
 		/* Resume all additional sessions from the master one. */
-		CHECK_FCT(fd_sctps_handshake_others(conn, priority));
-		
+		CHECK_FCT(fd_sctps_handshake_others(conn, priority, alt_creds));
+		
+		/* Mark the connection as protected from here */
+		conn->cc_tls = 1;
+
 		/* Start decrypting the messages from all threads and queuing them in target queue */
 		CHECK_FCT(fd_sctps_startthreads(conn));
 #endif /* DISABLE_SCTP */
 	} else {
+		/* Mark the connection as protected from here */
+		conn->cc_tls = 1;
+
 		/* Start decrypting the data */
 		CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
 	}
-
+	
 	return 0;
 }
Index: freeDiameter/cnxctx.h
===================================================================
--- freeDiameter/cnxctx.h	(revision 25)
+++ freeDiameter/cnxctx.h	(revision 29)
@@ -79,5 +79,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);
+int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds);
 
 /* TCP */
@@ -114,5 +114,5 @@
 
 int fd_sctps_init(struct cnxctx * conn);
-int fd_sctps_handshake_others(struct cnxctx * conn, char * priority);
+int fd_sctps_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds);
 int fd_sctps_startthreads(struct cnxctx * conn);
 void fd_sctps_stopthreads(struct cnxctx * conn);
Index: freeDiameter/fD.h
===================================================================
--- freeDiameter/fD.h	(revision 28)
+++ freeDiameter/fD.h	(revision 29)
@@ -177,4 +177,11 @@
 	(((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
 
+/* The data structure for FDEVP_CNX_INCOMING events */
+struct cnx_incoming {
+	struct msg	* cer;		/* the CER message received on this connection */
+	struct cnxctx	* cnx;		/* The connection context */
+	int  		  validate;	/* The peer is new, it must be validated (by an extension) or error CEA to be sent */
+};
+
 /* Structure to store a sent request */
 struct sentreq {
@@ -190,6 +197,7 @@
 int  fd_peer_alloc(struct fd_peer ** ptr);
 int  fd_peer_free(struct fd_peer ** ptr);
-int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx, int tls_done );
+int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
 /* fd_peer_add declared in freeDiameter.h */
+int fd_peer_validate( struct fd_peer * peer );
 
 /* Peer expiry */
@@ -216,7 +224,9 @@
 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
+int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
+int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
 char *          fd_cnx_getid(struct cnxctx * conn);
-int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
-int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority);
+int		fd_cnx_getproto(struct cnxctx * conn);
+int		fd_cnx_getTLS(struct cnxctx * conn);
 int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
 int             fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote);
Index: freeDiameter/p_psm.c
===================================================================
--- freeDiameter/p_psm.c	(revision 28)
+++ freeDiameter/p_psm.c	(revision 29)
@@ -209,4 +209,30 @@
 	}
 	
+	/* A new connection was established and CER containing this peer id was received */
+	if (event == FDEVP_CNX_INCOMING) {
+		struct cnx_incoming * params = ev_data;
+		ASSERT(params);
+		
+		switch (peer->p_hdr.info.pi_state) {
+			case STATE_CLOSED:
+				TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state");
+				break;
+				
+			case STATE_WAITCNXACK:
+			case STATE_WAITCEA:
+				TODO("Election");
+				break;
+				
+			default:
+				TODO("Reply with error CEA");
+				TODO("Close the connection");
+				/* reject_incoming_connection */
+			
+		}
+		
+		free(ev_data);
+		goto psm_loop;
+	}
+	
 	/* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */
 	/* If timeout or OPEN : call cb if defined */
@@ -223,6 +249,6 @@
 psm_end:
 	pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
-	pthread_detach(peer->p_psm);
 	peer->p_psm = (pthread_t)NULL;
+	pthread_detach(pthread_self());
 	return NULL;
 }	
Index: freeDiameter/peers.c
===================================================================
--- freeDiameter/peers.c	(revision 28)
+++ freeDiameter/peers.c	(revision 29)
@@ -376,5 +376,5 @@
 
 /* Handle an incoming CER request on a new connection */
-int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx, int tls_done )
+int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
 {
 	struct msg * msg;
@@ -385,7 +385,9 @@
 	struct fd_list * li;
 	int found = 0;
+	int ret = 0;
 	struct fd_peer * peer;
-	
-	TRACE_ENTRY("%p %p %d", cer, cnx, tls_done);
+	struct cnx_incoming * ev_data;
+	
+	TRACE_ENTRY("%p %p", cer, cnx);
 	CHECK_PARAMS(cer && *cer && cnx && *cnx);
 	
@@ -411,25 +413,46 @@
 	
 	if (!found) {
-		
-		TODO("Create a new peer entry with this diameter id (pf_responder = 1)");
-		TODO("Upgrade the lock to wr");
-		TODO("Add the new peer in the list");
-		TODO("Release the wr lock");
-		TODO("Start the peer PSM, which will have to validate if this peer is authorized to connect, and so on");
-	}
-		
-	TODO("Send the new connection event to the peer SM with the appropriate data: msg, conn, tls_done, found");
-	/* FDEVP_CNX_INCOMING */
-	
-	/* Reset the "out" parameters, so that they are not cleanup on function return. */
-	*cer = NULL;
-	*cnx = NULL;
-	
+		/* Create a new peer entry for this new remote peer */
+		peer = NULL;
+		CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
+		
+		/* Set the peer Diameter Id and the responder flag parameters */
+		CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );
+		CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
+		peer->p_flags.pf_responder = 1;
+		
+		/* Upgrade the lock to write lock */
+		CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&fd_g_peers_rw), goto out );
+		
+		/* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
+		fd_list_insert_before( li, &peer->p_hdr.chain );
+		
+		/* Release the write lock */
+		CHECK_POSIX_DO( ret = pthread_rwlock_unlock(&fd_g_peers_rw), goto out );
+		
+		/* Start the PSM, which will receive the event bellow */
+		CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
+	}
+		
+	/* Send the new connection event to the PSM */
+	CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
+	memset(ev_data, 0, sizeof(ev_data));
+	
+	ev_data->cer = msg;
+	ev_data->cnx = *cnx;
+	ev_data->validate = !found;
+	
+	CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
+	
+out:	
 	CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
 
-	
-	TODO("(later if not tls_done) handshake or start_clear(.., 1) ");
-	
-	return 0;
+	if (ret == 0) {
+		/* Reset the "out" parameters, so that they are not cleanup on function return. */
+		*cer = NULL;
+		*cnx = NULL;
+	}
+	
+	return ret;
 }
 
@@ -441,2 +464,11 @@
 	return ENOTSUP;
 }
+
+/* Validate a peer by calling the callbacks in turn -- return 0 if the peer is validated, ! 0 in case of error or if the peer is rejected */
+int fd_peer_validate( struct fd_peer * peer )
+{
+	TODO("Default to reject");
+	TODO("Call all callbacks in turn");
+	TODO("Save cb2 in the peer if needed");
+	return ENOTSUP;
+}
Index: freeDiameter/sctp.c
===================================================================
--- freeDiameter/sctp.c	(revision 27)
+++ freeDiameter/sctp.c	(revision 29)
@@ -45,10 +45,15 @@
 #endif /* CMSG_BUF_LEN */
 
+/* Level of SCTP-specific traces */
+#ifdef DEBUG_SCTP
+#define SCTP_LEVEL	FULL
+#else /* DEBUG_SCTP */
+#define SCTP_LEVEL	ANNOYING
+#endif /* DEBUG_SCTP */
+
 /* Pre-binding socket options -- # streams read in config */
 static int fd_setsockopt_prebind(int sk)
 {
-	#ifdef DEBUG_SCTP
 	socklen_t sz;
-	#endif /* DEBUG_SCTP */
 	
 	TRACE_ENTRY( "%d", sk);
@@ -74,23 +79,23 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) );
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(event);
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) );
-		if (sz != sizeof(event))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event));
-			return ENOTSUP;
-		}
-		
-		TRACE_DEBUG(FULL, "SCTP_EVENTS : sctp_data_io_event          : %hhu", event.sctp_data_io_event);
-		TRACE_DEBUG(FULL, "       	 sctp_association_event      : %hhu", event.sctp_association_event);
-		TRACE_DEBUG(FULL, "       	 sctp_address_event	     : %hhu", event.sctp_address_event);
-		TRACE_DEBUG(FULL, "       	 sctp_send_failure_event     : %hhu", event.sctp_send_failure_event);
-		TRACE_DEBUG(FULL, "       	 sctp_peer_error_event       : %hhu", event.sctp_peer_error_event);
-		TRACE_DEBUG(FULL, "       	 sctp_shutdown_event	     : %hhu", event.sctp_shutdown_event);
-		TRACE_DEBUG(FULL, "       	 sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event);
-		TRACE_DEBUG(FULL, "       	 sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event);
-		// TRACE_DEBUG(FULL, "             sctp_authentication_event    : %hhu", event.sctp_authentication_event);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(event);
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) );
+			if (sz != sizeof(event))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event));
+				return ENOTSUP;
+			}
+
+			fd_log_debug( "SCTP_EVENTS : sctp_data_io_event          : %hhu\n", event.sctp_data_io_event);
+			fd_log_debug( "       	     sctp_association_event      : %hhu\n", event.sctp_association_event);
+			fd_log_debug( "       	     sctp_address_event	         : %hhu\n", event.sctp_address_event);
+			fd_log_debug( "       	     sctp_send_failure_event     : %hhu\n", event.sctp_send_failure_event);
+			fd_log_debug( "       	     sctp_peer_error_event       : %hhu\n", event.sctp_peer_error_event);
+			fd_log_debug( "       	     sctp_shutdown_event	 : %hhu\n", event.sctp_shutdown_event);
+			fd_log_debug( "       	     sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event);
+			fd_log_debug( "       	     sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event);
+			// fd_log_debug( "             sctp_authentication_event    : %hhu\n", event.sctp_authentication_event);
+		}
 		
 	}
@@ -101,19 +106,19 @@
 		memset(&init, 0, sizeof(init));
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(init);
-		
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
-		if (sz != sizeof(init))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_INITMSG : sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
-		TRACE_DEBUG(FULL, "                   sinit_max_instreams  : %hu", init.sinit_max_instreams);
-		TRACE_DEBUG(FULL, "                   sinit_max_attempts   : %hu", init.sinit_max_attempts);
-		TRACE_DEBUG(FULL, "                   sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(init);
+
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
+			if (sz != sizeof(init))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams   : %hu\n", init.sinit_num_ostreams);
+			fd_log_debug( "                   sinit_max_instreams  : %hu\n", init.sinit_max_instreams);
+			fd_log_debug( "                   sinit_max_attempts   : %hu\n", init.sinit_max_attempts);
+			fd_log_debug( "                   sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo);
+		}
 
 		/* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */
@@ -124,12 +129,12 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_INITMSG : sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
-		TRACE_DEBUG(FULL, "                   sinit_max_instreams  : %hu", init.sinit_max_instreams);
-		TRACE_DEBUG(FULL, "                   sinit_max_attempts   : %hu", init.sinit_max_attempts);
-		TRACE_DEBUG(FULL, "                   sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
+			fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams   : %hu\n", init.sinit_num_ostreams);
+			fd_log_debug( "                   sinit_max_instreams  : %hu\n", init.sinit_max_instreams);
+			fd_log_debug( "                   sinit_max_attempts   : %hu\n", init.sinit_max_attempts);
+			fd_log_debug( "                   sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo);
+		}
 	}
 	
@@ -139,15 +144,15 @@
 		int nofrag;
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(nofrag);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
-		if (sz != sizeof(nofrag))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(nofrag);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
+			if (sz != sizeof(nofrag))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false");
+		}
 
 		nofrag = 0;	/* We turn ON the fragmentation */
@@ -156,9 +161,9 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
+			fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false");
+		}
 	}
 	#else /* SCTP_DISABLE_FRAGMENTS */
@@ -173,17 +178,17 @@
 		memset(&rtoinfo, 0, sizeof(rtoinfo));
 
-		#ifdef DEBUG_SCTP
-		sz = sizeof(rtoinfo);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
-		if (sz != sizeof(rtoinfo))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
-		TRACE_DEBUG(FULL, "                   srto_max     : %u", rtoinfo.srto_max);
-		TRACE_DEBUG(FULL, "                   srto_min     : %u", rtoinfo.srto_min);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(rtoinfo);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
+			if (sz != sizeof(rtoinfo))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial);
+			fd_log_debug( "                   srto_max     : %u\n", rtoinfo.srto_max);
+			fd_log_debug( "                   srto_min     : %u\n", rtoinfo.srto_min);
+		}
 
 		rtoinfo.srto_max     = fd_g_config->cnf_timer_tw * 500 - 1000;	/* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */
@@ -192,16 +197,14 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
-		TRACE_DEBUG(FULL, "                   srto_max     : %u", rtoinfo.srto_max);
-		TRACE_DEBUG(FULL, "                   srto_min     : %u", rtoinfo.srto_min);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
+			fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial);
+			fd_log_debug( "                   srto_max     : %u\n", rtoinfo.srto_max);
+			fd_log_debug( "                   srto_min     : %u\n", rtoinfo.srto_min);
+		}
 	}
 	#else /* SCTP_RTOINFO */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_RTOINFO");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO");
 	#endif /* SCTP_RTOINFO */
 	
@@ -212,19 +215,19 @@
 		memset(&assoc, 0, sizeof(assoc));
 
-		#ifdef DEBUG_SCTP
-		sz = sizeof(assoc);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
-		if (sz != sizeof(assoc))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
-		TRACE_DEBUG(FULL, "                     sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
-		TRACE_DEBUG(FULL, "                     sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
-		TRACE_DEBUG(FULL, "                     sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
-		TRACE_DEBUG(FULL, "                     sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(assoc);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
+			if (sz != sizeof(assoc))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu\n", assoc.sasoc_asocmaxrxt);
+			fd_log_debug( "                     sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations);
+			fd_log_debug( "                     sasoc_peer_rwnd                : %u\n" , assoc.sasoc_peer_rwnd);
+			fd_log_debug( "                     sasoc_local_rwnd               : %u\n" , assoc.sasoc_local_rwnd);
+			fd_log_debug( "                     sasoc_cookie_life              : %u\n" , assoc.sasoc_cookie_life);
+		}
 
 		assoc.sasoc_asocmaxrxt = 5;	/* Maximum retransmission attempts: we want fast detection of errors */
@@ -233,18 +236,16 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
-		TRACE_DEBUG(FULL, "                     sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
-		TRACE_DEBUG(FULL, "                     sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
-		TRACE_DEBUG(FULL, "                     sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
-		TRACE_DEBUG(FULL, "                     sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
+			fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu\n", assoc.sasoc_asocmaxrxt);
+			fd_log_debug( "                     sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations);
+			fd_log_debug( "                     sasoc_peer_rwnd                : %u\n" , assoc.sasoc_peer_rwnd);
+			fd_log_debug( "                     sasoc_local_rwnd               : %u\n" , assoc.sasoc_local_rwnd);
+			fd_log_debug( "                     sasoc_cookie_life              : %u\n" , assoc.sasoc_cookie_life);
+		}
 	}
 	#else /* SCTP_ASSOCINFO */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_ASSOCINFO");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO");
 	#endif /* SCTP_ASSOCINFO */
 	
@@ -256,16 +257,16 @@
 		memset(&linger, 0, sizeof(linger));
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(linger);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
-		if (sz != sizeof(linger))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SO_LINGER : l_onoff  : %d", linger.l_onoff);
-		TRACE_DEBUG(FULL, "                l_linger : %d", linger.l_linger);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(linger);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
+			if (sz != sizeof(linger))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SO_LINGER : l_onoff  : %d\n", linger.l_onoff);
+			fd_log_debug( " 	       l_linger : %d\n", linger.l_linger);
+		}
 		
 		linger.l_onoff	= 0;	/* Do not activate the linger */
@@ -275,15 +276,13 @@
 		CHECK_SYS(  setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
-		TRACE_DEBUG(FULL, "New SO_LINGER : l_onoff  : %d", linger.l_onoff);
-		TRACE_DEBUG(FULL, "                l_linger : %d", linger.l_linger);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
+			fd_log_debug( "New SO_LINGER : l_onoff  : %d\n", linger.l_onoff);
+			fd_log_debug( "		  l_linger : %d\n", linger.l_linger);
+		}
 	}
 	#else /* SO_LINGER */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SO_LINGER");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER");
 	#endif /* SO_LINGER */
 	
@@ -293,15 +292,15 @@
 		int nodelay;
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(nodelay);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
-		if (sz != sizeof(nodelay))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_NODELAY value : %s", nodelay ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(nodelay);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
+			if (sz != sizeof(nodelay))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false");
+		}
 
 		nodelay = 0;	/* We turn ON the Nagle algorithm (probably the default already) */
@@ -310,14 +309,12 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_NODELAY value : %s", nodelay ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
+			fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false");
+		}
 	}
 	#else /* SCTP_NODELAY */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_NODELAY");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY");
 	#endif /* SCTP_NODELAY */
 	
@@ -327,15 +324,15 @@
 		int interleave;
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(interleave);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
-		if (sz != sizeof(interleave))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_FRAGMENT_INTERLEAVE value : %d", interleave);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(interleave);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
+			if (sz != sizeof(interleave))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave);
+		}
 
 		#if 0
@@ -348,14 +345,12 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_FRAGMENT_INTERLEAVE value : %d", interleave);
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
+			fd_log_debug( "New SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave);
+		}
 	}
 	#else /* SCTP_FRAGMENT_INTERLEAVE */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_FRAGMENT_INTERLEAVE");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE");
 	#endif /* SCTP_FRAGMENT_INTERLEAVE */
 	
@@ -365,15 +360,15 @@
 		int v4mapped;
 		
-		#ifdef DEBUG_SCTP
-		sz = sizeof(v4mapped);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
-		if (sz != sizeof(v4mapped))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			sz = sizeof(v4mapped);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
+			if (sz != sizeof(v4mapped))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false");
+		}
 
 #ifndef SCTP_USE_MAPPED_ADDRESSES
@@ -386,14 +381,12 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
+			fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false");
+		}
 	}
 	#else /* SCTP_I_WANT_MAPPED_V4_ADDR */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR");
 	#endif /* SCTP_I_WANT_MAPPED_V4_ADDR */
 			   
@@ -456,17 +449,17 @@
 		int asconf;
 		
-		#ifdef DEBUG_SCTP
-		socklen_t sz;
-		
-		sz = sizeof(asconf);
-		/* Read socket defaults */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
-		if (sz != sizeof(asconf))
-		{
-			TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf));
-			return ENOTSUP;
-		}
-		TRACE_DEBUG(FULL, "Def SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			socklen_t sz;
+
+			sz = sizeof(asconf);
+			/* Read socket defaults */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
+			if (sz != sizeof(asconf))
+			{
+				TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf));
+				return ENOTSUP;
+			}
+			fd_log_debug( "Def SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false");
+		}
 
 		asconf = bound_to_default ? 1 : 0;	/* allow automatic use of added or removed addresses in the association (for bound-all sockets) */
@@ -475,14 +468,13 @@
 		CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf))  );
 		
-		#ifdef DEBUG_SCTP
-		/* Check new values */
-		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false");
-		#endif /* DEBUG_SCTP */
+		if (TRACE_BOOL(SCTP_LEVEL)) {
+			socklen_t sz = sizeof(asconf);
+			/* Check new values */
+			CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
+			fd_log_debug( "New SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false");
+		}
 	}
 	#else /* SCTP_AUTO_ASCONF */
-	# ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "Skipping SCTP_AUTO_ASCONF");
-	# endif /* DEBUG_SCTP */
+	TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_AUTO_ASCONF");
 	#endif /* SCTP_AUTO_ASCONF */
 	
@@ -600,6 +592,5 @@
 		}
 		
-		# ifdef DEBUG_SCTP
-		if (TRACE_BOOL(FULL)) {
+		if (TRACE_BOOL(SCTP_LEVEL)) {
 			int i;
 			ptr.buf = sar.buf;
@@ -610,5 +601,4 @@
 			}
 		}
-		#endif /* DEBUG_SCTP */
 		
 		/* Bind to this array */
@@ -622,7 +612,6 @@
 	CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) );
 	
-	#ifdef DEBUG_SCTP
 	/* Debug: show all local listening addresses */
-	if (TRACE_BOOL(FULL)) {
+	if (TRACE_BOOL(SCTP_LEVEL)) {
 		sSA *sar;
 		union {
@@ -640,5 +629,4 @@
 		sctp_freeladdrs(sar);
 	}
-	#endif /* DEBUG_SCTP */
 
 	return 0;
@@ -767,19 +755,21 @@
 		return ENOTSUP;
 	}
-	#ifdef DEBUG_SCTP
-	TRACE_DEBUG(FULL, "SCTP_STATUS : sstat_state                  : %i" , status.sstat_state);
-	TRACE_DEBUG(FULL, "              sstat_rwnd  	              : %u" , status.sstat_rwnd);
-	TRACE_DEBUG(FULL, "		 sstat_unackdata	      : %hu", status.sstat_unackdata);
-	TRACE_DEBUG(FULL, "		 sstat_penddata 	      : %hu", status.sstat_penddata);
-	TRACE_DEBUG(FULL, "		 sstat_instrms  	      : %hu", status.sstat_instrms);
-	TRACE_DEBUG(FULL, "		 sstat_outstrms 	      : %hu", status.sstat_outstrms);
-	TRACE_DEBUG(FULL, "		 sstat_fragmentation_point    : %u" , status.sstat_fragmentation_point);
-	TRACE_DEBUG_sSA(FULL, "		 sstat_primary.spinfo_address : ", &status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV, "" );
-	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_state   : %d" , status.sstat_primary.spinfo_state);
-	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_cwnd    : %u" , status.sstat_primary.spinfo_cwnd);
-	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_srtt    : %u" , status.sstat_primary.spinfo_srtt);
-	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_rto     : %u" , status.sstat_primary.spinfo_rto);
-	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_mtu     : %u" , status.sstat_primary.spinfo_mtu);
-	#endif /* DEBUG_SCTP */
+	if (TRACE_BOOL(SCTP_LEVEL)) {
+		fd_log_debug( "SCTP_STATUS : sstat_state                  : %i\n" , status.sstat_state);
+		fd_log_debug( "              sstat_rwnd  	          : %u\n" , status.sstat_rwnd);
+		fd_log_debug( "		     sstat_unackdata	          : %hu\n", status.sstat_unackdata);
+		fd_log_debug( "		     sstat_penddata 	          : %hu\n", status.sstat_penddata);
+		fd_log_debug( "		     sstat_instrms  	          : %hu\n", status.sstat_instrms);
+		fd_log_debug( "		     sstat_outstrms 	          : %hu\n", status.sstat_outstrms);
+		fd_log_debug( "		     sstat_fragmentation_point    : %u\n" , status.sstat_fragmentation_point);
+		fd_log_debug( "		     sstat_primary.spinfo_address : ");
+		sSA_DUMP_NODE_SERV(&status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV );
+		fd_log_debug( "\n" );
+		fd_log_debug( "		     sstat_primary.spinfo_state   : %d\n" , status.sstat_primary.spinfo_state);
+		fd_log_debug( "		     sstat_primary.spinfo_cwnd    : %u\n" , status.sstat_primary.spinfo_cwnd);
+		fd_log_debug( "		     sstat_primary.spinfo_srtt    : %u\n" , status.sstat_primary.spinfo_srtt);
+		fd_log_debug( "		     sstat_primary.spinfo_rto     : %u\n" , status.sstat_primary.spinfo_rto);
+		fd_log_debug( "		     sstat_primary.spinfo_mtu     : %u\n" , status.sstat_primary.spinfo_mtu);
+	}
 	
 	*in = status.sstat_instrms;
@@ -936,7 +926,5 @@
 	mhdr.msg_controllen = sizeof(anci);
 	
-	#ifdef DEBUG_SCTP
 	TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);
-	#endif /* DEBUG_SCTP */
 	
 	CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) );
@@ -1005,4 +993,6 @@
 	}
 	
+	TRACE_DEBUG(FULL, "Received %db data on socket %d", datasize, sock);
+	
 	/* Handle the case where the data received is a notification */
 	if (mhdr.msg_flags & MSG_NOTIFICATION) {
@@ -1012,11 +1002,9 @@
 			
 			case SCTP_ASSOC_CHANGE:
-				#ifdef DEBUG_SCTP
 				TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");
-				TRACE_DEBUG(FULL, "    state : %hu", notif->sn_assoc_change.sac_state);
-				TRACE_DEBUG(FULL, "    error : %hu", notif->sn_assoc_change.sac_error);
-				TRACE_DEBUG(FULL, "    instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
-				TRACE_DEBUG(FULL, "   outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
-				#endif /* DEBUG_SCTP */
+				TRACE_DEBUG(SCTP_LEVEL, "    state : %hu", notif->sn_assoc_change.sac_state);
+				TRACE_DEBUG(SCTP_LEVEL, "    error : %hu", notif->sn_assoc_change.sac_error);
+				TRACE_DEBUG(SCTP_LEVEL, "    instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
+				TRACE_DEBUG(SCTP_LEVEL, "   outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
 				
 				*event = FDEVP_CNX_EP_CHANGE;
@@ -1024,10 +1012,8 @@
 	
 			case SCTP_PEER_ADDR_CHANGE:
-				#ifdef DEBUG_SCTP
 				TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
-				TRACE_DEBUG_sSA(FULL, "    intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );
-				TRACE_DEBUG(FULL, "          state : %d", notif->sn_paddr_change.spc_state);
-				TRACE_DEBUG(FULL, "          error : %d", notif->sn_paddr_change.spc_error);
-				#endif /* DEBUG_SCTP */
+				TRACE_DEBUG_sSA(SCTP_LEVEL, "    intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );
+				TRACE_DEBUG(SCTP_LEVEL, "          state : %d", notif->sn_paddr_change.spc_state);
+				TRACE_DEBUG(SCTP_LEVEL, "          error : %d", notif->sn_paddr_change.spc_error);
 				
 				*event = FDEVP_CNX_EP_CHANGE;
@@ -1035,9 +1021,7 @@
 	
 			case SCTP_SEND_FAILED:
-				#ifdef DEBUG_SCTP
 				TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");
-				TRACE_DEBUG(FULL, "    len : %hu", notif->sn_send_failed.ssf_length);
-				TRACE_DEBUG(FULL, "    err : %d",  notif->sn_send_failed.ssf_error);
-				#endif /* DEBUG_SCTP */
+				TRACE_DEBUG(SCTP_LEVEL, "    len : %hu", notif->sn_send_failed.ssf_length);
+				TRACE_DEBUG(SCTP_LEVEL, "    err : %d",  notif->sn_send_failed.ssf_error);
 				
 				*event = FDEVP_CNX_ERROR;
@@ -1045,9 +1029,7 @@
 			
 			case SCTP_REMOTE_ERROR:
-				#ifdef DEBUG_SCTP
 				TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");
-				TRACE_DEBUG(FULL, "    err : %hu", ntohs(notif->sn_remote_error.sre_error));
-				TRACE_DEBUG(FULL, "    len : %hu", ntohs(notif->sn_remote_error.sre_length));
-				#endif /* DEBUG_SCTP */
+				TRACE_DEBUG(SCTP_LEVEL, "    err : %hu", ntohs(notif->sn_remote_error.sre_error));
+				TRACE_DEBUG(SCTP_LEVEL, "    len : %hu", ntohs(notif->sn_remote_error.sre_length));
 				
 				*event = FDEVP_CNX_ERROR;
@@ -1055,7 +1037,5 @@
 	
 			case SCTP_SHUTDOWN_EVENT:
-				#ifdef DEBUG_SCTP
 				TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");
-				#endif /* DEBUG_SCTP */
 				
 				*event = FDEVP_CNX_ERROR;
@@ -1096,16 +1076,16 @@
 			
 			sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);
-			#ifdef DEBUG_SCTP
-			TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV");
-			TRACE_DEBUG(FULL, "    sinfo_stream    : %hu", sndrcv->sinfo_stream);
-			TRACE_DEBUG(FULL, "    sinfo_ssn       : %hu", sndrcv->sinfo_ssn);
-			TRACE_DEBUG(FULL, "    sinfo_flags     : %hu", sndrcv->sinfo_flags);
-			/* TRACE_DEBUG(FULL, "    sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */
-			TRACE_DEBUG(FULL, "    sinfo_ppid      : %u" , sndrcv->sinfo_ppid);
-			TRACE_DEBUG(FULL, "    sinfo_context   : %u" , sndrcv->sinfo_context);
-			/* TRACE_DEBUG(FULL, "    sinfo_pr_value  : %u" , sndrcv->sinfo_pr_value); */
-			TRACE_DEBUG(FULL, "    sinfo_tsn       : %u" , sndrcv->sinfo_tsn);
-			TRACE_DEBUG(FULL, "    sinfo_cumtsn    : %u" , sndrcv->sinfo_cumtsn);
-			#endif /* DEBUG_SCTP */
+			if (TRACE_BOOL(SCTP_LEVEL)) {
+				fd_log_debug( "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV\n");
+				fd_log_debug( "    sinfo_stream    : %hu\n", sndrcv->sinfo_stream);
+				fd_log_debug( "    sinfo_ssn       : %hu\n", sndrcv->sinfo_ssn);
+				fd_log_debug( "    sinfo_flags     : %hu\n", sndrcv->sinfo_flags);
+				/* fd_log_debug( "    sinfo_pr_policy : %hu\n", sndrcv->sinfo_pr_policy); */
+				fd_log_debug( "    sinfo_ppid      : %u\n" , sndrcv->sinfo_ppid);
+				fd_log_debug( "    sinfo_context   : %u\n" , sndrcv->sinfo_context);
+				/* fd_log_debug( "    sinfo_pr_value  : %u\n" , sndrcv->sinfo_pr_value); */
+				fd_log_debug( "    sinfo_tsn       : %u\n" , sndrcv->sinfo_tsn);
+				fd_log_debug( "    sinfo_cumtsn    : %u\n" , sndrcv->sinfo_cumtsn);
+			}
 
 			*strid = sndrcv->sinfo_stream;
Index: freeDiameter/sctps.c
===================================================================
--- freeDiameter/sctps.c	(revision 27)
+++ freeDiameter/sctps.c	(revision 29)
@@ -73,8 +73,14 @@
 	
 	TRACE_ENTRY("%p", arg);
-	
 	CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Demuxer (%d)", conn->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
 	ASSERT( conn->cc_proto == IPPROTO_SCTP );
-	ASSERT( conn->cc_tls == 1 );
 	ASSERT( Target_Queue(conn) );
 	ASSERT( conn->cc_sctps_data.array );
@@ -115,8 +121,14 @@
 	
 	TRACE_ENTRY("%p", arg);
-	
 	CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error);
 	cnx = ctx->parent;
 	ASSERT( Target_Queue(cnx) );
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Decipher (%hu@%d)", ctx->strid, cnx->cc_socket);
+		fd_log_threadname ( buf );
+	}
 	
 	CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */);
@@ -209,4 +221,5 @@
 	pthread_rwlock_t lock;
 	struct cnxctx   *parent;
+	/* Add another list to chain in a global list to implement a garbage collector on sessions */
 };
 
@@ -219,5 +232,5 @@
 
 /* The level at which we debug session resuming */
-#define SR_LEVEL FULL
+#define SR_LEVEL (FULL + 1)
 
 /* Initialize the store area for a connection */
@@ -303,7 +316,7 @@
 	
 	CHECK_PARAMS_DO( sto && key.data && data.data, return -1 );
-	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session store [key ", key.data, key.size < 16 ? key.size : 16, "]");
 	
 	CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 );
+	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session store [key ", key.data, key.size, "]");
 	
 	li = find_or_next(sto, key, &match);
@@ -313,6 +326,8 @@
 		/* Check the data is the same */
 		if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) {
-			TRACE_DEBUG(INFO, "GnuTLS tried to store a session with same key and different data!");
+			TRACE_DEBUG(SR_LEVEL, "GnuTLS tried to store a session with same key and different data!");
 			ret = -1;
+		} else {
+			TRACE_DEBUG(SR_LEVEL, "GnuTLS tried to store a session with same key and same data, skipped.");
 		}
 		goto out;
@@ -350,7 +365,7 @@
 	
 	CHECK_PARAMS_DO( sto && key.data, return -1 );
-	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session delete [key ", key.data, key.size < 16 ? key.size : 16, "]");
 	
 	CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 );
+	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session delete [key ", key.data, key.size, "]");
 	
 	li = find_or_next(sto, key, &match);
@@ -382,7 +397,7 @@
 
 	CHECK_PARAMS_DO( sto && key.data, return error );
-	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session fetch [key ", key.data, key.size < 16 ? key.size : 16, "]");
 
 	CHECK_POSIX_DO( pthread_rwlock_rdlock(&sto->lock), return error );
+	TRACE_DEBUG_BUFFER(SR_LEVEL, "Session fetch [key ", key.data, key.size, "]");
 	
 	li = find_or_next(sto, key, &match);
@@ -394,4 +409,5 @@
 	}
 out:	
+	TRACE_DEBUG(SR_LEVEL, "Fetched (%p, %d) from store %p", res.data, res.size, sto);
 	CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return error);
 	return res;
@@ -417,8 +433,22 @@
 	TRACE_ENTRY("%p", arg);
 	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "Handshake resume (%hu@%d)", ctx->strid, ctx->parent->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
 	TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid);
 	CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
 			
-	/* We can trace success of resuming handshake by using gnutls_session_is_resumed */
+	if (TRACE_BOOL(FULL)) {
+		int resumed = gnutls_session_is_resumed(ctx->session);
+		if (resumed) {
+			fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
+		} else {
+			fd_log_debug("Session was NOT resumed (full handshake) on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
+		}
+	}
 			
 	/* Finish */
@@ -467,5 +497,5 @@
 
 /* Handshake other streams, after full handshake on the master session */
-int fd_sctps_handshake_others(struct cnxctx * conn, char * priority)
+int fd_sctps_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds)
 {
 	uint16_t i;
@@ -487,5 +517,5 @@
 	for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
 		/* Set credentials and priority */
-		CHECK_FCT( fd_tls_prepare(&conn->cc_sctps_data.array[i].session, conn->cc_tls_para.mode, priority) );
+		CHECK_FCT( fd_tls_prepare(&conn->cc_sctps_data.array[i].session, conn->cc_tls_para.mode, priority, alt_creds) );
 		
 		/* For the client, copy data from master session; for the server, set session resuming pointers */
@@ -550,4 +580,24 @@
 }
 
+static void * bye_th(void * arg)
+{
+	struct sctps_ctx * ctx = (struct sctps_ctx *) arg;
+	TRACE_ENTRY("%p", arg);
+	
+	/* Set the thread name */
+	{
+		char buf[48];
+		snprintf(buf, sizeof(buf), "gnutls_bye (%hu@%d)", ctx->strid, ctx->parent->cc_socket);
+		fd_log_threadname ( buf );
+	}
+	
+	CHECK_GNUTLS_DO( gnutls_bye(ctx->session, GNUTLS_SHUT_RDWR), /* Continue */ );
+			
+	/* Finish */
+	return arg;
+}
+
+
+
 /* Destroy a wrapper context */
 void fd_sctps_destroy(struct cnxctx * conn)
@@ -560,9 +610,12 @@
 	fd_sctps_stopthreads(conn);
 	
-	/* End all TLS sessions -- maybe we should do it in parallel ? */
-	for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
-		CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctps_data.array[i].session, GNUTLS_SHUT_RDWR), /* Continue */ );
-	}
-	
+	/* End all TLS sessions, in parallel */
+	for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
+		CHECK_POSIX_DO( pthread_create( &conn->cc_sctps_data.array[i].thr, NULL, bye_th, &conn->cc_sctps_data.array[i] ), break );
+	}
+	for (--i; i > 0; --i) {
+		CHECK_POSIX_DO( pthread_join( conn->cc_sctps_data.array[i].thr, NULL ), continue );
+	}
+skip:	
 	/* Now, stop the demux thread */
 	CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
@@ -572,5 +625,6 @@
 		fd_event_destroy( &conn->cc_sctps_data.array[i].raw_recv, free );
 		free(conn->cc_sctps_data.array[i].partial.buf);
-		gnutls_deinit(conn->cc_sctps_data.array[i].session);
+		if (i > 0)
+			gnutls_deinit(conn->cc_sctps_data.array[i].session);
 	}
 	
Index: freeDiameter/server.c
===================================================================
--- freeDiameter/server.c	(revision 28)
+++ freeDiameter/server.c	(revision 29)
@@ -116,5 +116,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);
+		int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL, NULL);
 		if (ret != 0) {
 			if (TRACE_BOOL(INFO)) {
@@ -153,5 +153,9 @@
 	
 	/* Finally, pass the information to the peers module which will handle it next */
-	CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c->conn, s->secur ), goto fatal_error );
+	pthread_cleanup_push((void *)fd_cnx_destroy, c->conn);
+	pthread_cleanup_push((void *)fd_msg_free, msg);
+	CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c->conn ), goto cleanup );
+	pthread_cleanup_pop(0);
+	pthread_cleanup_pop(0);
 	
 	/* The end, we cleanup the client structure */
Index: freeDiameter/tests/CMakeLists.txt
===================================================================
--- freeDiameter/tests/CMakeLists.txt	(revision 10)
+++ freeDiameter/tests/CMakeLists.txt	(revision 29)
@@ -18,4 +18,5 @@
 	testsess
 	testdisp
+	testcnx
 )
 
Index: freeDiameter/tests/testcnx.c
===================================================================
--- freeDiameter/tests/testcnx.c	(revision 29)
+++ freeDiameter/tests/testcnx.c	(revision 29)
@@ -0,0 +1,625 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+#ifndef TEST_PORT
+#define TEST_PORT	3868
+#endif /* TEST_PORT */
+
+#ifndef GNUTLS_DEFAULT_PRIORITY
+# define GNUTLS_DEFAULT_PRIORITY "NORMAL"
+#endif /* GNUTLS_DEFAULT_PRIORITY */
+
+#ifndef GNUTLS_DEFAULT_DHBITS
+# define GNUTLS_DEFAULT_DHBITS 1024
+#endif /* GNUTLS_DEFAULT_DHBITS */
+
+
+/* The cryptographic data */
+static char ca_data[] =		"-----BEGIN CERTIFICATE-----\n"
+				"MIIEqjCCA5KgAwIBAgIJANKgDwdlDYQDMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD\n"
+				"VQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNV\n"
+				"BAoMBFdJREUxDzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293\n"
+				"YWRkaWN0Lm9yZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDAe\n"
+				"Fw0wOTEwMDUwODUxNDRaFw0xOTEwMDMwODUxNDRaMIGUMQswCQYDVQQGEwJKUDEO\n"
+				"MAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUx\n"
+				"DzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293YWRkaWN0Lm9y\n"
+				"ZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDCCASIwDQYJKoZI\n"
+				"hvcNAQEBBQADggEPADCCAQoCggEBAM5c6w4NnngTvGNWcJzbo0Kklp+kvUNQNgGu\n"
+				"myvz826qPp07HTSyJrIcgFnuYDR0Nd130Ot9u5osqpQhHTvolxDE87Tii8i3hJSj\n"
+				"TTY9K0ZwGb4AZ6QkuyMXS1jtOY657HqjpGZqT/2Syh0i7dM/hqSXFw0SPbyq+W1H\n"
+				"SVFWa1CTkPywFWAzwdr5WKah77uZ1dxWqgPgUdcZOiIQtLRp5n3fg40Nwso5YdwS\n"
+				"64+ebBX1pkhrCQ8AGc8O61Ep1JTXcO7jqQmPgzjiN+FeostI1Dp73S3MqleTAHjR\n"
+				"hqZ77VF7nkroMM9btMHJBaxnfwc2ewULUJwnuOiGWrvMq/9Z4J8CAwEAAaOB/DCB\n"
+				"+TAdBgNVHQ4EFgQUkqpVn7N3gmiJ7X5zQ2bki+7qv4UwgckGA1UdIwSBwTCBvoAU\n"
+				"kqpVn7N3gmiJ7X5zQ2bki+7qv4WhgZqkgZcwgZQxCzAJBgNVBAYTAkpQMQ4wDAYD\n"
+				"VQQIDAVUb2t5bzEQMA4GA1UEBwwHS29nYW5laTENMAsGA1UECgwEV0lERTEPMA0G\n"
+				"A1UECwwGQUFBIFdHMR8wHQYDVQQDDBZjaGF2cm91eC5jb3dhZGRpY3Qub3JnMSIw\n"
+				"IAYJKoZIhvcNAQkBFhNzZGVjdWdpc0BuaWN0LmdvLmpwggkA0qAPB2UNhAMwDAYD\n"
+				"VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAJy0XLk8j8YLSTt2/VMy9TAUx\n"
+				"esXUiZj0Ung+gkr7A1K0NnwYxDzG2adMhf13upHoydu2ErLMmD6F77x+QuY/q7nc\n"
+				"ZvO0tvcoAP6ToSDwiypU5dnTmnfkgwVwzFkNCi1sGRosEm8c/c/8MfK0I0nVdj1/\n"
+				"BIkIG7tTDVi9JvkWYl0UlSKWTZKrntVwCmscfC02DGb+GoLbO9+QmiNM5Y3yOYZ4\n"
+				"Pc7SSoKLL0rwJBmpPNs7boYsweeSuCAVu0shRfgC90odXcej2EN5ETfCuU1evXNW\n"
+				"5cA+zZsDK/nWJwxBaW0CxAHX579FElFWlK4+BnzhZRdDhmJDnN5dh4ekJGM6Lg==\n"
+				"-----END CERTIFICATE-----\n";
+				
+
+static char client_cert_data[] ="-----BEGIN CERTIFICATE-----\n"
+				"MIIDiTCCAnGgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
+				"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
+				"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
+				"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
+				"MDQwNDA1WhcNMTkxMDI1MDQwNDA1WjCBgTELMAkGA1UEBhMCSlAxDjAMBgNVBAgM\n"
+				"BVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURFMQ8wDQYDVQQL\n"
+				"DAZBQUEgV0cxFDASBgNVBAMMC2NsaWVudC50ZXN0MRowGAYJKoZIhvcNAQkBFgtj\n"
+				"bGllbnRAdGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvetQHp16zZ27\n"
+				"57xOOEqyzJ60iXcB79HGGSkA/s48YgUTsYz/MXoPwS5LPAxAHjZOdtoKZEP8HuoM\n"
+				"l7JXnJyMkL3rI3u4t1wD7W9IVYqICDjFzTO3q6g6b38TEGWlULn0i8wu6XlYphHw\n"
+				"WEVB7zazNcsU7IIMrRFq6mTvKKJuR0UCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg\n"
+				"hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O\n"
+				"BBYEFL6ziU+dj2wgxNA+agURglBUSXCiMB8GA1UdIwQYMBaAFJKqVZ+zd4Joie1+\n"
+				"c0Nm5Ivu6r+FMA0GCSqGSIb3DQEBBQUAA4IBAQCjiPUVta0gYKGFGT+5Xh6+MX+E\n"
+				"esIYOmNqZx9Ghk0Q1h2tosgLlTP65AX0uHA0d/eFbnBGrDlUqV/qXtEzu8mjQoFB\n"
+				"kCW1kovobj6XBt2azClhNFrTHF2t0aPrake00MIXieHiLTYYUBrn1Pw4LkcLOVCH\n"
+				"L6oHZPiaTUcB2hDYl8emE7wOymPB8gn7+GqkXwi1re1PcbmJf0MnhXLnjahKzPY2\n"
+				"yoqugrWoQkGZh4R88JD9ypY3ouDZ+t2kyfFQt+Xmj6+DjCO2IMxm4whgEwKPQjoH\n"
+				"kac4snIW/b2pYPDinyPzwJnjF7wAfLOJnOr6PvZpoZjC7EbacLb5w5On/Dbd\n"
+				"-----END CERTIFICATE-----\n";
+static char client_priv_data[] ="-----BEGIN RSA PRIVATE KEY-----\n"
+				"MIICXgIBAAKBgQC961AenXrNnbvnvE44SrLMnrSJdwHv0cYZKQD+zjxiBROxjP8x\n"
+				"eg/BLks8DEAeNk522gpkQ/we6gyXslecnIyQvesje7i3XAPtb0hViogIOMXNM7er\n"
+				"qDpvfxMQZaVQufSLzC7peVimEfBYRUHvNrM1yxTsggytEWrqZO8oom5HRQIDAQAB\n"
+				"AoGBAIYnsOLPby3LnC5n8AEHkyHDgdgQvsd/MSYYtuFHIZRD7dNfu+xhQru9TdvO\n"
+				"84Pj7K07/FczRuc3gUmu6wBv/UIP9To15RHZh+/n537nybGus5S4IYKVvap477To\n"
+				"0rQDf9ec27iw77gxb7moQ9Otuxwbv0h0Z+1EVLI8d8jHOq0BAkEA9YNr0R+7KXBS\n"
+				"48yT43g5HpOFkTZzNXWVdpSvYGneb56wslk5Eatp235I4uz/a7Rej5v99W0M3nSe\n"
+				"/AgHfYn75QJBAMYH/pBx/WkrLj+pPaARlNwInCIC5zUhr6B0IKCt2tvy5eyuc5sd\n"
+				"AoTFaU+cSI+ZqsRzY8jMKkonktxBg48oJ+ECQQCt4AtlqcFVkbVCm8pJGQXq/7Ni\n"
+				"qlthiwr1Vkv2TkQ4bPza8pGWT/3Cc2ePPyWN08n8jw+G11p72cAW4mDbqfN5AkEA\n"
+				"mNYKrkiLn+NnqlJf8W4gSUGL3uQGtYbuGRQHKnuDckWhFm39YzWcgAQsJvkjN1EN\n"
+				"7thvpsWLzfeE7ODTPGVtgQJATObxYJOt6rms3fAStwuXW3ET77TA1ja4XsUEe5Yu\n"
+				"JpcQOruJb9XwndqzNbL0dSUePb9gFiBCGKYOyreNTTRTmw==\n"
+				"-----END RSA PRIVATE KEY-----\n";
+				
+static char server_cert_data[] ="-----BEGIN CERTIFICATE-----\n"
+				"MIIDhDCCAmygAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
+				"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
+				"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
+				"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
+				"MDQwMzM5WhcNMTkxMDI1MDQwMzM5WjB9MQswCQYDVQQGEwJKUDEOMAwGA1UECAwF\n"
+				"VG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUxDzANBgNVBAsM\n"
+				"BkFBQSBXRzESMBAGA1UEAwwJc2Vydi50ZXN0MRgwFgYJKoZIhvcNAQkBFglzZXJ2\n"
+				"QHRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKb3HKmQW/rI9qMEDNCL\n"
+				"RcOQ9y3Cyde9Zop8HFGJQJ7NcFfLAEej6HaLALPJww2xuSoIn1KSgtMYwdjRuB79\n"
+				"cf4j7BnpbZ39roi8OUR6N63GiNFkfLHUPKkwxN5RAsRITyU+L5OuJTJmmtz0REX/\n"
+				"fxJJlw0BjROa04+eLWKVAgrHAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4\n"
+				"QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQM\n"
+				"M8R/OdA0//hhoUaLSR2jV7NNWDAfBgNVHSMEGDAWgBSSqlWfs3eCaIntfnNDZuSL\n"
+				"7uq/hTANBgkqhkiG9w0BAQUFAAOCAQEAh/VJpgT5mJrxGmjOBq5MDAjrupjnP98i\n"
+				"fzWIHbeK84mjaA1TResjod1r3LCAWAwQC0l06qi2jC7Gc9x6dMdZPnla0lwVC/HY\n"
+				"GTcqwCJ1ED9M6aHg67KeCXA9Kkz+nJk2S6ps4YucquEpH0lrFNsSrs9oSt0D4Tut\n"
+				"ebRUhB27rEXEhfEDZWWWI67nlzxc285VNF3Dc+zN9g+lgV/Cq6NC+jZ/g+/bD81i\n"
+				"C+rZT3M1aF8j1Qq+/38jmq8Npfg+OvBjHOHSloHPe1pr0JtnVp6qqejxbPtUKxr0\n"
+				"7xZavh2pyNbM90KM/oMshIyA+xyI9jUcrkNy+mgwnCWL2yyEh3aduQ==\n"
+				"-----END CERTIFICATE-----\n";
+static char server_priv_data[] ="-----BEGIN RSA PRIVATE KEY-----\n"
+				"MIICXQIBAAKBgQCm9xypkFv6yPajBAzQi0XDkPctwsnXvWaKfBxRiUCezXBXywBH\n"
+				"o+h2iwCzycMNsbkqCJ9SkoLTGMHY0bge/XH+I+wZ6W2d/a6IvDlEejetxojRZHyx\n"
+				"1DypMMTeUQLESE8lPi+TriUyZprc9ERF/38SSZcNAY0TmtOPni1ilQIKxwIDAQAB\n"
+				"AoGAZv3Ddm0P79CLIt9asEFY1VvUvSuMqkGwwPfx1/HcJJkBFYapM4fN22G/Gyf3\n"
+				"47ifSWhsLtklTeXVnVMwSh14dJaJQuSEnaFnUUWfjiRbEAXZnMFwAIiaszEZbPap\n"
+				"NUNpcGl06FZrphYAMkjOVUfjCjfOZDAvL4JGpo271Zx4l0ECQQDYoFFQpBCPx0PK\n"
+				"TWUmvatXI/Amo94XkGfofbdeeI8PiAJBO5UI6rmjjIVwsJwO9dQb/IlP1/OnBeJv\n"
+				"p9YW5uixAkEAxVAOKu7mpGu0Q/K2iEUUYDX9YHf253kgkdIDF4iZk4Tcecjoxuru\n"
+				"fIWu9dMtyDVV+HT2X4cNEnO1/oS3kJII9wJBAJkdwDwiqz4lV6o/yFZ4zAoc8dsu\n"
+				"CoZXYMq5SYox5tTQit928OHLn4mVgqBjhPsiEVnyx0+zUZpmE2ZemHm5nxECQHfE\n"
+				"FBVzVYRP6+eil7E3XRrZKqc3qiLunxpkA4RxYebtKnaxwLmdOI1VB9InEQ8JcNmT\n"
+				"BUkOzJx6p+mJ3XJfchkCQQDWmbMYYJajsjlS4YpdUUj7cBSotA6vtkNVHFr0/ak/\n"
+				"S+tLkMNuruaInWizK+BKYTIJLlQDf5u5NTrw41vye5Hv\n"
+				"-----END RSA PRIVATE KEY-----\n";
+
+
+static char expired_cert_data[]="-----BEGIN CERTIFICATE-----\n"
+				"MIIDizCCAnOgAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
+				"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
+				"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
+				"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
+				"MDQwNjM1WhcNMDkxMDI4MDQwNjM1WjCBgzELMAkGA1UEBhMCSlAxDjAMBgNVBAgM\n"
+				"BVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURFMQ8wDQYDVQQL\n"
+				"DAZBQUEgV0cxFTATBgNVBAMMDGV4cGlyZWQudGVzdDEbMBkGCSqGSIb3DQEJARYM\n"
+				"ZXhwaXJlZEB0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjFxVUhdzP\n"
+				"x6AySkl9VXWbKRXbfocX2Q5lRFPXGTcnx8b+xtxyK9yGGv8kbGM/dZwKFOFwBnnU\n"
+				"uSbUaEwoOLo0YFYCPZRVSh9OWvClcUw+cWk5rbyqVTX7c1tfbDBxjoq2pQbM7t0p\n"
+				"x1INp5wPobpSEeIbuXRrCIcR0uyprGNjTwIDAQABo3sweTAJBgNVHRMEAjAAMCwG\n"
+				"CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV\n"
+				"HQ4EFgQUHK9mQlutqqWb2a46wVqsL8zOImwwHwYDVR0jBBgwFoAUkqpVn7N3gmiJ\n"
+				"7X5zQ2bki+7qv4UwDQYJKoZIhvcNAQEFBQADggEBAGCPVVVZgg9ky7gRyETOv2kH\n"
+				"Db7CNL5CangVOZ++ihfWQ0LJfPFtXarDG02w8LZzRiqHzVVWo23M3qgoalOFnuVo\n"
+				"tzz1chN70CHykUk14DceKBnVG8zhMh5/sIbfQ6RHDykL61FgmvXKUPQtWc38UJ0p\n"
+				"7UWY3qJc0bV6NK16c0iLopuJjkouKgQZ1mJqDfCW8vDQInc7f7Eq9DsXR144Bwll\n"
+				"rR3qRmlqlrZrO1zMbjDXy1NpWcJjeCsD1NT3FymZmkP/eAqvQsWzjQk4WzBwKMGX\n"
+				"q/1/h5rs8pdE//W5QTDRxjKYaTTEOTBv4tOycJdm7kH1rg8J8O1glmepis3WlfI=\n"
+				"-----END CERTIFICATE-----\n";
+static char expired_priv_data[]="-----BEGIN RSA PRIVATE KEY-----\n"
+				"MIICXgIBAAKBgQDjFxVUhdzPx6AySkl9VXWbKRXbfocX2Q5lRFPXGTcnx8b+xtxy\n"
+				"K9yGGv8kbGM/dZwKFOFwBnnUuSbUaEwoOLo0YFYCPZRVSh9OWvClcUw+cWk5rbyq\n"
+				"VTX7c1tfbDBxjoq2pQbM7t0px1INp5wPobpSEeIbuXRrCIcR0uyprGNjTwIDAQAB\n"
+				"AoGASwPoDui9XYHTIGm7xwRA+kVjLAOq+qy//aHJlEeHGcP7r1PfpHNqwH4QhGat\n"
+				"jlv6dLYbFld9TVDwS8A8UBkVIPLWnCysd5tF2A4C5akx6ouW6HliW/JheYrgl8AV\n"
+				"PVeR3bm91UbnpC0ABVlw87jp1Ovyr60Suo4jsoJz+CyTa2ECQQD0LJWpnwn1jIlR\n"
+				"DGkLi7F3E70JJcdhTWzBjGFD+Na+/2ZO0MKLhK+O1WUkKa0oi+e5P1JOnGIpTI8c\n"
+				"BJOO415RAkEA7hauapYuqGI/auSPH8/nFB5z1G94RTxo2a5THKcG5MqS/8N3ubFj\n"
+				"i2PPS0lEYVjqoHEsZUsMnDmXp6KDKMAfnwJBAIp+T1UqM8fmsmwaEerOjRXxSCNM\n"
+				"Hk5+T9Vn/jNDjOpAipLhrbbcx4bIWtmsGd8Jm6Fi3RhhcvvhxLorjlZZeEECQQCf\n"
+				"IaPD88sNmlUewdLzhUbCiLQMadCuHflKfRxpyy1tYAQuVFxCTdDlynkzra25ju+K\n"
+				"+vmcXjP4evnk/lbBtt+rAkEAgOr4Apgs3nMppngPV5yFx0NDqH2n8PlEAM1Il4Qs\n"
+				"IuuK18v0KwlUGAfEEmCiNh1e1qkLmD0CnI2QjYAjcLQUhw==\n"
+				"-----END RSA PRIVATE KEY-----\n";
+
+struct fd_list eps = FD_LIST_INITIALIZER(eps);
+
+struct connect_flags {
+	int	proto;
+};
+
+void * connect_thr(void * arg)
+{
+	struct connect_flags * cf = arg;
+	struct cnxctx * cnx = NULL;
+	
+	fd_log_threadname ( "testcnx:connect" );
+	
+	/* Connect to the server */
+	switch (cf->proto) {
+		case IPPROTO_TCP:
+			{
+				struct fd_endpoint * ep = (struct fd_endpoint *)(eps.next);
+				cnx = fd_cnx_cli_connect_tcp( &ep->sa, sSSlen(&ep->ss) );
+				CHECK( 1, cnx ? 1 : 0 );
+			}
+			break;
+#ifndef DISABLE_SCTP
+		case IPPROTO_SCTP:
+			{
+				cnx = fd_cnx_cli_connect_sctp(0, TEST_PORT, &eps);
+				CHECK( 1, cnx ? 1 : 0 );
+			}
+			break;
+#endif /* DISABLE_SCTP */
+		default:
+			CHECK( 0, 1 );
+	}
+	
+	/* exit */
+	return cnx;
+}
+
+struct handshake_flags {
+	struct cnxctx * cnx;
+	gnutls_certificate_credentials_t	creds;
+	int ret;
+};
+
+void * handshake_thr(void * arg)
+{
+	struct handshake_flags * hf = arg;
+	fd_log_threadname ( "testcnx:handshake" );
+	hf->ret = fd_cnx_handshake(hf->cnx, GNUTLS_CLIENT, NULL, hf->creds);
+	return NULL;
+}
+	
+void * destroy_thr(void * arg)
+{
+	struct cnxctx * cnx = arg;
+	fd_log_threadname ( "testcnx:destroy" );
+	fd_cnx_destroy(cnx);
+	return NULL;
+}
+	
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	gnutls_datum_t ca 		= { ca_data, 		sizeof(ca_data) 	  };
+	gnutls_datum_t server_cert 	= { server_cert_data, 	sizeof(server_cert_data)  };
+	gnutls_datum_t server_priv 	= { server_priv_data, 	sizeof(server_priv_data)  };
+	gnutls_datum_t client_cert	= { client_cert_data, 	sizeof(client_cert_data)  };
+	gnutls_datum_t client_priv 	= { client_priv_data, 	sizeof(client_priv_data)  };
+	gnutls_datum_t expired_cert 	= { expired_cert_data, 	sizeof(expired_cert_data) };
+	gnutls_datum_t expired_priv 	= { expired_priv_data, 	sizeof(expired_priv_data) };
+	
+	struct cnxctx * listener;
+#ifndef DISABLE_SCTP
+	struct cnxctx * listener_sctp;
+#endif /* DISABLE_SCTP */
+	struct cnxctx * server_side;
+	struct cnxctx * client_side;
+	pthread_t thr;
+	int ret;
+	uint8_t * cer_buf;
+	size_t 	  cer_sz;
+	uint8_t * rcv_buf;
+	size_t 	  rcv_sz;
+	
+	/* First, initialize the daemon modules */
+	INIT_FD();
+	
+	/* Set the CA parameter in the config */
+	CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( fd_g_config->cnf_sec_data.credentials,
+									 &ca,
+									 GNUTLS_X509_FMT_PEM), );
+	CHECK( 1, ret );
+	
+	/* Set the server credentials (in config) */
+	CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( fd_g_config->cnf_sec_data.credentials,
+									&server_cert,
+									&server_priv,
+									GNUTLS_X509_FMT_PEM), );
+	CHECK( GNUTLS_E_SUCCESS, ret );
+	
+	/* Set the default priority */
+	CHECK_GNUTLS_DO( ret = gnutls_priority_init( &fd_g_config->cnf_sec_data.prio_cache, GNUTLS_DEFAULT_PRIORITY, NULL), );
+	CHECK( GNUTLS_E_SUCCESS, ret );
+	
+	/* Set default DH params */
+	CHECK_GNUTLS_DO( ret = gnutls_dh_params_generate2( fd_g_config->cnf_sec_data.dh_cache, GNUTLS_DEFAULT_DHBITS), );
+	CHECK( GNUTLS_E_SUCCESS, ret );
+	
+	/* Initialize the server addresses */
+	{
+		struct addrinfo hints, *ai, *aip;
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags  = AI_NUMERICSERV;
+		hints.ai_family = AF_INET;
+		CHECK( 0, getaddrinfo("localhost", _stringize(TEST_PORT), &hints, &ai) );
+		aip = ai;
+		while (aip) {
+			CHECK( 0, fd_ep_add_merge( &eps, aip->ai_addr, aip->ai_addrlen, EP_FL_DISC ));
+			aip = aip->ai_next;
+		};
+		freeaddrinfo(ai);
+	}
+	
+	/* Start the server(s) */
+	{
+		/* TCP server */
+		listener = fd_cnx_serv_tcp(TEST_PORT, 0, (struct fd_endpoint *)(eps.next));
+		CHECK( 1, listener ? 1 : 0 );
+		
+		/* Accept incoming clients */
+		CHECK( 0, fd_cnx_serv_listen(listener));
+
+#ifndef DISABLE_SCTP
+		/* SCTP server */
+		listener_sctp = fd_cnx_serv_sctp(TEST_PORT, &eps);
+		CHECK( 1, listener_sctp ? 1 : 0 );
+		
+		/* Accept incoming clients */
+		CHECK( 0, fd_cnx_serv_listen(listener_sctp));
+#endif /* DISABLE_SCTP */
+
+	}	
+	
+	/* Initialize the CER message */
+	{
+		struct msg * cer;
+		struct dict_object * model = NULL;
+		struct avp * oh;
+		union avp_value value;
+
+		/* Find the CER dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &model, ENOENT ) );
+
+		/* Create the instance */
+		CHECK( 0, fd_msg_new ( model, 0, &cer ) );
+		
+		/* Now find the Origin-Host dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &model, ENOENT ) );
+
+		/* Create the instance */
+		CHECK( 0, fd_msg_avp_new ( model, 0, &oh ) );
+		value.os.data = "Client.side";
+		value.os.len = strlen(value.os.data);
+		CHECK( 0, fd_msg_avp_setvalue ( oh, &value ) );
+		
+		/* Add the AVP */
+		CHECK( 0, fd_msg_avp_add( cer, MSG_BRW_LAST_CHILD, oh) );
+
+		#if 1
+		/* For debug: dump the object */
+		fd_log_debug("Dumping CER\n");
+		fd_msg_dump_walk(0, cer);
+		#endif
+			
+		CHECK( 0, fd_msg_bufferize( cer, &cer_buf, &cer_sz ) );
+		CHECK( 0, fd_msg_free(cer) );
+	}
+	
+	/* Simple TCP client / server test (no TLS) */
+	{
+		struct connect_flags cf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_TCP;
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		CHECK( 1, server_side ? 1 : 0 );
+		CHECK( 0, fd_cnx_start_clear(server_side, 0) );
+		
+		/* Retrieve the client connection object */
+		CHECK( 0, pthread_join( thr, (void *)&client_side ) );
+		CHECK( 1, client_side ? 1 : 0 );
+		CHECK( 0, fd_cnx_start_clear(client_side, 0) );
+		
+		/* Send a message and receive it */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Do it in the other direction */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Now close the connection */
+		fd_cnx_destroy(client_side);
+		fd_cnx_destroy(server_side);
+	}
+		
+#ifndef DISABLE_SCTP
+	/* Simple SCTP client / server test (no TLS) */
+	{
+		struct connect_flags cf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_SCTP;
+		
+		/* Start the client thread */
+		CHECK( 0, pthread_create(&thr, 0, 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 );
+		
+		CHECK( 0, fd_cnx_start_clear(server_side, 1) );
+		
+		/* Send a message and receive it */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		CHECK( EINVAL, fd_cnx_receive(client_side, NULL, &rcv_buf, &rcv_sz));
+		CHECK( 0, fd_cnx_start_clear(client_side, 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 ) );
+		
+		/* Do it in the other direction */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Do it one more time to use another stream */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Now close the connection */
+		fd_cnx_destroy(client_side);
+		fd_cnx_destroy(server_side);
+	}
+#endif /* DISABLE_SCTP */
+	
+	/* TCP Client / server emulating old Diameter behavior (handshake after 1 message exchange) */
+	{
+		struct connect_flags cf;
+		struct handshake_flags hf;
+		
+		memset(&cf, 0, sizeof(cf));
+		cf.proto = IPPROTO_TCP;
+		
+		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 */
+		CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
+
+		/* Accept the connection of the client */
+		server_side = fd_cnx_serv_accept(listener);
+		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;
+		
+		/* In legacy Diameter, we exchange first one message (CER / CEA) */
+		
+		CHECK( 0, fd_cnx_start_clear(server_side, 0) );
+		CHECK( 0, fd_cnx_start_clear(client_side, 0) );
+		
+		/* Send a message and receive it */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* And the supposed reply */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* At this point in legacy Diameter we start the handshake */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a TLS protected message, and a reply */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+	}
+		
+#ifndef DISABLE_SCTP
+	/* SCTP Client / server emulating old Diameter behavior (handshake after 1 message exchange) */
+	{
+		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 */
+		CHECK( 0, pthread_create(&thr, 0, 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;
+		
+		/* In legacy Diameter, we exchange first one message (CER / CEA) */
+		
+		CHECK( 0, fd_cnx_start_clear(server_side, 0) );
+		CHECK( 0, fd_cnx_start_clear(client_side, 0) );
+		
+		/* Send a message and receive it */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* And the supposed reply */
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* At this point in legacy Diameter we start the handshake */
+		CHECK( 0, pthread_create(&thr, 0, handshake_thr, &hf) );
+		CHECK( 0, fd_cnx_handshake(server_side, GNUTLS_SERVER, NULL, NULL) );
+		CHECK( 0, pthread_join(thr, NULL) );
+		CHECK( 0, hf.ret );
+		
+		/* Send a few TLS protected message, and a reply */
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(server_side, cer_buf, cer_sz));
+		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 ) );
+		
+		CHECK( 0, fd_cnx_send(client_side, cer_buf, cer_sz));
+		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 ) );
+		
+		/* Now close the connection */
+		CHECK( 0, pthread_create(&thr, 0, destroy_thr, client_side) );
+		fd_cnx_destroy(server_side);
+		CHECK( 0, pthread_join(thr, NULL) );
+	}
+#endif /* DISABLE_SCTP */
+	
+	
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
+	
Index: freeDiameter/tests/tests.h
===================================================================
--- freeDiameter/tests/tests.h	(revision 10)
+++ freeDiameter/tests/tests.h	(revision 29)
@@ -46,8 +46,9 @@
 #include <pthread.h>
 #include <errno.h>
+#include <gcrypt.h>
 
 /* Test timeout duration, unless -n is passed on the command line */
 #ifndef TEST_TIMEOUT
-#define TEST_TIMEOUT	5	/* 5 seconds */
+#define TEST_TIMEOUT	30	/* in seconds */
 #endif /* TEST_TIMEOUT */
 
@@ -78,4 +79,7 @@
 struct fd_config * fd_g_config = &conf;
 
+/* gcrypt functions to support posix threads */
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+
 /* Define the standard check routines */
 #define CHECK( _val, _assert ){				\
@@ -99,11 +103,14 @@
 
 /* Minimum inits */
-#define INIT_FD() {						\
-	memset(fd_g_config, 0, sizeof(struct fd_config));	\
-	CHECK( 0, fd_lib_init() );				\
-	fd_log_threadname(basename(__FILE__));			\
-	CHECK( 0, fd_conf_init() );				\
-	CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) );	\
-	parse_cmdline(argc, argv);				\
+#define INIT_FD() {								\
+	memset(fd_g_config, 0, sizeof(struct fd_config));			\
+	CHECK( 0, fd_lib_init() );						\
+	fd_log_threadname(basename(__FILE__));					\
+	(void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);	\
+	(void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);			\
+	CHECK( 0, gnutls_global_init());					\
+	CHECK( 0, fd_conf_init() );						\
+	CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) );		\
+	parse_cmdline(argc, argv);						\
 }
 
Index: include/freeDiameter/libfreeDiameter.h
===================================================================
--- include/freeDiameter/libfreeDiameter.h	(revision 25)
+++ include/freeDiameter/libfreeDiameter.h	(revision 29)
@@ -181,5 +181,5 @@
 /* Helper for function entry -- for very detailed trace of the execution */
 #define TRACE_ENTRY(_format,_args... ) \
-	TRACE_DEBUG(FCTS, "->%s (" #_args ") = (" _format ") >", __PRETTY_FUNCTION__, ##_args );
+	TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
 
 /* Helper for debugging by adding traces -- for debuging a specific location of the code */
@@ -470,5 +470,5 @@
 	
 	if (th_ret != NULL) {
-		TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret);
+		TRACE_DEBUG(ANNOYING, "The thread returned the following value: %p (ignored)", th_ret);
 	}
 	
