Index: libfdcore/cnxctx.c
===================================================================
--- libfdcore/cnxctx.c	(revision 803)
+++ libfdcore/cnxctx.c	(revision 807)
@@ -587,5 +587,5 @@
 	
 	TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid);
-	
+
 	/* Mark the error */
 	fd_cnx_addstate(conn, CC_STATUS_ERROR);
@@ -597,4 +597,5 @@
 		fd_cnx_addstate(conn, CC_STATUS_SIGNALED);
 	}
+	
 	return;
 fatal:
@@ -843,7 +844,4 @@
 				case GNUTLS_E_REHANDSHAKE: 
 					if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
-						#ifdef GNUTLS_VERSION_310
-						GNUTLS_TRACE( gnutls_handshake_set_timeout( session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
-						#endif /* GNUTLS_VERSION_310 */
 						CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
 							{
@@ -891,8 +889,4 @@
 				case GNUTLS_E_REHANDSHAKE: 
 					if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
-						#ifdef GNUTLS_VERSION_310
-						GNUTLS_TRACE( gnutls_handshake_set_timeout( session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
-						#endif /* GNUTLS_VERSION_310 */
-
 						CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
 							{
@@ -1031,7 +1025,9 @@
 		gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE);
 	}
-	
+		
 	return 0;
 }
+
+#ifndef GNUTLS_VERSION_300
 
 /* Verify remote credentials after successful handshake (return 0 if OK, EINVAL otherwise) */
@@ -1254,4 +1250,238 @@
 }
 
+#else /* GNUTLS_VERSION_300 */
+
+/* Verify remote credentials DURING handshake (return gnutls status) */
+int fd_tls_verify_credentials_2(gnutls_session_t session)
+{
+	/* inspired from gnutls 3.x guidelines */
+	unsigned int status;
+	const gnutls_datum_t *cert_list = NULL;
+	unsigned int cert_list_size;
+	gnutls_x509_crt_t cert;
+	struct cnxctx * conn;
+	int hostname_verified = 0;
+
+	TRACE_ENTRY("%p", session);
+	
+	/* get the associated connection */
+	conn = gnutls_session_get_ptr (session);
+	
+	/* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
+	if (TRACE_BOOL(FULL)) {
+		const char *tmp;
+		gnutls_credentials_type_t cred;
+		gnutls_kx_algorithm_t kx;
+		int dhe, ecdh;
+
+		dhe = ecdh = 0;
+
+		fd_log_debug("TLS Session information for connection '%s':\n", 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\n", tmp);
+
+		/* Check the authentication type used and switch
+		* to the appropriate.
+		*/
+		GNUTLS_TRACE( cred = gnutls_auth_get_type (session) );
+		switch (cred)
+		{
+			case GNUTLS_CRD_IA:
+				fd_log_debug("\t - TLS/IA session\n");
+				break;
+
+
+			#ifdef ENABLE_SRP
+			case GNUTLS_CRD_SRP:
+				fd_log_debug("\t - SRP session with username %s\n",
+					gnutls_srp_server_get_username (session));
+				break;
+			#endif
+
+			case GNUTLS_CRD_PSK:
+				/* This returns NULL in server side.
+				*/
+				if (gnutls_psk_client_get_hint (session) != NULL)
+					fd_log_debug("\t - PSK authentication. PSK hint '%s'\n",
+						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'\n",
+						gnutls_psk_server_get_username (session));
+
+				if (kx == GNUTLS_KX_ECDHE_PSK)
+					ecdh = 1;
+				else if (kx == GNUTLS_KX_DHE_PSK)
+					dhe = 1;
+				break;
+
+			case GNUTLS_CRD_ANON:      /* anonymous authentication */
+				fd_log_debug("\t - Anonymous DH using prime of %d bits\n",
+					gnutls_dh_get_prime_bits (session));
+				if (kx == GNUTLS_KX_ANON_ECDH)
+					ecdh = 1;
+				else if (kx == GNUTLS_KX_ANON_DH)
+					dhe = 1;
+				break;
+
+			case GNUTLS_CRD_CERTIFICATE:       /* certificate authentication */
+
+				/* Check if we have been using ephemeral Diffie-Hellman.
+				*/
+				if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
+					dhe = 1;
+				else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA)
+					ecdh = 1;
+				
+				/* Now print some info on the remote certificate */
+				if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) {
+					gnutls_datum_t cinfo;
+
+					cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+
+					fd_log_debug("\t Peer provided %d certificates.\n", cert_list_size);
+
+					if (cert_list_size > 0)
+					{
+						int ret;
+
+						/* we only print information about the first certificate.
+						*/
+						gnutls_x509_crt_init (&cert);
+
+						gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
+
+						fd_log_debug("\t Certificate info:\n");
+
+						/* This is the preferred way of printing short information about
+						 a certificate. */
+
+						ret = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
+						if (ret == 0)
+						{
+						  fd_log_debug("\t\t%s\n", cinfo.data);
+						  gnutls_free (cinfo.data);
+						}
+						
+						if (conn->cc_tls_para.cn) {
+							if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
+								fd_log_debug("\tTLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+								fd_log_debug("\t - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
+								gnutls_x509_crt_deinit (cert);
+								return GNUTLS_E_CERTIFICATE_ERROR;
+							}
+							
+						}
+
+						hostname_verified = 1;
+
+						gnutls_x509_crt_deinit (cert);
+
+					}
+    				}
+				break;
+
+		}                           /* switch */
+
+		if (ecdh != 0)
+			fd_log_debug("\t - Ephemeral ECDH using curve %s\n",
+				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\n",
+				gnutls_dh_get_prime_bits (session));
+
+		/* 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\n", 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\n", tmp);
+
+		/* print the compression algorithm (if any)
+		*/
+		tmp = gnutls_compression_get_name (gnutls_compression_get (session));
+		fd_log_debug("\t - Compression: %s\n", 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\n", tmp);
+
+		/* Print the MAC algorithms name.
+		* ie SHA1
+		*/
+		tmp = gnutls_mac_get_name (gnutls_mac_get (session));
+		fd_log_debug("\t - MAC: %s\n", tmp);
+	
+	}
+
+	/* This verification function uses the trusted CAs in the credentials
+	* structure. So you must have installed one or more CA certificates.
+	*/
+	CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &status), return GNUTLS_E_CERTIFICATE_ERROR );
+	if (TRACE_BOOL(INFO) && (status & GNUTLS_CERT_INVALID)) {
+		fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+		if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+			fd_log_debug(" - The certificate hasn't got a known issuer.\n");
+
+		if (status & GNUTLS_CERT_REVOKED)
+			fd_log_debug(" - The certificate has been revoked.\n");
+
+		if (status & GNUTLS_CERT_EXPIRED)
+			fd_log_debug(" - The certificate has expired.\n");
+
+		if (status & GNUTLS_CERT_NOT_ACTIVATED)
+			fd_log_debug(" - The certificate is not yet activated.\n");
+	}	
+	if (status & GNUTLS_CERT_INVALID)
+	{
+		return GNUTLS_E_CERTIFICATE_ERROR;
+	}
+	
+	/* Up to here the process is the same for X.509 certificates and
+	* OpenPGP keys. From now on X.509 certificates are assumed. This can
+	* be easily extended to work with openpgp keys as well.
+	*/
+	if ((!hostname_verified) && (conn->cc_tls_para.cn)) {
+		if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
+			TRACE_DEBUG(INFO, "TLS: Remote credentials are not x509, rejected on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+			return GNUTLS_E_CERTIFICATE_ERROR;
+		}
+
+		CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return GNUTLS_E_CERTIFICATE_ERROR );
+
+		cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+		CHECK_PARAMS_DO( cert_list, return GNUTLS_E_CERTIFICATE_ERROR );
+
+		CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER), return GNUTLS_E_CERTIFICATE_ERROR );
+
+		if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
+			if (TRACE_BOOL(INFO)) {
+				fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
+				fd_log_debug(" - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
+			}
+			gnutls_x509_crt_deinit (cert);
+			return GNUTLS_E_CERTIFICATE_ERROR;
+		}
+
+		gnutls_x509_crt_deinit (cert);
+	}
+
+	/* notify gnutls to continue handshake normally */
+	return 0;
+}
+
+#endif /* GNUTLS_VERSION_300 */
+
 /* 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)
@@ -1289,5 +1519,23 @@
 		GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) );
 	}
-
+	
+	/* additional initialization for gnutls 3.x */
+	#ifdef GNUTLS_VERSION_300
+		/* the verify function has already been set in the global initialization in config.c */
+	
+	/* fd_tls_verify_credentials_2 uses the connection */
+	gnutls_session_set_ptr (conn->cc_tls_para.session, (void *) conn);
+	
+	if ((conn->cc_tls_para.cn != NULL) && (mode == GNUTLS_CLIENT)) {
+		/* this might allow virtual hosting on the remote peer */
+		CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_tls_para.session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
+	}
+	
+	#endif /* GNUTLS_VERSION_300 */
+
+	#ifdef GNUTLS_VERSION_310
+	GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
+	#endif /* GNUTLS_VERSION_310 */
+	
 	/* Mark the connection as protected from here, so that the gnutls credentials will be freed */
 	fd_cnx_addstate(conn, CC_STATUS_TLS);
