changeset 471:35729a52fda5

Socket: - No more Ipv4 and Ipv6, Ip only. It's possible to control which domain to use by default with Ip::setDefault. - Add lot of more documentation, - Add State::Disconnected.
author David Demelier <markand@malikania.fr>
date Thu, 05 Nov 2015 14:54:08 +0100
parents bc3a211c5e33
children f8594d3394ab
files C++/modules/Socket/Sockets.cpp C++/modules/Socket/Sockets.h C++/tests/Socket/main.cpp
diffstat 3 files changed, 223 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Socket/Sockets.cpp	Thu Nov 05 09:07:34 2015 +0100
+++ b/C++/modules/Socket/Sockets.cpp	Thu Nov 05 14:54:08 2015 +0100
@@ -166,10 +166,13 @@
 
 /* {{{ Addresses */
 
-Ip::Ip(int domain) noexcept
-	: m_domain{domain}
+/* Default domain */
+int Ip::m_default{AF_INET};
+
+Ip::Ip(Type domain) noexcept
+	: m_domain(static_cast<int>(domain))
 {
-	assert(domain == AF_INET6 || domain == AF_INET);
+	assert(m_domain == AF_INET6 || m_domain == AF_INET);
 
 	if (m_domain == AF_INET6) {
 		std::memset(&m_sin6, 0, sizeof (sockaddr_in6));
@@ -178,10 +181,10 @@
 	}
 }
 
-Ip::Ip(int domain, const std::string &host, int port)
-	: m_domain{domain}
+Ip::Ip(const std::string &host, int port, Type domain)
+	: m_domain(static_cast<int>(domain))
 {
-	assert(domain == AF_INET6 || domain == AF_INET);
+	assert(m_domain == AF_INET6 || m_domain == AF_INET);
 
 	if (host == "*") {
 		if (m_domain == AF_INET6) {
--- a/C++/modules/Socket/Sockets.h	Thu Nov 05 09:07:34 2015 +0100
+++ b/C++/modules/Socket/Sockets.h	Thu Nov 05 14:54:08 2015 +0100
@@ -405,6 +405,7 @@
 	Accepted,		//!< Socket has been accepted (client)
 	Accepting,		//!< The client acceptation is in progress
 	Closed,			//!< The socket has been closed
+	Disconnected,		//!< The connection was lost
 };
 
 /* }}} */
@@ -795,7 +796,6 @@
 	 *
 	 * @param option the option
 	 * @throw Error on errors
-	 * @example socket.set(option::ReuseAddress{true});
 	 */
 	template <typename Option>
 	inline void set(const Option &option)
@@ -833,7 +833,6 @@
 	 *
 	 * @return the same value as get() in the option
 	 * @throw Error on errors
-	 * @example socket.get<option::ReuseAddress>();
 	 */
 	template <typename Option>
 	inline auto get() -> decltype(std::declval<Option>().get(*this))
@@ -1109,7 +1108,7 @@
 		unsigned nbread = m_proto.recv(*this, data, length);
 
 		assert((m_action == Action::None    && m_condition == Condition::None) ||
-		       (m_action != Action::Receive && m_condition != Condition::None));
+		       (m_action == Action::Receive && m_condition != Condition::None));
 
 		return nbread;
 	}
@@ -1153,7 +1152,7 @@
 		unsigned nbsent = m_proto.send(*this, data, length);
 
 		assert((m_action == Action::None && m_condition == Condition::None) ||
-		       (m_action != Action::Send && m_condition != Condition::None));
+		       (m_action == Action::Send && m_condition != Condition::None));
 
 		return nbsent;
 	}
@@ -1376,6 +1375,9 @@
 
 /* {{{ Options */
 
