NazaraEngine/src/Nazara/Network/SocketPoller.cpp

196 lines
6.4 KiB
C++

// Copyright (C) 2017 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 <Nazara/Network/SocketPoller.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Network/Win32/SocketPollerImpl.hpp>
#elif defined(NAZARA_PLATFORM_LINUX)
#include <Nazara/Network/Linux/SocketPollerImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Network/Posix/SocketPollerImpl.hpp>
#else
#error Missing implementation: SocketPoller
#endif
#include <Nazara/Network/Debug.hpp>
namespace Nz
{
/*!
* \ingroup network
* \class Nz::SocketPoller
* \brief Network class allowing an application to wait on multiples sockets for them to become active (readable)
*/
/*!
* \brief Constructs an empty SocketPoller object
*/
SocketPoller::SocketPoller() :
m_impl(new SocketPollerImpl)
{
}
/*!
* \brief Destructs the SocketPoller
*
* \remark When the SocketPoller gets destroyed, all sockets are automatically unregistered from it.
*/
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 to read (has incoming data).
*
* A socket in the ready to read state (with the exception of TcpServer) has incoming data and can be read without blocking.
*
* \remark You must call Wait before using this function in order to refresh the read state.
* \remark A socket must be registered with SocketPollerEvent_Read event flag for its read state to be watched
* \remark A TcpServer socket becomes ready to read when it is ready to accept a new client.
*
* \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::IsReadyToRead(const AbstractSocket& socket) const
{
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
return m_impl->IsReadyToRead(socket.GetNativeHandle());
}
/*!
* \brief Checks if a specific socket is ready to write data
*
* This function allows you to read the results of the last Wait operation and if a specific socket is ready to write (can be written to without blocking).
*
* \remark You must call Wait before using this function in order to refresh the read state.
* \remark A socket must be registered with SocketPollerEvent_Write event flag for its read state to be watched
*
* \param socket Reference to the socket to check
*
* \return True if the socket is available for writing without blocking, false otherwise
*
* \see Wait
*/
bool SocketPoller::IsReadyToWrite(const AbstractSocket& socket) const
{
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
return m_impl->IsReadyToWrite(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 according to the event flags passed when registered.
*
* 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
* \param eventFlags Socket events to watch
*
* \return True if the socket is registered, false otherwise
*
* \see IsRegistered
* \see UnregisterSocket
*/
bool SocketPoller::RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller");
return m_impl->RegisterSocket(socket.GetNativeHandle(), eventFlags);
}
/*!
* \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 IsReadyToRead or IsReadyToWrite functions.
*
* \param msTimeout Maximum time to wait in milliseconds, 0 will returns immediately and -1 will block indefinitely
*
* \return True if at least one socket registered to the poller is ready.
*
* \remark It is an error to try to unregister a non-registered socket from a SocketPoller.
*
* \see IsReady
* \see RegisterSocket
*/
bool SocketPoller::Wait(int 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;
}
}