# HG changeset patch # User David Demelier # Date 1456153791 -3600 # Node ID 627284574e426b1d5e520750a287a1ceb64fa194 # Parent ebe16d7afbe6533cd38d23a2dcd0804164a26b5e Sockets: massive update - Separate Ip in Ipv4 and Ipv6, - Socket have no state, condition, action anymore (use Condition instead), - Get rid of Stream(Client|Connection|Server). diff -r ebe16d7afbe6 -r 627284574e42 modules/sockets/CMakeLists.txt --- a/modules/sockets/CMakeLists.txt Wed Feb 03 14:06:18 2016 +0100 +++ b/modules/sockets/CMakeLists.txt Mon Feb 22 16:09:51 2016 +0100 @@ -26,6 +26,7 @@ code_define_module( NAME sockets INCLUDES ${OPENSSL_INCLUDE_DIR} + FLAGS -DSOCKET_NO_SSL LIBRARIES ${LIBRARIES} ${OPENSSL_LIBRARIES} diff -r ebe16d7afbe6 -r 627284574e42 modules/sockets/sockets.cpp --- a/modules/sockets/sockets.cpp Wed Feb 03 14:06:18 2016 +0100 +++ b/modules/sockets/sockets.cpp Mon Feb 22 16:09:51 2016 +0100 @@ -185,30 +185,30 @@ /* {{{ Error */ Error::Error(Code code, std::string function) - : m_code{code} - , m_function{std::move(function)} - , m_error{error()} + : m_code(code) + , m_function(std::move(function)) + , m_error(error()) { } Error::Error(Code code, std::string function, int n) - : m_code{code} - , m_function{std::move(function)} - , m_error{error(n)} + : m_code(code) + , m_function(std::move(function)) + , m_error(error(n)) { } Error::Error(Code code, std::string function, std::string error) - : m_code{code} - , m_function{std::move(function)} - , m_error{std::move(error)} + : m_code(code) + , m_function(std::move(function)) + , m_error(std::move(error)) { } /* }}} */ /* - * Predefine addressed to be used + * Predefined addressed to be used * ------------------------------------------------------------------ */ @@ -216,76 +216,84 @@ namespace address { -/* Default domain */ -int Ip::m_default{AF_INET}; +namespace { -Ip::Ip(Type domain) noexcept - : m_domain(static_cast(domain)) +void resolv(sockaddr *destination, const std::string host, std::uint16_t port, int domain) { - assert(m_domain == AF_INET6 || m_domain == AF_INET); + assert(domain == AF_INET || domain == AF_INET6); + + addrinfo hints, *res; + + std::memset(&hints, 0, sizeof (addrinfo)); + hints.ai_family = domain; + + auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res); + if (error != 0) + throw Error(Error::System, "getaddrinfo", gai_strerror(error)); + + if (domain == AF_INET6) + std::memcpy(destination, res->ai_addr, res->ai_addrlen); + else + std::memcpy(destination, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); +} - if (m_domain == AF_INET6) { - std::memset(&m_sin6, 0, sizeof (sockaddr_in6)); +} // !namespace + +/* {{{ Ipv4 */ + +Ipv4::Ipv4() noexcept +{ + std::memset(&m_sin, 0, sizeof (sockaddr_in)); +} + +Ipv4::Ipv4(const std::string &host, std::uint16_t port) + : Ipv4() +{ + if (host == "*") { + m_sin.sin_addr.s_addr = INADDR_ANY; + m_sin.sin_family = AF_INET; + m_sin.sin_port = htons(port); } else { - std::memset(&m_sin, 0, sizeof (sockaddr_in)); + resolv(reinterpret_cast(&m_sin), host, port, AF_INET); } } -Ip::Ip(const std::string &host, int port, Type domain) - : m_domain(static_cast(domain)) +Ipv4::Ipv4(const sockaddr_storage *ss, socklen_t length) noexcept { - assert(m_domain == AF_INET6 || m_domain == AF_INET); + std::memcpy(&m_sin, ss, length); +} - if (host == "*") { - if (m_domain == AF_INET6) { - std::memset(&m_sin6, 0, sizeof (sockaddr_in6)); +/* }}} */ - m_length = sizeof (sockaddr_in6); - m_sin6.sin6_addr = in6addr_any; - m_sin6.sin6_family = AF_INET6; - m_sin6.sin6_port = htons(port); - } else { - std::memset(&m_sin, 0, sizeof (sockaddr_in)); +/* {{{ Ipv6 */ - m_length = sizeof (sockaddr_in); - m_sin.sin_addr.s_addr = INADDR_ANY; - m_sin.sin_family = AF_INET; - m_sin.sin_port = htons(port); - } - } else { - addrinfo hints, *res; - - std::memset(&hints, 0, sizeof (addrinfo)); - hints.ai_family = domain; +Ipv6::Ipv6() noexcept +{ + std::memset(&m_sin6, 0, sizeof (sockaddr_in6)); +} - auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res); - if (error != 0) { - throw Error{Error::System, "getaddrinfo", gai_strerror(error)}; - } - - if (m_domain == AF_INET6) { - std::memcpy(&m_sin6, res->ai_addr, res->ai_addrlen); - } else { - std::memcpy(&m_sin, res->ai_addr, res->ai_addrlen); - } - - m_length = res->ai_addrlen; - freeaddrinfo(res); +Ipv6::Ipv6(const std::string &host, std::uint16_t port) + : Ipv6() +{ + if (host == "*") { + m_sin6.sin6_addr = in6addr_any; + m_sin6.sin6_family = AF_INET6; + m_sin6.sin6_port = htons(port); + } else { + resolv(reinterpret_cast(&m_sin6), host, port, AF_INET6); } } -Ip::Ip(const sockaddr_storage *ss, socklen_t length) noexcept - : m_length{length} - , m_domain{ss->ss_family} +Ipv6::Ipv6(const sockaddr_storage *ss, socklen_t length) noexcept { - assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET); + std::memcpy(&m_sin6, ss, length); +} - if (ss->ss_family == AF_INET6) { - std::memcpy(&m_sin6, ss, length); - } else if (ss->ss_family == AF_INET) { - std::memcpy(&m_sin, ss, length); - } -} +/* }}} */ + +/* {{{ Local */ #if !defined(_WIN32) @@ -295,12 +303,11 @@ } Local::Local(std::string path, bool rm) noexcept - : m_path{std::move(path)} + : m_path(std::move(path)) { /* Silently remove the file even if it fails */ - if (rm) { + if (rm) ::remove(m_path.c_str()); - } /* Copy the path */ std::memset(m_sun.sun_path, 0, sizeof (m_sun.sun_path)); @@ -322,11 +329,19 @@ #endif // !_WIN32 +/* }}} */ + } // !address /* }}} */ /* + * Listener backends + * ------------------------------------------------------------------ + */ + +/* {{{ Backends */ +/* * Select * ------------------------------------------------------------------ */ @@ -506,26 +521,22 @@ { uint32_t events = 0; - if ((condition & Condition::Readable) == Condition::Readable) { + if ((condition & Condition::Readable) == Condition::Readable) events |= EPOLLIN; - } - if ((condition & Condition::Writable) == Condition::Writable) { + if ((condition & Condition::Writable) == Condition::Writable) events |= EPOLLOUT; - } return events; } Condition Epoll::toCondition(uint32_t events) const noexcept { - Condition condition{Condition::None}; + Condition condition = Condition::None; - if ((events & EPOLLIN) || (events & EPOLLHUP)) { + if ((events & EPOLLIN) || (events & EPOLLHUP)) condition |= Condition::Readable; - } - if (events & EPOLLOUT) { + if (events & EPOLLOUT) condition |= Condition::Writable; - } return condition; } @@ -539,22 +550,21 @@ ev.events = eflags; ev.data.fd = h; - if (epoll_ctl(m_handle, op, h, &ev) < 0) { - throw Error{Error::System, "epoll_ctl"}; - } + if (epoll_ctl(m_handle, op, h, &ev) < 0) + throw Error(Error::System, "epoll_ctl"); } Epoll::Epoll() - : m_handle{epoll_create1(0)} + : m_handle(epoll_create1(0)) { - if (m_handle < 0) { + if (m_handle < 0) throw Error{Error::System, "epoll_create"}; - } } Epoll::~Epoll() { - close(m_handle); + if (m_handle != -1) + close(m_handle); } /* @@ -595,16 +605,13 @@ int ret = epoll_wait(m_handle, m_events.data(), m_events.size(), ms); std::vector result; - if (ret == 0) { - throw Error{Error::Timeout, "epoll_wait", TIMEOUT_MSG}; - } - if (ret < 0) { - throw Error{Error::System, "epoll_wait"}; - } + if (ret == 0) + throw Error(Error::Timeout, "epoll_wait", TIMEOUT_MSG); + if (ret < 0) + throw Error(Error::System, "epoll_wait"); - for (int i = 0; i < ret; ++i) { + for (int i = 0; i < ret; ++i) result.push_back(ListenerStatus{m_events[i].data.fd, toCondition(m_events[i].events)}); - } return result; } @@ -625,14 +632,14 @@ Kqueue::Kqueue() : m_handle(kqueue()) { - if (m_handle < 0) { - throw Error{Error::System, "kqueue"}; - } + if (m_handle < 0) + throw Error(Error::System, "kqueue"); } Kqueue::~Kqueue() { - close(m_handle); + if (m_handle != -1) + close(m_handle); } void Kqueue::update(Handle h, int filter, int kflags) @@ -706,4 +713,6 @@ /* }}} */ +/* }}} */ + } // !net diff -r ebe16d7afbe6 -r 627284574e42 modules/sockets/sockets.h --- a/modules/sockets/sockets.h Wed Feb 03 14:06:18 2016 +0100 +++ b/modules/sockets/sockets.h Mon Feb 22 16:09:51 2016 +0100 @@ -161,6 +161,7 @@ #include #include +#include #include #include #include @@ -449,7 +450,6 @@ Connecting, //!< The connection is in progress Connected, //!< Connection is complete Accepted, //!< Socket has been accepted (client) - Accepting, //!< The client acceptation is in progress Closed, //!< The socket has been closed Disconnected, //!< The connection was lost }; @@ -457,39 +457,6 @@ /* }}} */ /* - * Action enum - * ------------------------------------------------------------------ - * - * Defines the pending operation. - */ - -/* {{{ Action */ - -/** - * @enum Action - * @brief Define the current operation that must complete. - * - * Some operations like accept, connect, recv or send must sometimes do several round-trips to complete and the socket - * action is set with that enumeration. The user is responsible of calling accept, connect send or recv until the - * operation is complete. - * - * Note: the user must wait for the appropriate condition in Socket::condition to check if the required condition is - * met. - * - * It is important to complete the operation in the correct order because protocols like Tls may require to continue - * re-negociating when calling Socket::send or Socket::Recv. - */ -enum class Action { - None, //!< No action is required, socket is ready - Accept, //!< The socket is not yet accepted, caller must call accept() again - Connect, //!< The socket is not yet connected, caller must call connect() again - Receive, //!< The received operation has not succeeded yet, caller must call recv() or recvfrom() again - Send //!< The send operation has not succeded yet, caller must call send() or sendto() again -}; - -/* }}} */ - -/* * Condition enum * ------------------------------------------------------------------ * @@ -627,9 +594,6 @@ class Socket { private: Protocol m_proto; - State m_state{State::Closed}; - Action m_action{Action::None}; - Condition m_condition{Condition::None}; protected: /** @@ -649,8 +613,6 @@ * @param protocol the protocol * @param iface the implementation * @throw net::Error on errors - * @post state is set to Open - * @post handle is not set to Invalid */ Socket(int domain, int type, int protocol, Protocol iface = {}) : m_proto(std::move(iface)) @@ -660,14 +622,10 @@ #endif m_handle = ::socket(domain, type, protocol); - if (m_handle == Invalid) { - throw Error{Error::System, "socket"}; - } + if (m_handle == Invalid) + throw Error(Error::System, "socket"); m_proto.create(*this); - m_state = State::Open; - - assert(m_handle != Invalid); } /** @@ -680,7 +638,7 @@ * @throw net::Error on errors */ explicit inline Socket(Protocol protocol = {}, const Address &address = {}) - : Socket{address.domain(), protocol.type(), 0, std::move(protocol)} + : Socket(address.domain(), protocol.type(), 0, std::move(protocol)) { } @@ -690,23 +648,18 @@ * @param handle the native descriptor * @param state specify the socket state * @param protocol the type of socket implementation - * @post action is set to None - * @post condition is set to None */ explicit inline Socket(Handle handle, State state = State::Closed, Protocol protocol = {}) noexcept : m_proto(std::move(protocol)) - , m_state{state} - , m_handle{handle} + , m_handle(handle) { - assert(m_action == Action::None); - assert(m_condition == Condition::None); } /** * Create an invalid socket. Can be used when you cannot instanciate the socket immediately. */ explicit inline Socket(std::nullptr_t) noexcept - : m_handle{Invalid} + : m_handle(Invalid) { } @@ -722,16 +675,10 @@ */ inline Socket(Socket &&other) noexcept : m_proto(std::move(other.m_proto)) - , m_state{other.m_state} - , m_action{other.m_action} - , m_condition{other.m_condition} - , m_handle{other.m_handle} + , m_handle(other.m_handle) { /* Invalidate other */ other.m_handle = Invalid; - other.m_state = State::Closed; - other.m_action = Action::None; - other.m_condition = Condition::None; } /** @@ -764,83 +711,31 @@ } /** - * Get the current socket state. - * - * @return the state - */ - inline State state() const noexcept - { - return m_state; - } - - /** - * Change the current socket state. + * Tells if the socket is not invalid. * - * @param state the new state - * @warning only implementations should call this function + * @return true if not invalid */ - inline void setState(State state) noexcept - { - m_state = state; - } - - /** - * Get the pending operation. - * - * @return the action to complete before continuing - * @note usually only needed in non-blocking sockets - */ - inline Action action() const noexcept + inline bool isOpen() const noexcept { - return m_action; - } - - /** - * Change the pending operation. - * - * @param action the action - * @warning you should not call this function yourself - */ - inline void setAction(Action action) noexcept - { - m_action = action; - } - - /** - * Get the condition to wait for. - * - * @return the condition - */ - inline Condition condition() const noexcept - { - return m_condition; - } - - /** - * Change the condition required. - * - * @param condition the condition - * @warning you should not call this function yourself - */ - inline void setCondition(Condition condition) noexcept - { - m_condition = condition; + return m_handle != Invalid; } /** * Set an option for the socket. Wrapper of setsockopt(2). * + * @pre isOpen() * @param level the setting level * @param name the name * @param arg the value * @throw net::Error on errors */ template - void set(int level, int name, const Argument &arg) + inline void set(int level, int name, const Argument &arg) { - if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) { - throw Error{Error::System, "set"}; - } + assert(m_handle != Invalid); + + if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) + throw Error(Error::System, "set"); } /** @@ -848,18 +743,22 @@ * * The object must have `set(Socket &) const`. * + * @pre isOpen() * @param option the option * @throw net::Error on errors */ template inline void set(const Option &option) { + assert(m_handle != Invalid); + option.set(*this); } /** * Get an option for the socket. Wrapper of getsockopt(2). * + * @pre isOpen() * @param level the setting level * @param name the name * @throw net::Error on errors @@ -867,12 +766,13 @@ template Argument get(int level, int name) { + assert(m_handle != Invalid); + Argument desired, result{}; socklen_t size = sizeof (result); - if (getsockopt(m_handle, level, name, (Arg)&desired, &size) == Failure) { - throw Error{Error::System, "get"}; - } + if (getsockopt(m_handle, level, name, (Arg)&desired, &size) == Failure) + throw Error(Error::System, "get"); std::memcpy(&result, &desired, size); @@ -885,13 +785,16 @@ * The object must have `T get(Socket &) const`, T can be any type and it is the value * returned from this function. * + * @pre isOpen() * @return the same value as get() in the option * @throw net::Error on errors */ template inline auto get() -> decltype(std::declval