mirror of
https://github.com/SFML/CSFML.git
synced 2026-10-28 05:46:12 +01:00
Add readiness types and callbacks to sfSocketSelector
This commit is contained in:
4 files changed
+278
-22
No files matched your search
@@ -32,6 +32,31 @@
|
||||
#include <CSFML/Network/Types.h>
|
||||
#include <CSFML/System/Time.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Readiness types a socket selector can check for
|
||||
///
|
||||
/// The values can be combined with a bitwise OR.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef enum
|
||||
{
|
||||
sfSocketSelectorReceive = 1 << 0, ///< Check if sockets are ready to be received from
|
||||
sfSocketSelectorSend = 1 << 1 ///< Check if sockets are ready to be sent to
|
||||
} sfSocketSelectorReadiness;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Callback that is called when a socket is ready
|
||||
///
|
||||
/// \param readiness Readiness of the socket, a combination of sfSocketSelectorReadiness values
|
||||
/// \param userData User data passed when adding the socket
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef void (*sfSocketSelectorCallback)(uint32_t readiness, void* userData);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new selector
|
||||
@@ -66,13 +91,64 @@ CSFML_NETWORK_API void sfSocketSelector_destroy(const sfSocketSelector* selector
|
||||
/// so you have to make sure that the socket is not destroyed
|
||||
/// while it is stored in the selector.
|
||||
///
|
||||
/// The socket is checked for being ready to receive.
|
||||
///
|
||||
/// \param selector Socket selector object
|
||||
/// \param socket Pointer to the socket to add
|
||||
///
|
||||
/// \return True if the socket was successfully added
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CSFML_NETWORK_API void sfSocketSelector_addTcpListener(sfSocketSelector* selector, sfTcpListener* socket);
|
||||
CSFML_NETWORK_API void sfSocketSelector_addTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket);
|
||||
CSFML_NETWORK_API void sfSocketSelector_addUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addTcpListener(sfSocketSelector* selector, sfTcpListener* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Add a new socket to a socket selector with the readiness to check for and an optional callback
|
||||
///
|
||||
/// This function keeps a weak pointer to the socket,
|
||||
/// so you have to make sure that the socket is not destroyed
|
||||
/// while it is stored in the selector.
|
||||
///
|
||||
/// The readiness to wait for can be specified as a combination
|
||||
/// of sfSocketSelectorReceive and sfSocketSelectorSend.
|
||||
///
|
||||
/// If a callback is provided, it will be called with the
|
||||
/// readiness of the socket when sfSocketSelector_dispatchReadyCallbacks
|
||||
/// is called after sfSocketSelector_wait returned true. Using
|
||||
/// callbacks scales better than checking every socket with
|
||||
/// sfSocketSelector_isXxxReadyFor.
|
||||
///
|
||||
/// Adding a socket that has already been added updates its
|
||||
/// readiness and callback.
|
||||
///
|
||||
/// \param selector Socket selector object
|
||||
/// \param socket Pointer to the socket to add
|
||||
/// \param readiness Readiness to wait for, combination of sfSocketSelectorReadiness values
|
||||
/// \param callback Callback to call when the socket is ready, can be NULL
|
||||
/// \param userData User data that will be passed to the callback
|
||||
///
|
||||
/// \return True if the socket was successfully added
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addTcpListenerWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfTcpListener* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addTcpSocketWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfTcpSocket* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_addUdpSocketWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfUdpSocket* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Remove a socket from a socket selector
|
||||
@@ -83,10 +159,12 @@ CSFML_NETWORK_API void sfSocketSelector_addUdpSocket(sfSocketSelector* selector,
|
||||
/// \param selector Socket selector object
|
||||
/// \param socket Pointer to the socket to remove
|
||||
///
|
||||
/// \return True if the socket was successfully removed
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CSFML_NETWORK_API void sfSocketSelector_removeTcpListener(sfSocketSelector* selector, sfTcpListener* socket);
|
||||
CSFML_NETWORK_API void sfSocketSelector_removeTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket);
|
||||
CSFML_NETWORK_API void sfSocketSelector_removeUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_removeTcpListener(sfSocketSelector* selector, sfTcpListener* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_removeTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_removeUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Remove all the sockets stored in a selector
|
||||
@@ -101,11 +179,13 @@ CSFML_NETWORK_API void sfSocketSelector_removeUdpSocket(sfSocketSelector* select
|
||||
CSFML_NETWORK_API void sfSocketSelector_clear(sfSocketSelector* selector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Wait until one or more sockets are ready to receive
|
||||
/// \brief Wait until one or more sockets are ready
|
||||
///
|
||||
/// This function returns as soon as at least one socket has
|
||||
/// some data available to be received. To know which sockets are
|
||||
/// ready, use the sfSocketSelector_isXxxReady functions.
|
||||
/// This function returns as soon as at least one socket is
|
||||
/// ready for the readiness it was added with (by default
|
||||
/// having some data available to be received). To know which
|
||||
/// sockets are ready, use the sfSocketSelector_isXxxReady
|
||||
/// functions or sfSocketSelector_dispatchReadyCallbacks.
|
||||
/// If you use a timeout and no socket is ready before the timeout
|
||||
/// is over, the function returns false.
|
||||
///
|
||||
@@ -136,3 +216,41 @@ CSFML_NETWORK_API bool sfSocketSelector_wait(sfSocketSelector* selector, sfTime
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isTcpListenerReady(const sfSocketSelector* selector, sfTcpListener* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isTcpSocketReady(const sfSocketSelector* selector, sfTcpSocket* socket);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isUdpSocketReady(const sfSocketSelector* selector, sfUdpSocket* socket);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Test a socket to know if it is ready for the given readiness
|
||||
///
|
||||
/// This function must be used after a call to
|
||||
/// sfSocketSelector_wait, to know which sockets are ready.
|
||||
///
|
||||
/// \param selector Socket selector object
|
||||
/// \param socket Socket to test
|
||||
/// \param readiness Readiness to check for, combination of sfSocketSelectorReadiness values
|
||||
///
|
||||
/// \return true if the socket is ready, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isTcpListenerReadyFor(const sfSocketSelector* selector,
|
||||
sfTcpListener* socket,
|
||||
uint32_t readiness);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isTcpSocketReadyFor(const sfSocketSelector* selector,
|
||||
sfTcpSocket* socket,
|
||||
uint32_t readiness);
|
||||
CSFML_NETWORK_API bool sfSocketSelector_isUdpSocketReadyFor(const sfSocketSelector* selector,
|
||||
sfUdpSocket* socket,
|
||||
uint32_t readiness);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Call the callbacks of all sockets that are ready
|
||||
///
|
||||
/// After sfSocketSelector_wait returned true, at least one
|
||||
/// socket is ready. Calling this function will call the
|
||||
/// callbacks of all the sockets that became ready during
|
||||
/// the wait. Calling this function multiple times after a
|
||||
/// single call to sfSocketSelector_wait will run the callbacks
|
||||
/// multiple times.
|
||||
///
|
||||
/// \param selector Socket selector object
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CSFML_NETWORK_API void sfSocketSelector_dispatchReadyCallbacks(sfSocketSelector* selector);
|
||||
@@ -31,6 +31,22 @@
|
||||
#include <CSFML/Network/TcpSocketStruct.hpp>
|
||||
#include <CSFML/Network/UdpSocketStruct.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] std::function<void(sf::SocketSelector::ReadinessType)> convertCallback(sfSocketSelectorCallback callback,
|
||||
void* userData)
|
||||
{
|
||||
if (!callback)
|
||||
return {};
|
||||
|
||||
return [callback, userData](sf::SocketSelector::ReadinessType readiness) { callback(readiness, userData); };
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sfSocketSelector* sfSocketSelector_create()
|
||||
@@ -55,44 +71,86 @@ void sfSocketSelector_destroy(const sfSocketSelector* selector)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void sfSocketSelector_addTcpListener(sfSocketSelector* selector, sfTcpListener* socket)
|
||||
bool sfSocketSelector_addTcpListener(sfSocketSelector* selector, sfTcpListener* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->add(*socket);
|
||||
return selector->add(*socket);
|
||||
}
|
||||
void sfSocketSelector_addTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket)
|
||||
bool sfSocketSelector_addTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->add(*socket);
|
||||
return selector->add(*socket);
|
||||
}
|
||||
void sfSocketSelector_addUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket)
|
||||
bool sfSocketSelector_addUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->add(*socket);
|
||||
return selector->add(*socket);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void sfSocketSelector_removeTcpListener(sfSocketSelector* selector, sfTcpListener* socket)
|
||||
bool sfSocketSelector_addTcpListenerWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfTcpListener* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->remove(*socket);
|
||||
return selector->add(*socket, readiness, convertCallback(callback, userData));
|
||||
}
|
||||
void sfSocketSelector_removeTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_addTcpSocketWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfTcpSocket* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->remove(*socket);
|
||||
return selector->add(*socket, readiness, convertCallback(callback, userData));
|
||||
}
|
||||
void sfSocketSelector_removeUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_addUdpSocketWithReadiness(
|
||||
sfSocketSelector* selector,
|
||||
sfUdpSocket* socket,
|
||||
uint32_t readiness,
|
||||
sfSocketSelectorCallback callback,
|
||||
void* userData)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
selector->remove(*socket);
|
||||
return selector->add(*socket, readiness, convertCallback(callback, userData));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_removeTcpListener(sfSocketSelector* selector, sfTcpListener* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->remove(*socket);
|
||||
}
|
||||
bool sfSocketSelector_removeTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->remove(*socket);
|
||||
}
|
||||
bool sfSocketSelector_removeUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->remove(*socket);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,3 +189,38 @@ bool sfSocketSelector_isUdpSocketReady(const sfSocketSelector* selector, sfUdpSo
|
||||
assert(socket);
|
||||
return selector->isReady(*socket);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_isTcpListenerReadyFor(const sfSocketSelector* selector, sfTcpListener* socket, uint32_t readiness)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->isReady(*socket, readiness);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_isTcpSocketReadyFor(const sfSocketSelector* selector, sfTcpSocket* socket, uint32_t readiness)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->isReady(*socket, readiness);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool sfSocketSelector_isUdpSocketReadyFor(const sfSocketSelector* selector, sfUdpSocket* socket, uint32_t readiness)
|
||||
{
|
||||
assert(selector);
|
||||
assert(socket);
|
||||
return selector->isReady(*socket, readiness);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void sfSocketSelector_dispatchReadyCallbacks(sfSocketSelector* selector)
|
||||
{
|
||||
assert(selector);
|
||||
selector->dispatchReadyCallbacks();
|
||||
}
|
||||
@@ -70,6 +70,7 @@ add_executable(test-csfml-network
|
||||
Network/Ftp.test.cpp
|
||||
Network/Http.test.cpp
|
||||
Network/IpAddress.test.cpp
|
||||
Network/SocketSelector.test.cpp
|
||||
Network/SocketStatus.test.cpp
|
||||
Network/TcpSocket.test.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <CSFML/Network/SocketSelector.h>
|
||||
#include <CSFML/Network/TcpListener.h>
|
||||
#include <CSFML/Network/TcpSocket.h>
|
||||
|
||||
#include <SFML/Network/SocketSelector.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE("[Network] sfSocketSelector")
|
||||
{
|
||||
SECTION("sfSocketSelectorReadiness")
|
||||
{
|
||||
STATIC_CHECK(sfSocketSelectorReceive == static_cast<int>(sf::SocketSelector::Receive));
|
||||
STATIC_CHECK(sfSocketSelectorSend == static_cast<int>(sf::SocketSelector::Send));
|
||||
}
|
||||
|
||||
SECTION("Ready callbacks")
|
||||
{
|
||||
sfTcpListener* listener = sfTcpListener_create();
|
||||
REQUIRE(sfTcpListener_listen(listener, 0, sfIpAddress_LocalHost) == sfSocketDone);
|
||||
|
||||
sfTcpSocket* client = sfTcpSocket_create();
|
||||
REQUIRE(sfTcpSocket_connect(client, sfIpAddress_LocalHost, sfTcpListener_getLocalPort(listener), sfSeconds(1)) ==
|
||||
sfSocketDone);
|
||||
|
||||
sfSocketSelector* selector = sfSocketSelector_create();
|
||||
|
||||
uint32_t readiness = 0;
|
||||
const auto callback = [](uint32_t ready, void* userData) { *static_cast<uint32_t*>(userData) |= ready; };
|
||||
CHECK(sfSocketSelector_addTcpListenerWithReadiness(selector, listener, sfSocketSelectorReceive, callback, &readiness));
|
||||
|
||||
REQUIRE(sfSocketSelector_wait(selector, sfSeconds(1)));
|
||||
CHECK(sfSocketSelector_isTcpListenerReady(selector, listener));
|
||||
CHECK(sfSocketSelector_isTcpListenerReadyFor(selector, listener, sfSocketSelectorReceive));
|
||||
sfSocketSelector_dispatchReadyCallbacks(selector);
|
||||
CHECK(readiness == sfSocketSelectorReceive);
|
||||
|
||||
CHECK(sfSocketSelector_removeTcpListener(selector, listener));
|
||||
|
||||
sfSocketSelector_destroy(selector);
|
||||
sfTcpSocket_destroy(client);
|
||||
sfTcpListener_destroy(listener);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user