+/**
+ * Namespace of predefined options.
+ */
 namespace option {
 
 /**
@@ -1566,8 +1568,7 @@
  * Predefined addressed to be used
  * ------------------------------------------------------------------
  *
- * - Ipv6,
- * - Ipv4,
+ * - Ip,
  * - Local.
  */
 
@@ -1578,7 +1579,24 @@
  * @brief Base class for IPv6 and IPv4, you can use it if you don't know in advance if you'll use IPv6 or IPv4.
  */
 class Ip {
+public:
+	/**
+	 * @enum Type
+	 * @brief Type of ip address.
+	 */
+	enum Type {
+		v4 = AF_INET,		//!< AF_INET
+		v6 = AF_INET6		//!< AF_INET6
+	};
+
 private:
+	/*
+	 * Default domain when using default constructors.
+	 *
+	 * Note: AF_INET or AF_INET6, not 
+	 */
+	static int m_default;
+
 	union {
 		sockaddr_in m_sin;
 		sockaddr_in6 m_sin6;
@@ -1589,23 +1607,43 @@
 
 public:
 	/**
+	 * Set the default domain to use when using default Ip constructor. By default, AF_INET is used.
+	 *
+	 * @pre domain must be Type::v4 or Type::v6
+	 */
+	static inline void setDefault(Type domain) noexcept
+	{
+		assert(domain == Type::v4 || domain == Type::v6);
+
+		m_default = static_cast<int>(domain);
+	}
+
+	/**
+	 * Construct using the default domain.
+	 */
+	inline Ip() noexcept
+		: Ip(static_cast<Type>(m_default))
+	{
+	}
+
+	/**
 	 * Default initialize the Ip domain.
 	 *
 	 * @pre domain must be AF_INET or AF_INET6 only
 	 * @param domain the domain (AF_INET or AF_INET6)
 	 */
-	Ip(int domain = AF_INET6) noexcept;
+	Ip(Type domain) noexcept;
 
 	/**
 	 * Construct an address suitable for bind() or connect().
 	 *
-	 * @pre domain must be AF_INET or AF_INET6 only
+	 * @pre domain must be Type::v4 or Type::v6
 	 * @param domain the domain (AF_INET or AF_INET6)
 	 * @param host the host (* for any)
 	 * @param port the port number
 	 * @throw Error on errors
 	 */
-	Ip(int domain, const std::string &host, int port);
+	Ip(const std::string &host, int port, Type domain = v4);
 
 	/**
 	 * Construct an address from a storage.
@@ -1665,82 +1703,6 @@
 	}
 };
 
-/**
- * @class Ipv6
- * @brief Use IPv6 address (helper).
- */
-class Ipv6 : public Ip {
-public:
-	/**
-	 * Construct an empty address.
-	 */
-	inline Ipv6() noexcept
-		: Ip{AF_INET6}
-	{
-	}
-
-	/**
-	 * Construct an address on a specific host.
-	 *
-	 * @param host the host ("*" for any)
-	 * @param port the port
-	 * @throw Error on errors
-	 */
-	inline Ipv6(const std::string &host, int port)
-		: Ip{AF_INET6, host, port}
-	{
-	}
-
-	/**
-	 * Construct an address from a storage.
-	 *
-	 * @param ss the storage
-	 * @param length the length
-	 */
-	inline Ipv6(const sockaddr_storage *ss, socklen_t length) noexcept
-		: Ip{ss, length}
-	{
-	}
-};
-
-/**
- * @class Ipv4
- * @brief Use IPv4 address (helper).
- */
-class Ipv4 : public Ip {
-public:
-	/**
-	 * Construct an empty address.
-	 */
-	inline Ipv4() noexcept
-		: Ip{AF_INET}
-	{
-	}
-
-	/**
-	 * Construct an address on a specific host.
-	 *
-	 * @param host the host ("*" for any)
-	 * @param port the port
-	 * @throw Error on errors
-	 */
-	inline Ipv4(const std::string &host, int port)
-		: Ip{AF_INET, host, port}
-	{
-	}
-
-	/**
-	 * Construct an address from a storage.
-	 *
-	 * @param ss the storage
-	 * @param length the length
-	 */
-	inline Ipv4(const sockaddr_storage *ss, socklen_t length) noexcept
-		: Ip{ss, length}
-	{
-	}
-};
-
 #if !defined(_WIN32)
 
 /**
@@ -1832,6 +1794,9 @@
 /**
  * @class Tcp
  * @brief Clear TCP implementation.
+ *
+ * This is the basic TCP protocol that implements recv, send, connect and accept as wrappers of the usual
+ * C functions.
  */
 class Tcp {
 public:
@@ -1840,26 +1805,43 @@
 	 *
 	 * @return SOCK_STREAM
 	 */
-	inline int type() noexcept
+	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> &) noexcept
+	inline void create(Socket<Address, Tcp> &) const noexcept
 	{
 		/* No-op */
 	}
 
 	/**
-	 * Standard connect. Wrapper of connect(2)
+	 * Standard connect.
+	 *
+	 * If the socket is marked non-blocking and the connection cannot be established immediately, then the
+	 * following is true:
+	 *
+	 * - state is set to State::Connecting,
+	 * - action is set to Action::Connect,
+	 * - condition is set to Condition::Writable.
+	 *
+	 * Then the user must wait until the socket is writable and call connect() with 0 arguments.
+	 *
+	 * If the socket is blocking, this function blocks until the connection is complete or an error occurs, in
+	 * that case state is either set to State::Connected or State::Disconnected but action and condition are
+	 * not set.
 	 *
 	 * @param sc the socket
 	 * @param address the address
 	 * @param length the length
+	 * @throw net::Error on errors
+	 * @note Wrapper of connect(2)
 	 */
 	template <typename Address, typename Protocol>
 	void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length)
@@ -1877,6 +1859,7 @@
 				sc.setAction(Action::Connect);
 				sc.setCondition(Condition::Writable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "connect", error};
 			}
 #else
@@ -1885,6 +1868,7 @@
 				sc.setAction(Action::Connect);
 				sc.setCondition(Condition::Writable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "connect"};
 			}
 #endif
