diff --git a/doc/dox_comments/header_files/wolfio.h b/doc/dox_comments/header_files/wolfio.h index 42a39dfe67b..a081cb1e33c 100644 --- a/doc/dox_comments/header_files/wolfio.h +++ b/doc/dox_comments/header_files/wolfio.h @@ -459,7 +459,9 @@ void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags); \param nxsocket a pointer to type NX_TCP_SOCKET that is set to the nxTcpSocket member of the nxCtx structure. \param waitoption a ULONG type that is set to the nxWait member of - the nxCtx structure. + the nxCtx structure. With NX_NO_WAIT, or any wait option that can expire, + the callbacks report WANT_READ/WANT_WRITE instead of a fatal error, so + the wolfSSL call can be retried. _Example_ \code @@ -496,6 +498,10 @@ void wolfSSL_SetIO_NetX(WOLFSSL* ssl, NX_TCP_SOCKET* nxsocket, \param nxdip the destination NXD_ADDRESS (passed by value; IPv4 or IPv6). \param nxport the destination UDP port number. \param waitoption a ULONG NetX wait option (e.g. NX_WAIT_FOREVER or ticks). + With NX_NO_WAIT, or any wait option that can expire, NetX_SendTo reports + WANT_WRITE instead of a fatal error. A receive that expires reports + WANT_READ when the session is set non blocking, and a timeout otherwise so + that DTLS can retransmit. _Example_ \code diff --git a/src/wolfio.c b/src/wolfio.c index a87db3bb5c6..beaf3ace74e 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -2807,6 +2807,46 @@ void wolfSSL_CTX_SetIOSetPeer(WOLFSSL_CTX* ctx, CallbackSetPeer cb) #ifdef HAVE_NETX +/* Map a failing NetX status onto a wolfSSL CBIO error code. + * Transient conditions must not be reported as fatal, otherwise a non + * blocking (or short wait option) setup cannot retry the operation. */ +static int NetX_TranslateReturnCode(UINT status, int direction) +{ + int ret; + + switch (status) { + /* Receive queue empty, packet pool exhausted, peer receive window + * full or transmit queue at max depth. All clear on their own. */ + case NX_NO_PACKET: + case NX_WINDOW_OVERFLOW: + case NX_TX_QUEUE_DEPTH: + WOLFSSL_MSG("\tWould block"); + ret = (direction == SOCKET_SENDING) ? WOLFSSL_CBIO_ERR_WANT_WRITE + : WOLFSSL_CBIO_ERR_WANT_READ; + break; + + /* A suspended wait was aborted, treated like an interrupted call. */ + case NX_WAIT_ABORTED: + WOLFSSL_MSG("\tSocket interrupted"); + ret = WOLFSSL_CBIO_ERR_ISR; + break; + + /* NetX has no separate reset status, so a peer reset also lands + * here and is reported as a close. */ + case NX_NOT_CONNECTED: + WOLFSSL_MSG("\tConnection closed"); + ret = WOLFSSL_CBIO_ERR_CONN_CLOSE; + break; + + default: + WOLFSSL_MSG_EX("\tGeneral error: %u", (unsigned int)status); + ret = WOLFSSL_CBIO_ERR_GENERAL; + break; + } + + return ret; +} + /* The NetX receive callback for TLS * return : bytes read, or error */ @@ -2830,7 +2870,7 @@ int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx) nxCtx->nxWait); if (status != NX_SUCCESS) { WOLFSSL_MSG("NetX Recv receive error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_RECEIVING); } } @@ -2885,21 +2925,21 @@ int NetX_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx) nxCtx->nxWait); if (status != NX_SUCCESS) { WOLFSSL_MSG("NetX Send packet alloc error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait); if (status != NX_SUCCESS) { nx_packet_release(packet); WOLFSSL_MSG("NetX Send data append error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } status = nx_tcp_socket_send(nxCtx->nxTcpSocket, packet, nxCtx->nxWait); if (status != NX_SUCCESS) { nx_packet_release(packet); WOLFSSL_MSG("NetX Send socket send error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } return sz; @@ -3019,7 +3059,7 @@ int NetX_ReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) : WOLFSSL_CBIO_ERR_TIMEOUT; } WOLFSSL_MSG("NetX Recv receive error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_RECEIVING); } status = nxd_udp_source_extract(nxCtx->nxPacket, &srcIp, &srcPort); @@ -3137,14 +3177,14 @@ int NetX_SendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) nxCtx->nxWait); if (status != NX_SUCCESS) { WOLFSSL_MSG("NetX Send packet alloc error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait); if (status != NX_SUCCESS) { nx_packet_release(packet); WOLFSSL_MSG("NetX Send data append error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } if (nxCtx->nxdIp.nxd_ip_version == NX_IP_VERSION_V4) { @@ -3159,7 +3199,7 @@ int NetX_SendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) if (status != NX_SUCCESS) { nx_packet_release(packet); WOLFSSL_MSG("NetX Send socket send error"); - return WOLFSSL_CBIO_ERR_GENERAL; + return NetX_TranslateReturnCode(status, SOCKET_SENDING); } return sz; diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 2194c254c29..4d578d61182 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -411,10 +411,14 @@ #define SOCKET_ECONNREFUSED SOCKET_ERROR #define SOCKET_ECONNABORTED SOCKET_ERROR #elif defined(HAVE_NETX) - #define SOCKET_EWOULDBLOCK NX_NOT_CONNECTED - #define SOCKET_EAGAIN NX_NOT_CONNECTED + /* NetX has no errno, these map onto the closest nx_api.h status codes. + * A send can also block as NX_WINDOW_OVERFLOW or NX_TX_QUEUE_DEPTH, so + * use the WANT_READ/WANT_WRITE the callbacks return rather than testing + * a NetX status against these. */ + #define SOCKET_EWOULDBLOCK NX_NO_PACKET + #define SOCKET_EAGAIN NX_NO_PACKET #define SOCKET_ECONNRESET NX_NOT_CONNECTED - #define SOCKET_EINTR NX_NOT_CONNECTED + #define SOCKET_EINTR NX_WAIT_ABORTED #define SOCKET_EPIPE NX_NOT_CONNECTED #define SOCKET_ECONNREFUSED NX_NOT_CONNECTED #define SOCKET_ECONNABORTED NX_NOT_CONNECTED