diff --git a/ixwebsocket/IXNetSystem.h b/ixwebsocket/IXNetSystem.h index 2ff12823..061b3622 100644 --- a/ixwebsocket/IXNetSystem.h +++ b/ixwebsocket/IXNetSystem.h @@ -34,6 +34,7 @@ #undef EINPROGRESS #undef EBADF #undef EINVAL +#undef ECONNRESET // map to WSA error codes #define EWOULDBLOCK WSAEWOULDBLOCK @@ -41,6 +42,7 @@ #define EINPROGRESS WSAEINPROGRESS #define EBADF WSAEBADF #define EINVAL WSAEINVAL +#define ECONNRESET WSAECONNRESET // Define our own poll on Windows, as a wrapper on top of select typedef unsigned long int nfds_t; diff --git a/ixwebsocket/IXSocket.cpp b/ixwebsocket/IXSocket.cpp index 8f9e5665..0181db10 100644 --- a/ixwebsocket/IXSocket.cpp +++ b/ixwebsocket/IXSocket.cpp @@ -286,6 +286,17 @@ namespace ix return err; } + void Socket::setErrno(int err) + { +#ifdef _WIN32 + // getErrno() reads WSAGetLastError() on Windows, the CRT errno is + // invisible to it + WSASetLastError(err); +#else + errno = err; +#endif + } + bool Socket::isWaitNeeded() { int err = getErrno(); diff --git a/ixwebsocket/IXSocket.h b/ixwebsocket/IXSocket.h index 411371bb..6c9f54de 100644 --- a/ixwebsocket/IXSocket.h +++ b/ixwebsocket/IXSocket.h @@ -81,6 +81,7 @@ namespace ix const CancellationRequest& isCancellationRequested); static int getErrno(); + static void setErrno(int err); static bool isWaitNeeded(); static void closeSocket(socket_t fd); diff --git a/ixwebsocket/IXSocketAppleSSL.cpp b/ixwebsocket/IXSocketAppleSSL.cpp index 3a529dd2..caa6ae16 100644 --- a/ixwebsocket/IXSocketAppleSSL.cpp +++ b/ixwebsocket/IXSocketAppleSSL.cpp @@ -267,13 +267,13 @@ namespace ix if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify || status == errSSLClosedAbort) { - errno = ECONNRESET; + Socket::setErrno(ECONNRESET); return -1; } if (status == errSSLWouldBlock) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); return -1; } } @@ -297,13 +297,13 @@ namespace ix if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify || status == errSSLClosedAbort) { - errno = ECONNRESET; + Socket::setErrno(ECONNRESET); return -1; } if (status == errSSLWouldBlock) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); return -1; } } diff --git a/ixwebsocket/IXSocketMbedTLS.cpp b/ixwebsocket/IXSocketMbedTLS.cpp index aa404f76..fc2013a1 100644 --- a/ixwebsocket/IXSocketMbedTLS.cpp +++ b/ixwebsocket/IXSocketMbedTLS.cpp @@ -347,7 +347,7 @@ namespace ix } else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); return -1; } else @@ -369,14 +369,30 @@ namespace ix return res; } + // TLS 1.3 (mbedtls 3.6+): the server can send post-handshake messages + // (NewSessionTicket, early data) which surface as non-fatal "read again" + // return codes. Retry the read instead of treating them as errors. +#if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) + if (res == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) + { + continue; + } +#endif +#if defined(MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) + if (res == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) + { + continue; + } +#endif + if (res == 0) { - errno = ECONNRESET; + Socket::setErrno(ECONNRESET); } if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); } return -1; } diff --git a/ixwebsocket/IXSocketOpenSSL.cpp b/ixwebsocket/IXSocketOpenSSL.cpp index 5ce165f4..93863315 100644 --- a/ixwebsocket/IXSocketOpenSSL.cpp +++ b/ixwebsocket/IXSocketOpenSSL.cpp @@ -837,7 +837,7 @@ namespace ix } else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); return -1; } else @@ -869,7 +869,7 @@ namespace ix if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE) { - errno = EWOULDBLOCK; + Socket::setErrno(EWOULDBLOCK); } return -1; }