@@ -1894,10 +1878,16 @@
 	}
 
 	/**
-	 * Continue the connection. Just check for SOL_SOCKET/SO_ERROR.
+	 * Continue the connection. This function must only be called when the socket is ready for writing,
+	 * the user is responsible of waiting for that condition.
+	 *
+	 * This function check for SOL_SOCKET/SO_ERROR status.
+	 *
+	 * If the connection is complete, status is set to State::Connected, otherwise it is set to
+	 * State::Disconnected. In both cases, action and condition are not set.
 	 *
 	 * @param sc the socket
-	 * @throw Error on errors
+	 * @throw net::Error on errors
 	 */
 	template <typename Address, typename Protocol>
 	void connect(Socket<Address, Protocol> &sc)
@@ -1905,6 +1895,7 @@
 		int error = sc.template get<int>(SOL_SOCKET, SO_ERROR);
 
 		if (error == Failure) {
+			sc.setState(State::Disconnected);
 			throw Error{Error::System, "connect", error};
 		}
 
@@ -1912,13 +1903,25 @@
 	}
 
 	/**
-	 * Accept a clear client. Wrapper of accept(2).
+	 * Accept a clear client.
+	 *
+	 * If the socket is marked non-blocking and there are no pending connection, this function throws an
+	 * error. The user must wait that the socket is readable before calling this function.
+	 *
+	 * If the socket is blocking, this function blocks until a new client is connected or throws an error on
+	 * errors.
+	 *
+	 * If the socket is correctly returned, its state is set to State::Accepted and its action and condition
+	 * are not set.
+	 *
+	 * In any case, action and condition of this socket are not set.
 	 *
 	 * @param sc the socket
 	 * @param address the address destination
 	 * @param length the address length
 	 * @return the socket
-	 * @throw Error on errors
+	 * @throw net::Error on errors
+	 * @note Wrapper of accept(2)
 	 */
 	template <typename Address, typename Protocol>
 	Socket<Address, Protocol> accept(Socket<Address, Protocol> &sc, sockaddr *address, socklen_t *length)
