Mercurial > hg > freeDiameter
diff libfdcore/cnxctx.c @ 1181:22de21feec64
Preparing for DTLS support
author | Sebastien Decugis <sdecugis@freediameter.net> |
---|---|
date | Wed, 05 Jun 2013 19:22:26 +0800 |
parents | 773498f59520 |
children | 56c36d1007b4 |
line wrap: on
line diff
--- a/libfdcore/cnxctx.c Wed Jun 05 15:02:29 2013 +0800 +++ b/libfdcore/cnxctx.c Wed Jun 05 19:22:26 2013 +0800 @@ -95,6 +95,8 @@ return conn; } +#define CC_ID_HDR "{----} " + /* Create and bind a server socket to the given endpoint and port */ struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep) { @@ -138,7 +140,7 @@ rc = getnameinfo(sa, sSAlen(sa), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (rc) snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); - snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); + snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); } cnx->cc_proto = IPPROTO_TCP; @@ -178,7 +180,7 @@ CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, cnx->cc_family, ep_list, port ), goto error ); /* Generate the name for the connection object */ - snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP srv :%hu (%d)", port, cnx->cc_socket); + snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP srv :%hu (%d)", port, cnx->cc_socket); cnx->cc_proto = IPPROTO_SCTP; @@ -248,7 +250,7 @@ } /* Numeric values for debug... */ - snprintf(cli->cc_id, sizeof(cli->cc_id), "%s from [%s]:%s (%d<-%d)", + snprintf(cli->cc_id, sizeof(cli->cc_id), CC_ID_HDR "%s from [%s]:%s (%d<-%d)", IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket); @@ -312,7 +314,7 @@ { int rc; - snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP,#%d->%s", cnx->cc_socket, sa_buf); + snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP,#%d->%s", cnx->cc_socket, sa_buf); /* ...Name for log messages */ rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); @@ -375,7 +377,7 @@ { int rc; - snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP,#%d->%s", cnx->cc_socket, sa_buf); + snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP,#%d->%s", cnx->cc_socket, sa_buf); /* ...Name for log messages */ rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); @@ -432,16 +434,39 @@ CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } ); return st & flag; } +void fd_cnx_update_id(struct cnxctx * conn) { + if (conn->cc_state & CC_STATUS_CLOSING) + conn->cc_id[1] = 'C'; + else + conn->cc_id[1] = '-'; + + if (conn->cc_state & CC_STATUS_ERROR) + conn->cc_id[2] = 'E'; + else + conn->cc_id[2] = '-'; + + if (conn->cc_state & CC_STATUS_SIGNALED) + conn->cc_id[3] = 'S'; + else + conn->cc_id[3] = '-'; + + if (conn->cc_state & CC_STATUS_TLS) + conn->cc_id[4] = 'T'; + else + conn->cc_id[4] = '-'; +} void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate) { CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } ); conn->cc_state |= orstate; + fd_cnx_update_id(conn); CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } ); } void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate) { CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } ); conn->cc_state = abstate; + fd_cnx_update_id(conn); CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } ); } @@ -658,7 +683,7 @@ return ret; } -#ifndef DISABLE_SCTP +#ifndef DISABLE_SCTP /* WE use this function only in SCTP code */ static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl) { uint8_t * ret = NULL; @@ -852,12 +877,12 @@ -/* Returns 0 on error, received data size otherwise (always >= 0) */ +/* Returns 0 on error, received data size otherwise (always >= 0). This is not used for DTLS-protected associations. */ static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) { ssize_t ret; again: - CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), + CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), { switch (ret) { case GNUTLS_E_REHANDSHAKE: @@ -884,7 +909,11 @@ break; default: - TRACE_DEBUG(INFO, "This GNU TLS error is not handled, assume unrecoverable error"); + if (gnutls_error_is_fatal (ret) == 0) { + LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret)); + goto again; + } + LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); } } ); @@ -897,7 +926,7 @@ return ret; } -/* Wrapper around gnutls_record_send to handle some error codes */ +/* Wrapper around gnutls_record_send to handle some error codes. This is also used for DTLS-protected associations */ static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) { ssize_t ret; @@ -924,7 +953,11 @@ break; default: - TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error"); + if (gnutls_error_is_fatal (ret) == 0) { + LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret)); + goto again; + } + LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); } } ); end: @@ -936,9 +969,15 @@ /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ +/* For the case of DTLS, since we are not using SCTP_UNORDERED, the messages over a single stream are ordered. + Furthermore, as long as messages are shorter than the MTU [2^14 = 16384 bytes], they are delivered in a single + record, as far as I understand. + For larger messages, however, it is possible that pieces of messages coming from different streams can get interleaved. + As a result, we do not use the following function for DTLS reception, because we use the sequence number to rebuild the + messages. */ int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) { - /* No guarantee 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]; struct fd_cnx_rcvdata rcv_data; @@ -1024,8 +1063,13 @@ } /* Prepare a gnutls session object for handshake */ -int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds) +int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds) { + if (dtls) { + LOG_E("DTLS sessions not yet supported"); + return ENOTSUP; + } + /* Create the session context */ CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); @@ -1065,17 +1109,18 @@ CHECK_PARAMS(conn); /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ - if (verbose && TRACE_BOOL(FULL)) { + #ifdef DEBUG + if (verbose) { const char *tmp; gnutls_kx_algorithm_t kx; gnutls_credentials_type_t cred; - fd_log_debug("TLS Session information for connection '%s':", conn->cc_id); + LOG_A("TLS Session information for connection '%s':", conn->cc_id); /* print the key exchange's algorithm name */ GNUTLS_TRACE( kx = gnutls_kx_get (session) ); GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); - fd_log_debug("\t - Key Exchange: %s", tmp); + LOG_A("\t - Key Exchange: %s", tmp); /* Check the authentication type used and switch * to the appropriate. */ @@ -1083,35 +1128,35 @@ switch (cred) { case GNUTLS_CRD_IA: - fd_log_debug("\t - TLS/IA session"); + LOG_A("\t - TLS/IA session"); break; case GNUTLS_CRD_PSK: /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint (session) != NULL) - fd_log_debug("\t - PSK authentication. PSK hint '%s'", + LOG_A("\t - PSK authentication. PSK hint '%s'", gnutls_psk_client_get_hint (session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username (session) != NULL) - fd_log_debug("\t - PSK authentication. Connected as '%s'", + LOG_A("\t - PSK authentication. Connected as '%s'", gnutls_psk_server_get_username (session)); break; case GNUTLS_CRD_ANON: /* anonymous authentication */ - fd_log_debug("\t - Anonymous DH using prime of %d bits", + LOG_A("\t - Anonymous DH using prime of %d bits", gnutls_dh_get_prime_bits (session)); break; case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */ /* Check if we have been using ephemeral Diffie-Hellman. */ if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { - fd_log_debug("\t - Ephemeral DH using prime of %d bits", + LOG_A("\t - Ephemeral DH using prime of %d bits", gnutls_dh_get_prime_bits (session)); } break; #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: - fd_log_debug("\t - SRP session with username %s", + LOG_A("\t - SRP session with username %s", gnutls_srp_server_get_username (session)); break; #endif /* ENABLE_SRP */ @@ -1124,24 +1169,25 @@ /* print the protocol's name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); - fd_log_debug("\t - Protocol: %s", tmp); + LOG_A("\t - Protocol: %s", tmp); /* print the certificate type of the peer. ie X.509 */ tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)); - fd_log_debug("\t - Certificate Type: %s", tmp); + LOG_A("\t - Certificate Type: %s", tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name (gnutls_compression_get (session)); - fd_log_debug("\t - Compression: %s", tmp); + LOG_A("\t - Compression: %s", tmp); /* print the name of the cipher used. ie 3DES. */ tmp = gnutls_cipher_get_name (gnutls_cipher_get (session)); - fd_log_debug("\t - Cipher: %s", tmp); + LOG_A("\t - Cipher: %s", tmp); /* Print the MAC algorithms name. ie SHA1 */ tmp = gnutls_mac_get_name (gnutls_mac_get (session)); - fd_log_debug("\t - MAC: %s", tmp); + LOG_A("\t - MAC: %s", tmp); } + #endif /* DEBUG */ /* First, use built-in verification */ CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, >ret), return EINVAL ); @@ -1172,27 +1218,27 @@ now = time(NULL); - if (verbose && TRACE_BOOL(FULL)) { + #ifdef DEBUG char serial[40]; char dn[128]; size_t size; unsigned int algo, bits; time_t expiration_time, activation_time; - fd_log_debug("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size); + LOG_D("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size); for (i = 0; i < cert_list_size; i++) { CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL); CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL); - fd_log_debug(" Certificate %d info:", i); + LOG_A(" Certificate %d info:", i); GNUTLS_TRACE( expiration_time = gnutls_x509_crt_get_expiration_time (cert) ); GNUTLS_TRACE( activation_time = gnutls_x509_crt_get_activation_time (cert) ); - fd_log_debug("\t - Certificate is valid since: %s", ctime (&activation_time)); - fd_log_debug("\t - Certificate expires: %s", ctime (&expiration_time)); + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate is valid since: %.24s", ctime (&activation_time)); + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate expires: %.24s", ctime (&expiration_time)); /* Print the serial number of the certificate. */ size = sizeof (serial); @@ -1205,29 +1251,29 @@ for (j = 0; j < size; j++) { snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%02hhx", serial[j]); } - fd_log_debug("%s", buf); + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "%s", buf); } /* Extract some of the public key algorithm's parameters */ GNUTLS_TRACE( algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits) ); - fd_log_debug("\t - Certificate public key: %s", + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate public key: %s", gnutls_pk_algorithm_get_name (algo)); /* Print the version of the X.509 certificate. */ - fd_log_debug("\t - Certificate version: #%d", + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate version: #%d", gnutls_x509_crt_get_version (cert)); size = sizeof (dn); GNUTLS_TRACE( gnutls_x509_crt_get_dn (cert, dn, &size) ); - fd_log_debug("\t - DN: %s", dn); + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - DN: %s", dn); size = sizeof (dn); GNUTLS_TRACE( gnutls_x509_crt_get_issuer_dn (cert, dn, &size) ); - fd_log_debug("\t - Issuer's DN: %s", dn); + LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Issuer's DN: %s", dn); GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) ); } - } + #endif /* DEBUG */ /* Check validity of all the certificates */ for (i = 0; i < cert_list_size; i++) @@ -1290,7 +1336,7 @@ conn = gnutls_session_get_ptr (session); /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ - if (TRACE_BOOL(FULL)) { +#ifdef DEBUG const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; @@ -1298,13 +1344,13 @@ dhe = ecdh = 0; - fd_log_debug("TLS Session information for connection '%s':", conn->cc_id); + LOG_A("TLS Session information for connection '%s':", conn->cc_id); /* print the key exchange's algorithm name */ GNUTLS_TRACE( kx = gnutls_kx_get (session) ); GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); - fd_log_debug("\t- Key Exchange: %s", tmp); + LOG_A("\t- Key Exchange: %s", tmp); /* Check the authentication type used and switch * to the appropriate. @@ -1313,13 +1359,13 @@ switch (cred) { case GNUTLS_CRD_IA: - fd_log_debug("\t - TLS/IA session"); + LOG_A("\t - TLS/IA session"); break; #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: - fd_log_debug("\t - SRP session with username %s", + LOG_A("\t - SRP session with username %s", gnutls_srp_server_get_username (session)); break; #endif @@ -1328,12 +1374,12 @@ /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint (session) != NULL) - fd_log_debug("\t - PSK authentication. PSK hint '%s'", + LOG_A("\t - PSK authentication. PSK hint '%s'", gnutls_psk_client_get_hint (session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username (session) != NULL) - fd_log_debug("\t - PSK authentication. Connected as '%s'", + LOG_A("\t - PSK authentication. Connected as '%s'", gnutls_psk_server_get_username (session)); if (kx == GNUTLS_KX_ECDHE_PSK) @@ -1343,7 +1389,7 @@ break; case GNUTLS_CRD_ANON: /* anonymous authentication */ - fd_log_debug("\t - Anonymous DH using prime of %d bits", + LOG_A("\t - Anonymous DH using prime of %d bits", gnutls_dh_get_prime_bits (session)); if (kx == GNUTLS_KX_ANON_ECDH) ecdh = 1; @@ -1366,7 +1412,7 @@ cert_list = gnutls_certificate_get_peers (session, &cert_list_size); - fd_log_debug("\t Peer provided %d certificates.", cert_list_size); + LOG_A("\t Peer provided %d certificates.", cert_list_size); if (cert_list_size > 0) { @@ -1378,7 +1424,7 @@ gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER); - fd_log_debug("\t Certificate info:"); + LOG_A("\t Certificate info:"); /* This is the preferred way of printing short information about a certificate. */ @@ -1386,7 +1432,7 @@ ret = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo); if (ret == 0) { - fd_log_debug("\t\t%s", cinfo.data); + LOG_A("\t\t%s", cinfo.data); gnutls_free (cinfo.data); } @@ -1409,46 +1455,46 @@ break; default: - fd_log_debug("\t - unknown session type (%d)", cred); + LOG_A("\t - unknown session type (%d)", cred); } /* switch */ if (ecdh != 0) - fd_log_debug("\t - Ephemeral ECDH using curve %s", + LOG_A("\t - Ephemeral ECDH using curve %s", gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session))); else if (dhe != 0) - fd_log_debug("\t - Ephemeral DH using prime of %d bits", + LOG_A("\t - Ephemeral DH using prime of %d bits", gnutls_dh_get_prime_bits (session)); /* print the protocol's name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); - fd_log_debug("\t - Protocol: %s", tmp); + LOG_A("\t - Protocol: %s", tmp); /* print the certificate type of the peer. * ie X.509 */ tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)); - fd_log_debug("\t - Certificate Type: %s", tmp); + LOG_A("\t - Certificate Type: %s", tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name (gnutls_compression_get (session)); - fd_log_debug("\t - Compression: %s", tmp); + LOG_A("\t - Compression: %s", tmp); /* print the name of the cipher used. * ie 3DES. */ tmp = gnutls_cipher_get_name (gnutls_cipher_get (session)); - fd_log_debug("\t - Cipher: %s", tmp); + LOG_A("\t - Cipher: %s", tmp); /* Print the MAC algorithms name. * ie SHA1 */ tmp = gnutls_mac_get_name (gnutls_mac_get (session)); - fd_log_debug("\t - MAC: %s", tmp); + LOG_A("\t - MAC: %s", tmp); - } +#endif /* DEBUG */ /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. @@ -1508,14 +1554,29 @@ #endif /* GNUTLS_VERSION_300 */ +static int fd_cnx_may_dtls(struct cnxctx * conn) { +#ifndef DISABLE_SCTP + if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_tls_para.algo == ALGO_HANDSHAKE_DEFAULT)) + return 1; +#endif /* DISABLE_SCTP */ + return 0; +} + +static int fd_cnx_uses_dtls(struct cnxctx * conn) { + return fd_cnx_may_dtls(conn) && (fd_cnx_teststate(conn, CC_STATUS_TLS)); +} + /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ -int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds) +int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds) { - TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds); + int dtls = 0; + + TRACE_ENTRY( "%p %d %d %p %p", conn, mode, algo, priority, alt_creds); CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); /* Save the mode */ conn->cc_tls_para.mode = mode; + conn->cc_tls_para.algo = algo; /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */ CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); @@ -1523,11 +1584,13 @@ /* Once TLS handshake is done, we don't stop after the first message */ conn->cc_loop = 1; + dtls = fd_cnx_may_dtls(conn); + /* Prepare the master session credentials and priority */ - CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) ); + CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, dtls, 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) { + if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { #ifdef DISABLE_SCTP ASSERT(0); CHECK_FCT( ENOTSUP ); @@ -1540,8 +1603,13 @@ GNUTLS_TRACE( gnutls_transport_set_ptr( conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn ) ); /* Set the push and pull callbacks */ - GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) ); - GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) ); + if (!dtls) { + GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) ); + GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) ); + } else { + TODO("DTLS push/pull functions"); + return ENOTSUP; + } } /* additional initialization for gnutls 3.x */ @@ -1588,9 +1656,9 @@ }); #endif /* GNUTLS_VERSION_300 */ } - + /* Multi-stream TLS: handshake other streams as well */ - if (conn->cc_sctp_para.pairs > 1) { + if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { #ifndef DISABLE_SCTP /* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */ CHECK_FCT(fd_sctp3436_startthreads(conn, 0)); @@ -1603,7 +1671,13 @@ #endif /* DISABLE_SCTP */ } else { /* Start decrypting the data */ - CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) ); + if (!dtls) { + CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) ); + } else { + TODO("Signal the dtls_push function that multiple streams can be used from this point."); + TODO("Create DTLS rcvthr (must reassembly based on seq numbers & stream id ?)"); + return ENOTSUP; + } } return 0; @@ -1736,40 +1810,49 @@ #ifndef DISABLE_SCTP case IPPROTO_SCTP: { - if (flags & FD_CNX_ORDERED) { - /* We send over stream #0 */ - CHECK_FCT( send_simple(conn, buf, len) ); - } else { - /* Default case : no flag specified */ - - int another_str = 0; /* do we send over stream #0 ? */ - - if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1))) { - /* Update the id of the stream we will send this message over */ - conn->cc_sctp_para.next += 1; - conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); - another_str = (conn->cc_sctp_para.next ? 1 : 0); - } + int dtls = fd_cnx_uses_dtls(conn); - if ( ! another_str ) { + if (!dtls) { + if (flags & FD_CNX_ORDERED) { + /* We send over stream #0 */ CHECK_FCT( send_simple(conn, buf, len) ); } else { - if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { - CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } ); + /* Default case : no flag specified */ + + int another_str = 0; /* do we send over stream #0 ? */ + + if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1))) { + /* Update the id of the stream we will send this message over */ + conn->cc_sctp_para.next += 1; + conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); + another_str = (conn->cc_sctp_para.next ? 1 : 0); + } + + if ( ! another_str ) { + CHECK_FCT( send_simple(conn, buf, len) ); } else { - /* push the record to the appropriate session */ - ssize_t ret; - size_t sent = 0; - ASSERT(conn->cc_sctp3436_data.array != NULL); - do { - CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), ); - if (ret <= 0) - return ENOTCONN; + if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { + CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } ); + } else { + /* push the record to the appropriate session */ + ssize_t ret; + size_t sent = 0; + ASSERT(conn->cc_sctp3436_data.array != NULL); + do { + CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), ); + if (ret <= 0) + return ENOTCONN; - sent += ret; - } while ( sent < len ); + sent += ret; + } while ( sent < len ); + } } } + } else { + /* DTLS */ + /* We signal the push function directly to tell if using stream 0 or round-robin */ + TODO("DTLS send"); + return ENOTSUP; } } break; @@ -1801,7 +1884,8 @@ /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */ if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { #ifndef DISABLE_SCTP - if (conn->cc_sctp_para.pairs > 1) { + int dtls = fd_cnx_uses_dtls(conn); + if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) { /* Bye on master session */ CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );