changeset 565:a1841ba6eb61

Net: various documentation fixes
author David Demelier <markand@malikania.fr>
date Thu, 23 Jun 2016 13:50:27 +0200
parents 21fa534ce42f
children 72390061044d
files modules/net/net.hpp modules/net/test/main.cpp
diffstat 2 files changed, 289 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/modules/net/net.hpp	Thu Jun 23 07:37:02 2016 +0200
+++ b/modules/net/net.hpp	Thu Jun 23 13:50:27 2016 +0200
@@ -1,5 +1,5 @@
 /*
- * net.hpp -- portable C++ socket wrappers
+ * net.hpp -- portable C++ socket wrapper
  *
  * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
  *
@@ -66,7 +66,6 @@
  *   - \subpage net-configuration
  *   - \subpage net-options
  *   - \subpage net-concepts
- *   - \subpage net-examples
  */
 
 /**
@@ -151,7 +150,7 @@
  * ## Synopsis
  *
  * ````
- * Address(); // (0);
+ * Address(); // (0)
  * Address(const sockaddr *sa, socklen_t length); // (1)
  * ````
  *
@@ -354,95 +353,48 @@
  *
  * The type of socket.
  *
- * # create
- *
- * Function called immediately after creation of socket. Interface must provides this function even if the
- * interface does not require anything.
- *
- * ## Synopsis
- *
- * ````
- * template <typename Address>
- * void create(Socket<Address, Tcp> &) const noexcept;
- * ````
- *
  * # connect
  *
- * Initial connect function.
- *
- * In this function, the interface receive the socket, address and a condition (initially set to None). If the
- * underlying socket is marked non-blocking and the operation would block, the interface must set the condition
- * to the required one.
+ * Connect to the given address.
  *
  * ## Synopsis
  *
  * ````
- * template <typename Address>
- * void connect(Socket<Address> &sc, const sockaddr *address, socklen_t length, Condition &cond);
+ * void connect(const sockaddr *address, socklen_t length); // (0)
+ * void connect(const Address &address); // 1 (Optional)
  * ````
  *
  * ## Arguments
  *
- *   - **sc**: the socket,
  *   - **address**: the address,
- *   - **length**: the address length,
- *   - **cond**: the condition to update.
- *
- * # resumeConnect
- *
- * Continue the connection.
+ *   - **length**: the address length.
  *
- * ## Synopsis
+ * ## Throws
  *
- * ````
- * template <typename Address>
- * void resumeConnect(Socket<Address> &sc, Condition &cond)
- * ````
- *
- * ## Arguments
- *
- *   - **sc**: the socket,
- *   - **cond**: the condition to update.
+ *   - **WouldBlockError**: if the operation would block,
+ *   - **Error**: on other error.
  *
  * # accept
  *
  * Accept a new client.
  *
- * If the interface has no pending connection, an invalid socket SHOULD be returned, otherwise return the client and
- * set the condition if the accept process is not complete yet.
- *
- * The interface MUST stores the client information into address and length parameters, they are guaranted to never be
- * null.
+ * If no pending connection is available and operation would block, the implementation must throw WouldBlockError. Any other error
+ * can be thrown otherwise a valid socket must be returned.
  *
  * ## Synopsis
  *
  * ````
- * template <typename Address>
- * Socket<Address> accept(Socket<Address> &sc, sockaddr *address, socklen_t *length, Condition &cond);
+ * Socket<Address> accept();
  * ````
  *
- * ## Arguments
+ * ## Returns
  *
- *   - **sc**: the socket,
- *   - **address**: the information address,
- *   - **length**: the address initial length (sockaddr_storage),
- *   - **cond**: the condition to update.
- *
- * # resumeAccept
- *
- * Continue the accept process on the returned client.
+ * The new socket.
  *
- * ## Synopsis
+ * ## Throws
  *
- * ````
- * template <typename Address>
- * void accept(Socket<Address> &sc, Condition &cond) const noexcept;
- * ````
- *
- * ## Arguments
- *
- *   - **sc**: the socket,
- *   - **cond**: the condition to update.
+ *   - **WouldBlockError**: if the operation would block,
+ *   - **Error**: on other error.
  *
  * # recv
  *
@@ -451,16 +403,13 @@
  * ## Synopsis
  *
  * ````
- * 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);
  * ````
  *
  * ## Arguments
  *
- *   - **sc**: the socket,
  *   - **data**: the destination buffer,
- *   - **length**: the destination buffer length,
- *   - **cond**: the condition to update.
+ *   - **length**: the destination buffer length.
  *
  * ## Returns
  *
@@ -473,16 +422,13 @@
  * ## Synopsis
  *
  * ````
- * 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);
  * ````
  *
  * ## Arguments
  *
- *   - **sc**: the socket,
  *   - **data**: the data to send,
- *   - **length**: the data length,
- *   - **cond**: the condition to update.
+ *   - **length**: the data length.
  *
  * ## Returns
  *
@@ -515,18 +461,16 @@
  * ## Synopsis
  *
  * ````
- * template <typename Address>
- * std::size_t recvfrom(Socket<Address> &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); // (0)
+ * unsigned recvfrom(void *data, unsigned length, Address *source) // (1) (Optional)
  * ````
  *
  * ## Arguments
  *
- *   - **sc**: the socket,
  *   - **data**: the data,
  *   - **length**: the length,
  *   - **address**: the source address,
- *   - **addrlen**: the source address in/out length,
- *   - **cond**: the condition.
+ *   - **addrlen**: the source address in/out length.
  *
  * ## Returns
  *
@@ -535,108 +479,22 @@
  * # sendto
  *
  * ````
- * 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);
+ * unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen); // (0)
+ * unsigned sendto(const void *data, unsigned length, const Address &address); // (1) (Optional)
  * ````
  *
  * ## Arguments
  *
- *   - **sc**: the socket,
  *   - **data**: the data to send,
  *   - **length**: the data length,
  *   - **address**: the destination address,
- *   - **addrlen**: the destination address length,
- *   - **cond**: the condition.
+ *   - **addrlen**: the destination address length.
  *
  * ## Returns
  *
  * The number of bytes sent.
  */
 
