diff freeDiameter/cnxctx.c @ 203:536b1dde8761

Some cleanups in the cnxctx module
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 10 Feb 2010 17:47:39 +0900
parents 1b47afa59358
children e1da03ba112f
line wrap: on
line diff
--- a/freeDiameter/cnxctx.c	Wed Feb 10 14:31:33 2010 +0900
+++ b/freeDiameter/cnxctx.c	Wed Feb 10 17:47:39 2010 +0900
@@ -226,7 +226,7 @@
 		fd_log_debug("].\n");
 	}
 	
-	CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } );
+	CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } );
 	cli->cc_socket = cli_sock;
 	cli->cc_proto = serv->cc_proto;
 	
@@ -324,10 +324,6 @@
 	}
 	
 	return cnx;
-
-error:
-	fd_cnx_destroy(cnx);
-	return NULL;
 }
 
 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */
@@ -348,7 +344,7 @@
 	CHECK_FCT_DO( fd_sctp_client( &sock, no_ip6, port, list ), return NULL );
 	
 	/* Once the socket is created successfuly, prepare the remaining of the cnx */
-	CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } );
+	CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
 	
 	cnx->cc_socket = sock;
 	cnx->cc_proto  = IPPROTO_SCTP;
@@ -527,6 +523,10 @@
 		CHECK_SYS_DO(ret, /* continue */);
 	}
 	
+	/* Mark the error */
+	if (ret <= 0)
+		conn->cc_goterror=1;
+	
 	return ret;
 }
 
@@ -548,6 +548,10 @@
 		CHECK_SYS_DO(ret, /* continue */);
 	}
 	
+	/* Mark the error */
+	if (ret <= 0)
+		conn->cc_goterror=1;
+	
 	return ret;
 }
 
@@ -656,6 +660,7 @@
 	do {
 		CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_closing), goto error );
 		if (event == FDEVP_CNX_ERROR) {
+			conn->cc_goterror = 1;
 			goto error;
 		}
 		
@@ -707,9 +712,47 @@
 			}
 		} );
 end:	
+	if (ret <= 0)
+		conn->cc_goterror = 1;
 	return ret;
 }
 
+/* Wrapper around gnutls_record_send to handle some error codes */
+static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
+{
+	ssize_t ret;
+again:	
+	CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
+		{
+			switch (ret) {
+				case GNUTLS_E_REHANDSHAKE: 
+					if (!conn->cc_closing)
+						CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
+							{
+								if (TRACE_BOOL(INFO)) {
+									fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
+								}
+								goto end;
+							} );
+
+				case GNUTLS_E_AGAIN:
+				case GNUTLS_E_INTERRUPTED:
+					if (!conn->cc_closing)
+						goto again;
+					TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
+					break;
+
+				default:
+					TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
+			}
+		} );
+end:	
+	if (ret <= 0)
+		conn->cc_goterror = 1;
+	return ret;
+}
+
+
 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
 {
@@ -798,12 +841,12 @@
 	
 	CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop));
 	
+	/* Release resources in case of a previous call was already made */
+	CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
+	
 	/* Save the loop request */
 	conn->cc_loop = loop;
 	
-	/* Release resources in case of a previous call was already made */
-	CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
-	
 	switch (conn->cc_proto) {
 		case IPPROTO_TCP:
 			/* Start the tcp_notls thread */
@@ -1104,29 +1147,32 @@
 				if (TRACE_BOOL(INFO)) {
 					fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
 				}
+				conn->cc_goterror = 1;
 				return EINVAL;
 			} );
 
-		/* Now verify the remote credentials are valid -- only simple test here */
-		CHECK_FCT( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1) );
+		/* 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), 
+			{  
+				CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ );
+				gnutls_deinit(conn->cc_tls_para.session);
+				return EINVAL;
+			});
 	}
 
+	/* Mark the connection as protected from here */
+	conn->cc_tls = 1;
+
 	/* Multi-stream TLS: handshake other streams as well */
 	if (conn->cc_sctp_para.pairs > 1) {
 #ifndef DISABLE_SCTP
 		/* Resume all additional sessions from the master one. */
 		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 ) );
 	}