@@ -1934,21 +1937,32 @@
 
 	/**
 	 * Continue accept.
+	 *
+	 * This function is just present for compatibility, it should never be called.
 	 */
 	template <typename Address, typename Protocol>
-	inline void accept(Socket<Address, Protocol> &) noexcept
+	inline void accept(Socket<Address, Protocol> &) const noexcept
 	{
 		/* no-op */
 	}
 
 	/**
-	 * Receive data. Wrapper of recv(2).
+	 * Receive data.
+	 *
+	 * If the socket is marked non-blocking and no data is available, 0 is returned and condition is set to
+	 * Condition::Readable. If 0 is returned and condition is not set, then the state is set to
+	 * State::Disconnected.
+	 *
+	 * If the socket is blocking, this function blocks until some data is available or if an error occurs.
+	 *
+	 * In any case, action is never set.
 	 *
 	 * @param sc the socket
 	 * @param data the destination
 	 * @param length the destination length
 	 * @return the number of bytes read
 	 * @throw Error on errors
+	 * @note Wrapper of recv(2)
 	 */
 	template <typename Address>
 	unsigned recv(Socket<Address, Tcp> &sc, void *data, unsigned length)
@@ -1960,32 +1974,42 @@
 			int error = WSAGetLastError();
 
 			if (error == WSAEWOULDBLOCK) {
-				sc.setAction(Action::Receive);
 				sc.setCondition(Condition::Readable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "recv", error};
 			}
 #else
 			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				sc.setAction(Action::Receive);
 				sc.setCondition(Condition::Readable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "recv"};
 			}
 #endif
+		} else if (nbread == 0) {
+			sc.setState(State::Disconnected);
 		}
 
 		return static_cast<unsigned>(nbread);
 	}
 
 	/**
-	 * Send some data. Wrapper for send(2).
+	 * Send some data.
+	 *
+	 * If the socket is marked non-blocking and the operation would block, then 0 is returned and condition is set to
+	 * Condition::Writable.
+	 *
+	 * If the socket is blocking, this function blocks until the data has been sent.
+	 *
+	 * On any other errors, this function throw net::Error.
 	 *
 	 * @param sc the socket
 	 * @param data the buffer to send
 	 * @param length the buffer length
 	 * @return the number of bytes sent
-	 * @throw Error on errors
+	 * @throw net::Error on errors
+	 * @note Wrapper of send(2)
 	 */
 	template <typename Address>
 	unsigned send(Socket<Address, Tcp> &sc, const void *data, unsigned length)
@@ -1997,16 +2021,18 @@
 			int error = WSAGetLastError();
 
 			if (error == WSAEWOULDBLOCK) {
-				sc.setAction(Action::Send);
+				nbsent = 0;
 				sc.setCondition(Condition::Writable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "send", error};
 			}
 #else
 			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				sc.setAction(Action::Send);
+				nbsent = 0;
 				sc.setCondition(Condition::Writable);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "send"};
 			}
 #endif
@@ -2153,7 +2179,16 @@
 
 /**
  * @class Tls
- * @brief OpenSSL secure layer for TCP
+ * @brief OpenSSL secure layer for TCP.
+ *
+ * **Note:** This protocol is much more difficult to use with non-blocking sockets, if some operations would block, the
+ * user is responsible of calling the function again by waiting for the appropriate condition. See the functions for
+ * more details.
+ *
+ * @see Tls::accept
+ * @see Tls::connect
+ * @see Tls::recv
+ * @see Tls::send
  */
 class Tls : private Tcp {
 private:
@@ -2176,7 +2211,7 @@
 	bool m_verify{false};
 
 	/*
-	 * Construct with a context and ssl, for accept().
+	 * Construct with a context and ssl, for Tls::accept.
 	 */
 	Tls(Context context, Ssl ssl)
 		: m_context{std::move(context)}
@@ -2194,6 +2229,9 @@
 		return msg == nullptr ? "" : msg;
 	}
 