-/**
- * \page net-examples Examples
- *
- * # Non blocking examples
- *
- * Non-blocking sockets can be tedious, here various examples on how to do it with this module.
- *
- *   - \subpage net-example-non-blocking-connect
- */
-
-/**
- * \page net-example-non-blocking-connect Non-blocking connect
- *
- * This example shows how to make a non-blocking connect.
- *
- * Because SSL support is first class value, the connection functions are a bit more tricky but don't be afraid it is completely
- * transparent for the user.
- *
- * ## Background
- *
- * First, let's explain what usually happen in traditional fashion.
- *
- * When you use the connect(2) function in a non-blocking socket, EINPROGRESS is returned if the connection could not be immediately
- * established, the user must then wait until the socket is writable and check for SOL_SOCKET/SO_ERROR option. For OpenSSL, user must wait
- * for readable/writable depending on the current operation, remember that OpenSSL requires several roundtrips to finalize handshake.
- *
- * Because these operations are different on TCP and SSL sockets, the Socket class has a unique resumeConnect function which have a
- * different implementation depending if the socket is SSL or raw TCP. Also because resumeConnect() must be called only when the socket is
- * either readable or writable, a condition is given to the user in several function including Socket::connect().
- *
- * ## Code
- *
- * In this code, we will try to connect to example.org on port 9090 using TCP/IPv4.
- *
- * ````cpp
- * #include <iostream>
- *
- * #include "net.hpp"
- *
- * void connect(SocketTcpIpv4 &sc)
- * {
- *   // (0) The listener, used to wait for a condition.
- *   Listener<> listener;
- *
- *   // (1) The condition that we must wait for, no need to initialize.
- *   Condition cond;
- *
- *   // (2) Do the initial connection attempt
- *   //
- *   // 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());
- *
- *     // (4) Add the requested condition.
- *     listener.set(sc.handle(), cond);
- *
- *     // (5) Wait and try to resume the condition, don't forget to give cond again.
- *     listener.wait();
- *     sc.resumeConnect(cond);
- *   }
- * }
- *
- * int main()
- * {
- *   try {
- *     SocketTcpIpv4 sc;
- *
- *     // Set the socket non-blocking.
- *     sc.set(option::SockBlockMode(false));
- *
- *     connect(sc);
- *   } catch (const std::exception &ex) {
- *     std::cerr << ex.what() << std::endl;
- *     return 1;
- *   }
- *
- *   return 0;
- * }
- * ````
- */
-
 /*
  * Headers to include.
  * ------------------------------------------------------------------
@@ -644,22 +502,22 @@
 
 // Include Windows headers before because it brings _WIN32_WINNT if not specified by the user.
 #if defined(_WIN32)
-#  include <WinSock2.h>
-#  include <WS2tcpip.h>
+#   include <WinSock2.h>
+#   include <WS2tcpip.h>
 #else
-#  include <sys/ioctl.h>
-#  include <sys/types.h>
-#  include <sys/socket.h>
-#  include <sys/un.h>
-
-#  include <arpa/inet.h>
-
-#  include <netinet/in.h>
-#  include <netinet/tcp.h>
-
-#  include <fcntl.h>
-#  include <netdb.h>
-#  include <unistd.h>
+#   include <sys/ioctl.h>
+#   include <sys/types.h>
+#   include <sys/socket.h>
+#   include <sys/un.h>
+
+#   include <arpa/inet.h>
+
+#   include <netinet/in.h>
+#   include <netinet/tcp.h>
+
+#   include <fcntl.h>
+#   include <netdb.h>
+#   include <unistd.h>
 #endif
 
 #include <algorithm>
@@ -698,23 +556,23 @@
  */
 
 #if defined(_WIN32)