@@ -1296,10 +1544,5 @@
 	{
 		int ret;
-		#ifdef GNUTLS_VERSION_310
-		GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
-		#endif /* GNUTLS_VERSION_310 */
-
-		/* When gnutls 2.10.1 is around, we should use gnutls_certificate_set_verify_function and fd_tls_verify_credentials, so that handshake fails directly. */
-		
+	
 		CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session),
 			{
@@ -1311,4 +1554,5 @@
 			} );
 
+		#ifndef GNUTLS_VERSION_300
 		/* Now verify the remote credentials are valid -- only simple tests here */
 		CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1), 
@@ -1318,4 +1562,5 @@
 				return EINVAL;
 			});
+		#endif /* GNUTLS_VERSION_300 */
 	}
 
@@ -1325,5 +1570,5 @@
 		/* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */
 		CHECK_FCT(fd_sctps_startthreads(conn, 0));
-		
+
 		/* Resume all additional sessions from the master one. */
 		CHECK_FCT(fd_sctps_handshake_others(conn, priority, alt_creds));
Index: libfdcore/cnxctx.h
===================================================================
--- libfdcore/cnxctx.h	(revision 740)
+++ libfdcore/cnxctx.h	(revision 807)
@@ -98,5 +98,7 @@
 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);
+#ifndef GNUTLS_VERSION_300
 int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn, int verbose);
