Mercurial > code
changeset 245:3c12f0e8bbb9
Converter: add cstring missing
Sockets:
* Starts a PIMPL idiom to safely cast Socket with the future SocketSsl and be
able to return a class of type "Socket" whilst the interface returns
effectively a SocketSsl.
* Rename some function to be more cute to use like getDomain -> domain().
* SocketListener now owns completely sockets and must be moved to it, the
dedicated function select() always return a socket owned by SocketListener.
* Operation close is not needed anymore but the function stays in case it's
needed.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 28 Sep 2014 21:15:26 +0200 |
parents | 777bc3cb665a |
children | 9cfa6fbc9c03 d157f4747676 |
files | C++/Converter.cpp C++/Socket.cpp C++/Socket.h C++/SocketAddress.cpp C++/SocketAddress.h C++/SocketListener.cpp C++/SocketListener.h |
diffstat | 7 files changed, 498 insertions(+), 330 deletions(-) [+] |
line wrap: on
line diff
--- a/C++/Converter.cpp Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/Converter.cpp Sun Sep 28 21:15:26 2014 +0200 @@ -17,6 +17,7 @@ */ #include <cerrno> +#include <cstring> #include <string> #include <iterator> #include <memory>
--- a/C++/Socket.cpp Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/Socket.cpp Sun Sep 28 21:15:26 2014 +0200 @@ -31,7 +31,7 @@ m_error = error; } -const char *SocketError::what() const throw() +const char *SocketError::what() const noexcept { return m_error.c_str(); } @@ -54,7 +54,7 @@ #if defined(_WIN32) -std::string Socket::getLastSysError() +std::string Socket::syserror() { LPSTR str = nullptr; std::string errmsg = "Unknown error"; @@ -77,7 +77,9 @@ #else -std::string Socket::getLastSysError() +#include <cerrno> + +std::string Socket::syserror() { return strerror(errno); } @@ -91,6 +93,128 @@ #endif } +/* -------------------------------------------------------- + * Standard clear implementation + * -------------------------------------------------------- */ + +class Standard final : public SocketInterface { +public: + void bind(Socket &s, const SocketAddress &address) override; + void close(Socket &s) override; + void connect(Socket &s, const SocketAddress &address) override; + Socket accept(Socket &s, SocketAddress &info) override; + void listen(Socket &s, int max) override; + unsigned recv(Socket &s, void *data, unsigned len) override; + unsigned recvfrom(Socket &s, void *data, unsigned len, SocketAddress &info) override ; + unsigned send(Socket &s, const void *data, unsigned len) override; + unsigned sendto(Socket &s, const void *data, unsigned len, const SocketAddress &info) override; +}; + +void Standard::bind(Socket &s, const SocketAddress &addr) +{ + auto &sa = addr.address(); + auto addrlen = addr.length(); + + + if (::bind(s.handle(), (sockaddr *)&sa, addrlen) == SOCKET_ERROR) + throw SocketError(Socket::syserror()); +} + +void Standard::connect(Socket &s, const SocketAddress &addr) +{ + auto &sa = addr.address(); + auto addrlen = addr.length(); + + if (::connect(s.handle(), (sockaddr *)&sa, addrlen) == SOCKET_ERROR) + throw SocketError(Socket::syserror()); +} + +Socket Standard::accept(Socket &s, SocketAddress &info) +{ + Socket c; + Socket::Handle handle; + + // Store the information + sockaddr_storage address; + socklen_t addrlen; + + addrlen = sizeof (sockaddr_storage); + handle = ::accept(s.handle(), (sockaddr *)&address, &addrlen); + + if (handle == INVALID_SOCKET) + throw SocketError(Socket::syserror()); + + // Usually accept works only with SOCK_STREAM + info = SocketAddress(address, addrlen); + + return Socket(handle, address.ss_family, s.type(), s.protocol()); +} + +void Standard::listen(Socket &s, int max) +{ + if (::listen(s.handle(), max) == SOCKET_ERROR) + throw SocketError(Socket::syserror()); +} + +unsigned Standard::recv(Socket &s, void *data, unsigned dataLen) +{ + int nbread; + + nbread = ::recv(s.handle(), (Socket::Arg)data, dataLen, 0); + if (nbread == SOCKET_ERROR) + throw SocketError(Socket::syserror()); + + return (unsigned)nbread; +} + +unsigned Standard::send(Socket &s, const void *data, unsigned dataLen) +{ + int nbsent; + + nbsent = ::send(s.handle(), (Socket::ConstArg)data, dataLen, 0); + if (nbsent == SOCKET_ERROR) + throw SocketError(Socket::syserror()); + + return (unsigned)nbsent; +} + +unsigned Standard::recvfrom(Socket &s, void *data, unsigned dataLen, SocketAddress &info) +{ + int nbread; + + // Store information + sockaddr_storage address; + socklen_t addrlen; + + addrlen = sizeof (struct sockaddr_storage); + nbread = ::recvfrom(s.handle(), (Socket::Arg)data, dataLen, 0, (sockaddr *)&address, &addrlen); + + if (nbread == SOCKET_ERROR) + throw SocketError(Socket::syserror()); + + return (unsigned)nbread; +} + +unsigned Standard::sendto(Socket &s, const void *data, unsigned dataLen, const SocketAddress &info) +{ + int nbsent; + + nbsent = ::sendto(s.handle(), (Socket::ConstArg)data, dataLen, 0, (const sockaddr *)&info.address(), info.length()); + if (nbsent == SOCKET_ERROR) + throw SocketError(Socket::syserror()); + + return (unsigned)nbsent; +} + +void Standard::close(Socket &s) +{ + (void)closesocket(s.handle()); +} + +/* -------------------------------------------------------- + * Socket code + * -------------------------------------------------------- */ + Socket::Socket() : m_domain(0) , m_type(0) @@ -99,42 +223,86 @@ } Socket::Socket(int domain, int type, int protocol) - : m_domain(domain) + : m_interface(std::make_unique<Standard>()) + , m_domain(domain) , m_type(type) , m_protocol(protocol) { - Type s = socket(domain, type, protocol); + m_handle = socket(domain, type, protocol); + + if (m_handle == INVALID_SOCKET) + throw SocketError(syserror()); + + m_open = true; +} - if (s == INVALID_SOCKET) - throw SocketError(getLastSysError()); - - m_socket = std::shared_ptr<Type>(new Type(s), deleter); +Socket::Socket(Handle handle, int domain, int type, int protocol) + : m_handle(handle) + , m_domain(domain) + , m_type(type) + , m_protocol(protocol) + , m_open(true) +{ } -Socket::Type Socket::getSocket() const +Socket::Socket(Socket &&other) noexcept + : m_interface(std::move(other.m_interface)) + , m_handle(std::move(other.m_handle)) + , m_domain(other.m_domain) + , m_type(other.m_type) + , m_protocol(other.m_protocol) + , m_open(true) { - return *m_socket; + // invalidate other + other.m_handle = 0; + other.m_open = false; } -int Socket::getDomain() const +Socket &Socket::operator=(Socket &&other) noexcept +{ + m_interface = std::move(other.m_interface); + m_handle = std::move(other.m_handle); + m_domain = other.m_domain; + m_type = other.m_type; + m_protocol = other.m_protocol; + m_open = true; + + // invalidate other + other.m_handle = 0; + other.m_open = false; + + return *this; +} + +Socket::~Socket() +{ + close(); +} + +Socket::Handle Socket::handle() const +{ + return m_handle; +} + +int Socket::domain() const { return m_domain; } -int Socket::getType() const +int Socket::type() const { return m_type; } -int Socket::getProtocol() const +int Socket::protocol() const { return m_protocol; } void Socket::set(int level, int name, const void *arg, unsigned argLen) { - if (setsockopt(*m_socket, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR) - throw SocketError(getLastSysError()); + if (setsockopt(m_handle, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR) + throw SocketError(syserror()); } void Socket::blockMode(bool block) @@ -142,7 +310,7 @@ #if defined(O_NONBLOCK) && !defined(_WIN32) int flags; - if ((flags = fcntl(*m_socket, F_GETFL, 0)) == -1) + if ((flags = fcntl(m_handle, F_GETFL, 0)) == -1) flags = 0; if (!block) @@ -150,86 +318,21 @@ else flags |= O_NONBLOCK; - if (fcntl(*m_socket, F_SETFL, flags) == -1) - throw SocketError(getLastSysError()); + if (fcntl(m_handle, F_SETFL, flags) == -1) + throw SocketError(Socket::syserror()); #else unsigned long flags = (block) ? 0 : 1; - if (ioctlsocket(*m_socket, FIONBIO, &flags) == SOCKET_ERROR) - throw SocketError(getLastSysError()); + if (ioctlsocket(m_handle, FIONBIO, &flags) == SOCKET_ERROR) + throw SocketError(Socket::syserror()); #endif } -void Socket::bind(const SocketAddress &addr) -{ - const sockaddr_storage &sa = addr.address(); - size_t addrlen = addr.length(); - - if (::bind(*m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) - throw SocketError(getLastSysError()); -} - -void Socket::connect(const SocketAddress &addr) -{ - const sockaddr_storage &sa = addr.address(); - size_t addrlen = addr.length(); - - if (::connect(*m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) - throw SocketError(getLastSysError()); -} - Socket Socket::accept() { SocketAddress dummy; - return accept(dummy); -} - -Socket Socket::accept(SocketAddress &info) -{ - Socket s; - Type handle; - - info.m_addrlen = sizeof (sockaddr_storage); - handle = ::accept(*m_socket, (sockaddr *)&info.m_addr, &info.m_addrlen); - - if (handle == INVALID_SOCKET) - throw SocketError(getLastSysError()); - - // Usually accept works only with SOCK_STREAM - s.m_socket = std::shared_ptr<Type>(new Type(handle), deleter); - s.m_domain = info.m_addr.ss_family; - s.m_type = SOCK_STREAM; - - return s; -} - -void Socket::listen(int max) -{ - if (::listen(*m_socket, max) == SOCKET_ERROR) - throw SocketError(getLastSysError()); -} - -unsigned Socket::recv(void *data, unsigned dataLen) -{ - int nbread; - - nbread = ::recv(*m_socket, (Socket::Arg)data, dataLen, 0); - if (nbread == SOCKET_ERROR) - throw SocketError(getLastSysError()); - - return (unsigned)nbread; -} - -unsigned Socket::send(const void *data, unsigned dataLen) -{ - int nbsent; - - nbsent = ::send(*m_socket, (Socket::ConstArg)data, dataLen, 0); - if (nbsent == SOCKET_ERROR) - throw SocketError(getLastSysError()); - - return (unsigned)nbsent; + return m_interface->accept(*this, dummy); } unsigned Socket::send(const std::string &message) @@ -241,33 +344,7 @@ { SocketAddress dummy; - return recvfrom(data, dataLen, dummy); -} - -unsigned Socket::recvfrom(void *data, unsigned dataLen, SocketAddress &info) -{ - int nbread; - - info.m_addrlen = sizeof (struct sockaddr_storage); - nbread = ::recvfrom(*m_socket, (Socket::Arg)data, dataLen, 0, - (sockaddr *)&info.m_addr, &info.m_addrlen); - - if (nbread == SOCKET_ERROR) - throw SocketError(getLastSysError()); - - return (unsigned)nbread; -} - -unsigned Socket::sendto(const void *data, unsigned dataLen, const SocketAddress &info) -{ - int nbsent; - - nbsent = ::sendto(*m_socket, (Socket::ConstArg)data, dataLen, 0, - (const sockaddr *)&info.m_addr, info.m_addrlen); - if (nbsent == SOCKET_ERROR) - throw SocketError(getLastSysError()); - - return (unsigned)nbsent; + return m_interface->recvfrom(*this, data, dataLen, dummy); } unsigned Socket::sendto(const std::string &message, const SocketAddress &info) @@ -275,17 +352,12 @@ return sendto(message.c_str(), message.length(), info); } -void Socket::close() -{ - (void)closesocket(*m_socket); -} - bool operator==(const Socket &s1, const Socket &s2) { - return s1.getSocket() == s2.getSocket(); + return s1.handle() == s2.handle(); } bool operator<(const Socket &s1, const Socket &s2) { - return s1.getSocket() < s2.getSocket(); + return s1.handle() < s2.handle(); }
--- a/C++/Socket.h Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/Socket.h Sun Sep 28 21:15:26 2014 +0200 @@ -48,6 +48,7 @@ # define SOCKET_ERROR -1 #endif +class Socket; class SocketAddress; /** @@ -56,14 +57,114 @@ * * This class is mainly used in all socket operations that may fail. */ -class SocketError : public std::exception { +class SocketError final : public std::exception { private: std::string m_error; public: SocketError(const std::string &error); - virtual const char * what(void) const throw(); + const char * what(void) const noexcept override; +}; + +/** + * @class SocketInterface + * @brief Interface to implement + * + * This class implements the socket functions. + */ +class SocketInterface { +public: + /** + * Bind the socket. + * + * @param s the socket + * @param address the address + * @throw SocketError error + */ + virtual void bind(Socket &s, const SocketAddress &address) = 0; + + /** + * Close the socket. + * + * @param s the socket + */ + virtual void close(Socket &s) = 0; + + /** + * Try to connect to the specific address + * + * @param s the socket + * @param addr the address + * @throw SocketError on error + */ + virtual void connect(Socket &s, const SocketAddress &address) = 0; + + /** + * Accept a client. + * + * @param s the socket + * @param info the optional client info + * @return a client ready to use + * @throw SocketError on error + */ + virtual Socket accept(Socket &s, SocketAddress &info) = 0; + + /** + * Listen to a specific number of pending connections. + * + * @param s the socket + * @param max the max number of clients + * @throw SocketError on error + */ + virtual void listen(Socket &s, int max) = 0; + + /** + * Receive some data. + * + * @param s the socket + * @param data the destination pointer + * @param dataLen max length to receive + * @return the number of bytes received + * @throw SocketError on error + */ + virtual unsigned recv(Socket &s, void *data, unsigned len) = 0; + + /** + * Receive from a connection-less socket and get the client + * information. + * + * @param s the socket + * @param data the destination pointer + * @param dataLen max length to receive + * @param info the client info + * @return the number of bytes received + * @throw SocketError on error + */ + virtual unsigned recvfrom(Socket &s, void *data, unsigned len, SocketAddress &info) = 0; + + /** + * Send some data. + * + * @param s the socket + * @param data the data to send + * @param dataLen the data length + * @return the number of bytes sent + * @throw SocketError on error + */ + virtual unsigned send(Socket &s, const void *data, unsigned len) = 0; + + /** + * Send some data to a connection-less socket. + * + * @param s the socket + * @param data the data to send + * @param dataLen the data length + * @param address the address + * @return the number of bytes sent + * @throw SocketError on error + */ + virtual unsigned sendto(Socket &s, const void *data, unsigned len, const SocketAddress &info) = 0; }; /** @@ -72,34 +173,36 @@ * * This class is a big wrapper around sockets functions but portable, * there is some functions that helps for getting error reporting. + * + * This class is implemented as a PIMPL idiom, it is perfectly + * safe to cast the object to any other derivate children. */ class Socket { public: #if defined(_WIN32) - using Type = SOCKET; + using Handle = SOCKET; using ConstArg = const char *; using Arg = char *; #else - using Type = int; + using Handle = int; using ConstArg = const void *; using Arg = void *; #endif - using Ptr = std::shared_ptr<Type>; + using Iface = std::unique_ptr<SocketInterface>; private: - static inline void deleter(Type *t) - { - closesocket(*t); - - delete t; - } + // Be sure to not copy the socket + Socket(const Socket &) = delete; + Socket &operator=(const Socket &) = delete; protected: - Ptr m_socket; //!< the socket shared pointer - int m_domain; //!< the family - int m_type; //!< the type - int m_protocol; //!< the protocol + Iface m_interface; //!< the interface + Handle m_handle; //!< the socket shared pointer + int m_domain; //!< the domain + int m_type; //!< the type + int m_protocol; //!< the protocol + bool m_open { false }; //!< socket is valid and open public: /** @@ -112,7 +215,7 @@ * * @return a string message */ - static std::string getLastSysError(); + static std::string syserror(); /** * To be called before exiting. @@ -135,37 +238,62 @@ Socket(int domain, int type, int protocol); /** - * Destruct the socket and the handle. + * Create a socket object with a already initialized socket. + * + * @param handle the handle + * @param domain the domain + * @param type the type + * @param protocol the protocol + */ + Socket(Handle handle, int domain, int type, int protocol); + + /** + * Move constructor, transfers the socket handle. + * + * @param other the other */ - virtual ~Socket() = default; + Socket(Socket &&other) noexcept; + + /** + * Move operator, transfers the socket handle. + * + * @param other the other + * @return *this + */ + Socket &operator=(Socket &&) noexcept; + + /** + * Close the socket. + */ + virtual ~Socket(); /** * Get the socket. * * @return the socket */ - Type getSocket() const; + Handle handle() const; /** * Get the domain. * * @return the domain */ - int getDomain() const; + int domain() const; /** * Get the type of socket. * * @return the type */ - int getType() const; + int type() const; /** * Get the protocol. * * @return the protocol */ - int getProtocol() const; + int protocol() const; /** * Set an option for the socket. @@ -186,20 +314,31 @@ void blockMode(bool block = true); /** - * Bind the socket. - * - * @param location a IP or Unix location - * @throw SocketError error + * @copydoc SocketInterface::bind */ - void bind(const SocketAddress &address); + inline void bind(const SocketAddress &address) + { + m_interface->bind(*this, address); + } /** - * Try to connect to the specific address - * - * @param addr the address - * @throw SocketError on error + * @copydoc SocketInterface::close */ - virtual void connect(const SocketAddress &address); + inline void close() + { + if (m_open) { + m_interface->close(*this); + m_open = false; + } + } + + /** + * @copydoc SocketInterface::connect + */ + inline void connect(const SocketAddress &address) + { + m_interface->connect(*this, address); + } /** * Accept a client without getting its info. @@ -207,53 +346,31 @@ * @return a client ready to use * @throw SocketError on error */ - virtual Socket accept(); + Socket accept(); /** - * Accept a client. - * - * @param info the optional client info - * @return a client ready to use - * @throw SocketError on error + * @copydoc SocketInterface::accept */ - virtual Socket accept(SocketAddress &info); - - /** - * Listen to a specific number of pending connections. - * - * @param max the max number of clients - * @throw SocketError on error - */ - void listen(int max); + inline Socket accept(SocketAddress &info) + { + return m_interface->accept(*this, info); + } /** - * Receive some data. - * - * @param data the destination pointer - * @param dataLen max length to receive - * @return the number of bytes received - * @throw SocketError on error + * @copydoc SocketInterface::listen */ - virtual unsigned recv(void *data, unsigned dataLen); + inline void listen(int max) + { + m_interface->listen(*this, max); + } /** - * Send some data. - * - * @param data the data to send - * @param dataLen the data length - * @return the number of bytes sent - * @throw SocketError on error + * @copydoc SocketInterface::recv */ - virtual unsigned send(const void *data, unsigned dataLen); - - /** - * Send a message as a string. - * - * @param message the message - * @return the number of bytes sent - * @throw SocketError on error - */ - unsigned send(const std::string &message); + inline unsigned recv(void *data, unsigned dataLen) + { + return m_interface->recv(*this, data, dataLen); + } /** * Receive from a connection-less socket without getting @@ -267,27 +384,37 @@ unsigned recvfrom(void *data, unsigned dataLen); /** - * Receive from a connection-less socket and get the client - * information. - * - * @param data the destination pointer - * @param dataLen max length to receive - * @param info the client info - * @return the number of bytes received - * @throw SocketError on error + * @copydoc SocketInterface::recvfrom */ - unsigned recvfrom(void *data, unsigned dataLen, SocketAddress &info); + inline unsigned recvfrom(void *data, unsigned dataLen, SocketAddress &info) + { + return m_interface->recvfrom(*this, data, dataLen, info); + } /** - * Send some data to a connection-less socket. + * @copydoc SocketInterface::send + */ + inline unsigned send(const void *data, unsigned dataLen) + { + return m_interface->send(*this, data, dataLen); + } + + /** + * Send a message as a string. * - * @param data the data to send - * @param dataLen the data length - * @param address the address + * @param message the message * @return the number of bytes sent * @throw SocketError on error */ - unsigned sendto(const void *data, unsigned dataLen, const SocketAddress &info); + unsigned send(const std::string &message); + + /** + * @copydoc SocketInterface::sendto + */ + inline unsigned sendto(const void *data, unsigned dataLen, const SocketAddress &info) + { + return m_interface->sendto(*this, data, dataLen, info); + } /** * Send a message to a connection-less socket. @@ -298,11 +425,6 @@ * @throw SocketError on error */ unsigned sendto(const std::string &message, const SocketAddress &info); - - /** - * Close the socket. - */ - virtual void close(); }; bool operator==(const Socket &s1, const Socket &s2);
--- a/C++/SocketAddress.cpp Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/SocketAddress.cpp Sun Sep 28 21:15:26 2014 +0200 @@ -16,80 +16,56 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <cerrno> -#include <cstdio> #include <cstring> +#include "Socket.h" #include "SocketAddress.h" +namespace address { + /* -------------------------------------------------------- - * BindAddressIP implementation + * Internet implementation * -------------------------------------------------------- */ -BindAddressIP::BindAddressIP(const std::string &iface, unsigned port, int family) - : m_host(iface) - , m_family(family) - , m_port(port) +Internet::Internet(const std::string &host, unsigned port, int domain) { - if (m_family == AF_INET6) { - sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr; + if (host == "*") { + if (domain == AF_INET6) { + sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr; - ptr->sin6_family = AF_INET6; - ptr->sin6_port = htons(m_port); + ptr->sin6_family = AF_INET6; + ptr->sin6_port = htons(port); + } else { + sockaddr_in *ptr = (sockaddr_in *)&m_addr; - if (m_host == "*") - ptr->sin6_addr = in6addr_any; - else if (inet_pton(AF_INET6, m_host.c_str(), &ptr->sin6_addr) <= 0) - throw SocketError(Socket::getLastSysError()); - - m_addrlen = sizeof (sockaddr_in6); + ptr->sin_family = AF_INET; + ptr->sin_port = htons(port); + } } else { - sockaddr_in *ptr = (sockaddr_in *)&m_addr; + addrinfo hints, *res; - ptr->sin_family = AF_INET; - ptr->sin_port = htons(m_port); + std::memset(&hints, 0, sizeof (addrinfo)); + hints.ai_family = domain; - if (m_host == "*") - ptr->sin_addr.s_addr = INADDR_ANY; - else if (inet_pton(AF_INET, m_host.c_str(), &ptr->sin_addr) <= 0) - throw SocketError(Socket::getLastSysError()); + auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res); + if (error != 0) + throw std::runtime_error(gai_strerror(error)); - m_addrlen = sizeof (sockaddr_in); + std::memcpy(&m_addr, res->ai_addr, res->ai_addrlen); + m_addrlen = res->ai_addrlen; + freeaddrinfo(res); } } /* -------------------------------------------------------- - * ConnectAddressIP implementation - * -------------------------------------------------------- */ - -ConnectAddressIP::ConnectAddressIP(const std::string &host, unsigned port, int family, int type) -{ - addrinfo hints, *res; - int error; - - memset(&hints, 0, sizeof (hints)); - hints.ai_family = family; - hints.ai_socktype = type; - - error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res); - if (error) - throw SocketError(gai_strerrorA(error)); - - memcpy(&m_addr, res->ai_addr, res->ai_addrlen); - m_addrlen = res->ai_addrlen; - - freeaddrinfo(res); -} - -/* -------------------------------------------------------- - * AddressUnix implementation + * Unix implementation * -------------------------------------------------------- */ #if !defined(_WIN32) #include <sys/un.h> -AddressUnix::AddressUnix(const std::string &path, bool rm) +Unix::Unix(const std::string &path, bool rm) { sockaddr_un *sun = (sockaddr_un *)&m_addr; @@ -103,12 +79,13 @@ // Set the parameters sun->sun_family = AF_UNIX; - sun->sun_len = SUN_LEN(sun); m_addrlen = SUN_LEN(sun); } #endif // _WIN32 +} // !address + /* -------------------------------------------------------- * SocketAddress implementation * -------------------------------------------------------- */ @@ -125,10 +102,6 @@ { } -SocketAddress::~SocketAddress() -{ -} - const sockaddr_storage &SocketAddress::address() const { return m_addr;
--- a/C++/SocketAddress.h Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/SocketAddress.h Sun Sep 28 21:15:26 2014 +0200 @@ -19,8 +19,6 @@ #ifndef _SOCKET_ADDRESS_H_ #define _SOCKET_ADDRESS_H_ -#include "Socket.h" - /** * @class SocketAddress * @brief base class for socket addresses @@ -28,9 +26,8 @@ * This class is mostly used to bind, connect or getting information * on socket clients. * - * @see BindAddressIP - * @see ConnectAddressIP - * @see AddressUnix + * @see Internet + * @see Unix */ class SocketAddress { protected: @@ -38,9 +35,6 @@ socklen_t m_addrlen; public: - // Friends. - friend class Socket; - /** * Default constructor. */ @@ -57,7 +51,7 @@ /** * Default destructor. */ - virtual ~SocketAddress(); + virtual ~SocketAddress() = default; /** * Get the address length @@ -74,61 +68,37 @@ const sockaddr_storage &address() const; }; -/** - * @class BindAddressIP - * @brief internet protocol bind class - * - * Create a bind address for internet protocol, - * IPv4 or IPv6. - */ -class BindAddressIP : public SocketAddress { -private: - std::string m_host; - int m_family; - unsigned m_port; - -public: - /** - * Create a bind end point. - * - * @param addr the interface to bind - * @param port the port - * @param family AF_INET or AF_INET6 - * @throw SocketError on error - */ - BindAddressIP(const std::string &addr, unsigned port, int family); -}; +namespace address { /** - * @class ConnectAddressIP + * @class Internet * @brief internet protocol connect class * * Create a connect address for internet protocol, * using getaddrinfo(3). */ -class ConnectAddressIP : public SocketAddress { +class Internet final : public SocketAddress { public: /** - * Create a connect end point. + * Create an IPv4 or IPV6 end point. * * @param host the hostname * @param port the port * @param family AF_INET, AF_INET6, ... - * @param type of socket SOCK_STREAM, SOCK_DGRAM, ... * @throw SocketError on error */ - ConnectAddressIP(const std::string &host, unsigned port, int family, int type = SOCK_STREAM); + Internet(const std::string &host, unsigned port, int family); }; #if !defined(_WIN32) /** - * @class AddressUnix + * @class Unix * @brief unix family sockets * * Create an address to a specific path. Only available on Unix. */ -class AddressUnix : public SocketAddress { +class Unix final : public SocketAddress { public: /** * Construct an address to a path. @@ -136,9 +106,11 @@ * @param path the path * @param rm remove the file before (default: false) */ - AddressUnix(const std::string &path, bool rm = false); + Unix(const std::string &path, bool rm = false); }; +} // !address + #endif // ! !_WIN32 #endif // !_SOCKET_ADDRESS_H_
--- a/C++/SocketListener.cpp Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/SocketListener.cpp Sun Sep 28 21:15:26 2014 +0200 @@ -20,43 +20,47 @@ #include "SocketListener.h" -const char *SocketTimeout::what() const throw() +const char *SocketTimeout::what() const noexcept { return "Timeout occured"; } -void SocketListener::add(Socket &s) +SocketListener::SocketListener(int count) { - m_clients.push_back(s); + m_sockets.reserve(count); } -void SocketListener::remove(Socket &s) +void SocketListener::add(Socket &&s) { - m_clients.erase(std::remove(m_clients.begin(), m_clients.end(), s), m_clients.end()); + m_sockets.push_back(std::move(s)); +} + +void SocketListener::remove(const Socket &s) +{ + m_sockets.erase(std::remove(m_sockets.begin(), m_sockets.end(), s), m_sockets.end()); } void SocketListener::clear() { - m_clients.clear(); + m_sockets.clear(); } unsigned SocketListener::size() { - return m_clients.size(); + return m_sockets.size(); } Socket &SocketListener::select(int s, int us) { fd_set fds; timeval maxwait, *towait; - int error; - int fdmax = m_clients.front().getSocket(); + auto fdmax = m_sockets.front().handle(); FD_ZERO(&fds); - for (Socket &c : m_clients) { - FD_SET(c.getSocket(), &fds); - if ((int)c.getSocket() > fdmax) - fdmax = c.getSocket(); + for (auto &c : m_sockets) { + FD_SET(c.handle(), &fds); + if ((int)c.handle() > fdmax) + fdmax = c.handle(); } maxwait.tv_sec = s; @@ -65,14 +69,14 @@ // Set to NULL for infinite timeout. towait = (s == 0 && us == 0) ? nullptr : &maxwait; - error = ::select(fdmax + 1, &fds, NULL, NULL, towait); + auto error = ::select(fdmax + 1, &fds, NULL, NULL, towait); if (error == SOCKET_ERROR) - throw SocketError(Socket::getLastSysError()); + throw SocketError(Socket::syserror()); if (error == 0) throw SocketTimeout(); - for (Socket &c : m_clients) - if (FD_ISSET(c.getSocket(), &fds)) + for (Socket &c : m_sockets) + if (FD_ISSET(c.handle(), &fds)) return c; throw SocketError("No socket found");
--- a/C++/SocketListener.h Sat Sep 13 19:42:15 2014 +0200 +++ b/C++/SocketListener.h Sun Sep 28 21:15:26 2014 +0200 @@ -27,9 +27,9 @@ * @class SocketTimeout * @brief thrown when a timeout occured */ -class SocketTimeout : public std::exception { +class SocketTimeout final : public std::exception { public: - virtual const char * what(void) const throw(); + const char *what() const noexcept override; }; /** @@ -38,24 +38,31 @@ * * Convenient wrapper around the select() system call. */ -class SocketListener { +class SocketListener final { private: - std::vector<Socket> m_clients; + std::vector<Socket> m_sockets; public: /** + * Create a socket listener with a specific number of sockets to reserve. + * + * @param count the number of socket to reserve (default: 0) + */ + SocketListener(int count = 0); + + /** * Add a socket to listen to. * * @param s the socket */ - void add(Socket &s); + void add(Socket &&s); /** * Remove a socket from the list. * * @param s the socket */ - void remove(Socket &s); + void remove(const Socket &s); /** * Remove every sockets in the listener. @@ -73,13 +80,30 @@ * Wait for an event in the socket list. If both s and us are set to 0 then * it waits indefinitely. * + * Taking ownership of the returned socket is undefined behaviour. + * * @param s the timeout in seconds * @param us the timeout in milliseconds - * @return the socket ready + * @see take + * @return the socket ready owner by the SocketListener * @throw SocketError on error * @throw SocketTimeout on timeout */ Socket &select(int s = 0, int us = 0); + + /** + * Take back all sockets that listener own. + * + * @param func the function to call (void f(Socket &&s)) + */ + template <typename Func> + void take(Func func) + { + for (auto &x : m_sockets) + func(std::move(x)); + + clear(); + } }; #endif // !_SOCKET_LISTENER_H_