-#  if _WIN32_WINNT >= 0x0600 && !defined(NET_HAVE_POLL)
-#    define NET_HAVE_POLL
-#  endif
+#   if _WIN32_WINNT >= 0x0600 && !defined(NET_HAVE_POLL)
+#       define NET_HAVE_POLL
+#   endif
 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
-#  if !defined(NET_HAVE_KQUEUE)
-#    define NET_HAVE_KQUEUE
-#  endif
-#  if !defined(NET_HAVE_POLL)
-#    define NET_HAVE_POLL
-#  endif
+#   if !defined(NET_HAVE_KQUEUE)
+#       define NET_HAVE_KQUEUE
+#   endif
+#   if !defined(NET_HAVE_POLL)
+#       define NET_HAVE_POLL
+#   endif
 #elif defined(__linux__)
-#  if !defined(NET_HAVE_EPOLL)
-#    define NET_HAVE_EPOLL
-#  endif
-#  if !defined(NET_HAVE_POLL)
-#    define NET_HAVE_POLL
-#  endif
+#   if !defined(NET_HAVE_EPOLL)
+#       define NET_HAVE_EPOLL
+#   endif
+#   if !defined(NET_HAVE_POLL)
+#       define NET_HAVE_POLL
+#   endif
 #endif
 
 /*
@@ -726,26 +584,26 @@
  * \brief Tells if inet_pton is available
  */
 #if !defined(NET_HAVE_INET_PTON)
-#  if defined(_WIN32)
-#    if _WIN32_WINNT >= 0x0600
-#      define NET_HAVE_INET_PTON
-#    endif
-#  else
-#    define NET_HAVE_INET_PTON
-#  endif
+#   if defined(_WIN32)
+#       if _WIN32_WINNT >= 0x0600
+#           define NET_HAVE_INET_PTON
+#       endif
+#   else
+#       define NET_HAVE_INET_PTON
+#   endif
 #endif
 
 /**
  * \brief Tells if inet_ntop is available
  */
 #if !defined(NET_HAVE_INET_NTOP)
-#  if defined(_WIN32)
-#    if _WIN32_WINNT >= 0x0600
-#      define NET_HAVE_INET_NTOP
-#    endif
-#  else
-#    define NET_HAVE_INET_NTOP
-#  endif
+#   if defined(_WIN32)
+#       if _WIN32_WINNT >= 0x0600
+#           define NET_HAVE_INET_NTOP
+#       endif
+#   else
+#       define NET_HAVE_INET_NTOP
+#   endif
 #endif
 
 /*
@@ -759,35 +617,35 @@
  * \brief Defines the default backend
  */
 #if defined(_WIN32)
