Network/SocketPoller: Makes it possible to watch read and write states

This commit is contained in:
Lynix
2017-05-16 09:07:28 +02:00
parent 7425993d2d
commit 65d3b59e03
9 changed files with 192 additions and 93 deletions

View File

@@ -10,29 +10,43 @@ namespace Nz
SocketPollerImpl::SocketPollerImpl()
{
#if !NAZARA_NETWORK_POLL_SUPPORT
FD_ZERO(&m_activeSockets);
FD_ZERO(&m_sockets);
FD_ZERO(&m_readSockets);
FD_ZERO(&m_readyToReadSockets);
FD_ZERO(&m_readyToWriteSockets);
FD_ZERO(&m_writeSockets);
#endif
}
void SocketPollerImpl::Clear()
{
#if NAZARA_NETWORK_POLL_SUPPORT
m_activeSockets.clear();
m_allSockets.clear();
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
m_sockets.clear();
#else
FD_ZERO(&m_activeSockets);
FD_ZERO(&m_sockets);
FD_ZERO(&m_readSockets);
FD_ZERO(&m_readyToReadSockets);
FD_ZERO(&m_readyToWriteSockets);
FD_ZERO(&m_writeSockets);
#endif
}
bool SocketPollerImpl::IsReady(SocketHandle socket) const
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
{
#if NAZARA_NETWORK_POLL_SUPPORT
return m_activeSockets.count(socket) != 0;
return m_readyToReadSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_activeSockets) != 0;
return FD_ISSET(socket, &m_readyToReadSockets) != 0;
#endif
}
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
{
#if NAZARA_NETWORK_POLL_SUPPORT
return m_readyToWriteSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_readyToWriteSockets) != 0;
#endif
}
@@ -41,31 +55,45 @@ namespace Nz
#if NAZARA_NETWORK_POLL_SUPPORT
return m_allSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_sockets) != 0;
return FD_ISSET(socket, &m_readSockets) != 0 ||
FD_ISSET(socket, &m_writeSockets) != 0;
#endif
}
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
#if NAZARA_NETWORK_POLL_SUPPORT
PollSocket entry = {
socket,
POLLRDNORM,
0,
0
};
if (eventFlags & SocketPollEvent_Read)
entry.events |= POLLRDNORM;
if (eventFlags & SocketPollEvent_Write)
entry.events |= POLLWRNORM;
m_allSockets[socket] = m_sockets.size();
m_sockets.emplace_back(entry);
#else
if (m_sockets.fd_count > FD_SETSIZE)
for (std::size_t i = 0; i < 2; ++i)
{
NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
return false;
}
if (eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write) == 0)
continue;
FD_SET(socket, &m_sockets);
fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets;
if (targetSet.fd_count > FD_SETSIZE)
{
NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
return false;
}
FD_SET(socket, &targetSet);
}
#endif
return true;
@@ -88,13 +116,16 @@ namespace Nz
// Now move it properly (lastElement is invalid after the following line) and pop it
m_sockets[entry] = std::move(m_sockets.back());
}
m_sockets.pop_back();
m_activeSockets.erase(socket);
m_allSockets.erase(socket);
m_readyToReadSockets.erase(socket);
m_readyToWriteSockets.erase(socket);
#else
FD_CLR(socket, &m_activeSockets);
FD_CLR(socket, &m_sockets);
FD_CLR(socket, &m_readSockets);
FD_CLR(socket, &m_readyToReadSockets);
FD_CLR(socket, &m_readyToWriteSockets);
FD_CLR(socket, &m_writeSockets);
#endif
}
@@ -103,35 +134,18 @@ namespace Nz
int activeSockets;
#if NAZARA_NETWORK_POLL_SUPPORT
// Reset status of sockets
for (PollSocket& entry : m_sockets)
entry.revents = 0;
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
x
m_activeSockets.clear();
if (activeSockets > 0U)
{
int socketRemaining = activeSockets;
for (PollSocket& entry : m_sockets)
{
if (entry.revents & POLLRDNORM)
{
m_activeSockets.insert(entry.fd);
if (--socketRemaining == 0)
break;
}
}
}
#else
m_activeSockets = m_sockets;
m_readyToReadSockets = m_readSockets;
m_readyToWriteSockets = m_writeSockets;
timeval tv;
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
if (activeSockets == SOCKET_ERROR)
{
if (error)

View File

@@ -25,24 +25,28 @@ namespace Nz
void Clear();
bool IsReady(SocketHandle socket) const;
bool IsReadyToRead(SocketHandle socket) const;
bool IsReadyToWrite(SocketHandle socket) const;
bool IsRegistered(SocketHandle socket) const;
bool RegisterSocket(SocketHandle socket);
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
void UnregisterSocket(SocketHandle socket);
int Wait(UInt64 msTimeout, SocketError* error);
private:
#if NAZARA_NETWORK_POLL_SUPPORT
std::unordered_set<SocketHandle> m_activeSockets;
std::unordered_set<SocketHandle> m_readyToReadSockets;
std::unordered_set<SocketHandle> m_readyToWriteSockets;
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
std::vector<PollSocket> m_sockets;
#else
fd_set m_sockets;
fd_set m_activeSockets;
fd_set m_readSockets;
fd_set m_readyToReadSockets;
fd_set m_readyToWriteSockets;
fd_set m_writeSockets;
#endif
};
}
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
#endif // NAZARA_SOCKETPOLLERIMPL_HPP