diff --git a/examples/client/client.c b/examples/client/client.c index 35a61f05c8..3aba5f4587 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -138,13 +138,16 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl) else #endif { - #ifdef WOLFSSL_DTLS - currTimeout = wolfSSL_dtls_get_current_timeout(ssl); - #endif - select_ret = tcp_select(sockfd, currTimeout); + if (error != WOLFSSL_ERROR_WANT_WRITE) { + #ifdef WOLFSSL_DTLS + currTimeout = wolfSSL_dtls_get_current_timeout(ssl); + #endif + select_ret = tcp_select(sockfd, currTimeout); + } } - if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_ERROR_READY) + if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_SEND_READY) + || (select_ret == TEST_ERROR_READY) #ifdef WOLFSSL_ASYNC_CRYPT || error == WC_PENDING_E #endif @@ -156,6 +159,13 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl) #endif error = wolfSSL_get_error(ssl, 0); elapsedSec = 0; /* reset elapsed */ + if (error == WOLFSSL_ERROR_WANT_WRITE) { + /* Do a send select here. */ + select_ret = tcp_select_tx(sockfd, 1); + if (select_ret == TEST_TIMEOUT) { + error = WOLFSSL_FATAL_ERROR; + } + } } else if (select_ret == TEST_TIMEOUT && !wolfSSL_dtls(ssl)) { error = WOLFSSL_ERROR_WANT_READ; diff --git a/examples/server/server.c b/examples/server/server.c index a64f2cfda4..105ac547dd 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -115,6 +115,138 @@ static void err_sys_ex(int out, const char* msg) } } + +#ifdef WOLFSSL_DTLS + +/* Translates return codes returned from + * send() and recv() if need be. + */ +static WC_INLINE int TranslateReturnCode(int old, int sd) +{ + (void)sd; + +#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + if (old == 0) { + errno = SOCKET_EWOULDBLOCK; + return -1; /* convert to BSD style wouldblock as error */ + } + + if (old < 0) { + errno = RTCS_geterror(sd); + if (errno == RTCSERR_TCP_CONN_CLOSING) + return 0; /* convert to BSD style closing */ + if (errno == RTCSERR_TCP_CONN_RLSD) + errno = SOCKET_ECONNRESET; + if (errno == RTCSERR_TCP_TIMED_OUT) + errno = SOCKET_EAGAIN; + } +#endif + + return old; +} + +static WC_INLINE int wolfSSL_LastError(void) +{ +#ifdef USE_WINDOWS_API + return WSAGetLastError(); +#elif defined(EBSNET) + return xn_getlasterror(); +#else + return errno; +#endif +} + +/* wolfSSL Sock Addr */ +struct WOLFSSL_TEST_SOCKADDR { + unsigned int sz; /* sockaddr size */ + SOCKADDR_IN_T sa; /* pointer to the sockaddr_in or sockaddr_in6 */ +}; + +typedef struct WOLFSSL_TEST_DTLS_CTX { + struct WOLFSSL_TEST_SOCKADDR peer; + int rfd; + int wfd; + int failOnce; + word32 blockSeq; +} WOLFSSL_TEST_DTLS_CTX; + + +static WC_INLINE int PeekSeq(const char* buf, word32* seq) +{ + const char* c = buf + 3; + + if ((c[0] | c[1] | c[2] | c[3]) == 0) { + *seq = (c[4] << 24) | (c[5] << 16) | (c[6] << 8) | c[7]; + return 1; + } + + return 0; +} + + +/* The send embedded callback + * return : nb bytes sent, or error + */ +static int TestEmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_TEST_DTLS_CTX* dtlsCtx = (WOLFSSL_TEST_DTLS_CTX*)ctx; + int sd = dtlsCtx->wfd; + int sent; + int len = sz; + int err; + + (void)ssl; + + WOLFSSL_ENTER("TestEmbedSendTo()"); + + if (dtlsCtx->failOnce) { + word32 seq = 0; + + if (PeekSeq(buf, &seq) && seq == dtlsCtx->blockSeq) { + dtlsCtx->failOnce = 0; + WOLFSSL_MSG("Forcing WANT_WRITE"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + } + + sent = (int)sendto(sd, &buf[sz - len], len, 0, + (const SOCKADDR*)&dtlsCtx->peer.sa, + dtlsCtx->peer.sz); + + sent = TranslateReturnCode(sent, sd); + + if (sent < 0) { + err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Send To error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + WOLFSSL_MSG("\tWould Block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_EPIPE) { + WOLFSSL_MSG("\tSocket EPIPE"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return sent; +} + +#endif /* WOLFSSL_DTLS */ + + static int NonBlockingSSL_Accept(SSL* ssl) { #ifndef WOLFSSL_CALLBACKS @@ -149,13 +281,16 @@ static int NonBlockingSSL_Accept(SSL* ssl) else #endif { - #ifdef WOLFSSL_DTLS - currTimeout = wolfSSL_dtls_get_current_timeout(ssl); - #endif - select_ret = tcp_select(sockfd, currTimeout); + if (error != WOLFSSL_ERROR_WANT_WRITE) { + #ifdef WOLFSSL_DTLS + currTimeout = wolfSSL_dtls_get_current_timeout(ssl); + #endif + select_ret = tcp_select(sockfd, currTimeout); + } } - if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_ERROR_READY) + if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_SEND_READY) + || (select_ret == TEST_ERROR_READY) #ifdef WOLFSSL_ASYNC_CRYPT || error == WC_PENDING_E #endif @@ -167,6 +302,12 @@ static int NonBlockingSSL_Accept(SSL* ssl) srvHandShakeCB, srvTimeoutCB, srvTo); #endif error = SSL_get_error(ssl, 0); + if (error == WOLFSSL_ERROR_WANT_WRITE) { + /* Do a select here. */ + select_ret = tcp_select_tx(sockfd, 1); + if (select_ret == TEST_TIMEOUT) + error = WOLFSSL_FATAL_ERROR; + } } else if (select_ret == TEST_TIMEOUT && !wolfSSL_dtls(ssl)) { error = WOLFSSL_ERROR_WANT_READ; @@ -678,6 +819,9 @@ static void Usage(void) !defined(HAVE_SELFTEST) && !defined(WOLFSSL_OLD_PRIME_CHECK) printf("-2 Disable DH Prime check\n"); #endif +#ifdef WOLFSSL_DTLS + printf("-4 DTLS fake would-block for message seq\n"); +#endif #ifdef WOLFSSL_MULTICAST printf("%s", msg[++msgId]); /* -3 */ #endif @@ -719,6 +863,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) int dtlsUDP = 0; int dtlsSCTP = 0; int doMcast = 0; +#ifdef WOLFSSL_DTLS + int doBlockSeq = 0; + WOLFSSL_TEST_DTLS_CTX dtlsCtx; +#endif int needDH = 0; int useNtruKey = 0; int nonBlocking = 0; @@ -863,7 +1011,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:mnop:q:rstuv:wxy" "A:B:C:D:E:GH:IJKL:MNO:PQR:S:TUVYZ:" - "01:23:")) != -1) { + "01:23:4:")) != -1) { switch (ch) { case '?' : if(myoptarg!=NULL) { @@ -1219,6 +1367,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif break; + case '4' : + #ifdef WOLFSSL_DTLS + XMEMSET(&dtlsCtx, 0, sizeof(dtlsCtx)); + doBlockSeq = 1; + dtlsCtx.blockSeq = atoi(myoptarg); + #endif + break; + default: Usage(); XEXIT_T(MY_EX_USAGE); @@ -1598,6 +1754,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif } + if (doDTLS && dtlsUDP) { +#ifdef WOLFSSL_DTLS + if (doBlockSeq) { + wolfSSL_CTX_SetIOSend(ctx, TestEmbedSendTo); + } +#endif + } + #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx); @@ -1807,12 +1971,22 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) /* For DTLS, peek at the next datagram so we can get the client's * address and set it into the ssl object later to generate the * cookie. */ - n = (int)recvfrom(sockfd, (char*)b, sizeof(b), MSG_PEEK, + n = (int)recvfrom(clientfd, (char*)b, sizeof(b), MSG_PEEK, (struct sockaddr*)&cliaddr, &len); if (n <= 0) err_sys_ex(runWithErrors, "recvfrom failed"); - wolfSSL_dtls_set_peer(ssl, &cliaddr, len); + if (doBlockSeq) { + XMEMCPY(&dtlsCtx.peer.sa, &cliaddr, len); + dtlsCtx.peer.sz = len; + dtlsCtx.wfd = clientfd; + dtlsCtx.failOnce = 1; + + wolfSSL_SetIOWriteCtx(ssl, &dtlsCtx); + } + else { + wolfSSL_dtls_set_peer(ssl, &cliaddr, len); + } } #endif if ((usePsk == 0 || usePskPlus) || useAnon == 1 || cipherList != NULL diff --git a/src/internal.c b/src/internal.c index 6a231e3063..4bf2cbe0f6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6003,8 +6003,12 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) DtlsMsg* item; int ret = 0; - if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) + WOLFSSL_ENTER("DtlsMsgPoolSave()"); + + if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) { + WOLFSSL_ERROR(DTLS_POOL_SZ_E); return DTLS_POOL_SZ_E; + } item = DtlsMsgNew(dataSz, ssl->heap); @@ -6027,6 +6031,7 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) else ret = MEMORY_E; + WOLFSSL_LEAVE("DtlsMsgPoolSave()", ret); return ret; } @@ -6039,6 +6044,7 @@ int DtlsMsgPoolTimeout(WOLFSSL* ssl) ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; result = 0; } + WOLFSSL_LEAVE("DtlsMsgPoolTimeout()", result); return result; } @@ -6047,9 +6053,11 @@ int DtlsMsgPoolTimeout(WOLFSSL* ssl) * value. */ void DtlsMsgPoolReset(WOLFSSL* ssl) { + WOLFSSL_ENTER("DtlsMsgPoolReset()"); if (ssl->dtls_tx_msg_list) { DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); ssl->dtls_tx_msg_list = NULL; + ssl->dtls_tx_msg = NULL; ssl->dtls_tx_msg_list_sz = 0; ssl->dtls_timeout = ssl->dtls_timeout_init; } @@ -6078,9 +6086,25 @@ int VerifyForDtlsMsgPoolSend(WOLFSSL* ssl, byte type, word32 fragOffset) int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) { int ret = 0; - DtlsMsg* pool = ssl->dtls_tx_msg_list; + DtlsMsg* pool; + + WOLFSSL_ENTER("DtlsMsgPoolSend()"); + + pool = ssl->dtls_tx_msg == NULL ? ssl->dtls_tx_msg_list : ssl->dtls_tx_msg; if (pool != NULL) { + if ((ssl->options.side == WOLFSSL_SERVER_END && + !(ssl->options.acceptState == SERVER_HELLO_DONE || + ssl->options.acceptState == ACCEPT_FINISHED_DONE)) || + (ssl->options.side == WOLFSSL_CLIENT_END && + !(ssl->options.connectState == CLIENT_HELLO_SENT || + ssl->options.connectState == HELLO_AGAIN_REPLY || + ssl->options.connectState == FINISHED_DONE))) { + + WOLFSSL_ERROR(DTLS_RETX_OVER_TX); + ssl->error = DTLS_RETX_OVER_TX; + return WOLFSSL_FATAL_ERROR; + } while (pool != NULL) { if (pool->seq == 0) { @@ -6098,8 +6122,10 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) WriteSEQ(ssl, epochOrder, dtls->sequence_number); DtlsSEQIncrement(ssl, epochOrder); - if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) + if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) { + WOLFSSL_ERROR(ret); return ret; + } XMEMCPY(ssl->buffers.outputBuffer.buffer, pool->buf, pool->sz); @@ -6115,21 +6141,26 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) inputSz = pool->sz; sendSz = inputSz + MAX_MSG_EXTRA; - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + WOLFSSL_ERROR(ret); return ret; + } output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, handshake, 0, 0, 0); - if (sendSz < 0) + if (sendSz < 0) { + WOLFSSL_ERROR(BUILD_MSG_ERROR); return BUILD_MSG_ERROR; + } ssl->buffers.outputBuffer.length += sendSz; } ret = SendBuffered(ssl); if (ret < 0) { + WOLFSSL_ERROR(ret); return ret; } @@ -6148,9 +6179,11 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) } else pool = pool->next; + ssl->dtls_tx_msg = pool; } } + WOLFSSL_LEAVE("DtlsMsgPoolSend()", ret); return ret; } @@ -7094,6 +7127,7 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (IsDtlsNotSctpMode(ssl) && (!DtlsCheckWindow(ssl) || (ssl->options.handShakeDone && ssl->keys.curEpoch == 0))) { + WOLFSSL_LEAVE("GetRecordHeader()", SEQUENCE_ERROR); return SEQUENCE_ERROR; } #endif @@ -7186,8 +7220,10 @@ static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, word32 idx = *inOutIdx; *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; - if (*inOutIdx > totalSz) + if (*inOutIdx > totalSz) { + WOLFSSL_ERROR(BUFFER_E); return BUFFER_E; + } *type = input[idx++]; c24to32(input + idx, size); @@ -7203,8 +7239,10 @@ static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, if (ssl->curRL.pvMajor != ssl->version.major || ssl->curRL.pvMinor != ssl->version.minor) { - if (*type != client_hello && *type != hello_verify_request) + if (*type != client_hello && *type != hello_verify_request) { + WOLFSSL_ERROR(VERSION_ERROR); return VERSION_ERROR; + } else { WOLFSSL_MSG("DTLS Handshake ignoring hello or verify version"); } @@ -10551,10 +10589,17 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (!ssl->options.resuming && - ssl->msgsReceived.got_server_hello_done == 0) { - WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); - return OUT_OF_ORDER_E; + if (!ssl->options.resuming) { + if (ssl->msgsReceived.got_server_hello_done == 0) { + WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); + return OUT_OF_ORDER_E; + } + } + else { + if (ssl->msgsReceived.got_server_hello == 0) { + WOLFSSL_MSG("No ServerHello before ChangeCipher on Resume"); + return OUT_OF_ORDER_E; + } } #ifdef HAVE_SESSION_TICKET if (ssl->expect_session_ticket) { @@ -11240,6 +11285,8 @@ static int DtlsMsgDrain(WOLFSSL* ssl) DtlsMsg* item = ssl->dtls_rx_msg_list; int ret = 0; + WOLFSSL_ENTER("DtlsMsgDrain()"); + /* While there is an item in the store list, and it is the expected * message, and it is complete, and there hasn't been an error in the * last message... */ @@ -11263,6 +11310,7 @@ static int DtlsMsgDrain(WOLFSSL* ssl) ssl->dtls_rx_msg_list_sz--; } + WOLFSSL_LEAVE("DtlsMsgDrain()", ret); return ret; } @@ -11290,12 +11338,16 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* parse header */ if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, - &size, &fragOffset, &fragSz, totalSz) != 0) + &size, &fragOffset, &fragSz, totalSz) != 0) { + WOLFSSL_ERROR(PARSE_ERROR); return PARSE_ERROR; + } /* check that we have complete fragment */ - if (*inOutIdx + fragSz > totalSz) + if (*inOutIdx + fragSz > totalSz) { + WOLFSSL_ERROR(INCOMPLETE_DATA); return INCOMPLETE_DATA; + } /* Check the handshake sequence number first. If out of order, * add the current message to the list. If the message is in order, @@ -11340,6 +11392,7 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, *inOutIdx += fragSz; if(type == finished ) { if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); return BUFFER_E; } *inOutIdx += ssl->keys.padSz; @@ -13170,8 +13223,10 @@ int ProcessReply(WOLFSSL* ssl) ret = BUFFER_ERROR; #endif } - if (ret != 0) + if (ret != 0) { + WOLFSSL_ERROR(ret); return ret; + } break; case change_cipher_spec: @@ -13446,6 +13501,7 @@ int SendChangeCipher(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { + DtlsSEQIncrement(ssl, CUR_ORDER); if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } @@ -15796,6 +15852,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case EXT_MISSING: return "Required TLS extension missing"; + case DTLS_RETX_OVER_TX: + return "DTLS interrupting flight transmit with retransmit"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index 0111613671..755fe567aa 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8768,6 +8768,8 @@ int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) int timeout = 0; if (ssl) timeout = ssl->dtls_timeout; + + WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout()", timeout); return timeout; } @@ -8810,6 +8812,7 @@ int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) { int result = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_dtls_got_timeout()"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; @@ -8819,9 +8822,32 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) result = WOLFSSL_FATAL_ERROR; } + + WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout()", result); return result; } + +/* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ +int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_retransmit()"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone) { + int result = DtlsMsgPoolSend(ssl, 0); + if (result < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + } + + return 0; +} + #endif /* DTLS */ #endif /* LEANPSK */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 1fd9520f31..827ae0272c 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -163,6 +163,7 @@ enum wolfSSL_ErrorCodes { EXT_MISSING = -428, /* Required extension not found */ UNSUPPORTED_EXTENSION = -429, /* TLSX not requested by client */ PRF_MISSING = -430, /* PRF not compiled in */ + DTLS_RETX_OVER_TX = -431, /* Retransmit DTLS flight over */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a03e86f8cb..a22c367023 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3741,6 +3741,7 @@ struct WOLFSSL { word32 dtls_tx_msg_list_sz; word32 dtls_rx_msg_list_sz; DtlsMsg* dtls_tx_msg_list; + DtlsMsg* dtls_tx_msg; DtlsMsg* dtls_rx_msg_list; void* IOCB_CookieCtx; /* gen cookie ctx */ word32 dtls_expected_rx; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 8986804534..75a4b95589 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -723,6 +723,7 @@ WOLFSSL_API int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int); WOLFSSL_API int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int); WOLFSSL_API int wolfSSL_dtls_got_timeout(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_dtls_retransmit(WOLFSSL*); WOLFSSL_API int wolfSSL_dtls(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL*, void*, unsigned int); diff --git a/wolfssl/test.h b/wolfssl/test.h index 1c61f23af7..a9cc4e8681 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -909,15 +909,18 @@ enum { TEST_SELECT_FAIL, TEST_TIMEOUT, TEST_RECV_READY, + TEST_SEND_READY, TEST_ERROR_READY }; #if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_TCP_NET) && \ !defined(WOLFSSL_TIRTOS) -static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) +static WC_INLINE int tcp_select_ex(SOCKET_T socketfd, int to_sec, int rx) { - fd_set recvfds, errfds; + fd_set fds, errfds; + fd_set* recvfds = NULL; + fd_set* sendfds = NULL; SOCKET_T nfds = socketfd + 1; #if !defined(__INTEGRITY) struct timeval timeout = {(to_sec > 0) ? to_sec : 0, 0}; @@ -926,32 +929,56 @@ static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) #endif int result; - FD_ZERO(&recvfds); - FD_SET(socketfd, &recvfds); + FD_ZERO(&fds); + FD_SET(socketfd, &fds); FD_ZERO(&errfds); FD_SET(socketfd, &errfds); + if (rx) + recvfds = &fds; + else + sendfds = &fds; + #if defined(__INTEGRITY) timeout.tv_sec = (long long)(to_sec > 0) ? to_sec : 0, 0; #endif - result = select(nfds, &recvfds, NULL, &errfds, &timeout); + result = select(nfds, recvfds, sendfds, &errfds, &timeout); if (result == 0) return TEST_TIMEOUT; else if (result > 0) { - if (FD_ISSET(socketfd, &recvfds)) - return TEST_RECV_READY; + if (FD_ISSET(socketfd, &fds)) { + if (rx) + return TEST_RECV_READY; + else + return TEST_SEND_READY; + } else if(FD_ISSET(socketfd, &errfds)) return TEST_ERROR_READY; } return TEST_SELECT_FAIL; } + +static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) +{ + return tcp_select_ex(socketfd, to_sec, 1); +} + +static WC_INLINE int tcp_select_tx(SOCKET_T socketfd, int to_sec) +{ + return tcp_select_ex(socketfd, to_sec, 0); +} + #elif defined(WOLFSSL_TIRTOS) || defined(WOLFSSL_KEIL_TCP_NET) static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) { return TEST_RECV_READY; } +static WC_INLINE int tcp_select_tx(SOCKET_T socketfd, int to_sec) +{ + return TEST_SEND_READY; +} #endif /* !WOLFSSL_MDK_ARM */