-#  if !defined(NET_DEFAULT_BACKEND)
-#    if defined(NET_HAVE_POLL)
-#      define NET_DEFAULT_BACKEND Poll
-#    else
-#      define NET_DEFAULT_BACKEND Select
-#    endif
-#  endif
+#   if !defined(NET_DEFAULT_BACKEND)
+#       if defined(NET_HAVE_POLL)
+#           define NET_DEFAULT_BACKEND Poll
+#       else
+#           define NET_DEFAULT_BACKEND Select
+#       endif
+#   endif
 #elif defined(__linux__)
-#  include <sys/epoll.h>
-
-#  if !defined(NET_DEFAULT_BACKEND)
-#    define NET_DEFAULT_BACKEND Epoll
-#  endif
+#   include <sys/epoll.h>
+
+#   if !defined(NET_DEFAULT_BACKEND)
+#       define NET_DEFAULT_BACKEND Epoll
+#   endif
 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
-#  include <sys/types.h>
-#  include <sys/event.h>
-#  include <sys/time.h>
-
-#  if !defined(NET_DEFAULT_BACKEND)
-#    define NET_DEFAULT_BACKEND Kqueue
-#  endif
+#   include <sys/types.h>
+#   include <sys/event.h>
+#   include <sys/time.h>
+
+#   if !defined(NET_DEFAULT_BACKEND)
+#       define NET_DEFAULT_BACKEND Kqueue
+#   endif
 #else
-#  if !defined(NET_DEFAULT_BACKEND)
-#    define NET_DEFAULT_BACKEND Select
-#  endif
+#   if !defined(NET_DEFAULT_BACKEND)
+#       define NET_DEFAULT_BACKEND Select
+#   endif
 #endif
 
 #if defined(NET_HAVE_POLL) && !defined(_WIN32)
-#  include <poll.h>
+#    include <poll.h>
 #endif
 
 /**
@@ -1063,32 +921,64 @@
     }
 };
 
+/**
+ * \brief Timeout occured.
+ */
 class TimeoutError : public std::exception {
 public:
+    /**
+     * Get the error message.
+     *
+     * \return the message
+     */
     const char *what() const noexcept override
     {
         return std::strerror(ETIMEDOUT);
     }
 };
 
+/**
+ * \brief Operation would block.
+ */
 class WouldBlockError : public std::exception {
 public:
+    /**
+     * Get the error message.
+     *
+     * \return the message
+     */
     const char *what() const noexcept override
     {
         return std::strerror(EWOULDBLOCK);
     }
 };
 
+/**
+ * \brief Operation requires sending data to complete.
+ */
 class WantWriteError : public std::exception {
 public:
+    /**
+     * Get the error message.
+     *
+     * \return the message
+     */
     const char *what() const noexcept override
     {
         return "operation requires writing to complete";
     }
 };
 