+#endif /* GNUTLS_VERSION_300 */
 
 /* TCP */
@@ -143,5 +145,4 @@
 #endif /* DISABLE_SCTP */
 
-
 #endif /* _CNXCTX_H */
 
Index: libfdcore/config.c
===================================================================
--- libfdcore/config.c	(revision 805)
+++ libfdcore/config.c	(revision 807)
@@ -538,4 +538,9 @@
 	/* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
 	
+	#ifdef GNUTLS_VERSION_300
+	/* Use certificate verification during the handshake */
+	gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
+	#endif /* GNUTLS_VERSION_300 */
+	
 	/* DH */
 	if (fd_g_config->cnf_sec_data.dh_file) {
Index: libfdcore/fdcore-internal.h
===================================================================
--- libfdcore/fdcore-internal.h	(revision 805)
+++ libfdcore/fdcore-internal.h	(revision 807)
@@ -352,4 +352,7 @@
 int             fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, uint32_t flags);
 void            fd_cnx_destroy(struct cnxctx * conn);
+#ifdef GNUTLS_VERSION_300
+int             fd_tls_verify_credentials_2(gnutls_session_t session);
+#endif /* GNUTLS_VERSION_300 */
 
 /* Flags for the fd_cnx_send function : */
Index: libfdcore/sctps.c
===================================================================
--- libfdcore/sctps.c	(revision 803)
+++ libfdcore/sctps.c	(revision 807)
@@ -105,5 +105,4 @@
 			
 			case FDEVP_CNX_ERROR:
