changeset 155:30a7252cbb55

Cleanup connection cleanup sequence
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 19 Jan 2010 11:41:01 +0900
parents 4356de61174d
children e2dc300819b3
files freeDiameter/cnxctx.c freeDiameter/cnxctx.h freeDiameter/sctps.c
diffstat 3 files changed, 125 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameter/cnxctx.c	Tue Dec 22 15:53:13 2009 +0900
+++ b/freeDiameter/cnxctx.c	Tue Jan 19 11:41:01 2010 +0900
@@ -561,7 +561,9 @@
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
 error:
-	CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	if (!conn->cc_closing) {
+		CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	}
 	goto out;
 }
 
@@ -602,7 +604,9 @@
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
 error:
-	CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	if (!conn->cc_closing) {
+		CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	}
 	goto out;
 }
 #endif /* DISABLE_SCTP */
@@ -712,7 +716,9 @@
 	
 	CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
 error:
-	CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	if (!conn->cc_closing) {
+		CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	}
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
 }
@@ -1132,7 +1138,7 @@
 	return 0;
 }
 
-/* Wrapper around gnutls_record_recv to handle some error codes */
+/* 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;
@@ -1245,35 +1251,51 @@
 	
 	CHECK_PARAMS_DO(conn, return);
 	
-	/* Avoid sending further events to the alt fifo */
-	conn->cc_alt = NULL;
-
-	/* In case of TLS, stop receiver thread, then close properly the gnutls session */
-	if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) {
+	conn->cc_closing = 1;
+	
+	/* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */
+	if (conn->cc_tls) {
 #ifndef DISABLE_SCTP
-		/* Multi-stream TLS: Stop all decipher threads, but not the demux thread */
-		fd_sctps_stopthreads(conn);
+		if (conn->cc_sctp_para.pairs > 1) {
+			/* 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);
+			
+			/* Deinit gnutls resources */
+			fd_sctps_gnutls_deinit_others(conn);
+			gnutls_deinit(conn->cc_tls_para.session);
+			
+			/* Destroy the wrapper (also stops the demux thread) */
+			fd_sctps_destroy(conn);
+
+		} else {
 #endif /* DISABLE_SCTP */
-	} else {
-		/* Stop the decoding thread */
-		CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
+		/* 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;
+			}
+			
+			/* Free the resources of the TLS session */
+			gnutls_deinit(conn->cc_tls_para.session);
+		
+#ifndef DISABLE_SCTP
+		}
+#endif /* DISABLE_SCTP */
 	}
 	
-	/* Terminate properly the TLS session(s) */
-	if (conn->cc_tls) {
-		/* Master session */
-		CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ );
-		gnutls_deinit(conn->cc_tls_para.session);
+	/* Terminate the thread in case it is not done yet */
+	CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
 		
-#ifndef DISABLE_SCTP
-		if (conn->cc_sctp_para.pairs > 1) {
-			/* Multi-stream TLS: destroy the wrapper and stop the demux thread */
-			fd_sctps_destroy(conn);
-		}
-#endif /* DISABLE_SCTP */
-		
-	}
-	
 	/* Shut the connection down */
 	if (conn->cc_socket > 0) {
 		shutdown(conn->cc_socket, SHUT_RDWR);
--- a/freeDiameter/cnxctx.h	Tue Dec 22 15:53:13 2009 +0900
+++ b/freeDiameter/cnxctx.h	Tue Jan 19 11:41:01 2010 +0900
@@ -47,6 +47,7 @@
 
 	int 		cc_proto;	/* IPPROTO_TCP or IPPROTO_SCTP */
 	int		cc_tls;		/* Is TLS already started ? */
+	int		cc_closing;	/* True if the object is being destroyed: we don't send events anymore */
 
 	pthread_t	cc_rcvthr;	/* thread for receiving messages on the connection */
 	int		cc_loop;	/* tell the thread if it loops or stops after the first message is received */
@@ -117,6 +118,9 @@
 int fd_sctps_init(struct cnxctx * conn);
 int fd_sctps_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds);
 int fd_sctps_startthreads(struct cnxctx * conn);
+void fd_sctps_bye(struct cnxctx * conn);
+void fd_sctps_waitthreadsterm(struct cnxctx * conn);
+void fd_sctps_gnutls_deinit_others(struct cnxctx * conn);
 void fd_sctps_stopthreads(struct cnxctx * conn);
 void fd_sctps_destroy(struct cnxctx * conn);
 
--- a/freeDiameter/sctps.c	Tue Dec 22 15:53:13 2009 +0900
+++ b/freeDiameter/sctps.c	Tue Jan 19 11:41:01 2010 +0900
@@ -109,7 +109,9 @@
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
 error:
-	CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	if (!conn->cc_closing) {
+		CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	}
 	goto out;
 }
 
@@ -133,7 +135,9 @@
 	
 	CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */);
 error:
-	CHECK_FCT_DO( fd_event_send( Target_Queue(cnx), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	if (!cnx->cc_closing) {
+		CHECK_FCT_DO( fd_event_send( Target_Queue(cnx), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
+	}
 	TRACE_DEBUG(FULL, "Thread terminated");	
 	return NULL;
 }
@@ -578,6 +582,71 @@
 	return 0;
 }
 
+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_WR), /* Continue */ );
+			
+	/* Finish */
+	return NULL;
+}
+
+/* Initiate a "bye" on all stream pairs in paralel */
+void fd_sctps_bye(struct cnxctx * conn)
+{
+	uint16_t i;
+	
+	CHECK_PARAMS_DO( conn && conn->cc_sctps_data.array, return );
+	
+	/* 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 );
+	}
+}
+
+/* After "bye" was sent on all streams, read from sessions until an error is received */
+void fd_sctps_waitthreadsterm(struct cnxctx * conn)
+{
+	uint16_t i;
+	
+	TRACE_ENTRY("%p", conn);
+	CHECK_PARAMS_DO( conn && conn->cc_sctps_data.array, return );
+	
+	for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
+		if (conn->cc_sctps_data.array[i].thr != (pthread_t)NULL) {
+			CHECK_POSIX_DO( pthread_join(conn->cc_sctps_data.array[i].thr, NULL), /* continue */ );
+			conn->cc_sctps_data.array[i].thr = (pthread_t)NULL;
+		}
+	}
+	return;
+}
+
+/* Free gnutls resources of all sessions */
+void fd_sctps_gnutls_deinit_others(struct cnxctx * conn)
+{
+	uint16_t i;
+	
+	TRACE_ENTRY("%p", conn);
+	CHECK_PARAMS_DO( conn && conn->cc_sctps_data.array, return );
+	
+	for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
+		gnutls_deinit(conn->cc_sctps_data.array[i].session);
+	}
+}
+
+
 /* Stop all receiver threads */
 void fd_sctps_stopthreads(struct cnxctx * conn)
 {
@@ -592,26 +661,6 @@
 	return;
 }
 
-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)
 {
@@ -622,14 +671,6 @@
 	/* Terminate all receiving threads in case we did not do it yet */
 	fd_sctps_stopthreads(conn);
 	
-	/* 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 */ );
 	
"Welcome to our mercurial repository"