From 9452b98f4941c1ddb9a3dc06653cf992f2dc8e6c Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 22 Sep 2016 18:16:39 +0200 Subject: [PATCH] Network: Add SocketPoller class Former-commit-id: 86b9266d904551d19e7ec8e8d6bbe5f137e8d29f [formerly 34575937d84f796cfe36a5ab97ea1f787c1506ba] [formerly 6c8c621523800958ad38eef118fcb3687c34b367 [formerly a1f1330fbe6f990a21bbe6dccfe727edec0e2b44]] Former-commit-id: 6635c463a753f744b835267181b51ed89620b627 [formerly 14e84c7155cd669ac20a5492e67704059a442925] Former-commit-id: 7becccdf2d8aac7cdf526d855215d7d144be284c --- include/Nazara/Network/SocketPoller.hpp | 44 +++++ include/Nazara/Network/SocketPoller.inl | 37 ++++ src/Nazara/Network/Posix/IpAddressImpl.hpp | 7 + src/Nazara/Network/Posix/SocketImpl.cpp | 18 ++ src/Nazara/Network/Posix/SocketImpl.hpp | 18 ++ src/Nazara/Network/Posix/SocketPollerImpl.cpp | 92 ++++++++++ src/Nazara/Network/Posix/SocketPollerImpl.hpp | 42 +++++ src/Nazara/Network/SocketPoller.cpp | 160 ++++++++++++++++++ src/Nazara/Network/Win32/IpAddressImpl.hpp | 7 + src/Nazara/Network/Win32/SocketImpl.cpp | 28 +++ src/Nazara/Network/Win32/SocketImpl.hpp | 18 ++ src/Nazara/Network/Win32/SocketPollerImpl.cpp | 148 ++++++++++++++++ src/Nazara/Network/Win32/SocketPollerImpl.hpp | 48 ++++++ 13 files changed, 667 insertions(+) create mode 100644 include/Nazara/Network/SocketPoller.hpp create mode 100644 include/Nazara/Network/SocketPoller.inl create mode 100644 src/Nazara/Network/Posix/SocketPollerImpl.cpp create mode 100644 src/Nazara/Network/Posix/SocketPollerImpl.hpp create mode 100644 src/Nazara/Network/SocketPoller.cpp create mode 100644 src/Nazara/Network/Win32/SocketPollerImpl.cpp create mode 100644 src/Nazara/Network/Win32/SocketPollerImpl.hpp diff --git a/include/Nazara/Network/SocketPoller.hpp b/include/Nazara/Network/SocketPoller.hpp new file mode 100644 index 000000000..31dd22892 --- /dev/null +++ b/include/Nazara/Network/SocketPoller.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2015 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 + +#pragma once + +#ifndef NAZARA_SOCKETPOLLER_HPP +#define NAZARA_SOCKETPOLLER_HPP + +#include +#include +#include + +namespace Nz +{ + class SocketPollerImpl; + + class NAZARA_NETWORK_API SocketPoller + { + public: + SocketPoller(); + inline SocketPoller(SocketPoller&& socketPoller); + ~SocketPoller() = default; + + void Clear(); + + bool IsReady(const AbstractSocket& socket) const; + bool IsRegistered(const AbstractSocket& socket) const; + + bool RegisterSocket(AbstractSocket& socket); + void UnregisterSocket(AbstractSocket& socket); + + bool Wait(UInt64 msTimeout); + + inline SocketPoller& operator=(SocketPoller&& socketPoller); + + private: + SocketPollerImpl* m_impl; + }; +} + +#include + +#endif // NAZARA_SOCKETPOLLER_HPP \ No newline at end of file diff --git a/include/Nazara/Network/SocketPoller.inl b/include/Nazara/Network/SocketPoller.inl new file mode 100644 index 000000000..c3e415508 --- /dev/null +++ b/include/Nazara/Network/SocketPoller.inl @@ -0,0 +1,37 @@ +// Copyright (C) 2015 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 + +#include +#include +#include + +namespace Nz +{ + /*! + * \brief Constructs a SocketPoller object with another one by move semantic + * + * \param socketPoller SocketPoller to move into this + */ + inline SocketPoller::SocketPoller(SocketPoller&& socketPoller) : + m_impl(socketPoller.m_impl) + { + socketPoller.m_impl = nullptr; + } + + /*! + * \brief Moves the SocketPoller into this + * \return A reference to this + * + * \param socketPoller SocketPoller to move in this + */ + inline SocketPoller& SocketPoller::operator=(SocketPoller&& socketPoller) + { + m_impl = socketPoller.m_impl; + socketPoller.m_impl = nullptr; + + return *this; + } +} + +#include diff --git a/src/Nazara/Network/Posix/IpAddressImpl.hpp b/src/Nazara/Network/Posix/IpAddressImpl.hpp index 6ca919e78..fb435f9e1 100644 --- a/src/Nazara/Network/Posix/IpAddressImpl.hpp +++ b/src/Nazara/Network/Posix/IpAddressImpl.hpp @@ -2,6 +2,11 @@ // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp +#pragma once + +#ifndef NAZARA_IPADDRESSIMPL_HPP +#define NAZARA_IPADDRESSIMPL_HPP + #include #include #include @@ -30,3 +35,5 @@ namespace Nz static ResolveError TranslateEAIErrorToResolveError(int error); }; } + +#endif // NAZARA_IPADDRESSIMPL_HPP \ No newline at end of file diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index c2cf3a6f8..92588160c 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -397,6 +398,23 @@ namespace Nz return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } + int SocketImpl::Poll(PollSocket* fdarray, unsigned long nfds, int timeout, SocketError* error) + { + NazaraAssert(fdarray && nfds > 0, "Invalid fdarray"); + + static_assert(sizeof(PollSocket) == sizeof(pollfd), "PollSocket size must match WSAPOLLFD size"); + + int result = poll(reinterpret_cast(fdarray), static_cast(nfds), timeout); + if (result < 0) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return 0; + } + + return result; + } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) { diff --git a/src/Nazara/Network/Posix/SocketImpl.hpp b/src/Nazara/Network/Posix/SocketImpl.hpp index 8896ce597..c120bd19a 100644 --- a/src/Nazara/Network/Posix/SocketImpl.hpp +++ b/src/Nazara/Network/Posix/SocketImpl.hpp @@ -2,12 +2,26 @@ // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp +#pragma once + +#ifndef NAZARA_SOCKETIMPL_HPP +#define NAZARA_SOCKETIMPL_HPP + #include #include #include +#define NAZARA_NETWORK_POLL_SUPPORT 1 + namespace Nz { + struct PollSocket + { + SocketHandle fd; + short events; + short revents; + }; + class SocketImpl { public: @@ -42,6 +56,8 @@ namespace Nz static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr); static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr); + static int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, 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); @@ -66,3 +82,5 @@ namespace Nz static socketID s_socket; }; } + +#endif // NAZARA_SOCKETIMPL_HPP \ No newline at end of file diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.cpp b/src/Nazara/Network/Posix/SocketPollerImpl.cpp new file mode 100644 index 000000000..d94979863 --- /dev/null +++ b/src/Nazara/Network/Posix/SocketPollerImpl.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2015 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 + +#include +#include +#include + +namespace Nz +{ + void SocketPollerImpl::Clear() + { + m_activeSockets.clear(); + m_allSockets.clear(); + m_sockets.clear(); + } + + bool SocketPollerImpl::IsReady(SocketHandle socket) const + { + return m_activeSockets.count(socket) != 0; + } + + bool SocketPollerImpl::IsRegistered(SocketHandle socket) const + { + return m_allSockets.count(socket) != 0; + } + + bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + { + NazaraAssert(!IsRegistered(socket), "Socket is already registered"); + + PollSocket entry = { + socket, + POLLRDNORM, + 0 + }; + + m_allSockets[socket] = m_sockets.size(); + m_sockets.emplace_back(entry); + + return true; + } + + void SocketPollerImpl::UnregisterSocket(SocketHandle socket) + { + NazaraAssert(IsRegistered(socket), "Socket is not registered"); + + if (m_sockets.size() > 1U) + { + // Instead of using vector::erase, let's move the last element to the now unoccupied position + std::size_t entry = m_allSockets[socket]; + + // Get the last element and update it's position + const PollSocket& lastElement = m_sockets.back(); + m_allSockets[lastElement.fd] = entry; + + // 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); + } + + int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) + { + int activeSockets; + + // Reset status of sockets + for (PollSocket& entry : m_sockets) + entry.revents = 0; + + activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); + + m_activeSockets.clear(); + if (activeSockets > 0U) + { + for (PollSocket& entry : m_sockets) + { + if (entry.revents & POLLRDNORM) + { + m_activeSockets.insert(entry.fd); + if (--activeSockets == 0) + break; + } + } + } + + return activeSockets; + } +} diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.hpp b/src/Nazara/Network/Posix/SocketPollerImpl.hpp new file mode 100644 index 000000000..a561139fa --- /dev/null +++ b/src/Nazara/Network/Posix/SocketPollerImpl.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2015 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 + +#pragma once + +#ifndef NAZARA_SOCKETPOLLERIMPL_HPP +#define NAZARA_SOCKETPOLLERIMPL_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class SocketPollerImpl + { + public: + SocketPollerImpl() = default; + ~SocketPollerImpl() = default; + + void Clear(); + + bool IsReady(SocketHandle socket) const; + bool IsRegistered(SocketHandle socket) const; + + bool RegisterSocket(SocketHandle socket); + void UnregisterSocket(SocketHandle socket); + + int Wait(UInt64 msTimeout, SocketError* error); + + private: + std::unordered_set m_activeSockets; + std::unordered_map m_allSockets; + std::vector m_sockets; + }; +} + +#endif // NAZARA_SOCKETPOLLERIMPL_HPP \ No newline at end of file diff --git a/src/Nazara/Network/SocketPoller.cpp b/src/Nazara/Network/SocketPoller.cpp new file mode 100644 index 000000000..1364cb93d --- /dev/null +++ b/src/Nazara/Network/SocketPoller.cpp @@ -0,0 +1,160 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +#if defined(NAZARA_PLATFORM_WINDOWS) +#include +#elif defined(NAZARA_PLATFORM_POSIX) +#include +#else +#error Missing implementation: SocketPoller +#endif + +#include + +namespace Nz +{ + /*! + * \brief Constructs a SocketPoller object by default + */ + inline SocketPoller::SocketPoller() : + m_impl(new SocketPollerImpl) + { + } + + /*! + * \brief Destructs the SocketPoller + */ + SocketPoller::~SocketPoller() + { + delete m_impl; + } + + /*! + * \brief Clears the SocketPoller + * + * This function reverts the SocketPoller to the initial state, unregistering every socket from the SocketPoller. + * + * \see Unregister + */ + void SocketPoller::Clear() + { + m_impl->Clear(); + } + + /*! + * \brief Checks if a specific socket is ready to read data + * + * This function allows you to read the results of the last Wait operation and if a specific socket is ready. + * + * A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking. + * + * \remark When used on a TcpServer socket, this function returns true if the server is ready to accept a new client. + * \remark You must call Wait before using this function in order to refresh the state. + * + * \param socket Reference to the socket to check + * + * \return True if the socket is available for reading without blocking, false otherwise + * + * \see Wait + */ + bool SocketPoller::IsReady(const AbstractSocket& socket) const + { + NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller"); + + return m_impl->IsReady(socket.GetNativeHandle()); + } + + /*! + * \brief Checks if a specific socket is registered in the SocketPoller + * + * A registered socket is part of the SocketPoller and will be checked by the next Wait operations. + * + * \param socket Reference to the socket to check + * + * \return True if the socket is registered, false otherwise + * + * \see RegisterSocket + * \see UnregisterSocket + */ + bool SocketPoller::IsRegistered(const AbstractSocket& socket) const + { + return m_impl->IsRegistered(socket.GetNativeHandle()); + } + + /*! + * \brief Register a socket in the SocketPoller + * + * A registered socket is part of the SocketPoller and will be checked by the next Wait operations. + * + * The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler. + * + * It is possible for this function to fail if too many sockets are registered in the SocketPoller, the maximum number of socket handled limit is OS-dependent. + * + * \remark It is an error to register a socket twice in the same SocketPoller. + * \remark The socket should not be freed while it is registered in the SocketPooler. + * + * \param socket Reference to the socket to register + * + * \return True if the socket is registered, false otherwise + * + * \see IsRegistered + * \see UnregisterSocket + */ + bool SocketPoller::RegisterSocket(AbstractSocket& socket) + { + NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller"); + + return m_impl->RegisterSocket(socket.GetNativeHandle()); + } + + /*! + * \brief Unregister a socket from the SocketPoller + * + * After calling UnregisterSocket, the socket is no longer part of the SocketPoller and thus, not taken into account by any further Wait call until registered again. + * + * This function must be called before destroying a socket part of the SocketPoller. + * + * \remark It is an error to try to unregister a non-registered socket from a SocketPoller. + * + * \param socket Reference to the socket to unregister + * + * \see IsRegistered + * \see RegisterSocket + */ + void SocketPoller::UnregisterSocket(AbstractSocket& socket) + { + NazaraAssert(IsRegistered(socket), "This socket is not registered in this SocketPoller"); + + return m_impl->UnregisterSocket(socket.GetNativeHandle()); + } + + /*! + * \brief Wait until any registered socket switches to a ready state + * + * Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready. + * To query the ready state of the registered socket, use the IsReady function. + * + * \param msTimeout Maximum time to wait in milliseconds, 0 for infinity + * + * \remark It is an error to try to unregister a non-registered socket from a SocketPoller. + * + * \see IsReady + * \see RegisterSocket + */ + bool SocketPoller::Wait(UInt64 msTimeout) + { + SocketError error; + + int readySockets = m_impl->Wait(msTimeout, &error); + if (error != SocketError_NoError) + { + NazaraError("SocketPoller encountered an error (code: 0x" + String::Number(error, 16) + ')'); + return false; + } + + return readySockets > 0; + } +} diff --git a/src/Nazara/Network/Win32/IpAddressImpl.hpp b/src/Nazara/Network/Win32/IpAddressImpl.hpp index 960092839..000b407eb 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.hpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.hpp @@ -2,6 +2,11 @@ // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp +#pragma once + +#ifndef NAZARA_IPADDRESSIMPL_HPP +#define NAZARA_IPADDRESSIMPL_HPP + #include #include #include @@ -33,3 +38,5 @@ namespace Nz static ResolveError TranslateWSAErrorToResolveError(int error); }; } + +#endif // NAZARA_IPADDRESSIMPL_HPP \ No newline at end of file diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index 5f1c84ba8..628d29807 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -415,6 +415,34 @@ namespace Nz return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } + int SocketImpl::Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error) + { + NazaraAssert(fdarray && nfds > 0, "Invalid fdarray"); + + #if NAZARA_NETWORK_POLL_SUPPORT + static_assert(sizeof(PollSocket) == sizeof(WSAPOLLFD), "PollSocket size must match WSAPOLLFD size"); + + int result = WSAPoll(reinterpret_cast(fdarray), static_cast(nfds), timeout); + if (result == SOCKET_ERROR) + { + int errorCode = WSAGetLastError(); + if (error) + *error = TranslateWSAErrorToSocketError(errorCode); + + return 0; + } + + if (error) + *error = SocketError_NoError; + + return result; + #else + if (error) + *error = SocketError_NotSupported; + + return 0; + #endif + } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) { diff --git a/src/Nazara/Network/Win32/SocketImpl.hpp b/src/Nazara/Network/Win32/SocketImpl.hpp index dc0d77e73..ab93085d9 100644 --- a/src/Nazara/Network/Win32/SocketImpl.hpp +++ b/src/Nazara/Network/Win32/SocketImpl.hpp @@ -2,13 +2,27 @@ // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp +#pragma once + +#ifndef NAZARA_SOCKETIMPL_HPP +#define NAZARA_SOCKETIMPL_HPP + #include #include #include #include +#define NAZARA_NETWORK_POLL_SUPPORT NAZARA_CORE_WINDOWS_VISTA + namespace Nz { + struct PollSocket + { + SocketHandle fd; + short events; + short revents; + }; + class SocketImpl { public: @@ -43,6 +57,8 @@ namespace Nz static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr); static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr); + static int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, 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); @@ -66,3 +82,5 @@ namespace Nz static WSADATA s_WSA; }; } + +#endif // NAZARA_SOCKETIMPL_HPP \ No newline at end of file diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp new file mode 100644 index 000000000..b71e5107c --- /dev/null +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -0,0 +1,148 @@ +// Copyright (C) 2015 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 + +#include +#include + +namespace Nz +{ + SocketPollerImpl::SocketPollerImpl() + { + #if !NAZARA_NETWORK_POLL_SUPPORT + FD_ZERO(&m_activeSockets); + FD_ZERO(&m_sockets); + #endif + } + + void SocketPollerImpl::Clear() + { + #if NAZARA_NETWORK_POLL_SUPPORT + m_activeSockets.clear(); + m_allSockets.clear(); + m_sockets.clear(); + #else + FD_ZERO(&m_activeSockets); + FD_ZERO(&m_sockets); + #endif + } + + bool SocketPollerImpl::IsReady(SocketHandle socket) const + { + #if NAZARA_NETWORK_POLL_SUPPORT + return m_activeSockets.count(socket) != 0; + #else + return FD_ISSET(socket, &m_activeSockets) != 0; + #endif + } + + bool SocketPollerImpl::IsRegistered(SocketHandle socket) const + { + #if NAZARA_NETWORK_POLL_SUPPORT + return m_allSockets.count(socket) != 0; + #else + return FD_ISSET(socket, &m_sockets) != 0; + #endif + } + + bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + { + NazaraAssert(!IsRegistered(socket), "Socket is already registered"); + + #if NAZARA_NETWORK_POLL_SUPPORT + PollSocket entry = { + socket, + POLLRDNORM, + 0 + }; + + m_allSockets[socket] = m_sockets.size(); + m_sockets.emplace_back(entry); + #else + if (m_sockets.fd_count > FD_SETSIZE) + { + NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")"); + return false; + } + + FD_SET(socket, &m_sockets); + #endif + + return true; + } + + void SocketPollerImpl::UnregisterSocket(SocketHandle socket) + { + NazaraAssert(IsRegistered(socket), "Socket is not registered"); + + #if NAZARA_NETWORK_POLL_SUPPORT + if (m_sockets.size() > 1U) + { + // Instead of using vector::erase, let's move the last element to the now unoccupied position + std::size_t entry = m_allSockets[socket]; + + // Get the last element and update it's position + const PollSocket& lastElement = m_sockets.back(); + m_allSockets[lastElement.fd] = entry; + + // 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); + #else + FD_CLR(socket, &m_activeSockets); + FD_CLR(socket, &m_sockets); + #endif + } + + int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) + { + 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(msTimeout), error); + + m_activeSockets.clear(); + if (activeSockets > 0U) + { + for (PollSocket& entry : m_sockets) + { + if (entry.revents & POLLRDNORM) + { + m_activeSockets.insert(entry.fd); + if (--activeSockets == 0) + break; + } + } + } + #else + + m_activeSockets = m_sockets; + + timeval tv; + tv.tv_sec = static_cast(msTimeout / 1000ULL); + tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); + + activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + if (activeSockets == SOCKET_ERROR) + { + if (error) + *error = SocketImpl::TranslateWSAErrorToSocketError(WSAGetLastError()); + + return 0; + } + + if (error) + *error = SocketError_NoError; + #endif + + return activeSockets; + } +} diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.hpp b/src/Nazara/Network/Win32/SocketPollerImpl.hpp new file mode 100644 index 000000000..a8a45a7de --- /dev/null +++ b/src/Nazara/Network/Win32/SocketPollerImpl.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2015 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 + +#pragma once + +#ifndef NAZARA_SOCKETPOLLERIMPL_HPP +#define NAZARA_SOCKETPOLLERIMPL_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class SocketPollerImpl + { + public: + SocketPollerImpl(); + ~SocketPollerImpl() = default; + + void Clear(); + + bool IsReady(SocketHandle socket) const; + bool IsRegistered(SocketHandle socket) const; + + bool RegisterSocket(SocketHandle socket); + void UnregisterSocket(SocketHandle socket); + + int Wait(UInt64 msTimeout, SocketError* error); + + private: + #if NAZARA_NETWORK_POLL_SUPPORT + std::unordered_set m_activeSockets; + std::unordered_map m_allSockets; + std::vector m_sockets; + #else + fd_set m_sockets; + fd_set m_activeSockets; + #endif + }; +} + +#endif // NAZARA_SOCKETPOLLERIMPL_HPP \ No newline at end of file