From 2719f62feb97c321d87b62145fc9e92f76d3025e Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Mon, 11 Jan 2021 22:29:39 +0100 Subject: [PATCH 1/2] net/SocketError: relicense to BSD-2 --- src/net/SocketError.cxx | 36 +++++++++++++++++++++++------------- src/net/SocketError.hxx | 40 +++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/net/SocketError.cxx b/src/net/SocketError.cxx index 342900efd..2412549dd 100644 --- a/src/net/SocketError.cxx +++ b/src/net/SocketError.cxx @@ -1,20 +1,30 @@ /* - * Copyright 2003-2021 The Music Player Daemon Project - * http://www.musicpd.org + * Copyright 2015-2021 Max Kellermann <max.kellermann@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "SocketError.hxx" diff --git a/src/net/SocketError.hxx b/src/net/SocketError.hxx index 887542828..8e8db1ddf 100644 --- a/src/net/SocketError.hxx +++ b/src/net/SocketError.hxx @@ -1,24 +1,34 @@ /* - * Copyright 2003-2021 The Music Player Daemon Project - * http://www.musicpd.org + * Copyright 2015-2021 Max Kellermann <max.kellermann@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MPD_SOCKET_ERROR_HXX -#define MPD_SOCKET_ERROR_HXX +#ifndef SOCKET_ERROR_HXX +#define SOCKET_ERROR_HXX #include "util/Compiler.h" #include "system/Error.hxx" From 9e2d09dabc5abc8cc98c339c6fd34c769125096c Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 21 Jan 2021 22:04:14 +0100 Subject: [PATCH 2/2] 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)) {