-				fd_cnx_markerror(conn);
 				goto out;
 				
@@ -121,7 +120,9 @@
 	/* Signal termination of the connection to all decipher threads */
 	for (strid = 0; strid < conn->cc_sctp_para.pairs; strid++) {
-		if (conn->cc_sctps_data.array[strid].raw_recv)
+		if (conn->cc_sctps_data.array[strid].raw_recv) {
 			CHECK_FCT_DO(fd_event_send(conn->cc_sctps_data.array[strid].raw_recv, FDEVP_CNX_ERROR, 0, NULL), goto fatal );
-	}
+		}
+	}
+	fd_cnx_markerror(conn);
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
@@ -171,5 +172,5 @@
 	CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } );
 	
-	CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent, ctx->strid, (uint8_t *)data, len), /* errno is already set */ return -1 );
+	CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent, ctx->strid, (uint8_t *)data, len), return -1 );
 	
 	return len;
@@ -184,12 +185,14 @@
 	
 	TRACE_ENTRY("%p %p %zd", tr, buf, len);
-	CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; return -1; } );
+	CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } );
 	
 	/* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */
 	if (!ctx->partial.buf) {
 		int ev;
-		CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), return -1 );
-		if (ev == FDEVP_CNX_ERROR) 
-			return 0; /* connection closed */
+		CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), goto error );
+		if (ev == FDEVP_CNX_ERROR) {
+			/* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */
+			return -1;
+		}
 	}
 		
@@ -216,4 +219,8 @@
 	/* We are done */
 	return pulled;
+	
+error:
+	gnutls_transport_set_errno (ctx->session, errno);
+	return -1;
 }
 
@@ -463,19 +470,19 @@
 	
 	TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid);
-#ifdef GNUTLS_VERSION_310
-	GNUTLS_TRACE( gnutls_handshake_set_timeout( ctx->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
-#endif /* GNUTLS_VERSION_310 */
+
 	CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
 			
 	GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) );
+	#ifndef GNUTLS_VERSION_300
 	if (!resumed) {
 		/* Check the credentials here also */
 		CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent, 0), return NULL );
 	}
+	#endif /* GNUTLS_VERSION_300 */
 	if (TRACE_BOOL(FULL)) {
 		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 on stream %hu  (full handshake + verif) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
+			fd_log_debug("Session was NOT resumed on stream %hu  (full handshake) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
 		}
 	}
@@ -555,4 +562,22 @@
 		CHECK_FCT( fd_tls_prepare(&conn->cc_sctps_data.array[i].session, conn->cc_tls_para.mode, priority, alt_creds) );
 		
+		/* additional initialization for gnutls 3.x */
+		#ifdef GNUTLS_VERSION_300
+			/* the verify function has already been set in the global initialization in config.c */
+
+		/* fd_tls_verify_credentials_2 uses the connection */
+		gnutls_session_set_ptr (conn->cc_sctps_data.array[i].session, (void *) conn);
+
+		if ((conn->cc_tls_para.cn != NULL) && (conn->cc_tls_para.mode == GNUTLS_CLIENT)) {
+			/* this might allow virtual hosting on the remote peer */
+			CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_sctps_data.array[i].session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
+		}
+
+		#endif /* GNUTLS_VERSION_300 */
+
+		#ifdef GNUTLS_VERSION_310
+		GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_sctps_data.array[i].session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
+		#endif /* GNUTLS_VERSION_310 */
+
 		/* For the client, copy data from master session; for the server, set session resuming pointers */
 		if (conn->cc_tls_para.mode == GNUTLS_CLIENT) {
