Mercurial > hg > freeDiameter
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 */ );