From f52c43df49a469e9a206c6b55e6cc1e343c9a021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sat, 31 Oct 2020 17:33:56 +0100 Subject: [PATCH] Network: Fix TcpClient::PollConnection on Linux --- src/Nazara/Network/Posix/SocketImpl.cpp | 52 +++++++++++------------- src/Nazara/Network/Win32/SocketImpl.cpp | 54 ++++++++++++------------- 2 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index af0b5557f..d0386a891 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -411,32 +411,40 @@ namespace Nz SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) { - // http://developerweb.net/viewtopic.php?id=3196 - fd_set localSet; - FD_ZERO(&localSet); - FD_SET(handle, &localSet); + // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails) + pollfd descriptor; + descriptor.events = POLLOUT; + descriptor.fd = handle; + descriptor.revents = 0; - timeval tv; - tv.tv_sec = static_cast(msTimeout / 1000ULL); - tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - - int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits::max()) ? &tv : nullptr); - if (ret > 0) + int ret = ::poll(&descriptor, 1, (msTimeout != std::numeric_limits::max()) ? int(msTimeout) : -1); + if (ret == SOCKET_ERROR) { - int code = GetLastErrorCode(handle, error); - if (code < 0) //< GetLastErrorCode() failed - return SocketState_NotConnected; + if (error) + *error = TranslateErrnoToSocketError(GetLastErrorCode()); - if (code) + return SocketState_NotConnected; + } + else if (ret > 0) + { + if (descriptor.revents & (POLLERR | POLLHUP)) { if (error) - *error = TranslateErrnoToSocketError(code); + *error = GetLastError(handle); return SocketState_NotConnected; } + else if (descriptor.revents & POLLOUT) + return SocketState_Connected; + else + { + NazaraWarning("Socket " + String::Number(handle) + " was returned by poll without POLLOUT nor error events (events: 0x" + String::Number(descriptor.revents, 16) + ')'); + return SocketState_NotConnected; + } } - else if (ret == 0) + else { + // Still connecting if (error) { if (msTimeout > 0) @@ -447,18 +455,6 @@ namespace Nz return SocketState_Connecting; } - else - { - if (error) - *error = TranslateErrnoToSocketError(GetLastErrorCode()); - - return SocketState_NotConnected; - } - - if (error) - *error = SocketError_NoError; - - return SocketState_Connected; } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index f9e4b42f5..157f14811 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -452,32 +452,40 @@ namespace Nz SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) { - // http://developerweb.net/viewtopic.php?id=3196 - fd_set localSet; - FD_ZERO(&localSet); - FD_SET(handle, &localSet); + // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails) + WSAPOLLFD descriptor; + descriptor.events = POLLWRNORM; + descriptor.fd = handle; + descriptor.revents = 0; - timeval tv; - tv.tv_sec = static_cast(msTimeout / 1000ULL); - tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - - int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits::max()) ? &tv : nullptr); - if (ret > 0) + int ret = WSAPoll(&descriptor, 1, (msTimeout != std::numeric_limits::max()) ? INT(msTimeout) : INT(-1)); + if (ret == SOCKET_ERROR) { - int code = GetLastErrorCode(handle, error); - if (code < 0) //< GetLastErrorCode() failed - return SocketState_NotConnected; + if (error) + *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - if (code) + return SocketState_NotConnected; + } + else if (ret > 0) + { + if (descriptor.revents & (POLLERR | POLLHUP)) { if (error) - *error = TranslateWSAErrorToSocketError(code); + *error = GetLastError(handle); return SocketState_NotConnected; } + else if (descriptor.revents & POLLWRNORM) + return SocketState_Connected; + else + { + NazaraWarning("Socket " + String::Number(handle) + " was returned by poll without POLLOUT nor error events (events: 0x" + String::Number(descriptor.revents, 16) + ')'); + return SocketState_NotConnected; + } } - else if (ret == 0) + else { + // Still connecting if (error) { if (msTimeout > 0) @@ -488,18 +496,6 @@ namespace Nz return SocketState_Connecting; } - else - { - if (error) - *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - - return SocketState_NotConnected; - } - - if (error) - *error = SocketError_NoError; - - return SocketState_Connected; } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)