Network/TcpClient: Add PollForConnected

This commit is contained in:
Lynix 2018-10-01 23:04:53 +02:00
parent dad2dbae1c
commit 67c56b2aba
7 changed files with 159 additions and 119 deletions

View File

@ -149,6 +149,7 @@ Nazara Engine:
- ⚠️ AbstractSocket::OnStateChange has been replaced by OnStateChanged, which is now called after state has been changed (with oldState and newState as parameters).
- ⚠️ TcpClient::WaitForconnected now closes the socket on failure.
- ⚠️ TcpClient::WaitForconnected now returns the new socket state.
- Added TcpClient::PollForConnected
Nazara Development Kit:
- Added ImageWidget (#139)

View File

@ -45,6 +45,8 @@ namespace Nz
inline bool IsLowDelayEnabled() const;
inline bool IsKeepAliveEnabled() const;
SocketState PollForConnected(UInt64 waitDuration = 0);
bool Receive(void* buffer, std::size_t size, std::size_t* received);
bool ReceivePacket(NetPacket* packet);

View File

@ -138,59 +138,6 @@ namespace Nz
return SocketState_Connected;
}
SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error)
{
SocketState state = Connect(handle, address, error);
if (state == SocketState_Connecting)
{
// http://developerweb.net/viewtopic.php?id=3196
fd_set localSet;
FD_ZERO(&localSet);
FD_SET(handle, &localSet);
timeval tv;
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
int ret = select(handle + 1, nullptr, &localSet, &localSet, (msTimeout > 0) ? &tv : nullptr);
if (ret > 0)
{
int code = GetLastErrorCode(handle, error);
if (code < 0) //< GetLastErrorCode() failed
return SocketState_NotConnected;
if (code)
{
if (error)
*error = TranslateErrnoToSocketError(code);
return SocketState_NotConnected;
}
}
else if (ret == 0)
{
if (error)
*error = SocketError_TimedOut;
return SocketState_NotConnected;
}
else
{
if (error)
*error = TranslateErrnoToSocketError(GetLastErrorCode());
return SocketState_NotConnected;
}
if (error)
*error = SocketError_NoError;
state = SocketState_Connected;
}
return state;
}
bool SocketImpl::Initialize()
{
return true;
@ -462,6 +409,58 @@ namespace Nz
return static_cast<unsigned int>(result);
}
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);
timeval tv;
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout >= 0 && msTimeout != std::numeric_limits<UInt64>::max()) ? &tv : nullptr);
if (ret > 0)
{
int code = GetLastErrorCode(handle, error);
if (code < 0) //< GetLastErrorCode() failed
return SocketState_NotConnected;
if (code)
{
if (error)
*error = TranslateWSAErrorToSocketError(code);
return SocketState_NotConnected;
}
}
else if (ret == 0)
{
if (error)
{
if (msTimeout > 0)
*error = SocketError_TimedOut;
else
*error = SocketError_NoError;
}
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)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");

View File

@ -40,7 +40,6 @@ namespace Nz
static void Close(SocketHandle handle);
static SocketState Connect(SocketHandle handle, const IpAddress& address, SocketError* error);
static SocketState Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error);
static bool Initialize();
@ -61,6 +60,7 @@ namespace Nz
static std::size_t QuerySendBufferSize(SocketHandle handle, SocketError* error = nullptr);
static unsigned int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error);
static SocketState PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error);
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);

View File

