Mercurial > code
diff C++/SocketListener.h @ 258:4ad3c85ab73e
Sockets:
* set(), get() now take template to determine the size
* recv(), recvfrom() can take a template char array to determine the size
SocketListener:
* Additional preferred poll method now supported
* Support for both reading and writing polling
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 05 Oct 2014 11:00:16 +0200 |
parents | 806dbb6011c7 |
children | 46ccfbee84d9 |
line wrap: on
line diff
--- a/C++/SocketListener.h Fri Oct 03 16:26:26 2014 +0200 +++ b/C++/SocketListener.h Sun Oct 05 11:00:16 2014 +0200 @@ -19,17 +19,85 @@ #ifndef _SOCKET_LISTENER_H_ #define _SOCKET_LISTENER_H_ -#include <vector> +#include <chrono> +#include <functional> #include "Socket.h" /** - * @class SocketTimeout - * @brief thrown when a timeout occured + * @enum SocketDirection + * @brief The SocketDirection enum + * + * Bitmask that can be set to both reading and writing. */ -class SocketTimeout final : public std::exception { -public: - const char *what() const noexcept override; +enum class SocketDirection { + Read = (1 << 0), //!< only for receive + Write = (1 << 1) //!< only for sending +}; + +inline SocketDirection operator&(SocketDirection x, SocketDirection y) +{ + return static_cast<SocketDirection>(static_cast<int>(x) & static_cast<int>(y)); +} + +inline SocketDirection operator|(SocketDirection x, SocketDirection y) +{ + return static_cast<SocketDirection>(static_cast<int>(x) | static_cast<int>(y)); +} + +inline SocketDirection operator^(SocketDirection x, SocketDirection y) +{ + return static_cast<SocketDirection>(static_cast<int>(x) ^ static_cast<int>(y)); +} + +inline SocketDirection operator~(SocketDirection x) +{ + return static_cast<SocketDirection>(~static_cast<int>(x)); +} + +inline SocketDirection &operator&=(SocketDirection &x, SocketDirection y) +{ + x = x & y; + + return x; +} + +inline SocketDirection &operator|=(SocketDirection &x, SocketDirection y) +{ + x = x | y; + + return x; +} + +inline SocketDirection &operator^=(SocketDirection &x, SocketDirection y) +{ + x = x ^ y; + + return x; +} + +/** + * @enum SocketMethod + * @brief The SocketMethod enum + * + * Select the method of polling. It is only a preferred method, for example if you + * request for poll but it is not available, select will be used. + */ +enum class SocketMethod { + Select, //!< select(2) method, fallback + Poll //!< poll(2), everywhere possible +}; + +/** + * @struct SocketStatus + * @brief The SocketStatus struct + * + * Result of a select call, returns the first ready socket found with its + * direction. + */ +struct SocketStatus { + Socket socket; //!< which socket is ready + SocketDirection direction; //!< the direction }; /** @@ -39,55 +107,164 @@ * Convenient wrapper around the select() system call. */ class SocketListener final { -private: - std::vector<Socket> m_sockets; +public: + /** + * @brief Function for listing all sockets + */ + using MapFunc = std::function<void (Socket &, SocketDirection)>; + + /** + * @class Interface + * @brief Implement the polling method + */ + class Interface { + public: + /** + * Default destructor. + */ + virtual ~Interface() = default; + + /** + * List all sockets in the interface. + * + * @param func the function + */ + virtual void list(const MapFunc &func) = 0; + + /** + * Add a socket with a specified direction. + * + * @param s the socket + * @param direction the direction + */ + virtual void add(Socket &&s, SocketDirection direction) = 0; + + /** + * Remove a socket with a specified direction. + * + * @param s the socket + * @param direction the direction + */ + virtual void remove(const Socket &s, SocketDirection direction) = 0; + + /** + * Remove all sockets. + */ + virtual void clear() = 0; + + /** + * Get the total number of sockets in the listener. + */ + virtual unsigned size() const = 0; + + /** + * Select a socket. + * + * @param ms the number of milliseconds to wait, -1 means forever + * @return the socket status + * @throw error::Failure on failure + * @throw error::Timeout on timeout + */ + virtual SocketStatus select(int ms) = 0; + }; + + std::unique_ptr<Interface> m_interface; + +#if defined(_WIN32) +# if _WIN32_WINNT >= 0x0600 + static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll; +# else + static constexpr const SocketMethod PreferredMethod = SocketMethod::Select; +# endif +#else + static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll; +#endif public: /** - * Create a socket listener with a specific number of sockets to reserve. + * Create a socket listener. * - * @param count the number of socket to reserve (default: 0) + * @param method the preferred method */ - SocketListener(int count = 0); + SocketListener(SocketMethod method = SocketMethod::Poll); /** * Add a socket to listen to. * * @param s the socket + * @param direction the direction */ - void add(Socket s); + inline void add(Socket s, SocketDirection direction) + { + m_interface->add(std::move(s), direction); + } /** * Remove a socket from the list. * * @param s the socket + * @param direction the direction */ - void remove(const Socket &s); + inline void remove(const Socket &s, SocketDirection direction) + { + m_interface->remove(s, direction); + } /** * Remove every sockets in the listener. */ - void clear(); + inline void clear() + { + m_interface->clear(); + } /** * Get the number of clients in listener. * - * @return the number of clients in the listener. + * @return the total number of sockets in the listener */ - unsigned size(); + inline unsigned size() const + { + return m_interface->size(); + } /** - * Wait for an event in the socket list. If both s and us are set to 0 then - * it waits indefinitely. + * Select a socket. Waits for a specific amount of time specified as the duration. * - * @param s the timeout in seconds - * @param us the timeout in milliseconds - * @see take * @return the socket ready * @throw SocketError on error * @throw SocketTimeout on timeout */ - Socket &select(int s = 0, int us = 0); + template <typename Rep, typename Ratio> + inline SocketStatus select(const std::chrono::duration<Rep, Ratio> &duration) + { + auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); + + return m_interface->select(cvt.count()); + } + + /** + * Overload that waits indefinitely. + * + * @return the socket ready + * @throw SocketError on error + * @throw SocketTimeout on timeout + */ + inline SocketStatus select() + { + return m_interface->select(-1); + } + + /** + * List every socket in the listener. + * + * @param func the function to call + */ + template <typename Func> + inline void list(Func func) + { + m_interface->list(func); + } }; #endif // !_SOCKET_LISTENER_H_