changeset 572:ad302d1b7335

Net: Socket is no more a template, use raw addresses instead
author David Demelier <markand@malikania.fr>
date Thu, 30 Jun 2016 12:35:42 +0200
parents c79a501782b0
children db2934ac95c7
files modules/net/net.hpp modules/net/test/main.cpp
diffstat 2 files changed, 600 insertions(+), 1111 deletions(-) [+]
line wrap: on
line diff
--- a/modules/net/net.hpp	Wed Jun 29 19:18:39 2016 +0200
+++ b/modules/net/net.hpp	Thu Jun 30 12:35:42 2016 +0200
@@ -120,7 +120,6 @@
 /**
  * \page net-concepts Concepts
  *
- *   - \subpage net-concept-address
  *   - \subpage net-concept-backend
  *   - \subpage net-concept-option
  *   - \subpage net-concept-stream
@@ -128,75 +127,6 @@
  */
 
 /**
- * \page net-concept-address Address (Concept)
- *
- * An address is used in many places for creating, binding, connecting, receiving and sending. They are implemented as templates to allow
- * any type of address and to make sure the same address is used for a given socket.
- *
- * This concepts requires the following functions:
- *
- * # Address (constructor)
- *
- * The address must have the following constructor overloads.
- *
- * **Note**: the user can add custom constructors.
- *
- * ## Synopsis
- *
- * ````
- * Address(); // (0)
- * Address(const sockaddr *sa, socklen_t length); // (1)
- * ````
- *
- * ## Arguments
- *
- *   - **ss**: the storage to construct from,
- *   - **length**: the storage length.
- *
- * # domain
- *
- * Get the domain (e.g. AF_INET).
- *
- * ## Synopsis
- *
- * ````
- * int domain() const noexcept;
- * ````
- *
- * ## Returns
- *
- * The domain.
- *
- * # address
- *
- * Get the underlying address.
- *
- * ## Synopsis
- *
- * ````
- * const sockaddr *address() const noexcept;
- * ````
- *
- * ## Returns
- *
- * The address.
- *
- * # length
- *
- * Get the underlying length.
- *
- * ## Synopsis
- *
- * ````
- * socklen_t length() const noexcept;
- * ````
- *
- * ## Returns
- *
- * The length.
- */
-
-/**
  * \page net-concept-backend Backend (Concept)
  *
  * A backend is an interface for the Listener class. It is primarily designed to be the most suitable for the host environment.
@@ -300,7 +230,7 @@
  *
  * ````
  * template <typename Address>
- * void set(Socket<Address> &sc) const;
+ * void set(Socket &sc) const;
  * ````
  *
  * ## Arguments
@@ -315,7 +245,7 @@
  *
  * ````
  * template <typename Address>
- * T get(Socket<Address> &sc) const;
+ * T get(Socket &sc) const;
  * ````
  *
  * ## Arguments
@@ -377,7 +307,7 @@
  * ## Synopsis
  *
  * ````
- * Socket<Address> accept();
+ * Socket accept();
  * ````
  *
  * ## Returns
@@ -1105,9 +1035,292 @@
 }
 
 /**
+ * \brief Generic socket address storage.
+ * \ingroup net-module-addresses
+ */
+class Address {
+private:
+    sockaddr_storage m_storage;
+    socklen_t m_length;
+
+public:
+    /**
+     * Construct empty address.
+     */
+    inline Address() noexcept
+        : m_storage{}
+        , m_length(0)
+    {
+    }
+
+    /**
+     * Construct address from existing one.
+     *
+     * \pre address != nullptr
+     * \param address the address
+     * \param length the address length
+     */
+    inline Address(const sockaddr *address, socklen_t length) noexcept
+        : m_length(length)
+    {
+        assert(address);
+
+        std::memcpy(&m_storage, address, length);
+    }
+
+    /**
+     * Get the underlying address.
+     *
+     * \return the address
+     */
+    inline const sockaddr *get() const noexcept
+    {
+        return reinterpret_cast<const sockaddr *>(&m_storage);
+    }
+
+    /**
+     * Overloaded function
+     *
+     * \return the address
+     */
+    inline sockaddr *get() noexcept
+    {
+        return reinterpret_cast<sockaddr *>(&m_storage);
+    }
+
+    /**
+     * Get the underlying address as the given type (e.g sockaddr_in).
+     *
+     * \return the address reference
+     */
+    template <typename T>
+    inline const T &as() const noexcept
+    {
+        return reinterpret_cast<const T &>(m_storage);
+    }
+
+    /**
+     * Overloaded function
+     *
+     * \return the address reference
+     */
+    template <typename T>
+    inline T &as() noexcept
+    {
+        return reinterpret_cast<T &>(m_storage);
+    }
+
+    /**
+     * Get the underlying address length.
+     *
+     * \return the length
+     */
+    inline socklen_t length() const noexcept
+    {
+        return m_length;
+    }
+
+    /**
+     * Get the address domain.
+     *
+     * \return the domain
+     */
+    inline int domain() const noexcept
+    {
+        return m_storage.ss_family;
+    }
+};
+
+/**
+ * \brief Address iterator.
+ * \ingroup net-module-addresses
+ * \see resolve
+ *
+ * This iterator can be used to try to connect to an host.
+ *
+ * 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
+ * SocketTcp sc;
+ * AddressIterator end, it = resolve("hostname.test", "80");
+ *
+ * while (!connected_condition && it != end)
+ *   sc.connect(it->address(), it->length());
+ * ````
+ *
+ * When an iterator equals to a default constructed iterator, it is considered not dereferenceable.
+ */
+class AddressIterator : public std::iterator<std::forward_iterator_tag, Address> {
+private:
+    std::vector<Address> m_addresses;
+    std::size_t m_index{0};
+
+public:
+    /**
+     * Construct a null iterator.
+     *
+     * The default constructed iterator is not dereferenceable.
+     */
+    inline AddressIterator() noexcept = default;
+
+    /**
+     * Construct an address iterator with a set of addresses.
+     *
+     * \pre index < m_addresses.size()
+     * \param addresses the addresses
+     * \param index the first index
+     */
+    inline AddressIterator(std::vector<Address> addresses, std::size_t index = 0) noexcept
+        : m_addresses(std::move(addresses))
+        , m_index(index)
+    {
+        assert(index < m_addresses.size());
+    }
+
+    /**
+     * Get the generic address.
+     *
+     * \pre this is dereferenceable
+     * \return the generic address
+     */
+    inline const Address &operator*() const noexcept
+    {
+        assert(m_index <= m_addresses.size());
+
+        return m_addresses[m_index];
+    }
+
+    /**
+     * Overloaded function.
+     *
+     * \pre this is dereferenceable
+     * \return the generic address
+     */
+    inline Address &operator*() noexcept
+    {
+        assert(m_index <= m_addresses.size());
+
+        return m_addresses[m_index];
+    }
+
+    /**
+     * Get the generic address.
+     *
+     * \pre this is dereferenceable
+     * \return the generic address
+     */
+    inline const Address *operator->() const noexcept
+    {
+        assert(m_index <= m_addresses.size());
+
+        return &m_addresses[m_index];
+    }
+
+    /**
+     * Overloaded function.
+     *
+     * \pre this is dereferenceable
+     * \return the generic address
+     */
+    inline Address *operator->() noexcept
+    {
+        assert(m_index <= m_addresses.size());
+
+        return &m_addresses[m_index];
+    }
+
+    /**
+     * Pre-increment the iterator.
+     *
+     * \return this
+     */
+    inline AddressIterator &operator++(int) noexcept
+    {
+        if (m_index + 1 >= m_addresses.size()) {
+            m_addresses.clear();
+            m_index = 0;
+        } else
+            m_index ++;
+
+        return *this;
+    }
+
+    /**
+     * Post-increment the iterator.
+     *
+     * \return copy of this
+     */
+    inline AddressIterator operator++() noexcept
+    {
+        AddressIterator save = *this;
+
+        if (m_index + 1 >= m_addresses.size()) {
+            m_addresses.clear();
+            m_index = 0;
+        } else
+            m_index ++;
+
+        return save;
+    }
+
+    friend bool operator==(const AddressIterator &, const AddressIterator &) noexcept;
+    friend bool operator!=(const AddressIterator &, const AddressIterator &) noexcept;
+};
+
+/**
+ * Compare two address iterators.
+ *
+ * \param i1 the first iterator
+ * \param i2 the second iterator
+ * \return true if they equal
+ */
+inline bool operator==(const AddressIterator &i1, const AddressIterator &i2) noexcept
+{
+    return i1.m_addresses == i2.m_addresses && i1.m_index == i2.m_index;
+}
+
+/**
+ * Compare two address iterators.
+ *
+ * \param i1 the first iterator
+ * \param i2 the second iterator
+ * \return false if they equal
+ */
+inline bool operator!=(const AddressIterator &i1, const AddressIterator &i2) noexcept
+{
+    return !(i1 == i2);
+}
+
+/**
+ * Compare two generic addresses.
+ *
+ * \param a1 the first address
+ * \param a2 the second address
+ * \return true if they equal
+ */
+inline bool operator==(const Address &a1, const Address &a2) noexcept
+{
+    return a1.length() == a2.length() && std::memcmp(a1.get(), a2.get(), a1.length()) == 0;
+}
+
+/**
+ * Compare two generic addresses.
+ *
+ * \param a1 the first address
+ * \param a2 the second address
+ * \return false if they equal
+ */
+inline bool operator!=(const Address &a1, const Address &a2) noexcept
+{
+    return !(a1 == a2);
+}
+
+/**
  * \brief Base socket class.
  */