+	/*
+	 * Update the states after an uncompleted operation.
+	 */
 	template <typename Address, typename Protocol>
 	inline void updateStates(Socket<Address, Protocol> &sc, State state, Action action, int code)
 	{
@@ -2223,6 +2261,7 @@
 			if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) {
 				updateStates(sc, State::Connecting, Action::Connect, no);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error{Error::System, "connect", error(no)};
 			}
 		} else {
@@ -2244,6 +2283,7 @@
 			if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) {
 				updateStates(sc, State::Accepting, Action::Accept, no);
 			} else {
+				sc.setState(State::Disconnected);
 				throw Error(Error::System, "accept", error(no));
 			}
 		} else {
@@ -2255,7 +2295,7 @@
 	/**
 	 * @copydoc Tcp::type
 	 */
-	inline int type() noexcept
+	inline int type() const noexcept
 	{
 		return SOCK_STREAM;
 	}
@@ -2318,6 +2358,7 @@
 	 * Initialize the SSL objects after have created.
 	 *
 	 * @param sc the socket
+	 * @throw net::Error on errors
 	 */
 	template <typename Address>
 	inline void create(Socket<Address, Tls> &sc)
@@ -2344,10 +2385,18 @@
 	/**
 	 * Connect to a secure host.
 	 *
+	 * If the socket is marked non-blocking and the connection cannot be established yet, then the state is set
+	 * to State::Connecting, the condition is set to Condition::Readable or Condition::Writable, the user must
+	 * wait for the appropriate condition before calling the overload connect which takes 0 argument.
+	 *
+	 * If the socket is blocking, this functions blocks until the connection is complete.
+	 *
+	 * If the connection was completed correctly the state is set to State::Connected.
+	 *
 	 * @param sc the socket
 	 * @param address the address
 	 * @param length the address length
-	 * @throw Error on errors
+	 * @throw net::Error on errors
 	 */
 	template <typename Address, typename Protocol>
 	void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length)
@@ -2365,7 +2414,11 @@
 	/**
 	 * Continue the connection.
 	 *
+	 * This function must be called when the socket is ready for reading or writing (check with Socket::condition),
+	 * the state may change exactly like the initial connect call.
+	 *
 	 * @param sc the socket
+	 * @throw net::Error on errors
 	 */
 	template <typename Address, typename Protocol>
 	void connect(Socket<Address, Protocol> &sc)
@@ -2384,10 +2437,20 @@
 	/**
 	 * Accept a secure client.
 	 *
+	 * Because SSL needs several round-trips, if the socket is marked non-blocking and the connection is not
+	 * completed yet, a new socket is returned but with the State::Accepting state. Its condition is set to
+	 * Condition::Readable or Condition::Writable, the user is responsible of calling accept overload which takes
+	 * 0 arguments on the returned socket when the condition is met.
+	 *
+	 * If the socket is blocking, this function blocks until the client is accepted and returned.
+	 *
+	 * If the client is accepted correctly, its state is set to State::Accepted. This instance does not change.
+	 *
 	 * @param sc the socket
 	 * @param address the address destination
 	 * @param length the address length
 	 * @return the client
+	 * @throw net::Error on errors
 	 */
 	template <typename Address>
 	Socket<Address, Tls> accept(Socket<Address, Tls> &sc, sockaddr *address, socklen_t *length)
