From 9e2d09dabc5abc8cc98c339c6fd34c769125096c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 21 Jan 2021 22:04:14 +0100 Subject: [PATCH] net/SocketError: add syscall specific check functions Fixes Windows compatibility. --- NEWS | 2 + src/event/BufferedSocket.cxx | 2 +- src/event/FullyBufferedSocket.cxx | 2 +- src/net/SocketError.hxx | 73 ++++++++++++++++++++++-- src/output/plugins/httpd/HttpdClient.cxx | 6 +- 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index c67ff4e81..8d0c6455a 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.22.5 (not yet released) +* output + - httpd: error handling on Windows improved ver 0.22.4 (2021/01/21) * protocol diff --git a/src/event/BufferedSocket.cxx b/src/event/BufferedSocket.cxx index d40d2c013..5fa31afd1 100644 --- a/src/event/BufferedSocket.cxx +++ b/src/event/BufferedSocket.cxx @@ -36,7 +36,7 @@ BufferedSocket::DirectRead(void *data, size_t length) noexcept } const auto code = GetSocketError(); - if (IsSocketErrorAgain(code)) + if (IsSocketErrorReceiveWouldBlock(code)) return 0; if (IsSocketErrorClosed(code)) diff --git a/src/event/FullyBufferedSocket.cxx b/src/event/FullyBufferedSocket.cxx index 5f9dc544d..56390b679 100644 --- a/src/event/FullyBufferedSocket.cxx +++ b/src/event/FullyBufferedSocket.cxx @@ -31,7 +31,7 @@ FullyBufferedSocket::DirectWrite(const void *data, size_t length) noexcept const auto nbytes = GetSocket().Write((const char *)data, length); if (gcc_unlikely(nbytes < 0)) { const auto code = GetSocketError(); - if (IsSocketErrorAgain(code)) + if (IsSocketErrorSendWouldBlock(code)) return 0; IdleMonitor::Cancel(); diff --git a/src/net/SocketError.hxx b/src/net/SocketError.hxx index 8e8db1ddf..44989c52f 100644 --- a/src/net/SocketError.hxx +++ b/src/net/SocketError.hxx @@ -52,14 +52,79 @@ GetSocketError() noexcept #endif } -gcc_const -static inline bool -IsSocketErrorAgain(socket_error_t code) noexcept +constexpr bool +IsSocketErrorInProgress(socket_error_t code) noexcept { #ifdef _WIN32 return code == WSAEINPROGRESS; #else - return code == EAGAIN; + return code == EINPROGRESS; +#endif +} + +constexpr bool +IsSocketErrorWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + return code == WSAEWOULDBLOCK; +#else + return code == EWOULDBLOCK; +#endif +} + +constexpr bool +IsSocketErrorConnectWouldBlock(socket_error_t code) noexcept +{ +#if defined(_WIN32) || defined(__linux__) + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + /* on Linux, EAGAIN==EWOULDBLOCK is for local sockets and + EINPROGRESS is for all other sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just EINPROGRESS */ + return IsSocketErrorInProgress(code); +#endif +} + +constexpr bool +IsSocketErrorSendWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); +#endif +} + +constexpr bool +IsSocketErrorReceiveWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just + EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); +#endif +} + +constexpr bool +IsSocketErrorAcceptWouldBlock(socket_error_t code) noexcept +{ +#ifdef _WIN32 + /* on Windows, WSAEINPROGRESS is for blocking sockets and + WSAEWOULDBLOCK for non-blocking sockets */ + return IsSocketErrorInProgress(code) || IsSocketErrorWouldBlock(code); +#else + /* on all other operating systems, there's just + EAGAIN==EWOULDBLOCK */ + return IsSocketErrorWouldBlock(code); #endif } diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx index 16593001c..c5e2d819e 100644 --- a/src/output/plugins/httpd/HttpdClient.cxx +++ b/src/output/plugins/httpd/HttpdClient.cxx @@ -278,7 +278,7 @@ HttpdClient::TryWrite() noexcept metadata_current_position); if (nbytes < 0) { auto e = GetSocketError(); - if (IsSocketErrorAgain(e)) + if (IsSocketErrorSendWouldBlock(e)) return true; if (!IsSocketErrorClosed(e)) { @@ -305,7 +305,7 @@ HttpdClient::TryWrite() noexcept ssize_t nbytes = GetSocket().Write(&empty_data, 1); if (nbytes < 0) { auto e = GetSocketError(); - if (IsSocketErrorAgain(e)) + if (IsSocketErrorSendWouldBlock(e)) return true; if (!IsSocketErrorClosed(e)) { @@ -328,7 +328,7 @@ HttpdClient::TryWrite() noexcept bytes_to_write); if (nbytes < 0) { auto e = GetSocketError(); - if (IsSocketErrorAgain(e)) + if (IsSocketErrorSendWouldBlock(e)) return true; if (!IsSocketErrorClosed(e)) {