# HG changeset patch # User David Demelier # Date 1445587247 -7200 # Node ID 9c85d9158990507b24bbbf381cc0535b2ffa6c59 # Parent 44887104242a4d87ba62ff5890564039de6ff00f Socket: constructor can now take an address for genericity with Ipv4 and Ipv6 diff -r 44887104242a -r 9c85d9158990 C++/modules/Socket/Sockets.cpp --- a/C++/modules/Socket/Sockets.cpp Fri Oct 23 08:31:46 2015 +0200 +++ b/C++/modules/Socket/Sockets.cpp Fri Oct 23 10:00:47 2015 +0200 @@ -176,7 +176,7 @@ } } -Ip::Ip(const std::string &host, int port, int domain) +Ip::Ip(int domain, const std::string &host, int port) : m_domain{domain} { if (host == "*") { diff -r 44887104242a -r 9c85d9158990 C++/modules/Socket/Sockets.h --- a/C++/modules/Socket/Sockets.h Fri Oct 23 08:31:46 2015 +0200 +++ b/C++/modules/Socket/Sockets.h Fri Oct 23 10:00:47 2015 +0200 @@ -133,6 +133,7 @@ #include #include #include +#include #include #include #include @@ -411,10 +412,11 @@ /** * This tries to create a socket. * + * @param address which type of address * @param type the type instance */ - inline Socket(Type type = Type{}) noexcept - : Socket{Address::domain(), Type::type(), 0} + explicit inline Socket(const Address &address = {}, Type type = Type{}) noexcept + : Socket{address.domain(), Type::type(), 0} { /* Some implementation requires more things */ m_type = std::move(type); @@ -933,14 +935,23 @@ socklen_t m_length{0}; int m_domain{AF_INET}; - Ip(const std::string &host, int port, int domain); public: /** * Default initialize the Ip domain. * * @param domain the domain (AF_INET or AF_INET6) */ - Ip(int domain = AF_INET) noexcept; + Ip(int domain = AF_INET6) noexcept; + + /** + * Construct an address suitable for bind() or connect(). + * + * @param domain the domain (AF_INET or AF_INET6) + * @param host the host (* for any) + * @param port the port number + * @throw Error on errors + */ + Ip(int domain, const std::string &host, int port); /** * Construct an address from a storage. @@ -951,6 +962,16 @@ Ip(const struct sockaddr_storage *ss, socklen_t length); /** + * Get the domain (AF_INET or AF_INET6). + * + * @return the domain + */ + inline int domain() const noexcept + { + return m_domain; + } + + /** * Return the underlying address, either sockaddr_in6 or sockaddr_in. * * @return the address @@ -982,16 +1003,6 @@ class Ipv6 : public Ip { public: /** - * Get the domain AF_INET6. - * - * @return AF_INET6 - */ - static inline int domain() noexcept - { - return AF_INET6; - } - - /** * Construct an empty address. */ inline Ipv6() noexcept @@ -1007,7 +1018,18 @@ * @throw Error on errors */ inline Ipv6(const std::string &host, int port) - : Ip{host, port, AF_INET6} + : Ip{AF_INET6, host, port} + { + } + + /** + * Construct an address from a storage. + * + * @param ss the storage + * @param length the length + */ + inline Ipv6(const struct sockaddr_storage *ss, socklen_t length) + : Ip{ss, length} { } }; @@ -1019,16 +1041,6 @@ class Ipv4 : public Ip { public: /** - * Get the domain AF_INET. - * - * @return AF_INET - */ - static inline int domain() noexcept - { - return AF_INET; - } - - /** * Construct an empty address. */ inline Ipv4() noexcept @@ -1044,7 +1056,18 @@ * @throw Error on errors */ inline Ipv4(const std::string &host, int port) - : Ip{host, port, AF_INET} + : Ip{AF_INET, host, port} + { + } + + /** + * Construct an address from a storage. + * + * @param ss the storage + * @param length the length + */ + inline Ipv4(const struct sockaddr_storage *ss, socklen_t length) + : Ip{ss, length} { } }; @@ -1068,7 +1091,7 @@ * * @return AF_LOCAL */ - static inline int domain() noexcept + inline int domain() noexcept { return AF_LOCAL; } @@ -2198,6 +2221,158 @@ /* }}} */ +#if 0 + +/* + * High level helpers coming soon. + */ + +template +class StreamServer; + +template +class StreamConnection { +private: + Socket m_socket; + std::string m_output; + +public: + StreamConnection(Socket s) + : m_socket{std::move(s)} + { + } + + inline Socket &socket() noexcept + { + return m_socket; + } + + const std::string &output() const noexcept + { + return m_output; + } +}; + +template +class StreamServer { +private: + Socket m_master; + Listener<> m_listener; + std::map> m_clients; + + /* Callbacks */ + template + using Callbacks = std::vector>; + + Callbacks &> m_onConnection; + Callbacks &> m_onDisconnection; + Callbacks &, const std::string &> m_onRead; + Callbacks &, const std::string &> m_onWrite; + + template + void notify(const List &list, Args&&... args) + { + for (const auto &f : list) { + f(std::forward(args)...); + } + } + + void processAccept() + { + StreamConnection connection{m_master.accept()}; + + /* Notify we have a new client */ + notify(m_onConnection, connection); + + m_listener.set(connection.socket().handle(), FlagRead); + m_clients.emplace(connection.socket().handle(), std::move(connection)); + } + + void processSync(const ListenerStatus &status) + { + auto &connection = m_clients.at(status.socket); + + try { + if (status.flags & FlagRead) { + auto buffer = connection.socket().recv(512); + + /* Empty mean normal disconnection */ + if (buffer.empty()) { + notify(m_onDisconnection, connection); + m_listener.remove(status.socket); + m_clients.erase(status.socket); + } else { + notify(m_onRead, connection, buffer); + } + } else if (status.flags & FlagWrite) { + /* Process write */ + } + } catch (const std::exception &ex) { + /* TODO: remove */ + } + } + +public: + /** + * Create a stream server with the specified address to bind. + * + * @param address the address to bind + * @param max the max number to listen + * @throw Error on errors + */ + template + StreamServer(const RealAddress &address, int max = 128) + : m_master{address.domain(), SOCK_STREAM, 0} + { + m_master.set(SOL_SOCKET, SO_REUSEADDR, 1); + m_master.bind(address); + m_master.listen(max); + m_listener.set(m_master.handle(), FlagRead); + } + + template + inline void addConnectionHandler(Func &&f) + { + m_onConnection.push_back(std::forward(f)); + } + + template + inline void addDisconnectionHandler(Func &&f) + { + m_onDisconnection.push_back(std::forward(f)); + } + + template + inline void addReadHandler(Func &&f) + { + m_onRead.push_back(std::forward(f)); + } + + template + inline void addWriteHandler(Func &&f) + { + m_onWrite.push_back(std::forward(f)); + } + + void poll(int timeout) + { + auto st = m_listener.wait(timeout); + + if (st.socket == m_master.handle()) { + processAccept(); + } else { + processSync(st); + } + } + + inline int wait() + { + poll(-1); + } +}; + +#endif + } // !net #endif // !_SOCKETS_H_