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