@@ -2411,8 +2474,12 @@
 	/**
 	 * Continue accept.
 	 *
+	 * This function must be called on the client that is being accepted.
+	 *
+	 * Like accept or connect, user is responsible of calling this function until the connection is complete.
+	 *
 	 * @param sc the socket
-	 * @throw Error on errors
+	 * @throw net::Error on errors
 	 */
 	template <typename Address, typename Protocol>
 	inline void accept(Socket<Address, Protocol> &sc)
@@ -2423,11 +2490,16 @@
 	/**
 	 * Receive some secure data.
 	 *
+	 * If the socket is marked non-blocking, 0 is returned if no data is available yet or if the connection
+	 * needs renegociation. If renegociation is required case, the action is set to Action::Receive and condition
+	 * is set to Condition::Readable or Condition::Writable. The user must wait that the condition is met and
+	 * call this function again.
+	 *
 	 * @param sc the socket
 	 * @param data the destination
 	 * @param len the buffer length
 	 * @return the number of bytes read
-	 * @throw Error on errors
+	 * @throw net::Error on errors
 	 */
 	template <typename Address>
 	unsigned recv(Socket<Address, Tls> &sc, void *data, unsigned len)
@@ -2438,6 +2510,7 @@
 			auto no = SSL_get_error(m_ssl.get(), nbread);
 
 			if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) {
+				nbread = 0;
 				updateStates(sc, sc.state(), Action::Receive, no);
 			} else {
 				throw Error{Error::System, "recv", error(no)};
@@ -2450,11 +2523,14 @@
 	/**
 	 * Send some data.
 	 *
+	 * Like recv, if the socket is marked non-blocking and no data can be sent or a negociation is required,
+	 * condition and action are set. See receive for more details
+	 *
 	 * @param sc the socket
 	 * @param data the data to send
 	 * @param len the buffer length
 	 * @return the number of bytes sent
-	 * @throw Error on errors
+	 * @throw net::Error on errors
 	 */
 	template <typename Address>
 	unsigned send(Socket<Address, Tls> &sc, const void *data, unsigned len)
@@ -2465,6 +2541,7 @@
 			auto no = SSL_get_error(m_ssl.get(), nbsent);
 
 			if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) {
+				nbread = 0
 				updateStates(sc, sc.state(), Action::Send, no);
 			} else {
 				throw Error{Error::System, "send", error(no)};
--- a/C++/tests/Socket/main.cpp	Thu Nov 05 09:07:34 2015 +0100
+++ b/C++/tests/Socket/main.cpp	Thu Nov 05 14:54:08 2015 +0100
@@ -85,8 +85,8 @@
 
 class TcpServerTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
+	SocketTcp<Ip> m_server;
+	SocketTcp<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -109,7 +109,7 @@
 TEST_F(TcpServerTest, connect)
 {
 	m_tserver = std::thread([this] () {
-		m_server.bind(Ipv4{"*", 16000});
+		m_server.bind(Ip{"*", 16000});
 		m_server.listen();
 		m_server.accept(nullptr);
 		m_server.close();
@@ -118,7 +118,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4{"127.0.0.1", 16000});
+		m_client.connect(Ip{"127.0.0.1", 16000});
 		m_client.close();
 	});
 }
