Mercurial > code
changeset 544:a5f488f88899
Net: no more bridges
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 14 Jun 2016 15:11:11 +0200 |
parents | dc1b5143c5e3 |
children | c0bdb6c091bc |
files | modules/net/net.hpp |
diffstat | 1 files changed, 361 insertions(+), 1225 deletions(-) [+] |
line wrap: on
line diff
--- a/modules/net/net.hpp Mon Jun 13 16:13:40 2016 +0200 +++ b/modules/net/net.hpp Tue Jun 14 15:11:11 2016 +0200 @@ -116,12 +116,12 @@ * # General options * * - **NET_NO_AUTO_INIT**: (bool) Set to 0 if you don't want Socket class to - * automatically calls net::init function and net::finish functions. + * automatically calls init function and finish functions. * * - **NET_NO_SSL**: (bool) Set to 0 if you don't have access to OpenSSL library. * * - **NET_NO_AUTO_SSL_INIT**: (bool) Set to 0 if you don't want Socket class with Tls to automatically init - * the OpenSSL library. You will need to call net::ssl::init and net::ssl::finish. + * the OpenSSL library. You will need to call ssl::init and ssl::finish. */ /** @@ -307,8 +307,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * inline void set(Socket<Address, Protocol> &sc) const; + * template <typename Address> + * inline void set(Socket<Address> &sc) const; * ```` * * ## Arguments @@ -322,8 +322,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * inline bool get(Socket<Address, Protocol> &sc) const; + * template <typename Address> + * inline bool get(Socket<Address> &sc) const; * ```` * * ## Arguments @@ -377,8 +377,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length, Condition &cond); + * template <typename Address> + * void connect(Socket<Address> &sc, const sockaddr *address, socklen_t length, Condition &cond); * ```` * * ## Arguments @@ -395,8 +395,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * void resumeConnect(Socket<Address, Protocol> &sc, Condition &cond) + * template <typename Address> + * void resumeConnect(Socket<Address> &sc, Condition &cond) * ```` * * ## Arguments @@ -417,8 +417,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * Socket<Address, Protocol> accept(Socket<Address, Protocol> &sc, sockaddr *address, socklen_t *length, Condition &cond); + * template <typename Address> + * Socket<Address> accept(Socket<Address> &sc, sockaddr *address, socklen_t *length, Condition &cond); * ```` * * ## Arguments @@ -435,8 +435,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * void accept(Socket<Address, Protocol> &sc, Condition &cond) const noexcept; + * template <typename Address> + * void accept(Socket<Address> &sc, Condition &cond) const noexcept; * ```` * * ## Arguments @@ -515,8 +515,8 @@ * ## Synopsis * * ```` - * template <typename Address, typename Protocol> - * std::size_t recvfrom(Socket<Address, Protocol> &sc, void *data, std::size_t length, sockaddr *address, socklen_t *addrlen, Condition &cond); + * template <typename Address> + * std::size_t recvfrom(Socket<Address> &sc, void *data, std::size_t length, sockaddr *address, socklen_t *addrlen, Condition &cond); * ```` * * ## Arguments @@ -535,8 +535,8 @@ * # sendto * * ```` - * template <typename Address, typename Protocol> - * std::size_t sendto(Socket<Address, Protocol> &sc, const void *data, std::size_t length, const sockaddr *address, socklen_t addrlen, Condition &cond); + * template <typename Address> + * std::size_t sendto(Socket<Address> &sc, const void *data, std::size_t length, const sockaddr *address, socklen_t addrlen, Condition &cond); * ```` * * ## Arguments @@ -592,20 +592,20 @@ * * #include "net.hpp" * - * void connect(net::SocketTcpIpv4 &sc) + * void connect(SocketTcpIpv4 &sc) * { * // (0) The listener, used to wait for a condition. - * net::Listener<> listener; + * Listener<> listener; * * // (1) The condition that we must wait for, no need to initialize. - * net::Condition cond; + * Condition cond; * * // (2) Do the initial connection attempt * // - * // If cond != net::Condition::None, the connection was unable to complete immediately. - * sc.connect(net::address::Ipv4::resolve("example.org", "9090"), cond); - * - * while (cond != net::Condition::None) { + * // If cond != Condition::None, the connection was unable to complete immediately. + * sc.connect(address::Ipv4::resolve("example.org", "9090"), cond); + * + * while (cond != Condition::None) { * // (3) Erase the previous condition. * listener.remove(sc.handle()); * @@ -621,10 +621,10 @@ * int main() * { * try { - * net::SocketTcpIpv4 sc; + * SocketTcpIpv4 sc; * * // Set the socket non-blocking. - * sc.set(net::option::SockBlockMode(false)); + * sc.set(option::SockBlockMode(false)); * * connect(sc); * } catch (const std::exception &ex) { @@ -1012,95 +1012,86 @@ */ /** - * \brief Base class for sockets error + * \brief Base class for sockets error. */ class Error : public std::exception { -public: - /** - * \enum Code - * \brief Which kind of error - */ - enum Code { - Timeout, ///!< The action did timeout - System, ///!< There is a system error - Other ///!< Other custom error - }; - private: - Code m_code; - std::string m_function; - std::string m_error; + std::string m_message; public: /** - * Constructor that use the last system error. + * Construct the error using the specified error from the system. * - * \param code which kind of error - * \param function the function name + * \param code the error code + * \warning the code must be a Winsock error or errno on Unix */ - inline Error(Code code, std::string function) - : m_code(code) - , m_function(std::move(function)) - , m_error(error()) + inline Error(int code) noexcept + : m_message(error(code)) { } /** - * Constructor that use the system error set by the user. + * Construct the error using the custom message. * - * \param code which kind of error - * \param function the function name - * \param n the error + * \param message the message */ - inline Error(Code code, std::string function, int n) - : m_code(code) - , m_function(std::move(function)) - , m_error(error(n)) + inline Error(std::string message) noexcept + : m_message(std::move(message)) { } /** - * Constructor that set the error specified by the user. - * - * \param code which kind of error - * \param function the function name - * \param error the error + * Construct the error using the last message from the system. */ - inline Error(Code code, std::string function, std::string error) - : m_code(code) - , m_function(std::move(function)) - , m_error(std::move(error)) + inline Error() noexcept +#if defined(_WIN32) + : Error(WSAGetLastError()) +#else + : Error(errno) +#endif { } /** - * Get which function has triggered the error. - * - * \return the function name (e.g connect) - */ - inline const std::string &function() const noexcept - { - return m_function; - } - - /** - * The error code. - * - * \return the code - */ - inline Code code() const noexcept - { - return m_code; - } - - /** * Get the error (only the error content). * * \return the error */ const char *what() const noexcept override { - return m_error.c_str(); + return m_message.c_str(); + } +}; + +class TimeoutError : public std::exception { +public: + const char *what() const noexcept override + { + return std::strerror(ETIMEDOUT); + } +}; + +class WouldBlockError : public std::exception { +public: + const char *what() const noexcept override + { + return std::strerror(EWOULDBLOCK); + } +}; + +class WantWriteError : public std::exception { +public: + const char *what() const noexcept override + { + return "operation requires writing to complete"; + } +}; + +class WantReadError : public std::exception { +public: + const char *what() const noexcept override + { + return "operation requires read to complete"; } }; @@ -1241,11 +1232,8 @@ * \see protocol::Tcp * \see protocol::Udp */ -template <typename Address, typename Protocol> +template <typename Address> class Socket { -private: - Protocol m_proto; - protected: /** * The native handle. @@ -1262,11 +1250,9 @@ * \param domain the domain AF_* * \param type the type SOCK_* * \param protocol the protocol - * \param iface the implementation - * \throw net::Error on errors + * \throw Error on errors */ - Socket(int domain, int type, int protocol, Protocol iface = {}) - : m_proto(std::move(iface)) + Socket(int domain, int type, int protocol) { #if !defined(NET_NO_AUTO_INIT) init(); @@ -1274,23 +1260,7 @@ m_handle = ::socket(domain, type, protocol); if (m_handle == Invalid) - throw Error(Error::System, "socket"); - - m_proto.create(*this); - } - - /** - * This tries to create a socket. - * - * Domain and type are determined by the Address and Protocol object. - * - * \param address which type of address - * \param protocol the protocol - * \throw net::Error on errors - */ - explicit inline Socket(const Address &address = {}, Protocol protocol = {}) - : Socket(address.domain(), protocol.type(), 0, std::move(protocol)) - { + throw Error(); } /** @@ -1299,9 +1269,8 @@ * \param handle the handle * \param protocol the protocol */ - explicit inline Socket(Handle handle, Protocol protocol = {}) noexcept - : m_proto(std::move(protocol)) - , m_handle(handle) + explicit inline Socket(Handle handle) noexcept + : m_handle(handle) { } @@ -1324,8 +1293,7 @@ * \param other the other socket */ inline Socket(Socket &&other) noexcept - : m_proto(std::move(other.m_proto)) - , m_handle(other.m_handle) + : m_handle(other.m_handle) { other.m_handle = Invalid; } @@ -1339,27 +1307,6 @@ } /** - * Access the implementation. - * - * \return the implementation - * \warning use this function with care - */ - inline const Protocol &protocol() const noexcept - { - return m_proto; - } - - /** - * Overloaded function. - * - * \return the implementation - */ - inline Protocol &protocol() noexcept - { - return m_proto; - } - - /** * Tells if the socket is not invalid. * * \return true if not invalid @@ -1376,25 +1323,25 @@ * \param level the setting level * \param name the name * \param arg the value - * \throw net::Error on errors + * \throw Error on errors */ template <typename Argument> inline void set(int level, int name, const Argument &arg) { assert(m_handle != Invalid); - if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) - throw Error(Error::System, "set"); + if (::setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) + throw Error(); } /** * Object-oriented option setter. * - * The object must have `set(Socket<Address, Protocol> &) const`. + * The object must have `set(Socket<Address> &) const`. * * \pre isOpen() * \param option the option - * \throw net::Error on errors + * \throw Error on errors */ template <typename Option> inline void set(const Option &option) @@ -1411,7 +1358,7 @@ * \param level the setting level * \param name the name * \return the value - * \throw net::Error on errors + * \throw Error on errors */ template <typename Argument> Argument get(int level, int name) @@ -1421,8 +1368,8 @@ 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(); std::memcpy(&result, &desired, size); @@ -1432,12 +1379,12 @@ /** * Object-oriented option getter. * - * The object must have `T get(Socket<Address, Protocol> &) const`, T can be any type and it is the value + * The object must have `T get(Socket<Address> &) 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 + * \throw Error on errors */ template <typename Option> inline auto get() -> decltype(std::declval<Option>().get(*this)) @@ -1464,14 +1411,14 @@ * \pre isOpen() * \param address the address * \param length the size - * \throw net::Error on errors + * \throw Error on errors */ inline void bind(const sockaddr *address, socklen_t length) { assert(m_handle != Invalid); if (::bind(m_handle, address, length) == Failure) - throw Error(Error::System, "bind"); + throw Error(); } /** @@ -1479,14 +1426,13 @@ * * \pre isOpen() * \param address the address - * \throw net::Error on errors + * \throw Error on errors */ inline void bind(const Address &address) { assert(m_handle != Invalid); - if (::bind(m_handle, address.address(), address.length()) == Failure) - throw Error(Error::System, "bind"); + bind(address.address(), address.length()); } /** @@ -1494,14 +1440,14 @@ * * \pre isOpen() * \param max the maximum number - * \throw net::Error on errors + * \throw Error on errors */ inline void listen(int max = 128) { assert(m_handle != Invalid); if (::listen(this->m_handle, max) == Failure) - throw Error(Error::System, "listen"); + throw Error(); } /** @@ -1519,7 +1465,7 @@ socklen_t length = sizeof (sockaddr_storage); if (::getsockname(m_handle, reinterpret_cast<sockaddr *>(&ss), &length) == Failure) - throw Error(Error::System, "getsockname"); + throw Error(); return Address(reinterpret_cast<sockaddr *>(&ss), length); } @@ -1539,577 +1485,12 @@ socklen_t length = sizeof (sockaddr_storage); if (::getpeername(m_handle, reinterpret_cast<sockaddr *>(&ss), &length) == Failure) - throw Error(Error::System, "getpeername"); + throw Error(); return Address(reinterpret_cast<sockaddr *>(&ss), length); } /** - * Initialize connection to the given address. - * - * \pre isOpen() - * \param address the address - * \param length the address length - * \param cond the condition - * \throw net::Error on failures - */ - inline void connect(const sockaddr *address, socklen_t length, Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - m_proto.connect(*this, address, length, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param address the address - * \param length the address length - * \throw net::Error on failures - */ - inline void connect(const sockaddr *address, socklen_t length) - { - Condition dummy; - - connect(address, length, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param address the address - * \param cond the condition - * \throw net::Error on failures - */ - inline void connect(const Address &address, Condition &cond) - { - connect(address.address(), address.length(), cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param address the address - * \throw net::Error on failures - */ - inline void connect(const Address &address) - { - Condition dummy; - - connect(address.address(), address.length(), dummy); - } - - /** - * Continue connect process. - * - * \pre isOpen() - * \param cond the condition require for next selection - * \throw net::Error on failures - */ - inline void resumeConnect(Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - m_proto.resumeConnect(*this, cond); - } - - /** - * Continue connect process. - * - * \pre isOpen() - * \throw net::Error on failures - */ - inline void resumeConnect() - { - Condition dummy; - - resumeConnect(dummy); - } - - /** - * Accept a new client. - * - * If no connection is available immediately, returns an invalid socket. - * - * \pre isOpen() - * \param address the client information - * \param cond the condition to wait to complete accept on the **client** - * \return the new client or an invalid if no client is immediately available - * \throw net::Error on failures - */ - Socket<Address, Protocol> accept(Address &address, Condition &cond) - { - assert(m_handle != Invalid); - - sockaddr_storage storage; - socklen_t length = sizeof (storage); - - cond = Condition::None; - - Socket<Address, Protocol> client = m_proto.accept(*this, reinterpret_cast<sockaddr *>(&storage), &length, cond); - - address = Address(reinterpret_cast<sockaddr *>(&storage), length); - - return client; - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param address the client information - * \return the new client or an invalid if no client is immediately available - * \throw net::Error on failures - */ - inline Socket<Address, Protocol> accept(Address &address) - { - Condition dummy; - - return accept(address, dummy); - } - - /** - * Overlaoded function. - * - * \pre isOpen() - * \return the new client or an invalid if no client is immediately available - * \throw net::Error on failures - */ - inline Socket<Address, Protocol> accept() - { - Address da; - Condition dc; - - return accept(da, dc); - } - - /** - * Continue accept process. - * - * \pre isOpen() - * \param cond the condition - * \throw net::Error on failures - * \note This should be called on the returned client from accept - */ - inline void resumeAccept(Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - m_proto.resumeAccept(*this, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \throw net::Error on failures - */ - inline void resumeAccept() - { - Condition dummy; - - resumeAccept(dummy); - } - - /** - * Receive some data. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the data length - * \param cond the condition - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recv(void *data, std::size_t length, Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - return m_proto.recv(*this, data, length, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the data length - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recv(void *data, std::size_t length) - { - Condition dummy; - - return recv(data, length, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param count number of bytes desired - * \param cond the condition - * \return the result string - * \throw net::Error on failures - */ - std::string recv(std::size_t count, Condition &cond) - { - assert(m_handle != Invalid); - - std::string result; - - result.resize(count); - auto n = recv(const_cast<char *>(result.data()), count, cond); - result.resize(n); - - return result; - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param count number of bytes desired - * \return the result string - * \throw net::Error on failures - */ - inline std::string recv(std::size_t count) - { - Condition dummy; - - return recv(count, dummy); - } - - /** - * Send some data. - * - * \pre isOpen() - * \param data the data to send - * \param length the length - * \param cond the condition - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t send(const void *data, std::size_t length, Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - return m_proto.send(*this, data, length, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data to send - * \param length the length - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t send(const void *data, std::size_t length) - { - Condition dummy; - - return send(data, length, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data to send - * \param cond the condition - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t send(const std::string &data, Condition &cond) - { - return send(data.c_str(), data.length(), cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data to send - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t send(const std::string &data) - { - Condition dummy; - - return send(data.c_str(), data.length(), dummy); - } - - /** - * Send some data to the given client. - * - * \pre isOpen() - * \param data the data - * \param length the length - * \param address the client address - * \param addrlen the client address length - * \param cond the condition - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const void *data, std::size_t length, const sockaddr *address, socklen_t addrlen, Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - return m_proto.sendto(*this, data, length, address, addrlen, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data - * \param length the length - * \param address the client address - * \param addrlen the client address length - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const void *data, std::size_t length, const sockaddr *address, socklen_t addrlen) - { - Condition dummy; - - return send(data, length, address, addrlen, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data - * \param length the length - * \param address the client address - * \param cond the condition - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const void *data, std::size_t length, const Address &address, Condition &cond) - { - return sendto(data, length, address.address(), address.length(), cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data - * \param length the length - * \param address the client address - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const void *data, std::size_t length, const Address &address) - { - Condition dummy; - - return sendto(data, length, address.address(), address.length(), dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data - * \param cond the condition - * \param address the client address - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const std::string &data, const Address &address, Condition &cond) - { - return sendto(data.c_str(), data.length(), address.address(), address.length(), cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the data - * \param address the client address - * \return the number of bytes sent - * \throw net::Error on failures - */ - inline std::size_t sendto(const std::string &data, const Address &address) - { - Condition dummy; - - return sendto(data.c_str(), data.length(), address.address(), address.length(), dummy); - } - - /** - * Receive some data from a client. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the buffer length - * \param address the client information - * \param addrlen the client address initial length - * \param cond the condition - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recvfrom(void *data, std::size_t length, sockaddr *address, socklen_t *addrlen, Condition &cond) - { - assert(m_handle != Invalid); - - cond = Condition::None; - - return m_proto.recvfrom(*this, data, length, address, addrlen, cond); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the buffer length - * \param address the client information - * \param addrlen the client address initial length - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recvfrom(void *data, std::size_t length, sockaddr *address, socklen_t *addrlen) - { - Condition dummy; - - return recvfrom(data, length, address, addrlen, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the buffer length - * \param address the client information - * \param cond the condition - * \return the number of bytes received - * \throw net::Error on failures - */ - std::size_t recvfrom(void *data, std::size_t length, Address &address, Condition &cond) - { - sockaddr_storage storage; - socklen_t addrlen = sizeof (sockaddr_storage); - - auto n = recvfrom(data, length, reinterpret_cast<sockaddr *>(&storage), &addrlen, cond); - - if (n != 0 && cond == Condition::None) - address = Address(reinterpret_cast<sockaddr *>(&storage), addrlen); - - return n; - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the buffer length - * \param address the client information - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recvfrom(void *data, std::size_t length, Address &address) - { - Condition dummy; - - return recvfrom(data, length, address, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param data the destination buffer - * \param length the buffer length - * \return the number of bytes received - * \throw net::Error on failures - */ - inline std::size_t recvfrom(void *data, std::size_t length) - { - Address da; - Condition dc; - - return recvfrom(data, length, da, dc); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param count the number of bytes desired - * \param address the client information - * \param cond the condition - * \return the result string - * \throw net::Error on failures - */ - std::string recvfrom(std::size_t count, Address &address, Condition &cond) - { - std::string result; - - result.resize(count); - auto n = recvfrom(const_cast<char *>(result.data()), count, address, cond); - result.resize(n); - - return result; - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param count the number of bytes desired - * \param address the client information - * \return the result string - * \throw net::Error on failures - */ - inline std::string recvfrom(std::size_t count, Address &address) - { - Condition dummy; - - return recvfrom(count, address, dummy); - } - - /** - * Overloaded function. - * - * \pre isOpen() - * \param count the number of bytes desired - * \return the result string - * \throw net::Error on failures - */ - inline std::string recvfrom(std::size_t count) - { - Address da; - Condition dc; - - return recvfrom(count, da, dc); - } - - /** * Close the socket. * * Automatically called from the destructor. @@ -2143,8 +1524,6 @@ Socket &operator=(Socket &&other) noexcept { m_handle = other.m_handle; - m_proto = std::move(other.m_proto); - other.m_handle = Invalid; return *this; @@ -2158,8 +1537,8 @@ * \param s2 the second socket * \return true if they equals */ -template <typename Address, typename Protocol> -inline bool operator==(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator==(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() == s2.handle(); } @@ -2171,8 +1550,8 @@ * \param s2 the second socket * \return true if they are different */ -template <typename Address, typename Protocol> -inline bool operator!=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator!=(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() != s2.handle(); } @@ -2184,8 +1563,8 @@ * \param s2 the second socket * \return true if s1 < s2 */ -template <typename Address, typename Protocol> -inline bool operator<(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator<(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() < s2.handle(); } @@ -2197,8 +1576,8 @@ * \param s2 the second socket * \return true if s1 > s2 */ -template <typename Address, typename Protocol> -inline bool operator>(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator>(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() > s2.handle(); } @@ -2210,8 +1589,8 @@ * \param s2 the second socket * \return true if s1 <= s2 */ -template <typename Address, typename Protocol> -inline bool operator<=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator<=(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() <= s2.handle(); } @@ -2223,203 +1602,157 @@ * \param s2 the second socket * \return true if s1 >= s2 */ -template <typename Address, typename Protocol> -inline bool operator>=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +template <typename Address> +inline bool operator>=(const Socket<Address> &s1, const Socket<Address> &s2) { return s1.handle() >= s2.handle(); } /** - * \brief Predefined protocols. - */ -namespace protocol { - -/** * \brief Clear TCP implementation. * \ingroup net-module-tcp * * This is the basic TCP protocol that implements recv, send, connect and accept as wrappers of the usual * C functions. */ -class Tcp { +template <typename Address> +class TcpSocket : public Socket<Address> { public: - /** - * Socket type. - * - * \return SOCK_STREAM - */ - inline int type() const noexcept - { - return SOCK_STREAM; - } - - /** - * Do nothing. - * - * This function is just present for compatibility, it should never be called. - */ - template <typename Address> - inline void create(Socket<Address, Tcp> &) const noexcept + using Socket<Address>::Socket; + + TcpSocket() + : Socket<Address>(Address().domain(), SOCK_STREAM, 0) { } /** * Initiate connection. * - * \param sc the socket * \param address the address * \param length the address length - * \param cond the condition + * \throw WouldBlockError if the socket is marked non-blocking and connection cannot be established immediately + * \throw Error on other errors */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length, Condition &cond) + void connect(const sockaddr *address, socklen_t length) { - if (::connect(sc.handle(), address, length) == Failure) { - /* - * Determine if the error comes from a non-blocking connect that cannot be - * accomplished yet. - */ + if (::connect(this->m_handle, address, length) == Failure) { #if defined(_WIN32) int error = WSAGetLastError(); if (error == WSAEWOULDBLOCK) - cond = Condition::Writable; + throw WouldBlockError(); else - throw Error(Error::System, "connect", error); + throw Error(error); #else if (errno == EINPROGRESS) - cond = Condition::Writable; + throw WouldBlockError(); else - throw Error(Error::System, "connect"); + throw Error(); #endif } } /** - * Resume the connection. - * - * Just check for SOL_SOCKET/SO_ERROR. - * - * User is responsible to wait before the socket is writable, otherwise behavior is undefined. + * Overloaded function. * - * \param sc the socket - * \param cond the condition + * \param address the address + * \throw WouldBlockError if the socket is marked non-blocking and connection cannot be established immediately + * \throw Error on other errors */ - template <typename Address, typename Protocol> - void resumeConnect(Socket<Address, Protocol> &sc, Condition &cond) + void connect(const Address &address) { - int error = sc.template get<int>(SOL_SOCKET, SO_ERROR); - -#if defined(_WIN32) - if (error == WSAEWOULDBLOCK) - cond = Condition::Writable; - else if (error != 0) - throw Error(Error::System, "connect", error); -#else - if (error == EINPROGRESS) - cond = Condition::Writable; - else if (error != 0) - throw Error(Error::System, "connect", error); -#endif + connect(address.address(), address.length()); } /** * Accept a new client. * - * If there are no pending connection, an invalid socket is returned, condition is left to Condition::None. + * If there are no pending connection, an invalid socket is returned. * * \param sc the socket - * \param address the address - * \param length the length * \return the new socket + * \throw WouldBlockError if the socket is marked non-blocking and no connection are available + * \throw Error on other errors */ - template <typename Address, typename Protocol> - Socket<Address, Protocol> accept(Socket<Address, Protocol> &sc, sockaddr *address, socklen_t *length, Condition &) + TcpSocket<Address> accept() { - Handle handle = ::accept(sc.handle(), address, length); - - if (handle == Invalid) - return Socket<Address, Protocol>(); - - return Socket<Address, Protocol>(handle); - } - - /** - * Resume accept process. - * - * No-op for TCP. - */ - template <typename Address, typename Protocol> - inline void resumeAccept(Socket<Address, Protocol> &, Condition &) const noexcept - { + Handle handle = ::accept(this->m_handle, nullptr, 0); + + if (handle == Invalid) { +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(error); +#else + if (errno == EWOULDBLOCK || errno = EAGAIN) + throw WouldBlockError(); + else + throw Error(); +#endif + } + + return TcpSocket<Address>(handle); } /** * Receive some data. * - * \param sc the socket * \param data the destination buffer * \param length the buffer length - * \param cond the condition - * \return the number of byte received + * \return the number of bytes received */ - template <typename Address> - std::size_t recv(Socket<Address, Tcp> &sc, void *data, std::size_t length, Condition &cond) + unsigned recv(void *data, unsigned length) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); - int nbread = ::recv(sc.handle(), (Arg)data, max, 0); + int nbread = ::recv(this->m_handle, (Arg)data, max, 0); if (nbread == Failure) { #if defined(_WIN32) int error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) { - nbread = 0; - cond = Condition::Readable; - } else - throw Error(Error::System, "recv", error); + if (error == WSAEWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(error); #else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbread = 0; - cond = Condition::Readable; - } else - throw Error(Error::System, "recv"); + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(); #endif } - return static_cast<std::size_t>(nbread); + return static_cast<unsigned>(nbread); } /** * Send some data. * - * \param sc the socket * \param data the data to send * \param length the length - * \param cond the condition * \return the number of bytes sent */ - template <typename Address> - std::size_t send(Socket<Address, Tcp> &sc, const void *data, std::size_t length, Condition &cond) + unsigned send(const void *data, unsigned length) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); - int nbsent = ::send(sc.handle(), (ConstArg)data, max, 0); + int nbsent = ::send(this->m_handle, (ConstArg)data, max, 0); if (nbsent == Failure) { #if defined(_WIN32) int error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) { - nbsent = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "send", error); + if (error == WSAEWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(); #else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbsent = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "send"); + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(); #endif } @@ -2432,60 +1765,36 @@ * * This class is the basic implementation of UDP sockets. */ -class Udp { +template <typename Address> +class UdpSocket { public: /** - * Socket type. - * - * \return SOCK_DGRAM - */ - inline int type() const noexcept - { - return SOCK_DGRAM; - } - - /** - * Do nothing. - */ - template <typename Address, typename Protocol> - inline void create(Socket<Address, Protocol> &) noexcept - { - } - - /** * Receive some data. * - * \param sc the socket * \param data the data * \param length the length * \param address the source address * \param addrlen the source address in/out length - * \param cond the condition * \return the number of bytes received */ - template <typename Address, typename Protocol> - std::size_t recvfrom(Socket<Address, Protocol> &sc, void *data, std::size_t length, sockaddr *address, socklen_t *addrlen, Condition &cond) + unsigned recvfrom(void *data, unsigned length, sockaddr *address, socklen_t *addrlen) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); - int nbread; - - nbread = ::recvfrom(sc.handle(), (Arg)data, max, 0, address, addrlen); + int nbread = ::recvfrom(this->m_handle, (Arg)data, max, 0, address, addrlen); if (nbread == Failure) { #if defined(_WIN32) int error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) { - nbread = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "recvfrom"); + if (error == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(error); #else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbread = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "recvfrom"); + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(); #endif } @@ -2495,36 +1804,30 @@ /** * Send some data. * - * \param sc the socket * \param data the data to send * \param length the data length * \param address the destination address * \param addrlen the destination address length - * \param cond the condition * \return the number of bytes sent */ - template <typename Address, typename Protocol> - std::size_t sendto(Socket<Address, Protocol> &sc, const void *data, std::size_t length, const sockaddr *address, socklen_t addrlen, Condition &cond) + unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); - int nbsent; - - nbsent = ::sendto(sc.handle(), (ConstArg)data, max, 0, address, addrlen); + int nbsent = ::sendto(this->m_handle, (ConstArg)data, max, 0, address, addrlen); + if (nbsent == Failure) { #if defined(_WIN32) int error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) { - nbsent = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "sendto", error); + if (error == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(error); #else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbsent = 0; - cond = Condition::Writable; - } else - throw Error(Error::System, "sendto"); + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw WouldBlockError(); + else + throw Error(); #endif } @@ -2539,33 +1842,27 @@ * \ingroup net-module-tls * \warning This class is highly experimental. */ -class Tls : private Tcp { +template <typename Address> +class TlsSocket : public Socket<Address> { +public: + /** + * \brief SSL connection mode. + */ + enum Mode { + /// Use Server when you accept a socket server side. + Server, + + /// Use Client when you connect to a server. + Client + }; + private: using Context = std::shared_ptr<SSL_CTX>; using Ssl = std::unique_ptr<SSL, void (*)(SSL *)>; - // OpenSSL objects. Context m_context; Ssl m_ssl{nullptr, nullptr}; - // Status. - bool m_tcpconnected{false}; - - /* - * User definable parameters. - */ - ssl::Method m_method{ssl::Tlsv1}; - std::string m_key; - std::string m_certificate; - bool m_verify{false}; - - // Construct with a context and ssl, for Tls::accept. - Tls(Context context, Ssl ssl) - : m_context(std::move(context)) - , m_ssl(std::move(ssl)) - { - } - inline std::string error() { BIO *bio = BIO_new(BIO_s_mem()); @@ -2582,7 +1879,7 @@ } template <typename Function> - void wrap(const std::string &func, Condition &cond, Function &&function) + void wrap(Function &&function) { auto ret = function(); @@ -2591,64 +1888,37 @@ switch (no) { case SSL_ERROR_WANT_READ: - cond = Condition::Readable; - break; + throw WantReadError(); case SSL_ERROR_WANT_WRITE: - cond = Condition::Writable; - break; + throw WantWriteError(); default: - throw Error(Error::System, func, error()); + throw Error(error()); } } } - template <typename Address, typename Protocol> - void doConnect(Socket<Address, Protocol> &, Condition &cond) - { - wrap("connect", cond, [&] () -> int { - return SSL_connect(m_ssl.get()); - }); - } - - template <typename Address, typename Protocol> - void doAccept(Socket<Address, Protocol> &, Condition &cond) - { - wrap("accept", cond, [&] () -> int { - return SSL_accept(m_ssl.get()); - }); - } - public: /** - * \copydoc Tcp::type + * Wrap a socket around an existing one. + * + * \param sock the TCP socket + * \param mode the mode */ - inline int type() const noexcept - { - return SOCK_STREAM; - } - - /** - * Empty TLS constructor. - */ - inline Tls() + inline TlsSocket(TcpSocket<Address> &sock, Mode mode = Server, const SSL_METHOD *method = TLSv1_method()) + : Socket<Address>(sock.handle()) { #if !defined(NET_NO_SSL_AUTO_INIT) ssl::init(); #endif - } - - /** - * Set the method. - * - * \param method the method - * \pre the socket must not be already created - */ - inline void setMethod(ssl::Method method) noexcept - { - assert(!m_context); - assert(!m_ssl); - - m_method = method; + m_context = Context(SSL_CTX_new(method), SSL_CTX_free); + m_ssl = Ssl(SSL_new(m_context.get()), SSL_free); + + SSL_set_fd(m_ssl.get(), this->m_handle); + + if (mode == Server) + SSL_set_accept_state(m_ssl.get()); + else + SSL_set_connect_state(m_ssl.get()); } /** @@ -2656,9 +1926,10 @@ * * \param file the path to the private key */ - inline void setPrivateKey(std::string file) noexcept + inline void setPrivateKey(std::string file, int type = SSL_FILETYPE_PEM) noexcept { - m_key = std::move(file); + if (SSL_use_PrivateKey_file(m_ssl.get(), file.c_str(), type) != 1) + throw Error(error()); } /** @@ -2666,142 +1937,24 @@ * * \param file the path to the file */ - inline void setCertificate(std::string file) noexcept + inline void setCertificate(std::string file, int type = SSL_FILETYPE_PEM) noexcept { - m_certificate = std::move(file); - } - - /** - * Set to true if we must verify the certificate and private key. - * - * \param verify the mode - */ - inline void setVerify(bool verify = true) noexcept - { - m_verify = verify; + if (SSL_use_certificate_file(m_ssl.get(), file.c_str(), type) != 1) + throw Error(error()); } /** - * Initialize the SSL objects after have created. + * Do handshake, needed in some case when you have non blocking sockets. * - * \param sc the socket - * \throw net::Error on errors - */ - template <typename Address> - void create(Socket<Address, Tls> &sc) - { - auto method = (m_method == ssl::Tlsv1) ? TLSv1_method() : SSLv23_method(); - - m_context = Context(SSL_CTX_new(method), SSL_CTX_free); - m_ssl = Ssl(SSL_new(m_context.get()), SSL_free); - - SSL_set_fd(m_ssl.get(), static_cast<int>(sc.handle())); - - /* - * Load certificates, the wrap function requires a condition so just add a dummy value. - */ - Condition dummy; - - if (m_certificate.size() > 0) - wrap("SSL_CTX_use_certificate_file", dummy, [&] () -> int { - return SSL_CTX_use_certificate_file(m_context.get(), m_certificate.c_str(), SSL_FILETYPE_PEM); - }); - if (m_key.size() > 0) - wrap("SSL_CTX_use_PrivateKey_file", dummy, [&] () -> int { - return SSL_CTX_use_PrivateKey_file(m_context.get(), m_key.c_str(), SSL_FILETYPE_PEM); - }); - if (m_verify && !SSL_CTX_check_private_key(m_context.get())) - throw Error(Error::System, "(openssl)", "unable to verify key"); - } - - /** - * Initiate connection. - * - * \param sc the socket * \param address the address * \param length the address length * \param cond the condition */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length, Condition &cond) - { - // 1. Connect using raw TCP. - Tcp::connect(sc, address, length, cond); - - // 2. If the connection is complete (e.g. non-blocking), try handshake. - if (cond == Condition::None) { - m_tcpconnected = true; - doConnect(sc, cond); - } - } - - /** - * Resume the connection. - * - * \param sc the socket - * \param cond the condition to wait - */ - template <typename Address, typename Protocol> - void resumeConnect(Socket<Address, Protocol> &sc, Condition &cond) + void handshake() { - // 1. Be sure to complete standard connect before. - if (!m_tcpconnected) { - Tcp::resumeConnect(sc, cond); - m_tcpconnected = (cond == Condition::None); - } - - // 2. Do SSL connect. - if (m_tcpconnected) - doConnect(sc, cond); - } - - /** - * Accept a new client. - * - * If there are no pending connection, an invalid socket is returned, condition is left to Condition::None. - * - * \param sc the socket - * \param address the address - * \param length the length - * \param cond the condition to wait - * \return the new socket - */ - template <typename Address> - Socket<Address, Tls> accept(Socket<Address, Tls> &sc, sockaddr *address, socklen_t *length, Condition &cond) - { - // 1. TCP returns empty client if no pending connection is available. - auto client = Tcp::accept(sc, address, length, cond); - - // 2. If a client is available, try initial accept. - if (client.isOpen()) { - Tls &proto = client.protocol(); - - // 2.1. Share the context. - proto.m_context = m_context; - - // 2.2. Create new SSL instance. - proto.m_ssl = Ssl(SSL_new(m_context.get()), SSL_free); - - SSL_set_fd(proto.m_ssl.get(), static_cast<int>(client.handle())); - - // 2.3. Try accept process on the **new** client. - proto.doAccept(client, cond); - } - - return client; - } - - /** - * Resume accept process. - * - * \param sc the socket - * \param cond the condition to wait - * \throw net::Error on failures - */ - template <typename Address, typename Protocol> - inline void resumeAccept(Socket<Address, Protocol> &sc, Condition &cond) - { - doAccept(sc, cond); + wrap([&] () -> int { + SSL_do_handshake(m_ssl.get()); + }); } /** @@ -2809,20 +1962,18 @@ * * \param data the destination buffer * \param length the buffer length - * \param cond the condition * \return the number of bytes received */ - template <typename Address> - std::size_t recv(Socket<Address, Tls> &, void *data, std::size_t length, Condition &cond) + unsigned recv(void *data, unsigned length) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); int nbread = 0; - wrap("recv", cond, [&] () -> int { + wrap([&] () -> int { return (nbread = SSL_read(m_ssl.get(), data, max)); }); - return static_cast<std::size_t>(nbread < 0 ? 0 : nbread); + return static_cast<unsigned>(nbread < 0 ? 0 : nbread); } /** @@ -2833,24 +1984,21 @@ * \param cond the condition * \return the number of bytes sent */ - template <typename Address> - std::size_t send(Socket<Address, Tls> &, const void *data, std::size_t length, Condition &cond) + unsigned send(const void *data, unsigned length) { int max = length > INT_MAX ? INT_MAX : static_cast<int>(length); int nbsent = 0; - wrap("send", cond, [&] () -> int { + wrap([&] () -> int { return (nbsent = SSL_write(m_ssl.get(), data, max)); }); - return static_cast<std::size_t>(nbsent < 0 ? 0 : nbsent); + return static_cast<unsigned>(nbsent < 0 ? 0 : nbsent); } }; #endif // !NET_NO_SSL -} // !protocol - /** * \brief Predefined addresses. */ @@ -2998,7 +2146,7 @@ * \param port the port * \param domain the domain * \warning If NET_HAVE_INET_PTON is undefined, host can not be other than "*" - * \throw net::Error on failures or if inet_pton is unavailable + * \throw Error on failures or if inet_pton is unavailable */ inline Ip(const std::string &ip, std::uint16_t port, int domain) : Ip(domain) @@ -3071,7 +2219,7 @@ * Get the ip address. * * \return the ip address - * \throw net::Error on errors or if inet_ntop is unavailable + * \throw Error on errors or if inet_ntop is unavailable */ inline std::string ip() const { @@ -3084,12 +2232,12 @@ * \param ip the ip address * \param port the port * \param sin the Ipv4 address - * \throw net::Error if inet_pton is unavailable + * \throw Error if inet_pton is unavailable */ static void make(const std::string &ip, std::uint16_t port, sockaddr_in &sin) { #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif sin.sin_family = AF_INET; @@ -3099,10 +2247,10 @@ sin.sin_addr.s_addr = INADDR_ANY; #if defined(NET_HAVE_INET_PTON) else if (inet_pton(AF_INET, ip.c_str(), &sin.sin_addr) <= 0) - throw Error(Error::System, "inet_pton"); + throw Error(); #else else - throw Error(Error::System, "inet_pton", std::strerror(ENOSYS)); + throw Error(std::strerror(ENOSYS)); #endif } @@ -3112,12 +2260,12 @@ * \param ip the ip address * \param port the port * \param sin6 the Ipv6 address - * \throw net::Error if inet_pton is unavailable + * \throw Error if inet_pton is unavailable */ static void make(const std::string &ip, std::uint16_t port, sockaddr_in6 &sin6) { #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif sin6.sin6_family = AF_INET6; @@ -3127,10 +2275,10 @@ sin6.sin6_addr = in6addr_any; #if defined(NET_HAVE_INET_PTON) else if (inet_pton(AF_INET6, ip.c_str(), &sin6.sin6_addr) <= 0) - throw Error(Error::System, "inet_pton"); + throw Error(); #else else - throw Error(Error::System, "inet_pton", std::strerror(ENOSYS)); + throw Error(std::strerror(ENOSYS)); #endif } @@ -3139,25 +2287,25 @@ * * \param sin the Ipv4 address * \return the ip address - * \throw net::Error if inet_ntop is unavailable + * \throw Error if inet_ntop is unavailable */ static std::string ip(const sockaddr_in &sin) { #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif #if !defined(NET_HAVE_INET_NTOP) (void)sin; - throw Error(Error::System, "inet_ntop", std::strerror(ENOSYS)); + throw Error(ENOSYS, std::strerror(ENOSYS)); #else char result[INET_ADDRSTRLEN + 1]; std::memset(result, 0, sizeof (result)); if (!inet_ntop(AF_INET, const_cast<in_addr *>(&sin.sin_addr), result, sizeof (result))) - throw Error(Error::System, "inet_ntop"); + throw Error(); return result; #endif @@ -3168,25 +2316,25 @@ * * \param sin6 the Ipv6 address * \return the ip address - * \throw net::Error if inet_ntop is unavailable + * \throw Error if inet_ntop is unavailable */ static std::string ip(const sockaddr_in6 &sin6) { #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif #if !defined(NET_HAVE_INET_NTOP) (void)sin6; - throw Error(Error::System, "inet_ntop", std::strerror(ENOSYS)); + throw Error(ENOSYS, std::strerror(ENOSYS)); #else char result[INET6_ADDRSTRLEN]; std::memset(result, 0, sizeof (result)); if (!inet_ntop(AF_INET6, const_cast<in6_addr *>(&sin6.sin6_addr), result, sizeof (result))) - throw Error(Error::System, "inet_ntop"); + throw Error(); return result; #endif @@ -3202,13 +2350,13 @@ * \param domain the domain (e.g. AF_INET) * \param type the socket type (e.g. SOCK_STREAM) * \return the resolved address - * \throw net::Error on failures + * \throw Error on failures */ static Ip resolve(const std::string &host, const std::string &service, int domain = AF_INET, int type = SOCK_STREAM) { assert(domain == AF_INET || domain == AF_INET6); #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif struct addrinfo hints, *res; @@ -3220,7 +2368,7 @@ int e = getaddrinfo(host.c_str(), service.c_str(), &hints, &res); if (e != 0) - throw Error(Error::System, "getaddrinfo", gai_strerror(e)); + throw Error(gai_strerror(e)); Ip ip(res->ai_addr, res->ai_addrlen); @@ -3253,7 +2401,7 @@ * \param ip the address or "*" for any * \param port the port * \warning If NET_HAVE_INET_PTON is undefined, host can not be other than "*" - * \throw net::Error on failures or if inet_pton is unavailable + * \throw Error on failures or if inet_pton is unavailable */ inline Ipv4(const std::string &ip, std::uint16_t port) : Ipv4() @@ -3319,7 +2467,7 @@ * Get the ip address. * * \return the ip address - * \throw net::Error on errors or if inet_ntop is unavailable + * \throw Error on errors or if inet_ntop is unavailable */ inline std::string ip() const { @@ -3333,7 +2481,7 @@ * \param service the service name (port or name) * \param type the socket type (e.g. SOCK_STREAM) * \return the resolved address - * \throw net::Error on failures + * \throw Error on failures */ static Ipv4 resolve(const std::string &host, const std::string &service, int type = SOCK_STREAM) { @@ -3366,7 +2514,7 @@ * \param ip the address or "*" for any * \param port the port * \warning If NET_HAVE_INET_PTON is undefined, host can not be other than "*" - * \throw net::Error on failures or if inet_pton is unavailable + * \throw Error on failures or if inet_pton is unavailable */ inline Ipv6(const std::string &ip, std::uint16_t port) : Ipv6() @@ -3432,7 +2580,7 @@ * Get the ip address. * * \return the ip address - * \throw net::Error on errors or if inet_ntop is unavailable + * \throw Error on errors or if inet_ntop is unavailable */ inline std::string ip() const { @@ -3446,7 +2594,7 @@ * \param service the service name (port or name) * \param type the socket type (e.g. SOCK_STREAM) * \return the resolved address - * \throw net::Error on failures + * \throw Error on failures */ static Ipv6 resolve(const std::string &host, const std::string &service, int type = SOCK_STREAM) { @@ -3558,14 +2706,14 @@ * * This iterator can be used to try to connect to an host. * - * When you use net::resolve with unspecified domain or socket type, the function may retrieve several different addresses that you can + * When you use resolve with unspecified domain or socket type, the function may retrieve several different addresses that you can * iterate over to try to connect to. * * Example: * * ````cpp - * net::SocketTcpIp sc; - * net::Iterator end, it = net::resolve("hostname.test", "80"); + * SocketTcpIp sc; + * Iterator end, it = resolve("hostname.test", "80"); * * while (!connected_condition && it != end) * sc.connect(it->address(), it->length()); @@ -3749,8 +2897,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - void set(Socket<Address, Protocol> &sc) const + template <typename Address> + void set(Socket<Address> &sc) const { #if defined(O_NONBLOCK) && !defined(_WIN32) int flags; @@ -3764,12 +2912,12 @@ flags |= O_NONBLOCK; if (fcntl(sc.handle(), F_SETFL, flags) < 0) - throw Error(Error::System, "fcntl"); + throw Error(); #else unsigned long flags = (m_value) ? 0 : 1; if (ioctlsocket(sc.handle(), FIONBIO, &flags) == Failure) - throw Error(Error::System, "fcntl"); + throw Error(); #endif } @@ -3780,20 +2928,20 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - bool get(Socket<Address, Protocol> &sc) const + template <typename Address> + bool get(Socket<Address> &sc) const { #if defined(O_NONBLOCK) && !defined(_WIN32) int flags = fcntl(sc.handle(), F_GETFL, 0); if (flags < 0) - throw Error(Error::System, "fcntl"); + throw Error(); return !(flags & O_NONBLOCK); #else (void)sc; - throw Error(Error::Other, "get", std::strerror(ENOSYS)); + throw Error(std::strerror(ENOSYS)); #endif } }; @@ -3823,8 +2971,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const + template <typename Address> + inline void set(Socket<Address> &sc) const { sc.set(SOL_SOCKET, SO_RCVBUF, m_value); } @@ -3836,8 +2984,8 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - inline int get(Socket<Address, Protocol> &sc) const + template <typename Address> + inline int get(Socket<Address> &sc) const { return sc.template get<int>(SOL_SOCKET, SO_RCVBUF); } @@ -3870,8 +3018,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const + template <typename Address> + inline void set(Socket<Address> &sc) const { sc.set(SOL_SOCKET, SO_REUSEADDR, m_value ? 1 : 0); } @@ -3883,8 +3031,8 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const + template <typename Address> + inline bool get(Socket<Address> &sc) const { return sc.template get<int>(SOL_SOCKET, SO_REUSEADDR) != 0; } @@ -3915,8 +3063,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const + template <typename Address> + inline void set(Socket<Address> &sc) const { sc.set(SOL_SOCKET, SO_SNDBUF, m_value); } @@ -3928,8 +3076,8 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - inline int get(Socket<Address, Protocol> &sc) const + template <typename Address> + inline int get(Socket<Address> &sc) const { return sc.template get<int>(SOL_SOCKET, SO_SNDBUF); } @@ -3962,8 +3110,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const + template <typename Address> + inline void set(Socket<Address> &sc) const { sc.set(IPPROTO_TCP, TCP_NODELAY, m_value ? 1 : 0); } @@ -3975,8 +3123,8 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const + template <typename Address> + inline bool get(Socket<Address> &sc) const { return sc.template get<int>(IPPROTO_TCP, TCP_NODELAY) != 0; } @@ -4012,8 +3160,8 @@ * \param sc the socket * \throw Error on errors */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const + template <typename Address> + inline void set(Socket<Address> &sc) const { sc.set(IPPROTO_IPV6, IPV6_V6ONLY, m_value ? 1 : 0); } @@ -4025,8 +3173,8 @@ * \return the value * \throw Error on errors */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const + template <typename Address> + inline bool get(Socket<Address> &sc) const { return sc.template get<int>(IPPROTO_IPV6, IPV6_V6ONLY) != 0; } @@ -4105,20 +3253,20 @@ ev.data.fd = h; if (epoll_ctl(m_handle, op, h, &ev) < 0) - throw Error(Error::System, "epoll_ctl"); + throw Error(); } public: /** * Create epoll. * - * \throw net::Error on failures + * \throw Error on failures */ inline Epoll() : m_handle(epoll_create1(0)) { if (m_handle < 0) - throw Error(Error::System, "epoll_create"); + throw Error(); } /** @@ -4160,7 +3308,7 @@ * \param h the handle * \param condition the condition * \param add set to true if the socket is new to the backend - * \throw net::Error on failures + * \throw Error on failures */ void set(const ListenerTable &table, Handle h, Condition condition, bool add) { @@ -4183,7 +3331,7 @@ * \param h the handle * \param condition the condition * \param add set to true if the socket is new to the backend - * \throw net::Error on failures + * \throw Error on failures */ void unset(const ListenerTable &table, Handle h, Condition condition, bool remove) { @@ -4199,7 +3347,7 @@ * * \param ms the milliseconds timeout * \return the sockets ready - * \throw net::Error on failures + * \throw Error on failures */ std::vector<ListenerStatus> wait(const ListenerTable &, int ms) { @@ -4265,7 +3413,7 @@ /** * Create kqueue. * - * \throw net::Error on failures + * \throw Error on failures */ inline Kqueue() : m_handle(kqueue()) @@ -4310,7 +3458,7 @@ * \param h the handle * \param condition the condition * \param add set to true if the socket is new to the backend - * \throw net::Error on failures + * \throw Error on failures */ void set(const ListenerTable &, Handle h, Condition condition, bool add) { @@ -4328,7 +3476,7 @@ * \param h the handle * \param condition the condition * \param remove set to true if the socket is completely removed - * \throw net::Error on failures + * \throw Error on failures */ void unset(const ListenerTable &, Handle h, Condition condition, bool remove) { @@ -4345,7 +3493,7 @@ * * \param ms the milliseconds timeout * \return the sockets ready - * \throw net::Error on failures + * \throw Error on failures */ std::vector<ListenerStatus> wait(const ListenerTable &, int ms) { @@ -4452,7 +3600,7 @@ * \param h the handle * \param condition the condition * \param add set to true if the socket is new to the backend - * \throw net::Error on failures + * \throw Error on failures */ void set(const ListenerTable &, Handle h, Condition condition, bool add) { @@ -4473,7 +3621,7 @@ * \param h the handle * \param condition the condition * \param remove set to true if the socket is completely removed - * \throw net::Error on failures + * \throw Error on failures */ void unset(const ListenerTable &, Handle h, Condition condition, bool remove) { @@ -4492,7 +3640,7 @@ * * \param ms the milliseconds timeout * \return the sockets ready - * \throw net::Error on failures + * \throw Error on failures */ std::vector<ListenerStatus> wait(const ListenerTable &, int ms) { @@ -4503,9 +3651,9 @@ #endif if (result == 0) - throw Error(Error::Timeout, "select", std::strerror(ETIMEDOUT)); + throw TimeoutError(); if (result < 0) - throw Error(Error::System, "poll"); + throw Error(); std::vector<ListenerStatus> sockets; @@ -4557,7 +3705,7 @@ * \param table the listener table * \param ms the milliseconds timeout * \return the sockets ready - * \throw net::Error on failures + * \throw Error on failures */ std::vector<ListenerStatus> wait(const ListenerTable &table, int ms) { @@ -4588,9 +3736,9 @@ auto error = ::select(static_cast<int>(max + 1), &readset, &writeset, nullptr, towait); if (error == Failure) - throw Error(Error::System, "select"); + throw Error(); if (error == 0) - throw Error(Error::Timeout, "select", std::strerror(ETIMEDOUT)); + throw TimeoutError(); std::vector<ListenerStatus> sockets; @@ -4857,55 +4005,42 @@ } }; -/** - * \ingroup net-module-tcp - * \brief Helper to create TCP sockets. - */ -template <typename Address> -using SocketTcp = Socket<Address, protocol::Tcp>; /** * \ingroup net-module-tcp * \brief Helper to create TCP/Ipv4 or TCP/Ipv6 sockets. */ -using SocketTcpIp = Socket<address::Ip, protocol::Tcp>; +using TcpSocketIp = TcpSocket<address::Ip>; /** * \ingroup net-module-tcp * \brief Helper to create TCP/Ipv4 sockets. */ -using SocketTcpIpv4 = Socket<address::Ipv4, protocol::Tcp>; +using TcpSocketIpv4 = TcpSocket<address::Ipv4>; /** * \ingroup net-module-tcp * \brief Helper to create TCP/Ipv6 sockets. */ -using SocketTcpIpv6 = Socket<address::Ipv6, protocol::Tcp>; - -/** - * \ingroup net-module-udp - * \brief Helper to create UDP sockets. - */ -template <typename Address> -using SocketUdp = Socket<Address, protocol::Udp>; +using TcpSocketIpv6 = TcpSocket<address::Ipv6>; /** * \ingroup net-module-udp * \brief Helper to create UDP/Ipv4 or UDP/Ipv6 sockets. */ -using SocketUdpIp = Socket<address::Ip, protocol::Udp>; +using UdpSocketIp = UdpSocket<address::Ip>; /** * \ingroup net-module-udp * \brief Helper to create UDP/Ipv4 sockets. */ -using SocketUdpIpv4 = Socket<address::Ipv4, protocol::Udp>; +using UdpSocketIpv4 = UdpSocket<address::Ipv4>; /** * \ingroup net-module-udp * \brief Helper to create UDP/Ipv6 sockets. */ -using SocketUdpIpv6 = Socket<address::Ipv6, protocol::Udp>; +using UdpSocketIpv6 = UdpSocket<address::Ipv6>; #if !defined(_WIN32) @@ -4913,13 +4048,13 @@ * \ingroup net-module-tcp * \brief Helper to create TCP/Local sockets. */ -using SocketTcpLocal = Socket<address::Local, protocol::Tcp>; +using TcpSocketLocal = TcpSocket<address::Local>; /** * \ingroup net-module-udp * \brief Helper to create UDP/Local sockets. */ -using SocketUdpLocal = Socket<address::Local, protocol::Udp>; +using UdpSocketLocal = TcpSocket<address::Local>; #endif @@ -4927,28 +4062,21 @@ /** * \ingroup net-module-tls - * \brief Helper to create TLS sockets. - */ -template <typename Address> -using SocketTls = Socket<Address, protocol::Tls>; - -/** - * \ingroup net-module-tls * \brief Helper to create TLS/Ipv4 or TLS/Ipv6 sockets. */ -using SocketTlsIp = Socket<address::Ip, protocol::Tls>; +using TlsSocketIp = TlsSocket<address::Ip>; /** * \ingroup net-module-tls * \brief Helper to create TLS/Ipv4 sockets. */ -using SocketTlsIpv4 = Socket<address::Ipv4, protocol::Tls>; +using TlsSocketIpv4 = TlsSocket<address::Ipv4>; /** * \ingroup net-module-tls * \brief Helper to create TLS/Ipv6 sockets. */ -using SocketTlsIpv6 = Socket<address::Ipv6, protocol::Tls>; +using TlsSocketIpv6 = TlsSocket<address::Ipv6>; #endif @@ -4962,12 +4090,12 @@ * \param domain the domain (e.g. AF_INET) * \param type the type (e.g. SOCK_STREAM) * \return the address iterator - * \throw net::Error on failures + * \throw Error on failures */ inline address::Iterator resolve(const std::string &host, const std::string &service, int domain = AF_UNSPEC, int type = 0) { #if !defined(NET_NO_AUTO_INIT) - net::init(); + init(); #endif struct addrinfo hints, *res, *p; @@ -4979,7 +4107,7 @@ int e = getaddrinfo(host.c_str(), service.c_str(), &hints, &res); if (e != 0) - throw Error(Error::System, "getaddrinfo", gai_strerror(e)); + throw Error(gai_strerror(e)); std::vector<address::Generic> addresses; @@ -4989,6 +4117,8 @@ return address::Iterator(addresses, 0); } +#if 0 + /** * \ingroup net-module-resolv * @@ -4998,14 +4128,16 @@ * \param host the hostname * \param service the service name * \return the address iterator - * \throw net::Error on failures + * \throw Error on failures */ -template <typename Address, typename Protocol> -address::Iterator resolve(const Socket<Address, Protocol> &sc, const std::string &host, const std::string &service) +template <typename Address> +address::Iterator resolve(const Socket<Address> &sc, const std::string &host, const std::string &service) { - return resolve(host, service, Address().domain(), sc.protocol().type()); + return resolve(host, service, Address().domain(), sc.type()); } +#endif + /** * \ingroup net-module-resolv * @@ -5016,7 +4148,7 @@ * \param domain the domain (e.g. AF_INET) * \param type the type (e.g. SOCK_STREAM) * \return the first generic address available - * \throw net::Error on failures + * \throw Error on failures * \note do not use AF_UNSPEC and 0 as type for this function */ inline address::Generic resolveOne(const std::string &host, const std::string &service, int domain, int type) @@ -5025,11 +4157,13 @@ address::Iterator it = resolve(host, service, domain, type); if (it == end) - throw Error(Error::Other, "resolveOne", "no address available"); + throw Error("no address available"); return *it; } +#if 0 + /** * \ingroup net-module-resolv * @@ -5039,14 +4173,16 @@ * \param host the hostname * \param service the service name * \return the first generic address available - * \throw net::Error on failures + * \throw Error on failures */ -template <typename Address, typename Protocol> -address::Generic resolveOne(const Socket<Address, Protocol> &sc, const std::string &host, const std::string &service) +template <typename Address> +address::Generic resolveOne(const Socket<Address> &sc, const std::string &host, const std::string &service) { - return resolveOne(host, service, Address().domain(), sc.protocol().type()); + return resolveOne(host, service, Address().domain(), sc.type()); } +#endif + } // !net #endif // !NET_HPP