@ -173,6 +173,50 @@ namespace Nz
return QueryAvailableBytes();
}
/*!
* \brief Polls the connection status of the currently connecting socket
* \return New socket state, which maybe unchanged (if connecting is still pending), SocketState_Connected if connection is successful or SocketState_NotConnected if connection failed
*
* This functions checks if the pending connection has either succeeded, failed or is still processing at the time of the call.
*
* \remark This function doesn't do anything if the socket is not currently connecting.
*
* \see WaitForConnected
*/
SocketState TcpClient::PollForConnected(UInt64 waitDuration)
{
switch (m_state)
{
case SocketState_Connecting:
{
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
SocketState newState = SocketImpl::PollConnection(m_handle, m_peerAddress, waitDuration, &m_lastError);
// Prevent valid peer address in non-connected state
if (newState == SocketState_NotConnected)
{
m_openMode = OpenMode_NotOpen;
m_peerAddress = IpAddress::Invalid;
}
UpdateState(newState);
return newState;
}
case SocketState_Connected:
case SocketState_NotConnected:
return m_state;
case SocketState_Bound:
case SocketState_Resolving:
break;
}
NazaraInternalError("Unexpected socket state (0x" + String::Number(m_state, 16) + ')');
return m_state;
}
/*!
* \brief Receives the data available
* \return true If data received
@ -439,6 +483,8 @@ namespace Nz
* \param msTimeout Time in milliseconds before time out (0 for system-specific duration, like a blocking connect would)
*
* \remark This function doesn't do anything if the socket is not currently connecting.
*
* \see PollForConnected
*/
SocketState TcpClient::WaitForConnected(UInt64 msTimeout)
{
@ -448,18 +494,11 @@ namespace Nz
{
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle");
CallOnExit restoreBlocking;
if (m_isBlockingEnabled)
{
SocketImpl::SetBlocking(m_handle, false);
restoreBlocking.Reset([this] ()
{
SocketImpl::SetBlocking(m_handle, true);
});
}
SocketState newState = SocketImpl::PollConnection(m_handle, m_peerAddress, (msTimeout > 0) ? msTimeout : std::numeric_limits<UInt64>::max(), &m_lastError);
SocketState newState = SocketImpl::Connect(m_handle, m_peerAddress, msTimeout, &m_lastError);
NazaraAssert(newState != SocketState_Connecting, "Invalid internal return"); //< Connect cannot return Connecting is a timeout was specified
// If connection is still pending after waiting, cancel it
if (newState == SocketState_Connecting)
newState = SocketState_NotConnected;
// Prevent valid stats in non-connected state
if (newState == SocketState_NotConnected)

View File

@ -154,59 +154,6 @@ namespace Nz
return SocketState_Connected;
}
SocketState SocketImpl::Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error)
{
SocketState state = Connect(handle, address, error);
if (state == SocketState_Connecting)
{
// http://developerweb.net/viewtopic.php?id=3196
fd_set localSet;
FD_ZERO(&localSet);
FD_SET(handle, &localSet);
timeval tv;
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
int ret = select(0, nullptr, &localSet, &localSet, (msTimeout > 0) ? &tv : nullptr);
if (ret > 0)
{
int code = GetLastErrorCode(handle, error);
if (code < 0) //< GetLastErrorCode() failed
return SocketState_NotConnected;
if (code)
{
if (error)
*error = TranslateWSAErrorToSocketError(code);
return SocketState_NotConnected;
}
}
else if (ret == 0)
{
if (error)
*error = SocketError_TimedOut;
return SocketState_NotConnected;
}
else
{
if (error)
*error = TranslateWSAErrorToSocketError(WSAGetLastError());
return SocketState_NotConnected;
}
if (error)
*error = SocketError_NoError;
state = SocketState_Connected;
}
return state;
}
bool SocketImpl::Initialize()
{
int errorCode = WSAStartup(MAKEWORD(2, 2), &s_WSA);
@ -502,6 +449,58 @@ namespace Nz
return 0;
#endif
}
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);
timeval tv;
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
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 (code < 0) //< GetLastErrorCode() failed
return SocketState_NotConnected;
if (code)
{
if (error)
*error = TranslateWSAErrorToSocketError(code);
return SocketState_NotConnected;
}
}
else if (ret == 0)
{
if (error)
{
if (msTimeout > 0)
*error = SocketError_TimedOut;
else
*error = SocketError_NoError;
}
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)
{

View File

@ -40,7 +40,6 @@ namespace Nz
static void Close(SocketHandle handle);
static SocketState Connect(SocketHandle handle, const IpAddress& address, SocketError* error);
static SocketState Connect(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error);
static bool Initialize();
@ -61,6 +60,7 @@ namespace Nz
static std::size_t QuerySendBufferSize(SocketHandle handle, SocketError* error = nullptr);
static unsigned int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error);
static SocketState PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error);
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);