@@ -126,7 +126,7 @@
 TEST_F(TcpServerTest, io)
 {
 	m_tserver = std::thread([this] () {
-		m_server.bind(Ipv4{"*", 16000});
+		m_server.bind(Ip{"*", 16000});
 		m_server.listen();
 
 		auto client = m_server.accept(nullptr);
@@ -140,7 +140,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4{"127.0.0.1", 16000});
+		m_client.connect(Ip{"127.0.0.1", 16000});
 		m_client.send("hello world");
 
 		ASSERT_EQ("hello world", m_client.recv(512));
@@ -155,8 +155,8 @@
 
 class UdpServerTest : public testing::Test {
 protected:
-	SocketUdp<Ipv4> m_server;
-	SocketUdp<Ipv4> m_client;
+	SocketUdp<Ip> m_server;
+	SocketUdp<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -179,8 +179,8 @@
 TEST_F(UdpServerTest, io)
 {
 	m_tserver = std::thread([this] () {
-		Ipv4 client;
-		Ipv4 info{"*", 16000};
+		Ip client;
+		Ip info{"*", 16000};
 
 		m_server.bind(info);
 		auto msg = m_server.recvfrom(512, &client);
@@ -194,7 +194,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		Ipv4 info{"127.0.0.1", 16000};
+		Ip info{"127.0.0.1", 16000};
 
 		m_client.sendto("hello world", info);
 
@@ -450,8 +450,8 @@
 class ListenerTest : public testing::Test {
 protected:
 	Listener<Select> m_listener;
-	SocketTcp<Ipv4> m_masterTcp;
-	SocketTcp<Ipv4> m_clientTcp;
+	SocketTcp<Ip> m_masterTcp;
+	SocketTcp<Ip> m_clientTcp;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -460,7 +460,7 @@
 	ListenerTest()
 	{
 		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_masterTcp.bind(Ipv4{"*", 16000});
+		m_masterTcp.bind(Ip{"*", 16000});
 		m_masterTcp.listen();
 	}
 
@@ -491,7 +491,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Ipv4{"127.0.0.1", 16000});
+		m_clientTcp.connect(Ip{"127.0.0.1", 16000});
 	});
 }
 
@@ -513,7 +513,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Ipv4{"127.0.0.1", 16000});
+		m_clientTcp.connect(Ip{"127.0.0.1", 16000});
 		m_clientTcp.send("hello");
 	});
 }
@@ -524,8 +524,8 @@
 
 class NonBlockingConnectTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
+	SocketTcp<Ip> m_server;
+	SocketTcp<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -551,8 +551,8 @@
 
 class TcpAcceptTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
+	SocketTcp<Ip> m_server;
+	SocketTcp<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -561,7 +561,7 @@
 	TcpAcceptTest()
 	{
 		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_server.bind(Ipv4{"*", 16000});
+		m_server.bind(Ip{"*", 16000});
 		m_server.listen();
 	}
 
@@ -580,8 +580,8 @@
 
 class TcpRecvTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
+	SocketTcp<Ip> m_server;
+	SocketTcp<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -590,7 +590,7 @@
 	TcpRecvTest()
 	{
 		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_server.bind(Ipv4{"*", 16000});
+		m_server.bind(Ip{"*", 16000});
 		m_server.listen();
 	}
 
@@ -614,7 +614,7 @@
 	std::this_thread::sleep_for(100ms);
 
 	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4{"127.0.0.1", 16000});
+		m_client.connect(Ip{"127.0.0.1", 16000});
 		m_client.send("hello");
 		m_client.close();
 	});
@@ -626,8 +626,8 @@
 
 class TlsRecvTest : public testing::Test {
 protected:
-	SocketTls<Ipv4> m_server{nullptr};
-	SocketTls<Ipv4> m_client;
+	SocketTls<Ip> m_server{nullptr};
+	SocketTls<Ip> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -641,9 +641,9 @@
 		protocol.setPrivateKey("Socket/test.key");
 		protocol.setVerify(false);
 
-		m_server = SocketTls<Ipv4>{std::move(protocol)};
+		m_server = SocketTls<Ip>{std::move(protocol)};
 		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		m_server.bind(Ipv4{"*", 16000});
+		m_server.bind(Ip{"*", 16000});
 		m_server.listen();
 	}
 
@@ -672,7 +672,7 @@
 
 	m_tclient = std::thread([this] () {
 		try {
-			m_client.connect(Ipv4{"127.0.0.1", 16000});
+			m_client.connect(Ip{"127.0.0.1", 16000});
 			m_client.send("hello");
 		} catch (const net::Error &ex) {
 			FAIL() << ex.function() << ": " << ex.what();