@@ -1210,37 +1256,6 @@
 	return 0;
 }
 
-/* Wrapper around gnutls_record_send to handle some error codes */
-static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
-{
-	ssize_t ret;
-again:	
-	CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
-		{
-			switch (ret) {
-				case GNUTLS_E_REHANDSHAKE: 
-					CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
-						{
-							if (TRACE_BOOL(INFO)) {
-								fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
-							}
-							goto end;
-						} );
-
-				case GNUTLS_E_AGAIN:
-				case GNUTLS_E_INTERRUPTED:
-					goto again;
-
-				default:
-					TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
-			}
-		} );
-end:	
-	return ret;
-}
-
-
-
 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/
 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len)
 {
@@ -1263,7 +1278,7 @@
 {
 	TRACE_ENTRY("%p %p %zd", conn, buf, len);
 	
-	CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
+	CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! conn->cc_goterror) && buf && len);
 
 	TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id);
 	
@@ -1287,7 +1302,7 @@
 				CHECK_FCT( send_simple(conn, buf, len) );
 			} else {
 				if (!conn->cc_tls) {
-					CHECK_FCT( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_closing) );
+					CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_closing), { conn->cc_goterror = 1; return ENOTCONN; } );
 				} else {
 					/* push the record to the appropriate session */
 					ssize_t ret;
@@ -1329,15 +1344,20 @@
 	if (conn->cc_tls) {
 #ifndef DISABLE_SCTP
 		if (conn->cc_sctp_para.pairs > 1) {
-			/* Bye on master session */
-			CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ );
-			
-			/* and other stream pairs */
-			fd_sctps_bye(conn);
-			
-			/* Now wait for all decipher threads to terminate */
-			fd_sctps_waitthreadsterm(conn);
-			
+			if (! conn->cc_goterror ) {
+				/* Bye on master session */
+				CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ );
+
+				/* and other stream pairs */
+				fd_sctps_bye(conn);
+
+				/* Now wait for all decipher threads to terminate */
+				fd_sctps_waitthreadsterm(conn);
+			} else {
+				/* Abord the threads, the connection is dead already */
+				fd_sctps_stopthreads(conn);
+			}
+
 			/* Deinit gnutls resources */
 			fd_sctps_gnutls_deinit_others(conn);
 			gnutls_deinit(conn->cc_tls_para.session);
@@ -1348,13 +1368,18 @@
 		} else {
 #endif /* DISABLE_SCTP */
 		/* We are not using the sctps wrapper layer */
-			/* Master session */
-			CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ );
-		
-			/* In this case, just wait for thread rcvthr_tls_single to terminate */
-			if (conn->cc_rcvthr != (pthread_t)NULL) {
-				CHECK_POSIX_DO(  pthread_join(conn->cc_rcvthr, NULL), /* continue */  );
-				conn->cc_rcvthr = (pthread_t)NULL;
+			if (! conn->cc_goterror ) {
+				/* Master session */
+				CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ );
+
+				/* In this case, just wait for thread rcvthr_tls_single to terminate */
+				if (conn->cc_rcvthr != (pthread_t)NULL) {
+					CHECK_POSIX_DO(  pthread_join(conn->cc_rcvthr, NULL), /* continue */  );
+					conn->cc_rcvthr = (pthread_t)NULL;
+				}
+			} else {
+				/* Cancel the receiver thread in case it did not already terminate */
+				CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
 			}
 			
 			/* Free the resources of the TLS session */
@@ -1365,7 +1390,7 @@
 #endif /* DISABLE_SCTP */
 	}
 	
-	/* Terminate the thread in case it is not done yet */
+	/* Terminate the thread in case it is not done yet -- is there any such case left ?*/
 	CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
 		
 	/* Shut the connection down */
"Welcome to our mercurial repository"