+/**
+ * \brief Operation requires reading data to complete.
+ */
 class WantReadError : public std::exception {
 public:
+    /**
+     * Get the error message.
+     *
+     * \return the message
+     */
     const char *what() const noexcept override
     {
         return "operation requires read to complete";
@@ -1105,9 +995,6 @@
 /**
  * \enum Condition
  * \brief Define the required condition for the socket.
- *
- * As explained in Action enumeration, some operations required to be called several times, before calling these
- * operations, the user must wait the socket to be readable or writable. This can be checked with Socket::condition.
  */
 enum class Condition {
     None,                       //!< No condition is required
@@ -1213,24 +1100,7 @@
  */
 
 /**
- * \brief Base socket class for socket operations.
- *
- * **Important:** When using non-blocking sockets, some considerations must be taken. See the implementation of the
- * underlying protocol for more details.
- *
- * When using non-blocking sockets, it is important to pass the condition to functions which may block, they indicate
- * the condition to wait to perform or continue the operation if they would block.
- *
- * For example, when trying to connect with non-blocking, user should do the following:
- *
- * 1. Call Socket::connect() with the condition,
- * 2. Loop until condition is not set to Condition::None (or an exception is thrown),
- * 3. Wait with a listener for the condition to be ready (see Listener::wait),
- * 4. Call Socket::resumeConnect() with the condition again.
- *
- * \see protocol::Tls
- * \see protocol::Tcp
- * \see protocol::Udp
+ * \brief Base socket class.
  */
 template <typename Address>
 class Socket {
@@ -1267,7 +1137,6 @@
      * Create the socket with an already defined handle and its protocol.
      *
      * \param handle the handle
-     * \param protocol the protocol
      */
     explicit inline Socket(Handle handle) noexcept
         : m_handle(handle)
@@ -1618,14 +1487,32 @@
 template <typename Address>
 class TcpSocket : public Socket<Address> {
 public:
+    /**
+     * Inherited constructors.
+     */
     using Socket<Address>::Socket;
 
-    TcpSocket()
+    /**
+     * Create a TCP socket using the address domain.
+     *
+     * \throw Error on errors
+     */
+    inline TcpSocket()
         : Socket<Address>(Address().domain(), SOCK_STREAM, 0)
     {
     }
 
     /**
+     * Get the type of the socket.
+     *
+     * \return the type
+     */
+    inline int type() const noexcept
+    {
+        return SOCK_STREAM;
+    }
+
+    /**
      * Initiate connection.
      *
      * \param address the address
@@ -1669,7 +1556,6 @@
      *
      * If there are no pending connection, an invalid socket is returned.
      *
-     * \param sc the socket
      * \return the new socket
      * \throw WouldBlockError if the socket is marked non-blocking and no connection are available
      * \throw Error on other errors
@@ -1766,9 +1652,34 @@
  * This class is the basic implementation of UDP sockets.
  */
 template <typename Address>
-class UdpSocket {
+class UdpSocket : public Socket<Address> {
 public:
     /**
+     * Inherited constructors.
+     */
+    using Socket<Address>::Socket;
+
+    /**
+     * Create a UDP socket using the address domain.
+     *
+     * \throw Error on errors
+     */
+    inline UdpSocket()
+        : Socket<Address>(Address().domain(), SOCK_DGRAM, 0)
+    {
+    }
+
+    /**
+     * Get the type of the socket.
+     *
+     * \return the type
+     */
+    inline int type() const noexcept
+    {
+        return SOCK_DGRAM;
+    }
+
+    /**
      * Receive some data.
      *
      * \param data the data
@@ -1776,6 +1687,8 @@
      * \param address the source address
      * \param addrlen the source address in/out length
      * \return the number of bytes received
+     * \throw WouldBlockError if the socket is marked non-blocking and the operation would block
+     * \throw Error on other errors
      */
     unsigned recvfrom(void *data, unsigned length, sockaddr *address, socklen_t *addrlen)
     {
@@ -1802,6 +1715,28 @@
     }
 
     /**
+     * Overloaded function.
+     *
+     * \param data the data
+     * \param length the length
+     * \param source the source information (optional)
+     * \throw WouldBlockError if the socket is marked non-blocking and the operation would block
+     * \throw Error on other errors
+     */
+    inline unsigned recvfrom(void *data, unsigned length, Address *source = nullptr)
+    {
+        sockaddr_storage st;
+        socklen_t socklen = sizeof (sockaddr_storage);
+
+        auto nr = recvfrom(data, length, reinterpret_cast<sockaddr *>(&st), &socklen);
+
+        if (source)
+            *source = Address(reinterpret_cast<const sockaddr *>(&st), socklen);
+
+        return nr;
+    }
+
+    /**
      * Send some data.
      *
      * \param data the data to send
@@ -1809,6 +1744,8 @@
      * \param address the destination address
      * \param addrlen the destination address length
      * \return the number of bytes sent
+     * \throw WouldBlockError if the socket is marked non-blocking and the operation would block
+     * \throw Error on other errors
      */
     unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen)
     {
@@ -1833,6 +1770,21 @@
 
         return static_cast<unsigned>(nbsent);
     }
+
+    /**
+     * Overloaded function
+     *
+     * \param data the data to send
+     * \param length the data length
+     * \param address the destination address
+     * \return the number of bytes sent
+     * \throw WouldBlockError if the socket is marked non-blocking and the operation would block
+     * \throw Error on other errors
+     */
+    inline unsigned sendto(const void *data, unsigned length, const Address &address)
+    {
+        return sendto(data, length, address.address(), address.length());
+    }
 };
 
 #if !defined(NET_NO_SSL)
@@ -1900,6 +1852,7 @@
      *
      * \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())
@@ -1919,9 +1872,20 @@
     }
 
     /**
+     * Get the type of socket.
+     *
+     * \return the type
+     */
+    inline int type() const noexcept
+    {
+        return SOCK_STREAM;
+    }
+
+    /**
      * Use the specified private key file.
      *
      * \param file the path to the private key
+     * \param type the type of file
      */
     inline void setPrivateKey(std::string file, int type = SSL_FILETYPE_PEM)
     {
@@ -1933,6 +1897,7 @@
      * Use the specified certificate file.
      *
      * \param file the path to the file
+     * \param type the type of file
      */
     inline void setCertificate(std::string file, int type = SSL_FILETYPE_PEM)
     {
@@ -1942,10 +1907,6 @@
 
     /**
      * Do handshake, needed in some case when you have non blocking sockets.
-     *
-     * \param address the address
-     * \param length the address length
-     * \param cond the condition
      */
     void handshake()
     {
@@ -1978,7 +1939,6 @@
      *
      * \param data the data to send
      * \param length the length
-     * \param cond the condition
      * \return the number of bytes sent
      */
     unsigned send(const void *data, unsigned length)
@@ -2295,7 +2255,7 @@
 #if !defined(NET_HAVE_INET_NTOP)
         (void)sin;
 
-        throw Error(ENOSYS, std::strerror(ENOSYS));
+        throw Error(std::strerror(ENOSYS));
 #else
         char result[INET_ADDRSTRLEN + 1];
 
@@ -2324,7 +2284,7 @@
 #if !defined(NET_HAVE_INET_NTOP)
         (void)sin6;
 
-        throw Error(ENOSYS, std::strerror(ENOSYS));
+        throw Error(std::strerror(ENOSYS));
 #else
         char result[INET6_ADDRSTRLEN];
 
@@ -4114,8 +4074,6 @@
     return address::Iterator(addresses, 0);
 }
 
-#if 0
-
 /**
  * \ingroup net-module-resolv
  *
@@ -4133,8 +4091,6 @@
     return resolve(host, service, Address().domain(), sc.type());
 }
 
-#endif
-
 /**
  * \ingroup net-module-resolv
  *
@@ -4159,8 +4115,6 @@
     return *it;
 }
 
-#if 0
-
 /**
  * \ingroup net-module-resolv
  *
@@ -4178,8 +4132,6 @@
     return resolveOne(host, service, Address().domain(), sc.type());
 }
 
-#endif
-
 } // !net
 
 #endif // !NET_HPP
--- a/modules/net/test/main.cpp	Thu Jun 23 07:37:02 2016 +0200
+++ b/modules/net/test/main.cpp	Thu Jun 23 13:50:27 2016 +0200
@@ -29,7 +29,6 @@
 using namespace net;
 using namespace net::address;
 using namespace net::option;
-using namespace net::protocol;
 
 using namespace std::literals::chrono_literals;
 
@@ -40,7 +39,7 @@
 
 TEST(Options, reuse)
 {
-    SocketTcpIp s;
+    TcpSocketIp s;
 
     try {
         s.set(option::SockReuseAddress(true));
@@ -55,7 +54,7 @@
 
 TEST(Options, nodelay)
 {
-    SocketTcpIp s;
+    TcpSocketIp s;
 
     try {
         s.set(option::TcpNoDelay(true));
@@ -70,7 +69,7 @@
 
 TEST(Options, v6only)
 {
-    SocketTcpIpv6 s;
+    TcpSocketIpv6 s;
 
     try {
         s.set(option::Ipv6Only(true));
@@ -90,8 +89,8 @@
 
 class TcpServerTest : public testing::Test {
 protected:
-    SocketTcp<Ipv4> m_server;
-    SocketTcp<Ipv4> m_client;
+    TcpSocketIpv4 m_server;
+    TcpSocketIpv4 m_client;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -115,7 +114,7 @@
 {
     m_tserver = std::thread([this] () {
         try {
-            SocketTcp<Ipv4> sc;
+            TcpSocketIpv4 sc;
 
             m_server.bind(Ipv4("*", 16000));
             m_server.listen();
@@ -144,22 +143,30 @@
         m_server.bind(Ipv4("*", 16000));
         m_server.listen();
 
-        SocketTcp<Ipv4> client = m_server.accept();
+        TcpSocketIpv4 client = m_server.accept();
 
-        auto msg = client.recv(512);
+        std::string msg;
+
+        msg.resize(512);
+        msg.resize(client.recv(&msg[0], 512));
 
         ASSERT_EQ("hello world", msg);
 
-        client.send(msg);
+        client.send(msg.data(), msg.length());
     });
 
     std::this_thread::sleep_for(100ms);
 
     m_tclient = std::thread([this] () {
+        std::string msg = "hello world";
+
         m_client.connect(Ipv4("127.0.0.1", 16000));
-        m_client.send("hello world");
+        m_client.send(msg.c_str(), msg.length());
 
-        ASSERT_EQ("hello world", m_client.recv(512));
+        msg.resize(512);
+        msg.resize(m_client.recv(&msg[0], 512));
+
+        ASSERT_EQ("hello world", msg);
     });
 }
 
@@ -170,8 +177,8 @@
 
 class UdpServerTest : public testing::Test {
 protected:
-    SocketUdp<Ipv4> m_server;
-    SocketUdp<Ipv4> m_client;
+    UdpSocketIpv4 m_server;
+    UdpSocketIpv4 m_client;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -200,14 +207,17 @@
 
             m_server.bind(info);
 
-            auto msg = m_server.recvfrom(512, client);
+            std::string msg;
+
+            msg.resize(512);
+            msg.resize(m_server.recvfrom(&msg[0], 512, &client));
 
             ASSERT_EQ("hello world", msg);
 
-            m_server.sendto(msg, client);
+            m_server.sendto(msg.c_str(), msg.length(), client);
             m_server.close();
         } catch (const net::Error &ex) {
-            FAIL() << ex.function() << ": " << ex.what();
+            FAIL() << ex.what();
         }
     });
 
@@ -216,14 +226,18 @@
     m_tclient = std::thread([this] () {
         try {
             Ipv4 info("127.0.0.1", 16000);
+            std::string msg = "hello world";
 
-            m_client.sendto("hello world", info);
+            m_client.sendto(msg.c_str(), msg.length(), info);
 
-            ASSERT_EQ("hello world", m_client.recvfrom(512, info));
+            msg.resize(512);
+            msg.resize(m_client.recvfrom(&msg[0], 512, &info));
+
+            ASSERT_EQ("hello world", msg);
 
             m_client.close();
         } catch (const net::Error &ex) {
-            FAIL() << ex.function() << ": " << ex.what();
+            FAIL() << ex.what();
         }
     });
 }
@@ -466,8 +480,8 @@
 class ListenerTest : public testing::Test {
 protected:
     Listener<backend::Select> m_listener;
-    SocketTcp<Ipv4> m_masterTcp;
-    SocketTcp<Ipv4> m_clientTcp;
+    TcpSocketIpv4 m_masterTcp;
+    TcpSocketIpv4 m_clientTcp;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -518,9 +532,14 @@
             m_listener.set(m_masterTcp.handle(), Condition::Readable);
             m_listener.wait();
 
-            SocketTcp<Ipv4> sc = m_masterTcp.accept();
+            TcpSocketIpv4 sc = m_masterTcp.accept();
+
+            std::string msg;
 
-            ASSERT_EQ("hello", sc.recv(512));
+            msg.resize(512);
+            msg.resize(sc.recv(&msg[0], 512));
+
+            ASSERT_EQ("hello", msg);
         } catch (const std::exception &ex) {
             FAIL() << ex.what();
         }
@@ -529,8 +548,10 @@
     std::this_thread::sleep_for(100ms);
 
     m_tclient = std::thread([this] () {
+        std::string msg = "hello";
+
         m_clientTcp.connect(Ipv4("127.0.0.1", 16000));
-        m_clientTcp.send("hello");
+        m_clientTcp.send(msg.c_str(), msg.length());
     });
 }
 
@@ -541,8 +562,8 @@
 
 class NonBlockingConnectTest : public testing::Test {
 protected:
-    SocketTcp<Ipv4> m_server;
-    SocketTcp<Ipv4> m_client;
+    TcpSocketIpv4 m_server;
+    TcpSocketIpv4 m_client;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -569,8 +590,8 @@
 
 class TcpAcceptTest : public testing::Test {
 protected:
-    SocketTcp<Ipv4> m_server;
-    SocketTcp<Ipv4> m_client;
+    TcpSocketIpv4 m_server;
+    TcpSocketIpv4 m_client;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -599,8 +620,8 @@
 
 class TcpRecvTest : public testing::Test {
 protected:
-    SocketTcp<Ipv4> m_server;
-    SocketTcp<Ipv4> m_client;
+    TcpSocketIpv4 m_server;
+    TcpSocketIpv4 m_client;
 
     std::thread m_tserver;
     std::thread m_tclient;
@@ -625,91 +646,26 @@
 TEST_F(TcpRecvTest, blockingSuccess)
 {
     m_tserver = std::thread([this] () {
-        SocketTcp<Ipv4> client = m_server.accept();
+        TcpSocketIpv4 client = m_server.accept();
+        std::string msg;
 
-        ASSERT_EQ("hello", client.recv(32));
+        msg.resize(512);
+        msg.resize(client.recv(&msg[0], 512));
+
+        ASSERT_EQ("hello", msg);
     });
 
     std::this_thread::sleep_for(100ms);
 
     m_tclient = std::thread([this] () {
+        std::string msg = "hello";
+
         m_client.connect(Ipv4("127.0.0.1", 16000));
-        m_client.send("hello");
+        m_client.send(msg.c_str(), msg.length());
         m_client.close();
     });
 }
 
-/*
- * Socket SSL.
- * ------------------------------------------------------------------
- */
-
-#if !defined(SOCKET_NO_SSL)
-
-class TlsRecvTest : public testing::Test {
-protected:
-    SocketTls<Ipv4> m_server{nullptr};
-    SocketTls<Ipv4> m_client{nullptr};
-
-    std::thread m_tserver;
-    std::thread m_tclient;
-
-public:
-    TlsRecvTest()
-    {
-        Tls cp, sp;
-
-        // Client.
-        cp.setVerify(false);
-
-        m_client = SocketTls<Ipv4>(Ipv4(), std::move(cp));
-
-        // Server.
-        sp.setVerify(false);
-        sp.setCertificate(DIRECTORY "test.crt");
-        sp.setPrivateKey(DIRECTORY "test.key");
-
-        m_server = SocketTls<Ipv4>(Ipv4(), std::move(sp));
-        m_server.set(SockReuseAddress());
-        m_server.bind(Ipv4("*", 16000));
-        m_server.listen();
-    }
-
-    ~TlsRecvTest()
-    {
-        if (m_tserver.joinable())
-            m_tserver.join();
-        if (m_tclient.joinable())
-            m_tclient.join();
-    }
-};
-
-TEST_F(TlsRecvTest, blockingSuccess)
-{
-    m_tserver = std::thread([this] () {
-        try {
-            SocketTls<Ipv4> client = m_server.accept();
-
-            ASSERT_EQ("hello", client.recv(32));
-        } catch (const net::Error &ex) {
-            FAIL() << ex.function() << ": " << ex.what();
-        }
-    });
-
-    std::this_thread::sleep_for(250ms);
-
-    m_tclient = std::thread([this] () {
-        try {
-            m_client.connect(Ipv4("127.0.0.1", 16000));
-            m_client.send("hello");
-        } catch (const net::Error &ex) {
-            FAIL() << ex.function() << ": " << ex.what();
-        }
-    });
-}
-
-#endif
-
 int main(int argc, char **argv)
 {
     testing::InitGoogleTest(&argc, argv);