-template <typename Address>
 class Socket {
 protected:
     /**
@@ -1211,7 +1424,7 @@
     /**
      * Object-oriented option setter.
      *
-     * The object must have `set(Socket<Address> &) const`.
+     * The object must have `set(Socket &) const`.
      *
      * \pre isOpen()
      * \param option the option
@@ -1253,7 +1466,7 @@
     /**
      * Object-oriented option getter.
      *
-     * The object must have `T get(Socket<Address> &) const`, T can be any type and it is the value
+     * The object must have `T get(Socket &) const`, T can be any type and it is the value
      * returned from this function.
      *
      * \pre isOpen()
@@ -1306,7 +1519,7 @@
     {
         assert(m_handle != Invalid);
 
-        bind(address.address(), address.length());
+        bind(address.get(), address.length());
     }
 
     /**
@@ -1411,8 +1624,7 @@
  * \param s2 the second socket
  * \return true if they equals
  */
-template <typename Address>
-inline bool operator==(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator==(const Socket &s1, const Socket &s2)
 {
     return s1.handle() == s2.handle();
 }
@@ -1424,8 +1636,7 @@
  * \param s2 the second socket
  * \return true if they are different
  */
-template <typename Address>
-inline bool operator!=(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator!=(const Socket &s1, const Socket &s2)
 {
     return s1.handle() != s2.handle();
 }
@@ -1437,8 +1648,7 @@
  * \param s2 the second socket
  * \return true if s1 < s2
  */
-template <typename Address>
-inline bool operator<(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator<(const Socket &s1, const Socket &s2)
 {
     return s1.handle() < s2.handle();
 }
@@ -1450,8 +1660,7 @@
  * \param s2 the second socket
  * \return true if s1 > s2
  */
-template <typename Address>
-inline bool operator>(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator>(const Socket &s1, const Socket &s2)
 {
     return s1.handle() > s2.handle();
 }
@@ -1463,8 +1672,7 @@
  * \param s2 the second socket
  * \return true if s1 <= s2
  */
-template <typename Address>
-inline bool operator<=(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator<=(const Socket &s1, const Socket &s2)
 {
     return s1.handle() <= s2.handle();
 }
@@ -1476,8 +1684,7 @@
  * \param s2 the second socket
  * \return true if s1 >= s2
  */
-template <typename Address>
-inline bool operator>=(const Socket<Address> &s1, const Socket<Address> &s2)
+inline bool operator>=(const Socket &s1, const Socket &s2)
 {
     return s1.handle() >= s2.handle();
 }
@@ -1488,21 +1695,22 @@
  *
  * This is the basic TCP protocol that implements recv, send, connect and accept as wrappers of the usual C functions.
  */
-template <typename Address>
-class TcpSocket : public Socket<Address> {
+class TcpSocket : public Socket {
 public:
     /**
      * Inherited constructors.
      */
-    using Socket<Address>::Socket;
+    using Socket::Socket;
 
     /**
-     * Create a TCP socket using the address domain.
+     * Construct a TCP socket.
      *
+     * \param domain the domain
+     * \param protocol the protocol
      * \throw Error on errors
      */
-    inline TcpSocket()
-        : Socket<Address>(Address().domain(), SOCK_STREAM, 0)
+    inline TcpSocket(int domain, int protocol)
+        : Socket(domain, SOCK_STREAM, protocol)
     {
     }
 
@@ -1552,7 +1760,7 @@
      */
     void connect(const Address &address)
     {
-        connect(address.address(), address.length());
+        connect(address.get(), address.length());
     }
 
     /**
@@ -1564,7 +1772,7 @@
      * \throw WouldBlockError if the socket is marked non-blocking and no connection are available
      * \throw Error on other errors
      */
-    TcpSocket<Address> accept()
+    TcpSocket accept()
     {
         Handle handle = ::accept(this->m_handle, nullptr, 0);
 
@@ -1584,7 +1792,7 @@
 #endif
         }
 
-        return TcpSocket<Address>(handle);
+        return TcpSocket(handle);
     }
 
     /**
@@ -1655,21 +1863,22 @@
  *
  * This class is the basic implementation of UDP sockets.
  */
-template <typename Address>
-class UdpSocket : public Socket<Address> {
+class UdpSocket : public Socket {
 public:
     /**
      * Inherited constructors.
      */
-    using Socket<Address>::Socket;
+    using Socket::Socket;
 
     /**
-     * Create a UDP socket using the address domain.
+     * Construct a TCP socket.
      *
+     * \param domain the domain
+     * \param protocol the protocol
      * \throw Error on errors
      */
-    inline UdpSocket()
-        : Socket<Address>(Address().domain(), SOCK_DGRAM, 0)
+    inline UdpSocket(int domain, int protocol)
+        : Socket(domain, SOCK_DGRAM, protocol)
     {
     }
 
@@ -1787,7 +1996,7 @@
      */
     inline unsigned sendto(const void *data, unsigned length, const Address &address)
     {
-        return sendto(data, length, address.address(), address.length());
+        return sendto(data, length, address.get(), address.length());
     }
 };
 
@@ -1798,8 +2007,7 @@
  * \ingroup net-module-tls
  * \warning This class is highly experimental.
  */
-template <typename Address>
-class TlsSocket : public Socket<Address> {
+class TlsSocket : public Socket {
 public:
     /**
      * \brief SSL connection mode.
@@ -1852,14 +2060,14 @@
 
 public:
     /**
-     * Wrap a socket around an existing one.
+     * Wrap a socket around an existing one, takes ownership.
      *
      * \param sock the TCP socket
      * \param mode the mode
      * \param method the method
      */
-    inline TlsSocket(TcpSocket<Address> &sock, Mode mode = Server, const SSL_METHOD *method = TLSv1_method())
-        : Socket<Address>(sock.handle())
+    inline TlsSocket(TcpSocket sock, Mode mode = Server, const SSL_METHOD *method = TLSv1_method())
+        : Socket(std::move(sock))
     {
 #if !defined(NET_NO_SSL_AUTO_INIT)
         ssl::init();
@@ -1961,870 +2169,272 @@
 #endif // !NET_NO_SSL
 
 /**
- * \brief Predefined addresses.
+ * \brief IPv4 functions.
  */
-namespace address {
+namespace ipv4 {
 
 /**
- * \brief Generic address.
- * \ingroup net-module-addresses
+ * Create an address to bind on any.
  *
- * This address can store anything that fits into a sockaddr_storage.
+ * \param port the port
+ * \return the address
  */
-class Generic {
-private:
-    sockaddr_storage m_address;
-    socklen_t m_length{0};
-
-public:
-    /**
-     * Construct a null address.
-     */
-    inline Generic() noexcept
-    {
-        std::memset(&m_address, 0, sizeof (sockaddr_storage));
-    }
-
-    /**
-     * Construct an address.
-     *
-     * \pre address is not null
-     * \pre length <= sizeof (sockaddr_storage)
-     * \param address the address to copy
-     * \param length the address length
-     */
-    inline Generic(const sockaddr *address, socklen_t length) noexcept
-        : m_length(length)
-    {
-        assert(address);
-        assert(length <= sizeof (sockaddr_storage));
-
-        std::memset(&m_address, 0, sizeof (sockaddr_storage));
-        std::memcpy(&m_address, address, length);
-    }
-
-    /**
-     * Get the address family.
-     *
-     * \return the address family
-     */
-    inline int domain() const noexcept
-    {
-        return m_address.ss_family;
-    }
-
-    /**
-     * Get the underlying address.
-     *
-     * \return the address
-     */
-    inline sockaddr *address() noexcept
-    {
-        return reinterpret_cast<sockaddr *>(&m_address);
-    }
-
-    /**
-     * Overloaded function.
-     *
-     * \return the address
-     */
-    inline const sockaddr *address() const noexcept
-    {
-        return reinterpret_cast<const sockaddr *>(&m_address);
-    }
-
-    /**
-     * Get the underlying address length.
-     *
-     * \return the length
-     */
-    inline socklen_t length() const noexcept
-    {
-        return m_length;
-    }
-};
-
-/**
- * Compare two generic addresses.
- *
- * \param a1 the first address
- * \param a2 the second address
- * \return true if they equal
- */
-inline bool operator==(const Generic &a1, const Generic &a2) noexcept
+inline Address any(std::uint16_t port)
 {
-    return a1.length() == a2.length() && std::memcmp(a1.address(), a2.address(), a1.length()) == 0;
+    sockaddr_in sin;
+    socklen_t length = sizeof (sockaddr_in);
+
+    std::memset(&sin, 0, sizeof (sockaddr_in));
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = INADDR_ANY;
+    sin.sin_port = htons(port);
+
+    return Address(reinterpret_cast<const sockaddr *>(&sin), length);
 }
 
 /**
- * Compare two generic addresses.
+ * Create an address from a IPv4 string.
  *
- * \param a1 the first address
- * \param a2 the second address
- * \return false if they equal
+ * \param ip the ip address
+ * \param port the port
+ * \return the address
+ * \throw Error if inet_pton is unavailable
  */
-inline bool operator!=(const Generic &a1, const Generic &a2) noexcept
+inline Address pton(const std::string &ip, std::uint16_t port)
 {
-    return !(a1 == a2);
+#if defined(NET_HAVE_INET_PTON)
+#if !defined(NET_NO_AUTO_INIT)
+    init();
+#endif
+
+    sockaddr_in sin;
+    socklen_t length = sizeof (sockaddr_in);
+
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(port);
+
+    if (inet_pton(AF_INET, ip.c_str(), &sin.sin_addr) <= 0)
+        throw Error();
+
+    return Address(reinterpret_cast<const sockaddr *>(&sin), length);
+#else
+    (void)ip;
+    (void)port;
+
+    throw Error(std::strerror(ENOSYS));
+#endif
+}
+
+/**
+ * Get the underlying ip from the given address.
+ *
+ * \pre address.domain() == AF_INET
+ * \param address the IPv6 address
+ * \return the ip address
+ * \throw Error if inet_ntop is unavailable
+ */
+inline std::string ntop(const Address &address)
+{
+    assert(address.domain() == AF_INET);
+
+#if !defined(NET_NO_AUTO_INIT)
+    init();
+#endif
+
+#if defined(NET_HAVE_INET_NTOP)
+    char result[INET_ADDRSTRLEN + 1];
+
+    std::memset(result, 0, sizeof (result));
+
+    if (!inet_ntop(AF_INET, const_cast<in_addr *>(&address.as<sockaddr_in>().sin_addr), result, sizeof (result)))
+        throw Error();
+
+    return result;
+#else
+    (void)address;
+
+    throw Error(std::strerror(ENOSYS));
+#endif
 }
 
 /**
- * \brief Generic IP address.
- * \ingroup net-module-addresses
+ * Get the port from the IPv4 address.
  *
- * You can use this address instead of Ipv4 or Ipv6 if you don't know which address to use at runtime. However,
- * when creating your socket, you will need to define the correct domain.
+ * \pre address.domain() == AF_INET4
+ * \param address the address
+ * \return the port
+ */
+inline std::uint16_t port(const Address &address) noexcept
+{
+    assert(address.domain() == AF_INET);
+
+    return ntohs(address.as<sockaddr_in>().sin_port);
+}
+
+} // !ipv4
+
+/**
+ * \brief IPv6 functions.
  */
-class Ip {
-private:
-    union {
-        sockaddr_in6 m_sin6;
-        sockaddr_in m_sin;
-    };
-
-    int m_domain;
-
-public:
-    /**
-     * Create IP address, defaults to IPv4.
-     *
-     * \pre domain must be AF_INET or AF_INET6
-     * \param domain the domain
-     */
-    inline Ip(int domain = AF_INET) noexcept
-        : m_domain(domain)
-    {
-        assert(domain == AF_INET || domain == AF_INET6);
-
-        std::memset(&m_sin, 0, sizeof (sockaddr_in));
-    }
-
-    /**
-     * Create an IP address on the specific ip address.
-     *
-     * \pre domain must be AF_INET or AF_INET6
-     * \param ip the address or "*" for any
-     * \param port the port
-     * \param domain the domain
-     * \warning If NET_HAVE_INET_PTON is undefined, host can not be other than "*"
-     * \throw Error on failures or if inet_pton is unavailable
-     */
-    inline Ip(const std::string &ip, std::uint16_t port, int domain)
-        : Ip(domain)
-    {
-        if (m_domain == AF_INET)
-            make(ip, port, m_sin);
-        else
-            make(ip, port, m_sin6);
-    }
-
-    /**
-     * Create the IP address from the storage.
-     *
-     * \pre the storage domain must be AF_INET or AF_INET6
-     * \param ss the the storage
-     * \param length the storage length
-     */
-    inline Ip(const sockaddr *ss, socklen_t length) noexcept
-        : Ip(ss->sa_family)
-    {
-        assert(ss->sa_family == AF_INET || ss->sa_family == AF_INET6);
-
-        if (ss->sa_family == AF_INET)
-            std::memcpy(&m_sin, ss, length);
-        else
-            std::memcpy(&m_sin6, ss, length);
-    }
-
-    /**
-     * Get the domain.
-     *
-     * \return AF_INET or AF_INET6
-     */
-    inline int domain() const noexcept
-    {
-        return m_domain;
-    }
-
-    /**
-     * Get the underlying address, may be a sockaddr_in or sockaddr_in6.
-     *
-     * \return the address
-     */
-    inline const sockaddr *address() const noexcept
-    {
-        return m_domain == AF_INET ? reinterpret_cast<const sockaddr *>(&m_sin) : reinterpret_cast<const sockaddr *>(&m_sin6);
-    }
-
-    /**
-     * Get the address length.
-     *
-     * \return the address length
-     */
-    inline socklen_t length() const noexcept
-    {
-        return m_domain == AF_INET ? sizeof (sockaddr_in) : sizeof (sockaddr_in6);
-    }
-
-    /**
-     * Retrieve the port.
-     *
-     * \return the port
-     */
-    inline std::uint16_t port() const noexcept
-    {
-        return m_domain == AF_INET ? ntohs(m_sin.sin_port) : ntohs(m_sin6.sin6_port);
-    }
-
-    /**
-     * Get the ip address.
-     *
-     * \return the ip address
-     * \throw Error on errors or if inet_ntop is unavailable
-     */
-    inline std::string ip() const
-    {
-        return m_domain == AF_INET ? ip(m_sin) : ip(m_sin6);
-    }
-
-    /**
-     * Prepare the sockaddr_in structure with the given ip.
-     *
-     * \param ip the ip address
-     * \param port the port
-     * \param sin the Ipv4 address
-     * \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)
-        init();
-#endif
-
-        sin.sin_family = AF_INET;
-        sin.sin_port = htons(port);
-
-        if (ip == "*")
-            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();
-#else
-        else
-            throw Error(std::strerror(ENOSYS));
-#endif
-    }
-
-    /**
-     * Prepare the sockaddr_in structure with the given ip.
-     *
-     * \param ip the ip address
-     * \param port the port
-     * \param sin6 the Ipv6 address
-     * \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)
-        init();
-#endif
-
-        sin6.sin6_family = AF_INET6;
-        sin6.sin6_port = htons(port);
-
-        if (ip == "*")
-            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();
-#else
-        else
-            throw Error(std::strerror(ENOSYS));
-#endif
-    }
-
-    /**
-     * Get the underlying ip from the given address.
-     *
-     * \param sin the Ipv4 address
-     * \return the ip address
-     * \throw Error if inet_ntop is unavailable
-     */
-    static std::string ip(const sockaddr_in &sin)
-    {
-#if !defined(NET_NO_AUTO_INIT)
-        init();
-#endif
-
-#if !defined(NET_HAVE_INET_NTOP)
-        (void)sin;
-
-        throw Error(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();
-
-        return result;
-#endif
-    }
-
-    /**
-     * Get the underlying ip from the given address.
-     *
-     * \param sin6 the Ipv6 address
-     * \return the ip address
-     * \throw Error if inet_ntop is unavailable
-     */
-    static std::string ip(const sockaddr_in6 &sin6)
-    {
-#if !defined(NET_NO_AUTO_INIT)
-        init();
-#endif
-
-#if !defined(NET_HAVE_INET_NTOP)
-        (void)sin6;
-
-        throw Error(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();
-
-        return result;
-#endif
-    }
-
-    /**
-     * Resolve an hostname.
-     *
-     * This function wraps getaddrinfo and returns the first result.
-     *
-     * \param host the hostname
-     * \param service the service name (port or name)
-     * \param domain the domain (e.g. AF_INET)
-     * \param type the socket type (e.g. SOCK_STREAM)
-     * \return the resolved address
-     * \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)
-        init();
-#endif
-
-        struct addrinfo hints, *res;
-
-        std::memset(&hints, 0, sizeof (struct addrinfo));
-        hints.ai_family = domain;
-        hints.ai_socktype = type;
-
-        int e = getaddrinfo(host.c_str(), service.c_str(), &hints, &res);
-
-        if (e != 0)
-            throw Error(gai_strerror(e));
-
-        Ip ip(res->ai_addr, res->ai_addrlen);
-
-        freeaddrinfo(res);
-
-        return ip;
-    }
-};
+namespace ipv6 {
+
+/**
+ * Create an address to bind on any.
+ *
+ * \param port the port
+ * \return the address
+ */
+inline Address any(std::uint16_t port)
+{
+    sockaddr_in6 sin6;
+    socklen_t length = sizeof (sockaddr_in6);
+
+    std::memset(&sin6, 0, sizeof (sockaddr_in6));
+    sin6.sin6_family = AF_INET6;
+    sin6.sin6_addr = in6addr_any;
+    sin6.sin6_port = htons(port);
+
+    return Address(reinterpret_cast<const sockaddr *>(&sin6), length);
+}
 
 /**
- * \brief Ipv4 only address.
- * \ingroup net-module-addresses
+ * Create an address from a IPv4 string.
+ *
+ * \param ip the ip address
+ * \param port the port
+ * \return the address
+ * \throw Error if inet_pton is unavailable
  */
-class Ipv4 {
-private:
-    sockaddr_in m_sin;
-
-public:
-    /**
-     * Create an Ipv4 address.
-     */
-    inline Ipv4() noexcept
-    {
-        std::memset(&m_sin, 0, sizeof (sockaddr_in));
-    }
-
-    /**
-     * Create an Ipv4 address on the specific ip address.
-     *
-     * \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 Error on failures or if inet_pton is unavailable
-     */
-    inline Ipv4(const std::string &ip, std::uint16_t port)
-        : Ipv4()
-    {
-        Ip::make(ip, port, m_sin);
-    }
-
-    /**
-     * Create the IP address from the storage.
-     *
-     * \pre the storage domain must be AF_INET
-     * \param ss the the storage
-     * \param length the storage length
-     */
-    inline Ipv4(const sockaddr *ss, socklen_t length) noexcept
-    {
-        assert(ss->sa_family == AF_INET);
-
-        std::memcpy(&m_sin, ss, length);
-    }
-
-    /**
-     * Get the domain.
-     *
-     * \return AF_INET
-     */
-    inline int domain() const noexcept
-    {
-        return AF_INET;
-    }
-
-    /**
-     * Get the underlying address.
-     *
-     * \return the address
-     */
-    inline const sockaddr *address() const noexcept
-    {
-        return reinterpret_cast<const sockaddr *>(&m_sin);
-    }
-
-    /**
-     * Get the address length.
-     *
-     * \return the size of sockaddr_in
-     */
-    inline socklen_t length() const noexcept
-    {
-        return sizeof (sockaddr_in);
-    }
-
-    /**
-     * Get the port.
-     *
-     * \return the port
-     */
-    inline std::uint16_t port() const noexcept
-    {
-        return ntohs(m_sin.sin_port);
-    }
-
-    /**
-     * Get the ip address.
-     *
-     * \return the ip address
-     * \throw Error on errors or if inet_ntop is unavailable
-     */
-    inline std::string ip() const
-    {
-        return Ip::ip(m_sin);
-    }
-
-    /**
-     * Same as Ip::resolve with AF_INET as domain.
-     *
-     * \param host the hostname
-     * \param service the service name (port or name)
-     * \param type the socket type (e.g. SOCK_STREAM)
-     * \return the resolved address
-     * \throw Error on failures
-     */
-    static Ipv4 resolve(const std::string &host, const std::string &service, int type = SOCK_STREAM)
-    {
-        Ip result = Ip::resolve(host, service, AF_INET, type);
-
-        return Ipv4(result.address(), result.length());
-    }
-};
+inline Address pton(const std::string &ip, std::uint16_t port)
+{
+#if defined(NET_HAVE_INET_PTON)
+#if !defined(NET_NO_AUTO_INIT)
+    init();
+#endif
+
+    sockaddr_in6 sin6;
+    socklen_t length = sizeof (sockaddr_in6);
+
+    sin6.sin6_family = AF_INET6;
+    sin6.sin6_port = htons(port);
+
+
+    if (inet_pton(AF_INET6, ip.c_str(), &sin6.sin6_addr) <= 0)
+        throw Error();
+
+    return Address(reinterpret_cast<const sockaddr *>(&sin6), length);
+#else
+    (void)ip;
+    (void)port;
+
+    throw Error(std::strerror(ENOSYS));
+#endif
+}
 
 /**
- * \brief Ipv4 only address.
- * \ingroup net-module-addresses
+ * Get the underlying ip from the given address.
+ *
+ * \pre address.domain() == AF_INET6
+ * \param address the IPv6 address
+ * \return the ip address
+ * \throw Error if inet_ntop is unavailable
  */
-class Ipv6 {
-private:
-    sockaddr_in6 m_sin6;
-
-public:
-    /**
-     * Create an Ipv6 address.
-     */
-    inline Ipv6() noexcept
-    {
-        std::memset(&m_sin6, 0, sizeof (sockaddr_in6));
-    }
-
-    /**
-     * Create an Ipv6 address on the specific ip address.
-     *
-     * \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 Error on failures or if inet_pton is unavailable
-     */
-    inline Ipv6(const std::string &ip, std::uint16_t port)
-        : Ipv6()
-    {
-        Ip::make(ip, port, m_sin6);
-    }
-
-    /**
-     * Create the IP address from the storage.
-     *
-     * \pre the storage domain must be AF_INET6
-     * \param ss the the storage
-     * \param length the storage length
-     */
-    inline Ipv6(const sockaddr *ss, socklen_t length) noexcept
-    {
-        assert(ss->sa_family == AF_INET6);
-
-        std::memcpy(&m_sin6, ss, length);
-    }
-
-    /**
-     * Get the domain.
-     *
-     * \return AF_INET6
-     */
-    inline int domain() const noexcept
-    {
-        return AF_INET6;
-    }
-
-    /**
-     * Get the underlying address.
-     *
-     * \return the address
-     */
-    inline const sockaddr *address() const noexcept
-    {
-        return reinterpret_cast<const sockaddr *>(&m_sin6);
-    }
-
-    /**
-     * Get the address length.
-     *
-     * \return the size of sockaddr_in
-     */
-    inline socklen_t length() const noexcept
-    {
-        return sizeof (sockaddr_in6);
-    }
-
-    /**
-     * Get the port.
-     *
-     * \return the port
-     */
-    inline std::uint16_t port() const noexcept
-    {
-        return ntohs(m_sin6.sin6_port);
-    }
-
-    /**
-     * Get the ip address.
-     *
-     * \return the ip address
-     * \throw Error on errors or if inet_ntop is unavailable
-     */
-    inline std::string ip() const
-    {
-        return Ip::ip(m_sin6);
-    }
-
-    /**
-     * Same as Ip::resolve with AF_INET6 as domain.
-     *
-     * \param host the hostname
-     * \param service the service name (port or name)
-     * \param type the socket type (e.g. SOCK_STREAM)
-     * \return the resolved address
-     * \throw Error on failures
-     */
-    static Ipv6 resolve(const std::string &host, const std::string &service, int type = SOCK_STREAM)
-    {
-        Ip result = Ip::resolve(host, service, AF_INET6, type);
-
-        return Ipv6(result.address(), result.length());
-    }
-};
+inline std::string ntop(const Address &address)
+{
+    assert(address.domain() == AF_INET6);
+
+#if defined(NET_HAVE_INET_NTOP)
+#if !defined(NET_NO_AUTO_INIT)
+    init();
+#endif
+
+    char ret[INET6_ADDRSTRLEN];
+
+    std::memset(ret, 0, sizeof (ret));
+
+    if (!inet_ntop(AF_INET6, const_cast<in6_addr *>(&address.as<sockaddr_in6>().sin6_addr), ret, sizeof (ret)));
+        throw Error();
+
+    return ret;
+#else
+    (void)address;
+
+    throw Error(std::strerror(ENOSYS));
+#endif
+}
+
+/**
+ * Get the port from the IPv6 address.
+ *
+ * \pre address.domain() == AF_INET6
+ * \param address the address
+ * \return the port
+ */
+inline std::uint16_t port(const Address &address) noexcept
+{
+    assert(address.domain() == AF_INET6);
+
+    return ntohs(address.as<sockaddr_in6>().sin6_port);
+}
+
+} // !ipv6
 
 #if !defined(_WIN32)
 
 /**
- * \brief unix family sockets
- * \ingroup net-module-addresses
- *
- * Create an address to a specific path. Only available on Unix.
+ * \brief Unix domain functions.
  */
-class Local {
-private:
-    sockaddr_un m_sun;
-    std::string m_path;
-
-public:
-    /**
-     * Get the domain AF_LOCAL.
-     *
-     * \return AF_LOCAL
-     */
-    inline int domain() const noexcept
-    {
-        return AF_LOCAL;
-    }
-
-    /**
-     * Default constructor.
-     */
-    inline Local() noexcept
-    {
-        std::memset(&m_sun, 0, sizeof (sockaddr_un));
-    }
-
-    /**
-     * Construct an address to a path.
-     *
-     * \param path the path
-     * \param rm remove the file before (default: false)
-     */
-    Local(std::string path, bool rm = false) noexcept
-        : m_path(std::move(path))
-    {
-        // Silently remove the file even if it fails.
-        if (rm)
-            ::remove(m_path.c_str());
-
-        // Copy the path.
-        std::memset(m_sun.sun_path, 0, sizeof (m_sun.sun_path));
-        std::strncpy(m_sun.sun_path, m_path.c_str(), sizeof (m_sun.sun_path) - 1);
-
-        // Set the parameters.
-        m_sun.sun_family = AF_LOCAL;
-    }
-
-    /**
-     * Construct an unix address from a storage address.
-     *
-     * \pre storage's domain must be AF_LOCAL
-     * \param ss the storage
-     * \param length the length
-     */
-    Local(const sockaddr *ss, socklen_t length) noexcept
-    {
-        assert(ss->sa_family == AF_LOCAL);
-
-        std::memcpy(&m_sun, ss, length);
-        m_path = reinterpret_cast<const sockaddr_un &>(m_sun).sun_path;
-    }
-
-    /**
-     * Get the sockaddr_un.
-     *
-     * \return the address
-     */
-    inline const sockaddr *address() const noexcept
-    {
-        return reinterpret_cast<const sockaddr *>(&m_sun);
-    }
-
-    /**
-     * Get the address length.
-     *
-     * \return the length
-     */
-    inline socklen_t length() const noexcept
-    {
-#if defined(NET_HAVE_SUN_LEN)
-        return SUN_LEN(&m_sun);
-#else
-        return sizeof (m_sun);
-#endif
-    }
-};
-
-#endif // !_WIN32
+namespace local {
 
 /**
- * \brief Address iterator.
- * \ingroup net-module-addresses
- * \see resolve
- *
- * This iterator can be used to try to connect to an host.
- *
- * 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.
+ * Construct an address to a path.
  *
- * Example:
- *
- * ````cpp
- * SocketTcpIp sc;
- * Iterator end, it = resolve("hostname.test", "80");
- *
- * while (!connected_condition && it != end)
- *   sc.connect(it->address(), it->length());
- * ````
- *
- * When an iterator equals to a default constructed iterator, it is considered not dereferenceable.
+ * \pre !path.empty()
+ * \param path the path
+ * \param rm remove the file before (default: false)
  */
-class Iterator : public std::iterator<std::forward_iterator_tag, Generic> {
-private:
-    std::vector<Generic> m_addresses;
-    std::size_t m_index{0};
-
-public:
-    /**
-     * Construct a null iterator.
-     *
-     * The default constructed iterator is not dereferenceable.
-     */
-    inline Iterator() noexcept = default;
-
-    /**
-     * Construct an address iterator with a set of addresses.
-     *
-     * \pre index < m_addresses.size()
-     * \param addresses the addresses
-     * \param index the first index
-     */
-    inline Iterator(std::vector<Generic> addresses, std::size_t index = 0) noexcept
-        : m_addresses(std::move(addresses))
-        , m_index(index)
-    {
-        assert(index < m_addresses.size());
-    }
-
-    /**
-     * Get the generic address.
-     *
-     * \pre this is dereferenceable
-     * \return the generic address
-     */
-    inline const Generic &operator*() const noexcept
-    {
-        assert(m_index <= m_addresses.size());
-
-        return m_addresses[m_index];
-    }
-
-    /**
-     * Overloaded function.
-     *
-     * \pre this is dereferenceable
-     * \return the generic address
-     */
-    inline Generic &operator*() noexcept
-    {
-        assert(m_index <= m_addresses.size());
-
-        return m_addresses[m_index];
-    }
-
-    /**
-     * Get the generic address.
-     *
-     * \pre this is dereferenceable
-     * \return the generic address
-     */
-    inline const Generic *operator->() const noexcept
-    {
-        assert(m_index <= m_addresses.size());
-
-        return &m_addresses[m_index];
-    }
-
-    /**
-     * Overloaded function.
-     *
-     * \pre this is dereferenceable
-     * \return the generic address
-     */
-    inline Generic *operator->() noexcept
-    {
-        assert(m_index <= m_addresses.size());
-
-        return &m_addresses[m_index];
-    }
-
-    /**
-     * Pre-increment the iterator.
-     *
-     * \return this
-     */
-    inline Iterator &operator++(int) noexcept
-    {
-        if (m_index + 1 >= m_addresses.size()) {
-            m_addresses.clear();
-            m_index = 0;
-        } else
-            m_index ++;
-
-        return *this;
-    }
-
-    /**
-     * Post-increment the iterator.
-     *
-     * \return copy of this
-     */
-    inline Iterator operator++() noexcept
-    {
-        Iterator save = *this;
-
-        if (m_index + 1 >= m_addresses.size()) {
-            m_addresses.clear();
-            m_index = 0;
-        } else
-            m_index ++;
-
-        return save;
-    }
-
-    friend bool operator==(const Iterator &, const Iterator &) noexcept;
-    friend bool operator!=(const Iterator &, const Iterator &) noexcept;
-};
-
-/**
- * Compare two address iterators.
- *
- * \param i1 the first iterator
- * \param i2 the second iterator
- * \return true if they equal
- */
-inline bool operator==(const Iterator &i1, const Iterator &i2) noexcept
+inline Address create(const std::string &path, bool rm = false) noexcept
 {
-    return i1.m_addresses == i2.m_addresses && i1.m_index == i2.m_index;
+    assert(!path.empty());
+
+    // Silently remove the file even if it fails.
+    if (rm)
+        remove(path.c_str());
+
+    sockaddr_un sun;
+    socklen_t length;
+
+    std::memset(sun.sun_path, 0, sizeof (sun.sun_path));
+    std::strncpy(sun.sun_path, path.c_str(), sizeof (sun.sun_path) - 1);
+
+    sun.sun_family = AF_LOCAL;
+
+#if defined(NET_HAVE_SUN_LEN)
+    length = SUN_LEN(&sun);
+#else
+    length = sizeof (sun);
+#endif
+
+    return Address(reinterpret_cast<const sockaddr *>(&sun), length); 
 }
 
 /**
- * Compare two address iterators.
+ * Get the path from the address.
  *
- * \param i1 the first iterator
- * \param i2 the second iterator
- * \return false if they equal
+ * \pre address.domain() == AF_LOCAL
+ * \param address the local address
+ * \return the path to the socket file
  */
-inline bool operator!=(const Iterator &i1, const Iterator &i2) noexcept
+inline std::string path(const Address &address)
 {
-    return !(i1 == i2);
+    assert(address.domain() == AF_LOCAL);
+
+    return reinterpret_cast<const sockaddr_un *>(address.get())->sun_path;
 }
 
-} // !address
+} // !local
+
+#endif // !_WIN32
 
 /**
  * \brief Predefined options.
@@ -2859,8 +2469,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    void set(Socket<Address> &sc) const
+    void set(Socket &sc) const
     {
 #if defined(O_NONBLOCK) && !defined(_WIN32)
         int flags;
@@ -2890,8 +2499,7 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    bool get(Socket<Address> &sc) const
+    bool get(Socket &sc) const
     {
 #if defined(O_NONBLOCK) && !defined(_WIN32)
         int flags = fcntl(sc.handle(), F_GETFL, 0);
@@ -2933,8 +2541,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    inline void set(Socket<Address> &sc) const
+    inline void set(Socket &sc) const
     {
         sc.set(SOL_SOCKET, SO_RCVBUF, m_value);
     }
@@ -2946,10 +2553,9 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    inline int get(Socket<Address> &sc) const
+    inline int get(Socket &sc) const
     {
-        return sc.template get<int>(SOL_SOCKET, SO_RCVBUF);
+        return sc.get<int>(SOL_SOCKET, SO_RCVBUF);
     }
 };
 
@@ -2980,8 +2586,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    inline void set(Socket<Address> &sc) const
+    inline void set(Socket &sc) const
     {
         sc.set(SOL_SOCKET, SO_REUSEADDR, m_value ? 1 : 0);
     }
@@ -2993,10 +2598,9 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    inline bool get(Socket<Address> &sc) const
+    inline bool get(Socket &sc) const
     {
-        return sc.template get<int>(SOL_SOCKET, SO_REUSEADDR) != 0;
+        return sc.get<int>(SOL_SOCKET, SO_REUSEADDR) != 0;
     }
 };
 
@@ -3025,8 +2629,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    inline void set(Socket<Address> &sc) const
+    inline void set(Socket &sc) const
     {
         sc.set(SOL_SOCKET, SO_SNDBUF, m_value);
     }
@@ -3038,10 +2641,9 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    inline int get(Socket<Address> &sc) const
+    inline int get(Socket &sc) const
     {
-        return sc.template get<int>(SOL_SOCKET, SO_SNDBUF);
+        return sc.get<int>(SOL_SOCKET, SO_SNDBUF);
     }
 };
 
@@ -3072,8 +2674,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    inline void set(Socket<Address> &sc) const
+    inline void set(Socket &sc) const
     {
         sc.set(IPPROTO_TCP, TCP_NODELAY, m_value ? 1 : 0);
     }
@@ -3085,10 +2686,9 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    inline bool get(Socket<Address> &sc) const
+    inline bool get(Socket &sc) const
     {
-        return sc.template get<int>(IPPROTO_TCP, TCP_NODELAY) != 0;
+        return sc.get<int>(IPPROTO_TCP, TCP_NODELAY) != 0;
     }
 };
 
@@ -3122,8 +2722,7 @@
      * \param sc the socket
      * \throw Error on errors
      */
-    template <typename Address>
-    inline void set(Socket<Address> &sc) const
+    inline void set(Socket &sc) const
     {
         sc.set(IPPROTO_IPV6, IPV6_V6ONLY, m_value ? 1 : 0);
     }
@@ -3135,10 +2734,9 @@
      * \return the value
      * \throw Error on errors
      */
-    template <typename Address>
-    inline bool get(Socket<Address> &sc) const
+    inline bool get(Socket &sc) const
     {
-        return sc.template get<int>(IPPROTO_IPV6, IPV6_V6ONLY) != 0;
+        return sc.get<int>(IPPROTO_IPV6, IPV6_V6ONLY) != 0;
     }
 };
 
@@ -3968,80 +3566,6 @@
 };
 
 /**
- * \ingroup net-module-tcp
- * \brief Helper to create TCP/Ipv4 or TCP/Ipv6 sockets.
- */
-using TcpSocketIp = TcpSocket<address::Ip>;
-
-/**
- * \ingroup net-module-tcp
- * \brief Helper to create TCP/Ipv4 sockets.
- */
-using TcpSocketIpv4 = TcpSocket<address::Ipv4>;
-
-/**
- * \ingroup net-module-tcp
- * \brief Helper to create TCP/Ipv6 sockets.
- */
-using TcpSocketIpv6 = TcpSocket<address::Ipv6>;
-
-/**
- * \ingroup net-module-udp
- * \brief Helper to create UDP/Ipv4 or UDP/Ipv6 sockets.
- */
-using UdpSocketIp = UdpSocket<address::Ip>;
-
-/**
- * \ingroup net-module-udp
- * \brief Helper to create UDP/Ipv4 sockets.
- */
-using UdpSocketIpv4 = UdpSocket<address::Ipv4>;
-
-/**
- * \ingroup net-module-udp
- * \brief Helper to create UDP/Ipv6 sockets.
- */
-using UdpSocketIpv6 = UdpSocket<address::Ipv6>;
-
-#if !defined(_WIN32)
-
-/**
- * \ingroup net-module-tcp
- * \brief Helper to create TCP/Local sockets.
- */
-using TcpSocketLocal = TcpSocket<address::Local>;
-
-/**
- * \ingroup net-module-udp
- * \brief Helper to create UDP/Local sockets.
- */
-using UdpSocketLocal = TcpSocket<address::Local>;
-
-#endif
-
-#if !defined(NET_NO_SSL)
-
-/**
- * \ingroup net-module-tls
- * \brief Helper to create TLS/Ipv4 or TLS/Ipv6 sockets.
- */
-using TlsSocketIp = TlsSocket<address::Ip>;
-
-/**
- * \ingroup net-module-tls
- * \brief Helper to create TLS/Ipv4 sockets.
- */
-using TlsSocketIpv4 = TlsSocket<address::Ipv4>;
-
-/**
- * \ingroup net-module-tls
- * \brief Helper to create TLS/Ipv6 sockets.
- */
-using TlsSocketIpv6 = TlsSocket<address::Ipv6>;
-
-#endif
-
-/**
  * \ingroup net-module-resolv
  *
  * Resolve an hostname immediately.
@@ -4053,7 +3577,7 @@
  * \return the address iterator
  * \throw Error on failures
  */
-inline address::Iterator resolve(const std::string &host, const std::string &service, int domain = AF_UNSPEC, int type = 0)
+inline AddressIterator resolve(const std::string &host, const std::string &service, int domain = AF_UNSPEC, int type = 0)
 {
 #if !defined(NET_NO_AUTO_INIT)
         init();
@@ -4070,29 +3594,12 @@
     if (e != 0)
         throw Error(gai_strerror(e));
 
-    std::vector<address::Generic> addresses;
+    std::vector<Address> addresses;
 
     for (p = res; p != nullptr; p = p->ai_next)
-        addresses.push_back(address::Generic(p->ai_addr, p->ai_addrlen));
-
-    return address::Iterator(addresses, 0);
-}
-
-/**
- * \ingroup net-module-resolv
- *
- * Overloaded function.
- *
- * \param sc the parent socket
- * \param host the hostname
- * \param service the service name
- * \return the address iterator
- * \throw Error on failures
- */
-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.type());
+        addresses.push_back(Address(p->ai_addr, p->ai_addrlen));
+
+    return AddressIterator(addresses, 0);
 }
 
 /**
@@ -4108,10 +3615,10 @@
  * \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)
+inline Address resolveOne(const std::string &host, const std::string &service, int domain, int type)
 {
-    address::Iterator end;
-    address::Iterator it = resolve(host, service, domain, type);
+    AddressIterator it = resolve(host, service, domain, type);
+    AddressIterator end;
 
     if (it == end)
         throw Error("no address available");
@@ -4119,23 +3626,6 @@
     return *it;
 }
 
-/**
- * \ingroup net-module-resolv
- *
- * Overloaded function
- *
- * \param sc the parent socket
- * \param host the hostname
- * \param service the service name
- * \return the first generic address available
- * \throw Error on failures
- */
-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.type());
-}
-
 } // !net
 
 #endif // !NET_HPP
--- a/modules/net/test/main.cpp	Wed Jun 29 19:18:39 2016 +0200
+++ b/modules/net/test/main.cpp	Thu Jun 30 12:35:42 2016 +0200
@@ -27,7 +27,6 @@
 #include <net.hpp>
 
 using namespace net;
-using namespace net::address;
 using namespace net::option;
 
 using namespace std::literals::chrono_literals;
@@ -39,7 +38,7 @@
 
 TEST(Options, reuse)
 {
-    TcpSocketIp s;
+    TcpSocket s(AF_INET, 0);
 
     try {
         s.set(option::SockReuseAddress(true));
@@ -54,7 +53,7 @@
 
 TEST(Options, nodelay)
 {
-    TcpSocketIp s;
+    TcpSocket s(AF_INET, 0);
 
     try {
         s.set(option::TcpNoDelay(true));
@@ -69,7 +68,7 @@
 
 TEST(Options, v6only)
 {
-    TcpSocketIpv6 s;
+    TcpSocket s(AF_INET6, 0);
 
     try {
         s.set(option::Ipv6Only(true));
@@ -89,8 +88,8 @@
 
 class TcpServerTest : public testing::Test {
 protected:
-    TcpSocketIpv4 m_server;
-    TcpSocketIpv4 m_client;
+    TcpSocket m_server{AF_INET, 0};
+    TcpSocket m_client{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -114,9 +113,9 @@
 {
     m_tserver = std::thread([this] () {
         try {
-            TcpSocketIpv4 sc;
+            TcpSocket sc(AF_INET, 0);
 
-            m_server.bind(Ipv4("*", 16000));
+            m_server.bind(net::ipv4::any(16000));
             m_server.listen();
             m_server.accept();
             m_server.close();
@@ -129,7 +128,7 @@
 
     m_tclient = std::thread([this] () {
         try {
-            m_client.connect(Ipv4("127.0.0.1", 16000));
+            m_client.connect(net::ipv4::pton("127.0.0.1", 16000));
             m_client.close();
         } catch (const std::exception &ex) {
             FAIL() << ex.what();
@@ -140,10 +139,10 @@
 TEST_F(TcpServerTest, io)
 {
     m_tserver = std::thread([this] () {
-        m_server.bind(Ipv4("*", 16000));
+        m_server.bind(net::ipv4::any(16000));
         m_server.listen();
 
-        TcpSocketIpv4 client = m_server.accept();
+        TcpSocket client = m_server.accept();
 
         std::string msg;
 
@@ -160,7 +159,7 @@
     m_tclient = std::thread([this] () {
         std::string msg = "hello world";
 
-        m_client.connect(Ipv4("127.0.0.1", 16000));
+        m_client.connect(net::ipv4::pton("127.0.0.1", 16000));
         m_client.send(msg.c_str(), msg.length());
 
         msg.resize(512);
@@ -177,8 +176,8 @@
 
 class UdpServerTest : public testing::Test {
 protected:
-    UdpSocketIpv4 m_server;
-    UdpSocketIpv4 m_client;
+    UdpSocket m_server{AF_INET, 0};
+    UdpSocket m_client{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -202,8 +201,8 @@
 {
     m_tserver = std::thread([this] () {
         try {
-            Ipv4 client;
-            Ipv4 info("*", 16000);
+            Address client;
+            Address info = net::ipv4::any(16000);
 
             m_server.bind(info);
 
@@ -225,7 +224,7 @@
 
     m_tclient = std::thread([this] () {
         try {
-            Ipv4 info("127.0.0.1", 16000);
+            Address info = net::ipv4::pton("127.0.0.1", 16000);
             std::string msg = "hello world";
 
             m_client.sendto(msg.c_str(), msg.length(), info);
@@ -480,8 +479,8 @@
 class ListenerTest : public testing::Test {
 protected:
     Listener<backend::Select> m_listener;
-    TcpSocketIpv4 m_masterTcp;
-    TcpSocketIpv4 m_clientTcp;
+    TcpSocket m_masterTcp{AF_INET, 0};
+    TcpSocket m_clientTcp{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -490,7 +489,7 @@
     ListenerTest()
     {
         m_masterTcp.set(SockReuseAddress());
-        m_masterTcp.bind(Ipv4("*", 16000));
+        m_masterTcp.bind(net::ipv4::any(16000));
         m_masterTcp.listen();
     }
 
@@ -521,7 +520,7 @@
     std::this_thread::sleep_for(100ms);
 
     m_tclient = std::thread([this] () {
-        m_clientTcp.connect(Ipv4("127.0.0.1", 16000));
+        m_clientTcp.connect(net::ipv4::pton("127.0.0.1", 16000));
     });
 }
 
@@ -532,7 +531,7 @@
             m_listener.set(m_masterTcp.handle(), Condition::Readable);
             m_listener.wait();
 
-            TcpSocketIpv4 sc = m_masterTcp.accept();
+            TcpSocket sc = m_masterTcp.accept();
 
             std::string msg;
 
@@ -550,7 +549,7 @@
     m_tclient = std::thread([this] () {
         std::string msg = "hello";
 
-        m_clientTcp.connect(Ipv4("127.0.0.1", 16000));
+        m_clientTcp.connect(net::ipv4::pton("127.0.0.1", 16000));
         m_clientTcp.send(msg.c_str(), msg.length());
     });
 }
@@ -562,8 +561,8 @@
 
 class NonBlockingConnectTest : public testing::Test {
 protected:
-    TcpSocketIpv4 m_server;
-    TcpSocketIpv4 m_client;
+    TcpSocket m_server{AF_INET, 0};
+    TcpSocket m_client{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -590,8 +589,8 @@
 
 class TcpAcceptTest : public testing::Test {
 protected:
-    TcpSocketIpv4 m_server;
-    TcpSocketIpv4 m_client;
+    TcpSocket m_server{AF_INET, 0};
+    TcpSocket m_client{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -600,7 +599,7 @@
     TcpAcceptTest()
     {
         m_server.set(SockReuseAddress());
-        m_server.bind(Ipv4("*", 16000));
+        m_server.bind(net::ipv4::any(16000));
         m_server.listen();
     }
 
@@ -620,8 +619,8 @@
 
 class TcpRecvTest : public testing::Test {
 protected:
-    TcpSocketIpv4 m_server;
-    TcpSocketIpv4 m_client;
+    TcpSocket m_server{AF_INET, 0};
+    TcpSocket m_client{AF_INET, 0};
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -630,7 +629,7 @@
     TcpRecvTest()
     {
         m_server.set(SockReuseAddress());
-        m_server.bind(Ipv4("*", 16000));
+        m_server.bind(net::ipv4::any(16000));
         m_server.listen();
     }
 
@@ -646,7 +645,7 @@
 TEST_F(TcpRecvTest, blockingSuccess)
 {
     m_tserver = std::thread([this] () {
-        TcpSocketIpv4 client = m_server.accept();
+        TcpSocket client = m_server.accept();
         std::string msg;
 
         msg.resize(512);
@@ -660,7 +659,7 @@
     m_tclient = std::thread([this] () {
         std::string msg = "hello";
 
-        m_client.connect(Ipv4("127.0.0.1", 16000));
+        m_client.connect(net::ipv4::pton("127.0.0.1", 16000));
         m_client.send(msg.c_str(), msg.length());
         m_client.close();
     });