Network: Fix TcpClient::PollConnection on Linux

This commit is contained in:
Jérôme Leclercq 2020-10-31 17:33:56 +01:00
parent 602de2e772
commit f52c43df49
2 changed files with 49 additions and 57 deletions

View File

@ -411,32 +411,40 @@ namespace Nz
SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error)
{ {
// http://developerweb.net/viewtopic.php?id=3196 // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails)
fd_set localSet; pollfd descriptor;
FD_ZERO(&localSet); descriptor.events = POLLOUT;
FD_SET(handle, &localSet); descriptor.fd = handle;
descriptor.revents = 0;
timeval tv; int ret = ::poll(&descriptor, 1, (msTimeout != std::numeric_limits<UInt64>::max()) ? int(msTimeout) : -1);
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL); if (ret == SOCKET_ERROR)
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits<UInt64>::max()) ? &tv : nullptr);
if (ret > 0)
{ {
int code = GetLastErrorCode(handle, error); if (error)
if (code < 0) //< GetLastErrorCode() failed *error = TranslateErrnoToSocketError(GetLastErrorCode());
return SocketState_NotConnected;
if (code) return SocketState_NotConnected;
}
else if (ret > 0)
{
if (descriptor.revents & (POLLERR | POLLHUP))
{ {
if (error) if (error)
*error = TranslateErrnoToSocketError(code); *error = GetLastError(handle);
return SocketState_NotConnected; 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 (error)
{ {
if (msTimeout > 0) if (msTimeout > 0)
@ -447,18 +455,6 @@ namespace Nz
return SocketState_Connecting; 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) bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)

View File

@ -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" // This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp // 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) SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error)
{ {
// http://developerweb.net/viewtopic.php?id=3196 // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails)
fd_set localSet; WSAPOLLFD descriptor;
FD_ZERO(&localSet); descriptor.events = POLLWRNORM;
FD_SET(handle, &localSet); descriptor.fd = handle;
descriptor.revents = 0;
timeval tv; int ret = WSAPoll(&descriptor, 1, (msTimeout != std::numeric_limits<UInt64>::max()) ? INT(msTimeout) : INT(-1));
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL); if (ret == SOCKET_ERROR)
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits<UInt64>::max()) ? &tv : nullptr);
if (ret > 0)
{ {
int code = GetLastErrorCode(handle, error); if (error)
if (code < 0) //< GetLastErrorCode() failed *error = TranslateWSAErrorToSocketError(WSAGetLastError());
return SocketState_NotConnected;
if (code) return SocketState_NotConnected;
}
else if (ret > 0)
{
if (descriptor.revents & (POLLERR | POLLHUP))
{ {
if (error) if (error)
*error = TranslateWSAErrorToSocketError(code); *error = GetLastError(handle);
return SocketState_NotConnected; 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 (error)
{ {
if (msTimeout > 0) if (msTimeout > 0)
@ -488,18 +496,6 @@ namespace Nz
return SocketState_Connecting; 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) bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)