Mercurial > hg > freeDiameter
changeset 29:5ba91682f0bc
Added a test for cnxctx (tbc) and fixed some bugs
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 28 Oct 2009 15:19:50 +0900 |
parents | 3628f7d2ba88 |
children | bca243c65b56 |
files | contrib/ca_script/Makefile freeDiameter/cnxctx.c freeDiameter/cnxctx.h freeDiameter/fD.h freeDiameter/p_psm.c freeDiameter/peers.c freeDiameter/sctp.c freeDiameter/sctps.c freeDiameter/server.c freeDiameter/tests/CMakeLists.txt freeDiameter/tests/testcnx.c freeDiameter/tests/tests.h include/freeDiameter/libfreeDiameter.h |
diffstat | 13 files changed, 1100 insertions(+), 316 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/ca_script/Makefile Mon Oct 26 18:07:24 2009 +0900 +++ b/contrib/ca_script/Makefile Wed Oct 28 15:19:50 2009 +0900 @@ -32,6 +32,9 @@ O = WIDE OU = "AAA WG" +#Default lifetime +DAYS = 365 + #Values for the CA CA_CN = chavroux.cowaddict.org CA_mail = sdecugis@nict.go.jp @@ -129,6 +132,7 @@ fi; @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
--- a/freeDiameter/cnxctx.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/cnxctx.c Wed Oct 28 15:19:50 2009 +0900 @@ -396,6 +396,20 @@ return conn->cc_id; } +/* 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) { @@ -473,8 +487,15 @@ struct cnxctx * conn = arg; TRACE_ENTRY("%p", arg); + CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); - 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 ); ASSERT( Target_Queue(conn) ); @@ -547,8 +568,15 @@ int event; TRACE_ENTRY("%p", arg); + CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); - 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 ); ASSERT( Target_Queue(conn) ); @@ -606,7 +634,7 @@ /* 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) { - /* 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]; uint8_t * newmsg; @@ -615,7 +643,7 @@ size_t received = 0; 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 */ goto out; @@ -639,7 +667,7 @@ 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); if (ret == 0) { @@ -663,8 +691,15 @@ struct cnxctx * conn = arg; TRACE_ENTRY("%p", arg); + CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error); - 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) ); @@ -708,7 +743,7 @@ } /* 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 */ CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); @@ -723,7 +758,7 @@ } /* 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 */ if (mode == GNUTLS_SERVER) { @@ -734,7 +769,7 @@ } /* 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); CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); @@ -749,7 +784,7 @@ conn->cc_loop = 1; /* 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 */ if (conn->cc_sctp_para.pairs > 1) { @@ -800,16 +835,22 @@ 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)); + 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; }
--- a/freeDiameter/cnxctx.h Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/cnxctx.h Wed Oct 28 15:19:50 2009 +0900 @@ -78,7 +78,7 @@ /* 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 */ int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen ); @@ -113,7 +113,7 @@ }; 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); void fd_sctps_destroy(struct cnxctx * conn);
--- a/freeDiameter/fD.h Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/fD.h Wed Oct 28 15:19:50 2009 +0900 @@ -176,6 +176,13 @@ #define CHECK_EVENT( _e ) \ (((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 { struct fd_list chain; /* the "o" field points directly to the hop-by-hop of the request (uint32_t *) */ @@ -189,8 +196,9 @@ void fd_peer_dump(struct fd_peer * peer, int details); 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 */ int fd_p_expi_init(void); @@ -215,9 +223,11 @@ struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv); 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); char * fd_cnx_getremoteid(struct cnxctx * conn);
--- a/freeDiameter/p_psm.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/p_psm.c Wed Oct 28 15:19:50 2009 +0900 @@ -208,6 +208,32 @@ } } + /* 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 */ @@ -222,8 +248,8 @@ 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; }
--- a/freeDiameter/peers.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/peers.c Wed Oct 28 15:19:50 2009 +0900 @@ -375,7 +375,7 @@ } /* 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; struct dict_object *avp_oh_model; @@ -384,9 +384,11 @@ struct avp_hdr * avp_hdr; struct fd_list * li; int found = 0; + int ret = 0; struct fd_peer * peer; + struct cnx_incoming * ev_data; - TRACE_ENTRY("%p %p %d", cer, cnx, tls_done); + TRACE_ENTRY("%p %p", cer, cnx); CHECK_PARAMS(cer && *cer && cnx && *cnx); msg = *cer; @@ -410,27 +412,48 @@ } if (!found) { + /* Create a new peer entry for this new remote peer */ + peer = NULL; + CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out ); - 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"); + /* 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 ); } - TODO("Send the new connection event to the peer SM with the appropriate data: msg, conn, tls_done, found"); - /* FDEVP_CNX_INCOMING */ + /* 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)); - /* Reset the "out" parameters, so that they are not cleanup on function return. */ - *cer = NULL; - *cnx = NULL; + 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) ); + if (ret == 0) { + /* Reset the "out" parameters, so that they are not cleanup on function return. */ + *cer = NULL; + *cnx = NULL; + } - TODO("(later if not tls_done) handshake or start_clear(.., 1) "); - - return 0; + return ret; } /* Save a callback to accept / reject incoming unknown peers */ @@ -440,3 +463,12 @@ TODO("..."); 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; +}
--- a/freeDiameter/sctp.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/sctp.c Wed Oct 28 15:19:50 2009 +0900 @@ -44,12 +44,17 @@ #define CMSG_BUF_LEN 1024 #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); @@ -73,26 +78,26 @@ /* Set the option to the socket */ 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; + 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); } - 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 */ - } /* Set the INIT parameters, such as number of streams */ @@ -100,21 +105,21 @@ struct sctp_initmsg init; 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; + 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); } - 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 */ /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */ init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ @@ -123,14 +128,14 @@ /* Set the option to the socket */ 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); + } } /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ @@ -138,28 +143,28 @@ { 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; + 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"); } - TRACE_DEBUG(FULL, "Def SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false"); - #endif /* DEBUG_SCTP */ nofrag = 0; /* We turn ON the fragmentation */ /* Set the option to the socket */ 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 */ # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" @@ -172,37 +177,35 @@ struct sctp_rtoinfo rtoinfo; 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; + 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); } - 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 */ rtoinfo.srto_max = fd_g_config->cnf_timer_tw * 500 - 1000; /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */ /* Set the option to the socket */ 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 */ /* Set the ASSOCIATION parameters */ @@ -211,41 +214,39 @@ struct sctp_assocparams assoc; 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; + 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); } - 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 */ assoc.sasoc_asocmaxrxt = 5; /* Maximum retransmission attempts: we want fast detection of errors */ /* Set the option to the socket */ 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 */ @@ -255,18 +256,18 @@ struct linger linger; 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; + 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); } - TRACE_DEBUG(FULL, "Def SO_LINGER : l_onoff : %d", linger.l_onoff); - TRACE_DEBUG(FULL, " l_linger : %d", linger.l_linger); - #endif /* DEBUG_SCTP */ linger.l_onoff = 0; /* Do not activate the linger */ linger.l_linger = 0; /* Return immediately when closing (=> abort) */ @@ -274,17 +275,15 @@ /* Set the option */ 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 */ /* Set the NODELAY option (Nagle-like algorithm) */ @@ -292,33 +291,31 @@ { 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; + 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"); } - TRACE_DEBUG(FULL, "Def SCTP_NODELAY value : %s", nodelay ? "true" : "false"); - #endif /* DEBUG_SCTP */ nodelay = 0; /* We turn ON the Nagle algorithm (probably the default already) */ /* Set the option to the socket */ 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 */ /* Set the interleaving option */ @@ -326,17 +323,17 @@ { 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; + 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); } - TRACE_DEBUG(FULL, "Def SCTP_FRAGMENT_INTERLEAVE value : %d", interleave); - #endif /* DEBUG_SCTP */ #if 0 interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */ @@ -347,16 +344,14 @@ /* Set the option to the socket */ 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 */ /* Set the v4 mapped addresses option */ @@ -364,17 +359,17 @@ { 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; + 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"); } - TRACE_DEBUG(FULL, "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false"); - #endif /* DEBUG_SCTP */ #ifndef SCTP_USE_MAPPED_ADDRESSES v4mapped = 0; /* We don't want v4 mapped addresses */ @@ -385,16 +380,14 @@ /* Set the option to the socket */ 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 */ @@ -455,35 +448,34 @@ { 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; + 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"); } - TRACE_DEBUG(FULL, "Def SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false"); - #endif /* DEBUG_SCTP */ asconf = bound_to_default ? 1 : 0; /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */ /* Set the option to the socket */ 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 */ return 0; @@ -599,8 +591,7 @@ goto redo; } - # ifdef DEBUG_SCTP - if (TRACE_BOOL(FULL)) { + if (TRACE_BOOL(SCTP_LEVEL)) { int i; ptr.buf = sar.buf; fd_log_debug("Calling sctp_bindx with the following address array:\n"); @@ -609,7 +600,6 @@ ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ; } } - #endif /* DEBUG_SCTP */ /* Bind to this array */ CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) ); @@ -621,9 +611,8 @@ /* Now, the server is bound, set remaining sockopt */ 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 { sSA *sa; @@ -639,7 +628,6 @@ } sctp_freeladdrs(sar); } - #endif /* DEBUG_SCTP */ return 0; } @@ -766,21 +754,23 @@ TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %zd", sz, sizeof(status)); 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; *out = status.sstat_outstrms; @@ -935,9 +925,7 @@ mhdr.msg_control = &anci; 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) ); ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */ @@ -1004,6 +992,8 @@ goto incomplete; } + 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) { union sctp_notification * notif = (union sctp_notification *) data; @@ -1011,52 +1001,42 @@ switch (notif->sn_header.sn_type) { 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; break; 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; break; 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; break; 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; break; case SCTP_SHUTDOWN_EVENT: - #ifdef DEBUG_SCTP TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification"); - #endif /* DEBUG_SCTP */ *event = FDEVP_CNX_ERROR; break; @@ -1095,18 +1075,18 @@ } 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; }
--- a/freeDiameter/sctps.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/sctps.c Wed Oct 28 15:19:50 2009 +0900 @@ -72,10 +72,16 @@ uint16_t strid; TRACE_ENTRY("%p", arg); + CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); - 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 ); @@ -114,11 +120,17 @@ struct cnxctx *cnx; 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 */); error: CHECK_FCT_DO( fd_event_send( Target_Queue(cnx), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); @@ -208,6 +220,7 @@ struct fd_list list; /* list of sr_data, ordered by key.size then key.data */ pthread_rwlock_t lock; struct cnxctx *parent; + /* Add another list to chain in a global list to implement a garbage collector on sessions */ }; /* Saved master session data for resuming sessions */ @@ -218,7 +231,7 @@ }; /* The level at which we debug session resuming */ -#define SR_LEVEL FULL +#define SR_LEVEL (FULL + 1) /* Initialize the store area for a connection */ static int store_init(struct cnxctx * conn) @@ -302,9 +315,9 @@ int ret = 0; 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); if (match) { @@ -312,8 +325,10 @@ /* 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; } @@ -349,9 +364,9 @@ int ret = 0; 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); if (match) { @@ -381,9 +396,9 @@ gnutls_datum_t error = { NULL, 0 }; 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); if (match) { @@ -393,6 +408,7 @@ memcpy(res.data, sr->data.data, res.size); } 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; } @@ -416,10 +432,24 @@ struct sctps_ctx * ctx = (struct sctps_ctx *) arg; 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 */ return arg; @@ -466,7 +496,7 @@ } /* 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; int errors = 0; @@ -486,7 +516,7 @@ /* Initialize the session objects and start the handshake in a separate thread */ 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 */ if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { @@ -549,6 +579,26 @@ 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) { @@ -559,11 +609,14 @@ /* Terminate all receiving threads in case we did not do it yet */ 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 */ ); @@ -571,7 +624,8 @@ for (i = 0; i < conn->cc_sctp_para.pairs; i++) { 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); } /* Free the array itself now */
--- a/freeDiameter/server.c Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/server.c Wed Oct 28 15:19:50 2009 +0900 @@ -115,7 +115,7 @@ /* 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)) { fd_log_debug("TLS handshake failed for client '%s', connection aborted.\n", fd_cnx_getid(c->conn)); @@ -152,7 +152,11 @@ { fd_log_debug("Connection '%s', expecting CER, received something else, closing...\n", fd_cnx_getid(c->conn)); goto cleanup; } ); /* 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 */ cleanup:
--- a/freeDiameter/tests/CMakeLists.txt Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/tests/CMakeLists.txt Wed Oct 28 15:19:50 2009 +0900 @@ -17,6 +17,7 @@ testfifo testsess testdisp + testcnx ) #############################
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/tests/testcnx.c Wed Oct 28 15:19:50 2009 +0900 @@ -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(); +} +
--- a/freeDiameter/tests/tests.h Mon Oct 26 18:07:24 2009 +0900 +++ b/freeDiameter/tests/tests.h Wed Oct 28 15:19:50 2009 +0900 @@ -45,10 +45,11 @@ #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 */ /* Standard includes */ @@ -77,6 +78,9 @@ static struct fd_config conf; 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 ){ \ if (test_verbo > 0) { \ @@ -98,13 +102,16 @@ } /* 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); \ } static inline void parse_cmdline(int argc, char * argv[]) {
--- a/include/freeDiameter/libfreeDiameter.h Mon Oct 26 18:07:24 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Wed Oct 28 15:19:50 2009 +0900 @@ -180,7 +180,7 @@ /* 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 */ #define TRACE_HERE() \ @@ -469,7 +469,7 @@ CHECK_POSIX_DO( ret = pthread_join(*th, &th_ret), /* continue */ ); 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); } /* Clean the location */