changeset 514:d89a5e9e5fa7

Remove sockets directory
author David Demelier <markand@malikania.fr>
date Wed, 25 May 2016 14:17:55 +0200
parents ab70c638dc1d
children 409cf1aa4af9
files modules/sockets/sockets.cpp modules/sockets/sockets.h modules/sockets/test/main.cpp
diffstat 3 files changed, 0 insertions(+), 4205 deletions(-) [+]
line wrap: on
line diff
--- a/modules/sockets/sockets.cpp	Tue Apr 05 15:18:41 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,718 +0,0 @@
-/*
- * sockets.cpp -- portable C++ socket wrappers
- *
- * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define TIMEOUT_MSG "operation timeout"
-
-#include <algorithm>
-#include <atomic>
-#include <cstring>
-#include <mutex>
-
-#include "sockets.h"
-
-namespace net {
-
-/*
- * Portable constants
- * ------------------------------------------------------------------
- */
-
-/* {{{ Constants */
-
-#if defined(_WIN32)
-
-const Handle Invalid{INVALID_SOCKET};
-const int Failure{SOCKET_ERROR};
-
-#else
-
-const Handle Invalid{-1};
-const int Failure{-1};
-
-#endif
-
-/* }}} */
-
-/*
- * Portable functions
- * ------------------------------------------------------------------
- */
-
-/* {{{ Functions */
-
-#if defined(_WIN32)
-
-namespace {
-
-static std::mutex s_mutex;
-static std::atomic<bool> s_initialized{false};
-
-} // !namespace
-
-#endif // !_WIN32
-
-void init() noexcept
-{
-#if defined(_WIN32)
-	std::lock_guard<std::mutex> lock(s_mutex);
-
-	if (!s_initialized) {
-		s_initialized = true;
-
-		WSADATA wsa;
-		WSAStartup(MAKEWORD(2, 2), &wsa);
-
-		/*
-		 * If SOCKET_WSA_NO_INIT is not set then the user
-		 * must also call finish himself.
-		 */
-#if !defined(SOCKET_NO_AUTO_INIT)
-		atexit(finish);
-#endif
-	}
-#endif
-}
-
-void finish() noexcept
-{
-#if defined(_WIN32)
-	WSACleanup();
-#endif
-}
-
-std::string error(int errn)
-{
-#if defined(_WIN32)
-	LPSTR str = nullptr;
-	std::string errmsg = "Unknown error";
-
-	FormatMessageA(
-		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-		NULL,
-		errn,
-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-		(LPSTR)&str, 0, NULL);
-
-
-	if (str) {
-		errmsg = std::string(str);
-		LocalFree(str);
-	}
-
-	return errmsg;
-#else
-	return strerror(errn);
-#endif
-}
-
-std::string error()
-{
-#if defined(_WIN32)
-	return error(WSAGetLastError());
-#else
-	return error(errno);
-#endif
-}
-
-/* }}} */
-
-/*
- * SSL stuff
- * ------------------------------------------------------------------
- */
-
-/* {{{ SSL initialization */
-
-#if !defined(SOCKET_NO_SSL)
-
-namespace ssl {
-
-namespace {
-
-std::mutex mutex;
-std::atomic<bool> initialized{false};
-
-} // !namespace
-
-void finish() noexcept
-{
-	ERR_free_strings();
-}
-
-void init() noexcept
-{
-	std::lock_guard<std::mutex> lock{mutex};
-
-	if (!initialized) {
-		initialized = true;
-
-		SSL_library_init();
-		SSL_load_error_strings();
-		OpenSSL_add_all_algorithms();
-
-#if !defined(SOCKET_NO_AUTO_SSL_INIT)
-		atexit(finish);
-#endif // SOCKET_NO_AUTO_SSL_INIT
-	}
-}
-
-} // !ssl
-
-#endif // SOCKET_NO_SSL
-
-/* }}} */
-
-/*
- * Error class
- * ------------------------------------------------------------------
- */
-
-/* {{{ Error */
-
-Error::Error(Code code, std::string function)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(error())
-{
-}
-
-Error::Error(Code code, std::string function, int n)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(error(n))
-{
-}
-
-Error::Error(Code code, std::string function, std::string error)
-	: m_code(code)
-	, m_function(std::move(function))
-	, m_error(std::move(error))
-{
-}
-
-/* }}} */
-
-/*
- * Predefined addressed to be used
- * ------------------------------------------------------------------
- */
-
-/* {{{ Addresses */
-
-namespace address {
-
-namespace {
-
-void resolv(sockaddr *destination, const std::string host, std::uint16_t port, int domain)
-{
-	assert(domain == AF_INET || domain == AF_INET6);
-
-	addrinfo hints, *res;
-
-	std::memset(&hints, 0, sizeof (addrinfo));
-	hints.ai_family = domain;
-
-	auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
-	if (error != 0)
-		throw Error(Error::System, "getaddrinfo", gai_strerror(error));
-
-	if (domain == AF_INET6)
-		std::memcpy(destination, res->ai_addr, res->ai_addrlen);
-	else
-		std::memcpy(destination, res->ai_addr, res->ai_addrlen);
-
-	freeaddrinfo(res);
-}
-
-} // !namespace
-
-/* {{{ Ipv4 */
-
-Ipv4::Ipv4() noexcept
-{
-	std::memset(&m_sin, 0, sizeof (sockaddr_in));
-}
-
-Ipv4::Ipv4(const std::string &host, std::uint16_t port)
-	: Ipv4()
-{
-	if (host == "*") {
-		m_sin.sin_addr.s_addr = INADDR_ANY;
-		m_sin.sin_family = AF_INET;
-		m_sin.sin_port = htons(port);
-	} else {
-		resolv(reinterpret_cast<sockaddr *>(&m_sin), host, port, AF_INET);
-	}
-}
-
-Ipv4::Ipv4(const sockaddr_storage *ss, socklen_t length) noexcept
-{
-	std::memcpy(&m_sin, ss, length);
-}
-
-/* }}} */
-
-/* {{{ Ipv6 */
-
-Ipv6::Ipv6() noexcept
-{
-	std::memset(&m_sin6, 0, sizeof (sockaddr_in6));
-}
-
-Ipv6::Ipv6(const std::string &host, std::uint16_t port)
-	: Ipv6()
-{
-	if (host == "*") {
-		m_sin6.sin6_addr = in6addr_any;
-		m_sin6.sin6_family = AF_INET6;
-		m_sin6.sin6_port = htons(port);
-	} else {
-		resolv(reinterpret_cast<sockaddr *>(&m_sin6), host, port, AF_INET6);
-	}
-}
-
-Ipv6::Ipv6(const sockaddr_storage *ss, socklen_t length) noexcept
-{
-	std::memcpy(&m_sin6, ss, length);
-}
-
-/* }}} */
-
-/* {{{ Local */
-
-#if !defined(_WIN32)
-
-Local::Local() noexcept
-{
-	std::memset(&m_sun, 0, sizeof (sockaddr_un));
-}
-
-Local::Local(std::string path, bool rm) 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;
-}
-
-Local::Local(const sockaddr_storage *ss, socklen_t length) noexcept
-{
-	assert(ss->ss_family == AF_LOCAL);
-
-	if (ss->ss_family == AF_LOCAL) {
-		std::memcpy(&m_sun, ss, length);
-		m_path = reinterpret_cast<const sockaddr_un &>(m_sun).sun_path;
-	}
-}
-
-#endif // !_WIN32
-
-/* }}} */
-
-} // !address
-
-/* }}} */
-
-/*
- * Listener backends
- * ------------------------------------------------------------------
- */
-
-/* {{{ Backends */
-/*
- * Select
- * ------------------------------------------------------------------
- */
-
-/* {{{ Select */
-
-std::vector<ListenerStatus> Select::wait(const ListenerTable &table, int ms)
-{
-	timeval maxwait, *towait;
-	fd_set readset;
-	fd_set writeset;
-
-	FD_ZERO(&readset);
-	FD_ZERO(&writeset);
-
-	Handle max = 0;
-
-	for (const auto &pair : table) {
-		if ((pair.second & Condition::Readable) == Condition::Readable) {
-			FD_SET(pair.first, &readset);
-		}
-		if ((pair.second & Condition::Writable) == Condition::Writable) {
-			FD_SET(pair.first, &writeset);
-		}
-
-		if (pair.first > max) {
-			max = pair.first;
-		}
-	}
-
-	maxwait.tv_sec = 0;
-	maxwait.tv_usec = ms * 1000;
-
-	// Set to nullptr for infinite timeout.
-	towait = (ms < 0) ? nullptr : &maxwait;
-
-	auto error = ::select(max + 1, &readset, &writeset, nullptr, towait);
-	if (error == Failure) {
-		throw Error{Error::System, "select"};
-	}
-	if (error == 0) {
-		throw Error{Error::Timeout, "select", TIMEOUT_MSG};
-	}
-
-	std::vector<ListenerStatus> sockets;
-
-	for (const auto &pair : table) {
-		if (FD_ISSET(pair.first, &readset)) {
-			sockets.push_back(ListenerStatus{pair.first, Condition::Readable});
-		}
-		if (FD_ISSET(pair.first, &writeset)) {
-			sockets.push_back(ListenerStatus{pair.first, Condition::Writable});
-		}
-	}
-
-	return sockets;
-}
-
-/* }}} */
-
-/*
- * Poll
- * ------------------------------------------------------------------
- */
-
-/* {{{ Poll */
-
-/*
- * Poll implementation
- * ------------------------------------------------------------------
- */
-
-#if defined(SOCKET_HAVE_POLL)
-
-#if defined(_WIN32)
-#  define poll WSAPoll
-#endif
-
-short Poll::toPoll(Condition condition) const noexcept
-{
-	short result(0);
-
-	if ((condition & Condition::Readable) == Condition::Readable) {
-		result |= POLLIN;
-	}
-	if ((condition & Condition::Writable) == Condition::Writable) {
-		result |= POLLOUT;
-	}
-
-	return result;
-}
-
-Condition Poll::toCondition(short &event) const noexcept
-{
-	Condition condition{Condition::None};
-
-	/*
-	 * Poll implementations mark the socket differently regarding
-	 * the disconnection of a socket.
-	 *
-	 * At least, even if POLLHUP or POLLIN is set, recv() always
-	 * return 0 so we mark the socket as readable.
-	 */
-	if ((event & POLLIN) || (event & POLLHUP)) {
-		condition |= Condition::Readable;
-	}
-	if (event & POLLOUT) {
-		condition |= Condition::Writable;
-	}
-
-	/* Reset event for safety */
-	event = 0;
-
-	return condition;
-}
-
-void Poll::set(const ListenerTable &, Handle h, Condition condition, bool add)
-{
-	if (add) {
-		m_fds.push_back(pollfd{h, toPoll(condition), 0});
-	} else {
-		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const pollfd &pfd) {
-			return pfd.fd == h;
-		});
-
-		it->events |= toPoll(condition);
-	}
-}
-
-void Poll::unset(const ListenerTable &, Handle h, Condition condition, bool remove)
-{
-	auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const pollfd &pfd) {
-		return pfd.fd == h;
-	});
-
-	if (remove) {
-		m_fds.erase(it);
-	} else {
-		it->events &= ~(toPoll(condition));
-	}
-}
-
-std::vector<ListenerStatus> Poll::wait(const ListenerTable &, int ms)
-{
-	auto result = poll(m_fds.data(), m_fds.size(), ms);
-	if (result == 0) {
-		throw Error{Error::Timeout, "select", TIMEOUT_MSG};
-	}
-	if (result < 0) {
-		throw Error{Error::System, "poll"};
-	}
-
-	std::vector<ListenerStatus> sockets;
-	for (auto &fd : m_fds) {
-		if (fd.revents != 0) {
-			sockets.push_back(ListenerStatus{fd.fd, toCondition(fd.revents)});
-		}
-	}
-
-	return sockets;
-}
-
-#endif // !SOCKET_HAVE_POLL
-
-/* }}} */
-
-/*
- * Epoll implementation
- * ------------------------------------------------------------------
- */
-
-/* {{{ Epoll */
-
-#if defined(SOCKET_HAVE_EPOLL)
-
-uint32_t Epoll::toEpoll(Condition condition) const noexcept
-{
-	uint32_t events = 0;
-
-	if ((condition & Condition::Readable) == Condition::Readable)
-		events |= EPOLLIN;
-	if ((condition & Condition::Writable) == Condition::Writable)
-		events |= EPOLLOUT;
-
-	return events;
-}
-
-Condition Epoll::toCondition(uint32_t events) const noexcept
-{
-	Condition condition = Condition::None;
-
-	if ((events & EPOLLIN) || (events & EPOLLHUP))
-		condition |= Condition::Readable;
-	if (events & EPOLLOUT)
-		condition |= Condition::Writable;
-
-	return condition;
-}
-
-void Epoll::update(Handle h, int op, int eflags)
-{
-	epoll_event ev;
-
-	std::memset(&ev, 0, sizeof (epoll_event));
-
-	ev.events = eflags;
-	ev.data.fd = h;
-
-	if (epoll_ctl(m_handle, op, h, &ev) < 0)
-		throw Error(Error::System, "epoll_ctl");
-}
-
-Epoll::Epoll()
-	: m_handle(epoll_create1(0))
-{
-	if (m_handle < 0)
-		throw Error{Error::System, "epoll_create"};
-}
-
-Epoll::~Epoll()
-{
-	if (m_handle != -1)
-		close(m_handle);
-}
-
-/*
- * For set and unset, we need to apply the whole flags required, so if the socket
- * was set to Connection::Readable and user add Connection::Writable, we must
- * place both.
- */
-void Epoll::set(const ListenerTable &table, Handle sc, Condition condition, bool add)
-{
-	if (add) {
-		update(sc, EPOLL_CTL_ADD, toEpoll(condition));
-		m_events.resize(m_events.size() + 1);
-	} else {
-		update(sc, EPOLL_CTL_MOD, toEpoll(table.at(sc) | condition));
-	}
-}
-
-/*
- * Unset is a bit complicated case because Listener tells us which
- * flag to remove but to update epoll descriptor we need to pass
- * the effective flags that we want to be applied.
- *
- * So we put the same flags that are currently effective and remove the
- * requested one.
- */
-void Epoll::unset(const ListenerTable &table, Handle sc, Condition condition, bool remove)
-{
-	if (remove) {
-		update(sc, EPOLL_CTL_DEL, 0);
-		m_events.resize(m_events.size() - 1);
-	} else {
-		update(sc, EPOLL_CTL_MOD, toEpoll(table.at(sc) & ~(condition)));
-	}
-}
-
-std::vector<ListenerStatus> Epoll::wait(const ListenerTable &, int ms)
-{
-	int ret = epoll_wait(m_handle, m_events.data(), m_events.size(), ms);
-	std::vector<ListenerStatus> result;
-
-	if (ret == 0)
-		throw Error(Error::Timeout, "epoll_wait", TIMEOUT_MSG);
-	if (ret < 0)
-		throw Error(Error::System, "epoll_wait");
-
-	for (int i = 0; i < ret; ++i)
-		result.push_back(ListenerStatus{m_events[i].data.fd, toCondition(m_events[i].events)});
-
-	return result;
-}
-
-#endif // !SOCKET_HAVE_EPOLL
-
-/* }}} */
-
-/*
- * Kqueue implementation
- * ------------------------------------------------------------------
- */
-
-/* {{{ Kqueue */
-
-#if defined(SOCKET_HAVE_KQUEUE)
-
-Kqueue::Kqueue()
-	: m_handle(kqueue())
-{
-	if (m_handle < 0)
-		throw Error(Error::System, "kqueue");
-}
-
-Kqueue::~Kqueue()
-{
-	if (m_handle != -1)
-		close(m_handle);
-}
-
-void Kqueue::update(Handle h, int filter, int kflags)
-{
-	struct kevent ev;
-
-	EV_SET(&ev, h, filter, kflags, 0, 0, nullptr);
-
-	if (kevent(m_handle, &ev, 1, nullptr, 0, nullptr) < 0) {
-		throw Error{Error::System, "kevent"};
-	}
-}
-
-void Kqueue::set(const ListenerTable &, Handle h, Condition condition, bool add)
-{
-	if ((condition & Condition::Readable) == Condition::Readable) {
-		update(h, EVFILT_READ, EV_ADD | EV_ENABLE);
-	}
-	if ((condition & Condition::Writable) == Condition::Writable) {
-		update(h, EVFILT_WRITE, EV_ADD | EV_ENABLE);
-	}
-
-	if (add) {
-		m_result.resize(m_result.size() + 1);
-	}
-}
-
-void Kqueue::unset(const ListenerTable &, Handle h, Condition condition, bool remove)
-{
-	if ((condition & Condition::Readable) == Condition::Readable) {
-		update(h, EVFILT_READ, EV_DELETE);
-	}
-	if ((condition & Condition::Writable) == Condition::Writable) {
-		update(h, EVFILT_WRITE, EV_DELETE);
-	}
-
-	if (remove) {
-		m_result.resize(m_result.size() - 1);
-	}
-}
-
-std::vector<ListenerStatus> Kqueue::wait(const ListenerTable &, int ms)
-{
-	std::vector<ListenerStatus> sockets;
-	timespec ts = { 0, 0 };
-	timespec *pts = (ms <= 0) ? nullptr : &ts;
-
-	ts.tv_sec = ms / 1000;
-	ts.tv_nsec = (ms % 1000) * 1000000;
-
-	int nevents = kevent(m_handle, nullptr, 0, &m_result[0], m_result.capacity(), pts);
-
-	if (nevents == 0) {
-		throw Error{Error::Timeout, "kevent", TIMEOUT_MSG};
-	}
-	if (nevents < 0) {
-		throw Error{Error::System, "kevent"};
-	}
-
-	for (int i = 0; i < nevents; ++i) {
-		sockets.push_back(ListenerStatus{
-			static_cast<Handle>(m_result[i].ident),
-			m_result[i].filter == EVFILT_READ ? Condition::Readable : Condition::Writable
-		});
-	}
-
-	return sockets;
-}
-
-#endif // !SOCKET_HAVE_KQUEUE
-
-/* }}} */
-
-/* }}} */
-
-} // !net
--- a/modules/sockets/sockets.h	Tue Apr 05 15:18:41 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2783 +0,0 @@
-/*
- * sockets.h -- portable C++ socket wrappers
- *
- * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _SOCKETS_H_
-#define _SOCKETS_H_
-
-/**
- * @file sockets.h
- * @brief Portable socket abstraction
- *
- * # Introduction
- *
- * This file is a portable networking library.
- *
- * ## Options
- *
- * The user may set the following variables before compiling these files:
- *
- * ### General options
- *
- * - **SOCKET_NO_AUTO_INIT**: (bool) Set to 0 if you don't want Socket class to
- * automatically calls net::init function and net::finish functions.
- * - **SOCKET_NO_SSL**: (bool) Set to 0 if you don't have access to OpenSSL library.
- * - **SOCKET_NO_AUTO_SSL_INIT**: (bool) Set to 0 if you don't want Socket class with Tls to automatically init
- * the OpenSSL library. You will need to call net::ssl::init and net::ssl::finish.
- *
- * ### Options for Listener class
- *
- * Feature detection, multiple implementations may be avaible, for example, Linux has poll, select and epoll.
- *
- * We assume that `select(2)` is always available.
- *
- * Of course, you can set the variables yourself if you test it with your build system.
- *
- * - **SOCKET_HAVE_POLL**: Defined on all BSD, Linux. Also defined on Windows
- *   if _WIN32_WINNT is set to 0x0600 or greater.
- * - **SOCKET_HAVE_KQUEUE**: Defined on all BSD and Apple.
- * - **SOCKET_HAVE_EPOLL**: Defined on Linux only.
- * - **SOCKET_DEFAULT_BACKEND**: Which backend to use (e.g. `Select`).
- *
- * The preference priority is ordered from left to right.
- *
- * | System        | Backend                 | Class name   |
- * |---------------|-------------------------|--------------|
- * | Linux         | epoll(7)                | Epoll        |
- * | *BSD          | kqueue(2)               | Kqueue       |
- * | Windows       | poll(2), select(2)      | Poll, Select |
- * | Mac OS X      | kqueue(2)               | Kqueue       |
- */
-
-#if defined(_WIN32)
-#  if _WIN32_WINNT >= 0x0600 && !defined(SOCKET_HAVE_POLL)
-#    define SOCKET_HAVE_POLL
-#  endif
-#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
-#  if !defined(SOCKET_HAVE_KQUEUE)
-#    define SOCKET_HAVE_KQUEUE
-#  endif
-#  if !defined(SOCKET_HAVE_POLL)
-#    define SOCKET_HAVE_POLL
-#  endif
-#elif defined(__linux__)
-#  if !defined(SOCKET_HAVE_EPOLL)
-#    define SOCKET_HAVE_EPOLL
-#  endif
-#  if !defined(SOCKET_HAVE_POLL)
-#    define SOCKET_HAVE_POLL
-#  endif
-#endif
-
-/*
- * Define SOCKET_DEFAULT_BACKEND
- * ------------------------------------------------------------------
- */
-
-/**
- * Defines the default Listener backend to use.
- *
- * @note Do not rely on the value shown in doxygen.
- */
-#if defined(_WIN32)
-#  if !defined(SOCKET_DEFAULT_BACKEND)
-#    if defined(SOCKET_HAVE_POLL)
-#      define SOCKET_DEFAULT_BACKEND Poll
-#    else
-#      define SOCKET_DEFAULT_BACKEND Select
-#    endif
-#  endif
-#elif defined(__linux__)
-#  include <sys/epoll.h>
-
-#  if !defined(SOCKET_DEFAULT_BACKEND)
-#    define SOCKET_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(SOCKET_DEFAULT_BACKEND)
-#    define SOCKET_DEFAULT_BACKEND Kqueue
-#  endif
-#else
-#  if !defined(SOCKET_DEFAULT_BACKEND)
-#    define SOCKET_DEFAULT_BACKEND Select
-#  endif
-#endif
-
-#if defined(SOCKET_HAVE_POLL) && !defined(_WIN32)
-#  include <poll.h>
-#endif
-
-/*
- * Headers to include
- * ------------------------------------------------------------------
- */
-
-#if defined(_WIN32)
-#  include <cstdlib>
-
-#  include <WinSock2.h>
-#  include <WS2tcpip.h>
-#else
-#  include <cerrno>
-
-#  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
-
-#if !defined(SOCKET_NO_SSL)
-#  include <openssl/err.h>
-#  include <openssl/evp.h>
-#  include <openssl/ssl.h>
-#endif
-
-#include <cassert>
-#include <chrono>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <exception>
-#include <functional>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-/**
- * General network namespace.
- */
-namespace net {
-
-/*
- * Portables types
- * ------------------------------------------------------------------
- *
- * The following types are defined differently between Unix and Windows.
- */
-
-/* {{{ Protocols */
-
-#if defined(_WIN32)
-
-/**
- * Socket type, SOCKET.
- */
-using Handle	= SOCKET;
-
-/**
- * Argument to pass to set.
- */
-using ConstArg	= const char *;
-
-/**
- * Argument to pass to get.
- */
-using Arg	= char *;
-
-#else
-
-/**
- * Socket type, int.
- */
-using Handle	= int;
-
-/**
- * Argument to pass to set.
- */
-using ConstArg	= const void *;
-
-/**
- * Argument to pass to get.
- */
-using Arg	= void *;
-
-#endif
-
-/* }}} */
-
-/*
- * Portable constants
- * ------------------------------------------------------------------
- *
- * These constants are needed to check functions return codes, they are rarely needed in end user code.
- */
-
-/* {{{ Constants */
-
-/*
- * The following constants are defined differently from Unix
- * to Windows.
- */
-#if defined(_WIN32)
-
-/**
- * Socket creation failure or invalidation.
- */
-extern const Handle Invalid;
-
-/**
- * Socket operation failure.
- */
-extern const int Failure;
-
-#else
-
-/**
- * Socket creation failure or invalidation.
- */
-extern const int Invalid;
-
-/**
- * Socket operation failure.
- */
-extern const int Failure;
-
-#endif
-
-#if !defined(SOCKET_NO_SSL)
-
-namespace ssl {
-
-/**
- * @enum Method
- * @brief Which OpenSSL method to use.
- */
-enum Method {
-	Tlsv1,		//!< TLS v1.2 (recommended)
-	Sslv3		//!< SSLv3
-};
-
-} // !ssl
-
-#endif
-
-/* }}} */
-
-/*
- * Portable functions
- * ------------------------------------------------------------------
- *
- * The following free functions can be used to initialize the library or to get the last system error.
- */
-
-/* {{{ Functions */
-
-/**
- * Initialize the socket library. Except if you defined SOCKET_NO_AUTO_INIT, you don't need to call this
- * function manually.
- */
-void init() noexcept;
-
-/**
- * Close the socket library.
- */
-void finish() noexcept;
-
-#if !defined(SOCKET_NO_SSL)
-
-/**
- * OpenSSL namespace.
- */
-namespace ssl {
-
-/**
- * Initialize the OpenSSL library. Except if you defined SOCKET_NO_AUTO_SSL_INIT, you don't need to call this function
- * manually.
- */
-void init() noexcept;
-
-/**
- * Close the OpenSSL library.
- */
-void finish() noexcept;
-
-} // !ssl
-
-#endif // SOCKET_NO_SSL
-
-/**
- * Get the last socket system error. The error is set from errno or from
- * WSAGetLastError on Windows.
- *
- * @return a string message
- */
-std::string error();
-
-/**
- * Get the last system error.
- *
- * @param errn the error number (errno or WSAGetLastError)
- * @return the error
- */
-std::string error(int errn);
-
-/* }}} */
-
-/*
- * Error class
- * ------------------------------------------------------------------
- *
- * This is the main exception thrown on socket operations.
- */
-
-/* {{{ Error */
-
-/**
- * @class Error
- * @brief Base class for sockets error
- */
-class Error : public std::exception {
-public:
-	/**
-	 * @enum Code
-	 * @brief Which kind of error
-	 */
-	enum Code {
-		Timeout,		///!< The action did timeout
-		System,			///!< There is a system error
-		Other			///!< Other custom error
-	};
-
-private:
-	Code m_code;
-	std::string m_function;
-	std::string m_error;
-
-public:
-	/**
-	 * Constructor that use the last system error.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 */
-	Error(Code code, std::string function);
-
-	/**
-	 * Constructor that use the system error set by the user.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 * @param error the error
-	 */
-	Error(Code code, std::string function, int error);
-
-	/**
-	 * Constructor that set the error specified by the user.
-	 *
-	 * @param code which kind of error
-	 * @param function the function name
-	 * @param error the error
-	 */
-	Error(Code code, std::string function, std::string error);
-
-	/**
-	 * Get which function has triggered the error.
-	 *
-	 * @return the function name (e.g connect)
-	 */
-	inline const std::string &function() const noexcept
-	{
-		return m_function;
-	}
-
-	/**
-	 * The error code.
-	 *
-	 * @return the code
-	 */
-	inline Code code() const noexcept
-	{
-		return m_code;
-	}
-
-	/**
-	 * Get the error (only the error content).
-	 *
-	 * @return the error
-	 */
-	const char *what() const noexcept
-	{
-		return m_error.c_str();
-	}
-};
-
-/* }}} */
-
-/*
- * Condition enum
- * ------------------------------------------------------------------
- *
- * Defines if we must wait for reading or writing.
- */
-
-/* {{{ Condition */
-
-/**
- * @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
-	Readable = (1 << 0),	//!< The socket must be readable
-	Writable = (1 << 1)	//!< The socket must be writable
-};
-
-/**
- * Apply bitwise XOR.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-constexpr Condition operator^(Condition v1, Condition v2) noexcept
-{
-	return static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2));
-}
-
-/**
- * Apply bitwise AND.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-constexpr Condition operator&(Condition v1, Condition v2) noexcept
-{
-	return static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2));
-}
-
-/**
- * Apply bitwise OR.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-constexpr Condition operator|(Condition v1, Condition v2) noexcept
-{
-	return static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2));
-}
-
-/**
- * Apply bitwise NOT.
- *
- * @param v the value
- * @return the complement
- */
-constexpr Condition operator~(Condition v) noexcept
-{
-	return static_cast<Condition>(~static_cast<int>(v));
-}
-
-/**
- * Assign bitwise OR.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-inline Condition &operator|=(Condition &v1, Condition v2) noexcept
-{
-	v1 = static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2));
-
-	return v1;
-}
-
-/**
- * Assign bitwise AND.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-inline Condition &operator&=(Condition &v1, Condition v2) noexcept
-{
-	v1 = static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2));
-
-	return v1;
-}
-
-/**
- * Assign bitwise XOR.
- *
- * @param v1 the first value
- * @param v2 the second value
- * @return the new value
- */
-inline Condition &operator^=(Condition &v1, Condition v2) noexcept
-{
-	v1 = static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2));
-
-	return v1;
-}
-
-/* }}} */
-
-/*
- * Base Socket class
- * ------------------------------------------------------------------
- *
- * This base class has operations that are common to all types of sockets but you usually instanciate
- * a SocketTcp or SocketUdp
- */
-
-/* {{{ Socket */
-
-/**
- * @class Socket
- * @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.
- *
- * @see protocol::Tls
- * @see protocol::Tcp
- * @see protocol::Udp
- */
-template <typename Address, typename Protocol>
-class Socket {
-private:
-	Protocol m_proto;
-
-	inline void reset(Condition *condition) const noexcept
-	{
-		if (condition)
-			*condition = Condition::None;
-	}
-
-protected:
-	/**
-	 * The native handle.
-	 */
-	Handle m_handle{Invalid};
-
-public:
-	/**
-	 * Create a socket handle.
-	 *
-	 * This is the primary function and the only one that creates the socket handle, all other constructors
-	 * are just overloaded functions.
-	 *
-	 * @param domain the domain AF_*
-	 * @param type the type SOCK_*
-	 * @param protocol the protocol
-	 * @param iface the implementation
-	 * @throw net::Error on errors
-	 */
-	Socket(int domain, int type, int protocol, Protocol iface = {})
-		: m_proto(std::move(iface))
-	{
-#if !defined(SOCKET_NO_AUTO_INIT)
-		init();
-#endif
-		m_handle = ::socket(domain, type, protocol);
-
-		if (m_handle == Invalid)
-			throw Error(Error::System, "socket");
-
-		m_proto.create(*this);
-	}
-
-	/**
-	 * This tries to create a socket.
-	 *
-	 * Domain and type are determined by the Address and Protocol object.
-	 *
-	 * @param protocol the protocol
-	 * @param address which type of address
-	 * @throw net::Error on errors
-	 */
-	explicit inline Socket(Protocol protocol = {}, const Address &address = {})
-		: Socket(address.domain(), protocol.type(), 0, std::move(protocol))
-	{
-	}
-
-	explicit inline Socket(Handle handle, Protocol protocol = {}) noexcept
-		: m_proto(std::move(protocol))
-		, m_handle(handle)
-	{
-	}
-
-	/**
-	 * Create an invalid socket. Can be used when you cannot instanciate the socket immediately.
-	 */
-	explicit inline Socket(std::nullptr_t) noexcept
-		: m_handle(Invalid)
-	{
-	}
-
-	/**
-	 * Copy constructor deleted.
-	 */
-	Socket(const Socket &) = delete;
-
-	/**
-	 * Transfer ownership from other to this.
-	 *
-	 * @param other the other socket
-	 */
-	inline Socket(Socket &&other) noexcept
-		: m_proto(std::move(other.m_proto))
-		, m_handle(other.m_handle)
-	{
-		/* Invalidate other */
-		other.m_handle = Invalid;
-	}
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~Socket()
-	{
-		close();
-	}
-
-	/**
-	 * Access the implementation.
-	 *
-	 * @return the implementation
-	 * @warning use this function with care
-	 */
-	inline const Protocol &protocol() const noexcept
-	{
-		return m_proto;
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the implementation
-	 */
-	inline Protocol &protocol() noexcept
-	{
-		return m_proto;
-	}
-
-	/**
-	 * Tells if the socket is not invalid.
-	 *
-	 * @return true if not invalid
-	 */
-	inline bool isOpen() const noexcept
-	{
-		return m_handle != Invalid;
-	}
-
-	/**
-	 * Set an option for the socket. Wrapper of setsockopt(2).
-	 *
-	 * @pre isOpen()
-	 * @param level the setting level
-	 * @param name the name
-	 * @param arg the value
-	 * @throw net::Error on errors
-	 */
-	template <typename Argument>
-	inline void set(int level, int name, const Argument &arg)
-	{
-		assert(m_handle != Invalid);
-
-		if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure)
-			throw Error(Error::System, "set");
-	}
-
-	/**
-	 * Object-oriented option setter.
-	 *
-	 * The object must have `set(Socket<Address, Protocol> &) const`.
-	 *
-	 * @pre isOpen()
-	 * @param option the option
-	 * @throw net::Error on errors
-	 */
-	template <typename Option>
-	inline void set(const Option &option)
-	{
-		assert(m_handle != Invalid);
-
-		option.set(*this);
-	}
-
-	/**
-	 * Get an option for the socket. Wrapper of getsockopt(2).
-	 *
-	 * @pre isOpen()
-	 * @param level the setting level
-	 * @param name the name
-	 * @throw net::Error on errors
-	 */
-	template <typename Argument>
-	Argument get(int level, int name)
-	{
-		assert(m_handle != Invalid);
-
-		Argument desired, result{};
-		socklen_t size = sizeof (result);
-
-		if (getsockopt(m_handle, level, name, (Arg)&desired, &size) == Failure)
-			throw Error(Error::System, "get");
-
-		std::memcpy(&result, &desired, size);
-
-		return result;
-	}
-
-	/**
-	 * Object-oriented option getter.
-	 *
-	 * The object must have `T get(Socket<Address, Protocol> &) const`, T can be any type and it is the value
-	 * returned from this function.
-	 *
-	 * @pre isOpen()
-	 * @return the same value as get() in the option
-	 * @throw net::Error on errors
-	 */
-	template <typename Option>
-	inline auto get() -> decltype(std::declval<Option>().get(*this))
-	{
-		assert(m_handle != Invalid);
-
-		return Option().get(*this);
-	}
-
-	/**
-	 * Get the native handle.
-	 *
-	 * @return the handle
-	 * @warning Not portable
-	 */
-	inline Handle handle() const noexcept
-	{
-		return m_handle;
-	}
-
-	/**
-	 * Bind using a native address.
-	 *
-	 * @pre isOpen()
-	 * @param address the address
-	 * @param length the size
-	 * @throw net::Error on errors
-	 */
-	inline void bind(const sockaddr *address, socklen_t length)
-	{
-		assert(m_handle != Invalid);
-
-		if (::bind(m_handle, address, length) == Failure)
-			throw Error(Error::System, "bind");
-	}
-
-	/**
-	 * Overload that takes an address.
-	 *
-	 * @pre isOpen()
-	 * @param address the address
-	 * @throw net::Error on errors
-	 */
-	inline void bind(const Address &address)
-	{
-		assert(m_handle != Invalid);
-
-		if (::bind(m_handle, address.address(), address.length()) == Failure)
-			throw Error(Error::System, "bind");
-	}
-
-	/**
-	 * Overload that creates an address on the fly.
-	 *
-	 * @pre isOpen()
-	 * @param args the arguments to Address constructor
-	 * @throw net::Error on errors
-	 */
-	template <typename... Args>
-	inline void bind(Args&&... args)
-	{
-		assert(m_handle != Invalid);
-
-		Address address{std::forward<Args>(args)...};
-
-		if (::bind(m_handle, address.address(), address.length()) == Failure)
-			throw Error(Error::System, "bind");
-	}
-
-	/**
-	 * Listen for pending connection.
-	 *
-	 * @pre isOpen()
-	 * @param max the maximum number
-	 * @throw net::Error on errors
-	 */
-	inline void listen(int max = 128)
-	{
-		assert(m_handle != Invalid);
-
-		if (::listen(this->m_handle, max) == Failure)
-			throw Error(Error::System, "listen");
-	}
-
-	/**
-	 * Get the local name. This is a wrapper of getsockname().
-	 *
-	 * @pre isOpen()
-	 * @return the address
-	 * @throw Error on failures
-	 * @pre state() must not be State::Closed
-	 */
-	Address address() const
-	{
-		assert(m_handle != Invalid);
-
-		sockaddr_storage ss;
-		socklen_t length = sizeof (sockaddr_storage);
-
-		if (::getsockname(m_handle, reinterpret_cast<sockaddr *>(&ss), &length) == Failure)
-			throw Error(Error::System, "getsockname");
-
-		return Address(&ss, length);
-	}
-
-	void connect(const sockaddr *address, socklen_t length, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-		m_proto.connect(*this, address, length, cond ? *cond : dummy);
-	}
-
-	inline void connect(const Address &address, Condition *cond = nullptr)
-	{
-		connect(address.address(), address.length(), cond);
-	}
-
-	void connect(Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-		m_proto.connect(*this, cond ? *cond : dummy);
-	}
-
-	void accept(Socket<Address, Protocol> &client, Address *address = nullptr, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		reset(cond);
-
-		Condition dummy = Condition::None;
-		sockaddr_storage storage;
-		socklen_t length = sizeof (storage);
-
-		reset(cond);
-		m_proto.accept(*this, client, reinterpret_cast<sockaddr *>(&storage), &length, cond ? *cond : dummy);
-
-		if (address)
-			*address = Address(&storage, length);
-	}
-
-	void accept(Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-		m_proto.accept(*this, cond ? *cond : dummy);
-	}
-
-	unsigned recv(void *data, unsigned length, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-
-		return m_proto.recv(*this, data, length, cond ? *cond : dummy);
-	}
-
-	std::string recv(unsigned count, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		std::string result;
-
-		result.resize(count);
-		auto n = recv(const_cast<char *>(result.data()), count, cond);
-		result.resize(n);
-
-		return result;
-	}
-
-	unsigned send(const void *data, unsigned length, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-
-		return m_proto.send(*this, data, length, cond ? *cond : dummy);
-	}
-
-	inline unsigned send(const std::string &data, Condition *cond = nullptr)
-	{
-		return send(data.c_str(), data.length(), cond);
-	}
-
-	unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-
-		return m_proto.sendto(*this, data, length, address, addrlen, cond ? *cond : dummy);
-	}
-
-	inline unsigned sendto(const void *data, unsigned length, const Address &address, Condition *cond = nullptr)
-	{
-		return sendto(data, length, address.address(), address.length(), cond);
-	}
-
-	inline unsigned sendto(const std::string &data, const Address &address, Condition *cond = nullptr)
-	{
-		return sendto(data.c_str(), data.length(), address.address(), address.length(), cond);
-	}
-
-	unsigned recvfrom(void *data, unsigned length, sockaddr *address, socklen_t *addrlen, Condition *cond = nullptr)
-	{
-		assert(m_handle != Invalid);
-
-		Condition dummy = Condition::None;
-
-		reset(cond);
-
-		return m_proto.recvfrom(*this, data, length, address, addrlen, cond ? *cond : dummy);
-	}
-
-	unsigned recvfrom(void *data, unsigned length, Address *address = nullptr, Condition *cond = nullptr)
-	{
-		sockaddr_storage storage;
-		socklen_t addrlen = sizeof (sockaddr_storage);
-
-		auto n = recvfrom(data, length, reinterpret_cast<sockaddr *>(&storage), &addrlen, cond);
-
-		if (address && n != 0)
-			*address = Address(&storage, addrlen);
-
-		return n;
-	}
-
-	std::string recvfrom(unsigned count, Address *info = nullptr, Condition *cond = nullptr)
-	{
-		std::string result;
-
-		result.resize(count);
-		auto n = recvfrom(const_cast<char *>(result.data()), count, info, cond);
-		result.resize(n);
-
-		return result;
-	}
-
-	/**
-	 * Close the socket.
-	 *
-	 * Automatically called from the destructor.
-	 */
-	void close()
-	{
-		if (m_handle != Invalid) {
-#if defined(_WIN32)
-			::closesocket(m_handle);
-#else
-			::close(m_handle);
-#endif
-			m_handle = Invalid;
-		}
-	}
-
-	/**
-	 * Assignment operator forbidden.
-	 *
-	 * @return *this
-	 */
-	Socket &operator=(const Socket &) = delete;
-
-	/**
-	 * Transfer ownership from other to this. The other socket is left
-	 * invalid and will not be closed.
-	 *
-	 * @param other the other socket
-	 * @return this
-	 */
-	Socket &operator=(Socket &&other) noexcept
-	{
-		m_handle = other.m_handle;
-		m_proto = std::move(other.m_proto);
-
-		/* Invalidate other */
-		other.m_handle = Invalid;
-
-		return *this;
-	}
-};
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if they equals
- */
-template <typename Address, typename Protocol>
-bool operator==(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() == s2.handle();
-}
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if they are different
- */
-template <typename Address, typename Protocol>
-bool operator!=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() != s2.handle();
-}
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if s1 < s2
- */
-template <typename Address, typename Protocol>
-bool operator<(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() < s2.handle();
-}
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if s1 > s2
- */
-template <typename Address, typename Protocol>
-bool operator>(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() > s2.handle();
-}
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if s1 <= s2
- */
-template <typename Address, typename Protocol>
-bool operator<=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() <= s2.handle();
-}
-
-/**
- * Compare two sockets.
- *
- * @param s1 the first socket
- * @param s2 the second socket
- * @return true if s1 >= s2
- */
-template <typename Address, typename Protocol>
-bool operator>=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2)
-{
-	return s1.handle() >= s2.handle();
-}
-
-/* }}} */
-
-/*
- * Predefined options
- * ------------------------------------------------------------------
- */
-
-/* {{{ Options */
-
-/**
- * Namespace of predefined options.
- */
-namespace option {
-
-/*
- * Options for socket
- * ------------------------------------------------------------------
- */
-
-/* {{{ Options for socket */
-
-/**
- * @class SockBlockMode
- * @brief Set or get the blocking-mode for a socket.
- * @warning On Windows, it's not possible to check if the socket is blocking or not.
- */
-class SockBlockMode {
-private:
-	bool m_value;
-
-public:
-	inline SockBlockMode(bool value = true) noexcept
-		: m_value(value)
-	{
-	}
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	void set(Socket<Address, Protocol> &sc) const
-	{
-#if defined(O_NONBLOCK) && !defined(_WIN32)
-		int flags;
-
-		if ((flags = fcntl(sc.handle(), F_GETFL, 0)) < 0)
-			flags = 0;
-
-		if (m_value)
-			flags &= ~(O_NONBLOCK);
-		else
-			flags |= O_NONBLOCK;
-
-		if (fcntl(sc.handle(), F_SETFL, flags) < 0)
-			throw Error(Error::System, "fcntl");
-#else
-		unsigned long flags = (m_value) ? 0 : 1;
-
-		if (ioctlsocket(sc.handle(), FIONBIO, &flags) == Failure)
-			throw Error(Error::System, "fcntl");
-#endif
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	bool get(Socket<Address, Protocol> &sc) const
-	{
-#if defined(O_NONBLOCK) && !defined(_WIN32)
-		int flags = fcntl(sc.handle(), F_GETFL, 0);
-
-		if (flags < 0)
-			throw Error(Error::System, "fcntl");
-
-		return !(flags & O_NONBLOCK);
-#else
-		throw Error(Error::Other, "get", std::strerror(ENOSYS));
-#endif
-	}
-};
-
-/**
- * @class SockReuseAddress
- * @brief Reuse address, must be used before calling Socket::bind
- */
-class SockReuseAddress {
-private:
-	bool m_value;
-
-public:
-	inline SockReuseAddress(bool value = true) noexcept
-		: m_value(value)
-	{
-	}
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline void set(Socket<Address, Protocol> &sc) const
-	{
-		sc.set(SOL_SOCKET, SO_REUSEADDR, m_value ? 1 : 0);
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline bool get(Socket<Address, Protocol> &sc) const
-	{
-		return static_cast<bool>(sc.template get<int>(SOL_SOCKET, SO_REUSEADDR));
-	}
-};
-
-/**
- * @class SockSendBuffer
- * @brief Set or get the output buffer.
- */
-class SockSendBuffer {
-public:
-	/**
-	 * Set to the buffer size.
-	 */
-	int value{2048};
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline void set(Socket<Address, Protocol> &sc) const
-	{
-		sc.set(SOL_SOCKET, SO_SNDBUF, value);
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline int get(Socket<Address, Protocol> &sc) const
-	{
-		return sc.template get<int>(SOL_SOCKET, SO_SNDBUF);
-	}
-};
-
-/**
- * @class SockReceiveBuffer
- * @brief Set or get the input buffer.
- */
-class SockReceiveBuffer {
-public:
-	/**
-	 * Set to the buffer size.
-	 */
-	int value{2048};
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline void set(Socket<Address, Protocol> &sc) const
-	{
-		sc.set(SOL_SOCKET, SO_RCVBUF, value);
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline int get(Socket<Address, Protocol> &sc) const
-	{
-		return sc.template get<int>(SOL_SOCKET, SO_RCVBUF);
-	}
-};
-
-/* }}} */
-
-/* {{{ Options for TCP */
-
-/**
- * @class TcpNoDelay
- * @brief Set this option if you want to disable nagle's algorithm.
- */
-class TcpNoDelay {
-private:
-	bool m_value;
-
-public:
-	inline TcpNoDelay(bool value = true) noexcept
-		: m_value(value)
-	{
-	}
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline void set(Socket<Address, Protocol> &sc) const
-	{
-		sc.set(IPPROTO_TCP, TCP_NODELAY, m_value ? 1 : 0);
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline bool get(Socket<Address, Protocol> &sc) const
-	{
-		return static_cast<bool>(sc.template get<int>(IPPROTO_TCP, TCP_NODELAY));
-	}
-};
-
-/* }}} */
-
-/* {{{ Options for IPv6 */
-
-/**
- * @class Ipv6Only
- * @brief Control IPPROTO_IPV6/IPV6_V6ONLY
- *
- * Note: some systems may or not set this option by default so it's a good idea to set it in any case to either
- * false or true if portability is a concern.
- */
-class Ipv6Only {
-private:
-	bool m_value;
-
-public:
-	inline Ipv6Only(bool value = true) noexcept
-		: m_value(value)
-	{
-	}
-
-	/**
-	 * Set the option.
-	 *
-	 * @param sc the socket
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline void set(Socket<Address, Protocol> &sc) const
-	{
-		sc.set(IPPROTO_IPV6, IPV6_V6ONLY, m_value ? 1 : 0);
-	}
-
-	/**
-	 * Get the option.
-	 *
-	 * @return the value
-	 * @throw Error on errors
-	 */
-	template <typename Address, typename Protocol>
-	inline bool get(Socket<Address, Protocol> &sc) const
-	{
-		return static_cast<bool>(sc.template get<int>(IPPROTO_IPV6, IPV6_V6ONLY));
-	}
-};
-
-/* }}} */
-
-} // !option
-
-/* }}} */
-
-/*
- * Predefined addressed to be used
- * ------------------------------------------------------------------
- *
- * - Ipv4,
- * - Ipv6,
- * - Local.
- */
-
-/* {{{ Addresses */
-
-/**
- * Set of predefined addresses.
- */
-namespace address {
-
-class Ipv4 {
-public:
-private:
-	sockaddr_in m_sin;
-
-public:
-	Ipv4() noexcept;
-	Ipv4(const std::string &host, std::uint16_t port);
-	Ipv4(const sockaddr_storage *ss, socklen_t length) noexcept;
-
-	inline int domain() const noexcept
-	{
-		return AF_INET;
-	}
-
-	inline const sockaddr *address() const noexcept
-	{
-		return reinterpret_cast<const sockaddr *>(&m_sin);
-	}
-
-	/**
-	 * Return the underlying address length.
-	 *
-	 * @return the length
-	 */
-	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 in textual form.
-	 *
-	 * @return the address
-	 * @throw Error on errors
-	 */
-	std::string ip() const
-	{
-		char result[128];
-
-		std::memset(result, 0, sizeof (result));
-
-		if (!inet_ntop(AF_INET, const_cast<in_addr *>(&m_sin.sin_addr), result, sizeof (result)))
-			throw Error(Error::System, "inet_ntop");
-
-		return result;
-	}
-};
-
-class Ipv6 {
-private:
-	sockaddr_in6 m_sin6;
-
-public:
-	Ipv6() noexcept;
-	Ipv6(const std::string &host, std::uint16_t port);
-	Ipv6(const sockaddr_storage *ss, socklen_t length) noexcept;
-
-	inline int domain() const noexcept
-	{
-		return AF_INET6;
-	}
-
-	inline const sockaddr *address() const noexcept
-	{
-		return reinterpret_cast<const sockaddr *>(&m_sin6);
-	}
-
-	/**
-	 * Return the underlying address length.
-	 *
-	 * @return the length
-	 */
-	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 in textual form.
-	 *
-	 * @return the address
-	 * @throw Error on errors
-	 */
-	std::string ip() const
-	{
-		char result[128];
-
-		std::memset(result, 0, sizeof (result));
-
-		if (!inet_ntop(AF_INET6, const_cast<in6_addr *>(&m_sin6.sin6_addr), result, sizeof (result)))
-			throw Error(Error::System, "inet_ntop");
-
-		return result;
-	}
-};
-
-using Ip = Ipv4;
-
-#if !defined(_WIN32)
-
-/**
- * @class Local
- * @brief unix family sockets
- *
- * Create an address to a specific path. Only available on Unix.
- */
-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.
-	 */
-	Local() noexcept;
-
-	/**
-	 * 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;
-
-	/**
-	 * 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_storage *ss, socklen_t length) noexcept;
-
-	/**
-	 * 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(SOCKET_HAVE_SUN_LEN)
-		return SUN_LEN(&m_sun);
-#else
-		return sizeof (m_sun);
-#endif
-	}
-};
-
-#endif // !_WIN32
-
-} // !address
-
-/* }}} */
-
-/*
- * Predefined protocols
- * ------------------------------------------------------------------
- *
- * - Tcp, for standard stream connections,
- * - Udp, for standard datagram connections,
- * - Tls, for secure stream connections.
- */
-
-/* {{{ Protocols */
-
-/**
- * Set of predefined protocols.
- */
-namespace protocol {
-
-/* {{{ Tcp */
-
-/**
- * @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:
-	/**
-	 * Socket type.
-	 *
-	 * @return SOCK_STREAM
-	 */
-	inline int type() const noexcept
-	{
-		return SOCK_STREAM;
-	}
-
-	/**
-	 * Do nothing.
-	 *
-	 * This function is just present for compatibility, it should never be called.
-	 */
-	template <typename Address>
-	inline void create(Socket<Address, Tcp> &) const noexcept
-	{
-		/* No-op */
-	}
-
-	template <typename Address, typename Protocol>
-	void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length, Condition &cond)
-	{
-		if (::connect(sc.handle(), address, length) == Failure) {
-			/*
-			 * Determine if the error comes from a non-blocking connect that cannot be
-			 * accomplished yet.
-			 */
-#if defined(_WIN32)
-			int error = WSAGetLastError();
-
-			if (error == WSAEWOULDBLOCK)
-				cond = Condition::Writable;
-			else
-				throw Error(Error::System, "connect", error);
-#else
-			if (errno == EINPROGRESS)
-				cond = Condition::Writable;
-			else
-				throw Error(Error::System, "connect");
-#endif
-		}
-	}
-
-	template <typename Address, typename Protocol>
-	void connect(Socket<Address, Protocol> &sc, Condition &)
-	{
-		int error = sc.template get<int>(SOL_SOCKET, SO_ERROR);
-
-		if (error != 0)
-			throw Error(Error::System, "connect", error);
-	}
-
-	template <typename Address, typename Protocol>
-	void accept(Socket<Address, Protocol> &sc, Socket<Address, Protocol> &client, sockaddr *address, socklen_t *length, Condition &)
-	{
-		Handle handle = ::accept(sc.handle(), address, length);
-
-		if (handle == Invalid)
-			client = Socket<Address, Protocol>();
-
-		client = Socket<Address, Protocol>(handle);
-	}
-
-	template <typename Address, typename Protocol>
-	inline void accept(Socket<Address, Protocol> &, Condition &) const noexcept
-	{
-		/* no op */
-	}
-
-	template <typename Address>
-	unsigned recv(Socket<Address, Tcp> &sc, void *data, unsigned length, Condition &cond)
-	{
-		int nbread = ::recv(sc.handle(), (Arg)data, length, 0);
-
-		if (nbread == Failure) {
-#if defined(_WIN32)
-			int error = WSAGetLastError();
-
-			if (error == WSAEWOULDBLOCK) {
-				nbread = 0;
-				cond = Condition::Readable;
-			} else {
-				throw Error(Error::System, "recv", error);
-			}
-#else
-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				nbread = 0;
-				cond = Condition::Readable;
-			} else {
-				throw Error(Error::System, "recv");
-			}
-#endif
-		}
-
-		return static_cast<unsigned>(nbread);
-	}
-
-	template <typename Address>
-	unsigned send(Socket<Address, Tcp> &sc, const void *data, unsigned length, Condition &cond)
-	{
-		int nbsent = ::send(sc.handle(), (ConstArg)data, length, 0);
-
-		if (nbsent == Failure) {
-#if defined(_WIN32)
-			int error = WSAGetLastError();
-
-			if (error == WSAEWOULDBLOCK) {
-				nbsent = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "send", error);
-			}
-#else
-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				nbsent = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "send");
-			}
-#endif
-		}
-
-		return static_cast<unsigned>(nbsent);
-	}
-};
-
-/* }}} */
-
-/* {{{ Udp */
-
-/**
- * @class Udp
- * @brief Clear UDP type.
- *
- * This class is the basic implementation of UDP sockets.
- */
-class Udp {
-public:
-	/**
-	 * Socket type.
-	 *
-	 * @return SOCK_DGRAM
-	 */
-	inline int type() const noexcept
-	{
-		return SOCK_DGRAM;
-	}
-
-	/**
-	 * Do nothing.
-	 */
-	template <typename Address>
-	inline void create(Socket<Address, Udp> &) noexcept
-	{
-		/* No-op */
-	}
-
-	template <typename Address>
-	unsigned recvfrom(Socket<Address, Udp> &sc, void *data, unsigned length, sockaddr *address, socklen_t *addrlen, Condition &cond)
-	{
-		int nbread;
-
-		nbread = ::recvfrom(sc.handle(), (Arg)data, length, 0, address, addrlen);
-
-		if (nbread == Failure) {
-#if defined(_WIN32)
-			int error = WSAGetLastError();
-
-			if (error == WSAEWOULDBLOCK) {
-				nbread = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "recvfrom");
-			}
-#else
-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				nbread = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "recvfrom");
-			}
-#endif
-		}
-
-		return static_cast<unsigned>(nbread);
-	}
-
-	template <typename Address>
-	unsigned sendto(Socket<Address, Udp> &sc, const void *data, unsigned length, const sockaddr *address, socklen_t addrlen, Condition &cond)
-	{
-		int nbsent;
-
-		nbsent = ::sendto(sc.handle(), (ConstArg)data, length, 0, address, addrlen);
-		if (nbsent == Failure) {
-#if defined(_WIN32)
-			int error = WSAGetLastError();
-
-			if (error == WSAEWOULDBLOCK) {
-				nbsent = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "sendto", error);
-			}
-#else
-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				nbsent = 0;
-				cond = Condition::Writable;
-			} else {
-				throw Error(Error::System, "sendto");
-			}
-#endif
-		}
-
-		return static_cast<unsigned>(nbsent);
-	}
-};
-
-/* }}} */
-
-/* {{{ Tls */
-
-#if !defined(SOCKET_NO_SSL)
-
-class Tls : private Tcp {
-private:
-	using Context = std::shared_ptr<SSL_CTX>;
-	using Ssl = std::unique_ptr<SSL, void (*)(SSL *)>;
-
-	/* OpenSSL objects */
-	Context m_context;
-	Ssl m_ssl{nullptr, nullptr};
-
-	/* Status */
-	bool m_tcpconnected{false};
-
-	/*
-	 * User definable parameters
-	 */
-	ssl::Method m_method{ssl::Tlsv1};
-	std::string m_key;
-	std::string m_certificate;
-	bool m_verify{false};
-
-	/*
-	 * Construct with a context and ssl, for Tls::accept.
-	 */
-	Tls(Context context, Ssl ssl)
-		: m_context(std::move(context))
-		, m_ssl(std::move(ssl))
-	{
-	}
-
-	/*
-	 * Get the OpenSSL error message.
-	 */
-	inline std::string error(int error)
-	{
-		auto msg = ERR_reason_error_string(error);
-
-		return msg == nullptr ? "" : msg;
-	}
-
-	template <typename Function>
-	void wrap(const std::string &func, Condition &cond, Function &&function)
-	{
-		auto ret = function();
-
-		if (ret <= 0) {
-			int no = SSL_get_error(m_ssl.get(), ret);
-
-			switch (no) {
-			case SSL_ERROR_WANT_READ:
-				cond = Condition::Readable;
-				break;
-			case SSL_ERROR_WANT_WRITE:
-				cond = Condition::Writable;
-				break;
-			default:
-				throw Error(Error::System, func, error(no));
-			}
-		}
-	}
-
-	void doConnect(Condition &cond)
-	{
-		wrap("connect", cond, [&] () -> int {
-			return SSL_connect(m_ssl.get());
-		});
-	}
-
-	void doAccept(Condition &cond)
-	{
-		wrap("accept", cond, [&] () -> int {
-			return SSL_accept(m_ssl.get());
-		});
-	}
-
-public:
-	/**
-	 * @copydoc Tcp::type
-	 */
-	inline int type() const noexcept
-	{
-		return SOCK_STREAM;
-	}
-
-	/**
-	 * Empty TLS constructor.
-	 */
-	Tls()
-	{
-#if !defined(SOCKET_NO_SSL_AUTO_INIT)
-		::net::ssl::init();
-#endif
-	}
-
-	/**
-	 * Set the method.
-	 *
-	 * @param method the method
-	 * @pre the socket must not be already created
-	 */
-	inline void setMethod(ssl::Method method) noexcept
-	{
-		assert(!m_context);
-		assert(!m_ssl);
-
-		m_method = method;
-	}
-
-	/**
-	 * Use the specified private key file.
-	 *
-	 * @param file the path to the private key
-	 */
-	inline void setPrivateKey(std::string file) noexcept
-	{
-		m_key = std::move(file);
-	}
-
-	/**
-	 * Use the specified certificate file.
-	 *
-	 * @param file the path to the file
-	 */
-	inline void setCertificate(std::string file) noexcept
-	{
-		m_certificate = std::move(file);
-	}
-
-	/**
-	 * Set to true if we must verify the certificate and private key.
-	 *
-	 * @param verify the mode
-	 */
-	inline void setVerify(bool verify = true) noexcept
-	{
-		m_verify = verify;
-	}
-
-	/**
-	 * 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)
-	{
-		auto method = (m_method == ssl::Tlsv1) ? TLSv1_method() : SSLv3_method();
-
-		m_context = Context(SSL_CTX_new(method), SSL_CTX_free);
-		m_ssl = Ssl(SSL_new(m_context.get()), SSL_free);
-
-		SSL_set_fd(m_ssl.get(), sc.handle());
-
-		/* Load certificates */
-		if (m_certificate.size() > 0)
-			SSL_CTX_use_certificate_file(m_context.get(), m_certificate.c_str(), SSL_FILETYPE_PEM);
-		if (m_key.size() > 0)
-			SSL_CTX_use_PrivateKey_file(m_context.get(), m_key.c_str(), SSL_FILETYPE_PEM);
-		if (m_verify && !SSL_CTX_check_private_key(m_context.get()))
-			throw Error(Error::System, "(openssl)", "unable to verify key");
-	}
-
-	template <typename Address, typename Protocol>
-	void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length, Condition &cond)
-	{
-		/* 1. Connect using raw TCP */
-		Tcp::connect(sc, address, length, cond);
-
-		/* 2. If the connection is complete (e.g. non-blocking), try handshake */
-		if (cond == Condition::None) {
-			m_tcpconnected = true;
-			doConnect(cond);
-		}
-	}
-
-	template <typename Address, typename Protocol>
-	void connect(Socket<Address, Protocol> &sc, Condition &cond)
-	{
-		/* 1. Be sure to complete standard connect before */
-		if (!m_tcpconnected) {
-			Tcp::connect(sc, cond);
-			m_tcpconnected = cond = Condition::None;
-		}
-
-		if (m_tcpconnected)
-			doConnect(cond);
-	}
-
-	template <typename Address>
-	void accept(Socket<Address, Tls> &sc, Socket<Address, Tls> &client, sockaddr *address, socklen_t *length, Condition &cond)
-	{
-		/* TCP sets empty client if no pending connection is available */
-		Tcp::accept(sc, client, address, length, cond);
-
-		if (client.isOpen()) {
-			Tls &proto = client.protocol();
-
-			/* 1. Share the context */
-			proto.m_context = m_context;
-
-			/* 2. Create new SSL instance */
-			proto.m_ssl = Ssl(SSL_new(m_context.get()), SSL_free);
-
-			SSL_set_fd(proto.m_ssl.get(), client.handle());
-
-			/* 3. Try accept process on the **new** client */
-			proto.doAccept(cond);
-		}
-	}
-
-	template <typename Address, typename Protocol>
-	inline void accept(Socket<Address, Protocol> &sc, Condition &cond)
-	{
-		doAccept(cond);
-	}
-
-	template <typename Address>
-	unsigned recv(Socket<Address, Tls> &, void *data, unsigned len, Condition &cond)
-	{
-		int nbread = 0;
-
-		wrap("recv", cond, [&] () -> int {
-			return (nbread = SSL_read(m_ssl.get(), data, len));
-		});
-
-		return static_cast<unsigned>(nbread < 0 ? 0 : nbread);
-	}
-
-	template <typename Address>
-	unsigned send(Socket<Address, Tls> &, const void *data, unsigned len, Condition &cond)
-	{
-		int nbsent = 0;
-
-		wrap("send", cond, [&] () -> int {
-			return (nbsent = SSL_write(m_ssl.get(), data, len));
-		});
-
-		return static_cast<unsigned>(nbsent < 0 ? 0 : nbsent);
-	}
-};
-
-#endif // !SOCKET_NO_SSL
-
-/* }}} */
-
-} // !protocol
-
-/* }}} */
-
-/*
- * Convenient helpers
- * ------------------------------------------------------------------
- *
- * - SocketTcp<Address>, for TCP sockets,
- * - SocketUdp<Address>, for UDP sockets,
- * - SocketTls<Address>, for secure TCP sockets.
- */
-
-/* {{{ Helpers */
-
-/**
- * Helper to create TCP sockets.
- */
-template <typename Address>
-using SocketTcp = Socket<Address, protocol::Tcp>;
-
-/**
- * Helper to create TCP/IPv4 sockets.
- */
-using SocketTcpIp = Socket<address::Ipv4, protocol::Tcp>;
-
-/**
- * Helper to create TCP/IPv6 sockets.
- */
-using SocketTcpIpv6 = Socket<address::Ipv6, protocol::Tcp>;
-
-#if !defined(_WIN32)
-
-/**
- * Helper to create TCP/Local sockets.
- */
-using SocketTcpLocal = Socket<address::Local, protocol::Tcp>;
-
-#endif
-
-/**
- * Helper to create UDP sockets.
- */
-template <typename Address>
-using SocketUdp = Socket<Address, protocol::Udp>;
-
-/**
- * Helper to create UDP/IPv4 sockets.
- */
-using SocketUdpIp = Socket<address::Ipv4, protocol::Udp>;
-
-/**
- * Helper to create UDP/IPv6 sockets.
- */
-using SocketUdpIpv6 = Socket<address::Ipv6, protocol::Udp>;
-
-#if !defined(SOCKET_NO_SSL)
-
-/**
- * Helper to create OpenSSL TCP sockets.
- */
-template <typename Address>
-using SocketTls = Socket<Address, protocol::Tls>;
-
-/**
- * Helper to create OpenSSL TCP/Ip sockets.
- */
-using SocketTlsIp = Socket<address::Ipv4, protocol::Tls>;
-
-#endif // !SOCKET_NO_SSL
-
-/* }}} */
-
-/*
- * Listener
- * ------------------------------------------------------------------
- *
- * Wrapper for select(2) and other various implementations.
- */
-
-/* {{{ Listener stuff */
-
-/**
- * @class ListenerStatus
- * @brief Result of polling
- *
- * Result of a select call, returns the first ready socket found with its
- * flags.
- */
-class ListenerStatus {
-public:
-	Handle socket;		//!< which socket is ready
-	Condition flags;	//!< the flags
-};
-
-/**
- * Table used in the socket listener to store which sockets have been
- * set in which directions.
- */
-using ListenerTable = std::map<Handle, Condition>;
-
-/* {{{ Backends */
-
-/* {{{ Select */
-
-/**
- * @class Select
- * @brief Implements select(2)
- *
- * This class is the fallback of any other method, it is not preferred at all for many reasons.
- */
-class Select {
-public:
-	/**
-	 * No-op, uses the ListenerTable directly.
-	 */
-	inline void set(const ListenerTable &, Handle, Condition, bool) noexcept {}
-
-	/**
-	 * No-op, uses the ListenerTable directly.
-	 */
-	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept {}
-
-	/**
-	 * Return the sockets
-	 */
-	std::vector<ListenerStatus> wait(const ListenerTable &table, int ms);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "select";
-	}
-};
-
-/* }}} */
-
-/* {{{ Poll */
-
-#if defined(SOCKET_HAVE_POLL)
-
-/**
- * @class Poll
- * @brief Implements poll(2).
- *
- * Poll is widely supported and is better than select(2). It is still not the
- * best option as selecting the sockets is O(n).
- */
-class Poll {
-private:
-	std::vector<pollfd> m_fds;
-
-	short toPoll(Condition flags) const noexcept;
-	Condition toCondition(short &event) const noexcept;
-
-public:
-	/**
-	 * Set the handle.
-	 */
-	void set(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Unset the handle.
-	 */
-	void unset(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Wait for events.
-	 */
-	std::vector<ListenerStatus> wait(const ListenerTable &, int ms);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "poll";
-	}
-};
-
-#endif
-
-/* }}} */
-
-/* {{{ Epoll */
-
-#if defined(SOCKET_HAVE_EPOLL)
-
-/**
- * @class Epoll
- * @brief Linux's epoll.
- */
-class Epoll {
-private:
-	int m_handle{-1};
-	std::vector<epoll_event> m_events;
-
-	Epoll(const Epoll &) = delete;
-	Epoll &operator=(const Epoll &) = delete;
-
-	uint32_t toEpoll(Condition flags) const noexcept;
-	Condition toCondition(uint32_t events) const noexcept;
-	void update(Handle sc, int op, int eflags);
-
-public:
-	/**
-	 * Construct the epoll instance.
-	 */
-	Epoll();
-
-	inline Epoll(Epoll &&other) noexcept
-		: m_handle(other.m_handle)
-	{
-		other.m_handle = -1;
-	}
-	
-	Epoll &operator=(Epoll &&other)
-	{
-		m_handle = other.m_handle;
-		other.m_handle = -1;
-
-		return *this;
-	}
-
-	/**
-	 * Close the epoll instance.
-	 */
-	~Epoll();
-
-	/**
-	 * Set the handle.
-	 */
-	void set(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Unset the handle.
-	 */
-	void unset(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Wait for events.
-	 */
-	std::vector<ListenerStatus> wait(const ListenerTable &, int);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "epoll";
-	}
-};
-
-#endif
-
-/* }}} */
-
-/* {{{ Kqueue */
-
-#if defined(SOCKET_HAVE_KQUEUE)
-
-/**
- * @class Kqueue
- * @brief Implements kqueue(2).
- *
- * This implementation is available on all BSD and Mac OS X. It is better than
- * poll(2) because it's O(1), however it's a bit more memory consuming.
- */
-class Kqueue {
-private:
-	std::vector<struct kevent> m_result;
-	int m_handle;
-
-	Kqueue(const Kqueue &) = delete;
-	Kqueue &operator=(const Kqueue &) = delete;
-
-	void update(Handle sc, int filter, int kflags);
-
-public:
-	/**
-	 * Construct the kqueue instance.
-	 */
-	Kqueue();
-
-	inline Kqueue(Kqueue &&other) noexcept
-		: m_handle(other.m_handle)
-	{
-		other.m_handle = -1;
-	}
-
-	inline Kqueue &operator=(Kqueue &&other) noexcept
-	{
-		m_handle = other.m_handle;
-		other.m_handle = -1;
-
-		return *this;
-	}
-
-	/**
-	 * Destroy the kqueue instance.
-	 */
-	~Kqueue();
-
-	/**
-	 * Set the handle.
-	 */
-	void set(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Unset the handle.
-	 */
-	void unset(const ListenerTable &, Handle, Condition, bool);
-
-	/**
-	 * Wait for events.
-	 */
-	std::vector<ListenerStatus> wait(const ListenerTable &, int);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "kqueue";
-	}
-};
-
-#endif
-
-/* }}} */
-
-/* }}} */
-
-/* {{{ Listener */
-
-/**
- * @class Listener
- * @brief Synchronous multiplexing
- *
- * Convenient wrapper around the select() system call.
- *
- * This class is implemented using a bridge pattern to allow different uses
- * of listener implementation.
- *
- * You should not reinstanciate a new Listener at each iteartion of your
- * main loop as it can be extremely costly. Instead use the same listener that
- * you can safely modify on the fly.
- *
- * Currently, poll, epoll, select and kqueue are available.
- *
- * To implement the backend, the following functions must be available:
- *
- * ### Set
- *
- * @code
- * void set(const ListenerTable &, Handle sc, Condition condition, bool add);
- * @endcode
- *
- * This function, takes the socket to be added and the flags. The condition is
- * always guaranteed to be correct and the function will never be called twice
- * even if the user tries to set the same flag again.
- *
- * An optional add argument is added for backends which needs to do different
- * operation depending if the socket was already set before or if it is the
- * first time (e.g EPOLL_CTL_ADD vs EPOLL_CTL_MOD for epoll(7).
- *
- * ### Unset
- *
- * @code
- * void unset(const ListenerTable &, Handle sc, Condition condition, bool remove);
- * @endcode
- *
- * Like set, this function is only called if the condition is actually set and will
- * not be called multiple times.
- *
- * Also like set, an optional remove argument is set if the socket is being
- * completely removed (e.g no more flags are set for this socket).
- *
- * ### Wait
- *
- * @code
- * std::vector<ListenerStatus> wait(const ListenerTable &, int ms);
- * @endcode
- *
- * Wait for the sockets to be ready with the specified milliseconds. Must return a list of ListenerStatus,
- * may throw any exceptions.
- *
- * ### Name
- *
- * @code
- * inline const char *name() const noexcept
- * @endcode
- *
- * Returns the backend name. Usually the class in lower case.
- */
-template <typename Backend = SOCKET_DEFAULT_BACKEND>
-class Listener {
-private:
-	Backend m_backend;
-	ListenerTable m_table;
-
-public:
-	/**
-	 * Construct an empty listener.
-	 */
-	Listener() = default;
-
-	/**
-	 * Get the backend.
-	 *
-	 * @return the backend
-	 */
-	inline const Backend &backend() const noexcept
-	{
-		return m_backend;
-	}
-
-	/**
-	 * Get the non-modifiable table.
-	 *
-	 * @return the table
-	 */
-	inline const ListenerTable &table() const noexcept
-	{
-		return m_table;
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline ListenerTable::const_iterator begin() const noexcept
-	{
-		return m_table.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline ListenerTable::const_iterator cbegin() const noexcept
-	{
-		return m_table.cbegin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline ListenerTable::const_iterator end() const noexcept
-	{
-		return m_table.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline ListenerTable::const_iterator cend() const noexcept
-	{
-		return m_table.cend();
-	}
-
-	/**
-	 * Add or update a socket to the listener.
-	 *
-	 * If the socket is already placed with the appropriate flags, the
-	 * function is a no-op.
-	 *
-	 * If incorrect flags are passed, the function does nothing.
-	 *
-	 * @param sc the socket
-	 * @param condition the condition (may be OR'ed)
-	 * @throw Error if the backend failed to set
-	 */
-	void set(Handle sc, Condition condition)
-	{
-		/* Invalid or useless flags */
-		if (condition == Condition::None || static_cast<int>(condition) > 0x3)
-			return;
-
-		auto it = m_table.find(sc);
-
-		/*
-		 * Do not update the table if the backend failed to add
-		 * or update.
-		 */
-		if (it == m_table.end()) {
-			m_backend.set(m_table, sc, condition, true);
-			m_table.emplace(sc, condition);
-		} else {
-			/* Remove flag if already present */
-			if ((condition & Condition::Readable) == Condition::Readable &&
-			    (it->second & Condition::Readable) == Condition::Readable)
-				condition &= ~(Condition::Readable);
-			if ((condition & Condition::Writable) == Condition::Writable &&
-			    (it->second & Condition::Writable) == Condition::Writable)
-				condition &= ~(Condition::Writable);
-
-			/* Still need a call? */
-			if (condition != Condition::None) {
-				m_backend.set(m_table, sc, condition, false);
-				it->second |= condition;
-			}
-		}
-	}
-
-	/**
-	 * Unset a socket from the listener, only the flags is removed
-	 * unless the two flagss are requested.
-	 *
-	 * For example, if you added a socket for both reading and writing,
-	 * unsetting the write flags will keep the socket for reading.
-	 *
-	 * @param sc the socket
-	 * @param condition the condition (may be OR'ed)
-	 * @see remove
-	 */
-	void unset(Handle sc, Condition condition)
-	{
-		auto it = m_table.find(sc);
-
-		/* Invalid or useless flags */
-		if (condition == Condition::None || static_cast<int>(condition) > 0x3 || it == m_table.end())
-			return;
-
-		/*
-		 * Like set, do not update if the socket is already at the appropriate
-		 * state.
-		 */
-		if ((condition & Condition::Readable) == Condition::Readable &&
-		    (it->second & Condition::Readable) != Condition::Readable)
-			condition &= ~(Condition::Readable);
-		if ((condition & Condition::Writable) == Condition::Writable &&
-		    (it->second & Condition::Writable) != Condition::Writable)
-			condition &= ~(Condition::Writable);
-
-		if (condition != Condition::None) {
-			/* Determine if it's a complete removal */
-			bool removal = ((it->second) & ~(condition)) == Condition::None;
-
-			m_backend.unset(m_table, sc, condition, removal);
-
-			if (removal)
-				m_table.erase(it);
-			else
-				it->second &= ~(condition);
-		}
-	}
-
-	/**
-	 * Remove completely the socket from the listener.
-	 *
-	 * It is a shorthand for unset(sc, Condition::Readable | Condition::Writable);
-	 *
-	 * @param sc the socket
-	 */
-	inline void remove(Handle sc)
-	{
-		unset(sc, Condition::Readable | Condition::Writable);
-	}
-
-	/**
-	 * Remove all sockets.
-	 */
-	inline void clear()
-	{
-		while (!m_table.empty())
-			remove(m_table.begin()->first);
-	}
-
-	/**
-	 * Get the number of sockets in the listener.
-	 */
-	inline ListenerTable::size_type size() const noexcept
-	{
-		return m_table.size();
-	}
-
-	/**
-	 * Select a socket. Waits for a specific amount of time specified as the duration.
-	 *
-	 * @param duration the duration
-	 * @return the socket ready
-	 */
-	template <typename Rep, typename Ratio>
-	inline ListenerStatus wait(const std::chrono::duration<Rep, Ratio> &duration)
-	{
-		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-
-		return m_backend.wait(m_table, cvt.count())[0];
-	}
-
-	/**
-	 * Overload with milliseconds.
-	 *
-	 * @param timeout the optional timeout in milliseconds
-	 * @return the socket ready
-	 */
-	inline ListenerStatus wait(int timeout = -1)
-	{
-		return wait(std::chrono::milliseconds(timeout));
-	}
-
-	/**
-	 * Select multiple sockets.
-	 *
-	 * @param duration the duration
-	 * @return the socket ready
-	 */
-	template <typename Rep, typename Ratio>
-	inline std::vector<ListenerStatus> waitMultiple(const std::chrono::duration<Rep, Ratio> &duration)
-	{
-		auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-
-		return m_backend.wait(m_table, cvt.count());
-	}
-
-	/**
-	 * Overload with milliseconds.
-	 *
-	 * @return the socket ready
-	 */
-	inline std::vector<ListenerStatus> waitMultiple(int timeout = -1)
-	{
-		return waitMultiple(std::chrono::milliseconds(timeout));
-	}
-};
-
-/* }}} */
-
-/* }}} */
-
-} // !net
-
-#endif // !_SOCKETS_H_
--- a/modules/sockets/test/main.cpp	Tue Apr 05 15:18:41 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,704 +0,0 @@
-/*
- * main.cpp -- test sockets
- *
- * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <chrono>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include <sockets.h>
-
-using namespace net;
-using namespace net::address;
-using namespace net::option;
-using namespace net::protocol;
-
-using namespace std::literals::chrono_literals;
-
-/*
- * Options
- * ------------------------------------------------------------------
- */
-
-TEST(Options, reuse)
-{
-	SocketTcpIp s;
-
-	try {
-		s.set(option::SockReuseAddress(true));
-		ASSERT_TRUE(s.get<option::SockReuseAddress>());
-
-		s.set(option::SockReuseAddress(false));
-		ASSERT_FALSE(s.get<option::SockReuseAddress>());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Options, nodelay)
-{
-	SocketTcpIp s;
-
-	try {
-		s.set(option::TcpNoDelay(true));
-		ASSERT_TRUE(s.get<option::TcpNoDelay>());
-
-		s.set(option::TcpNoDelay(false));
-		ASSERT_FALSE(s.get<option::TcpNoDelay>());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-TEST(Options, v6only)
-{
-	SocketTcpIpv6 s;
-
-	try {
-		s.set(option::Ipv6Only(true));
-		ASSERT_TRUE(s.get<option::Ipv6Only>());
-
-		s.set(option::Ipv6Only(false));
-		ASSERT_FALSE(s.get<option::Ipv6Only>());
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-}
-
-/* --------------------------------------------------------
- * TCP tests
- * -------------------------------------------------------- */
-
-class TcpServerTest : public testing::Test {
-protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpServerTest()
-	{
-		m_server.set(SockReuseAddress());
-	}
-
-	~TcpServerTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(TcpServerTest, connect)
-{
-	m_tserver = std::thread([this] () {
-		SocketTcp<Ipv4> sc;
-
-		m_server.bind(Ipv4("*", 16000));
-		m_server.listen();
-		m_server.accept(sc);
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4("127.0.0.1", 16000));
-		m_client.close();
-	});
-}
-
-TEST_F(TcpServerTest, io)
-{
-	m_tserver = std::thread([this] () {
-		m_server.bind(Ipv4("*", 16000));
-		m_server.listen();
-
-		SocketTcp<Ipv4> client;
-
-		m_server.accept(client);
-
-		auto msg = client.recv(512);
-
-		ASSERT_EQ("hello world", msg);
-
-		client.send(msg);
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4("127.0.0.1", 16000));
-		m_client.send("hello world");
-
-		ASSERT_EQ("hello world", m_client.recv(512));
-	});
-}
-
-/* --------------------------------------------------------
- * UDP tests
- * -------------------------------------------------------- */
-
-class UdpServerTest : public testing::Test {
-protected:
-	SocketUdp<Ipv4> m_server;
-	SocketUdp<Ipv4> m_client;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	UdpServerTest()
-	{
-		m_server.set(SockBlockMode());
-	}
-
-	~UdpServerTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(UdpServerTest, io)
-{
-	m_tserver = std::thread([this] () {
-		Ipv4 client;
-		Ipv4 info("*", 16000);
-
-		m_server.bind(info);
-		auto msg = m_server.recvfrom(512, &client);
-
-		ASSERT_EQ("hello world", msg);
-
-		m_server.sendto(msg, client);
-		m_server.close();
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		Ipv4 info("127.0.0.1", 16000);
-
-		m_client.sendto("hello world", info);
-
-		ASSERT_EQ("hello world", m_client.recvfrom(512, &info));
-
-		m_client.close();
-	});
-}
-
-/* --------------------------------------------------------
- * Listener: set function
- * -------------------------------------------------------- */
-
-class TestBackendSet {
-public:
-	int m_callcount{0};
-	bool m_added{false};
-	Condition m_flags{Condition::None};
-
-	inline void set(const ListenerTable &, Handle, Condition flags, bool add) noexcept
-	{
-		m_callcount ++;
-		m_added = add;
-		m_flags |= flags;
-	}
-
-	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept
-	{
-	}
-
-	std::vector<ListenerStatus> wait(const ListenerTable &, int)
-	{
-		return {};
-	}
-};
-
-class TestBackendSetFail {
-public:
-	inline void set(const ListenerTable &, Handle, Condition, bool)
-	{
-		throw "fail";
-	}
-
-	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept
-	{
-	}
-
-	std::vector<ListenerStatus> wait(const ListenerTable &, int)
-	{
-		return {};
-	}
-};
-
-TEST(ListenerSet, initialAdd)
-{
-	Listener<TestBackendSet> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable);
-
-	ASSERT_EQ(1U, listener.size());
-	ASSERT_EQ(1, listener.backend().m_callcount);
-	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::Readable);
-}
-
-TEST(ListenerSet, readThenWrite)
-{
-	Listener<TestBackendSet> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable);
-	listener.set(s, Condition::Writable);
-
-	ASSERT_EQ(1U, listener.size());
-	ASSERT_EQ(2, listener.backend().m_callcount);
-	ASSERT_FALSE(listener.backend().m_added);
-	ASSERT_TRUE(static_cast<int>(listener.backend().m_flags) == 0x3);
-}
-
-TEST(ListenerSet, allOneShot)
-{
-	Listener<TestBackendSet> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable | Condition::Writable);
-
-	ASSERT_EQ(1U, listener.size());
-	ASSERT_EQ(1, listener.backend().m_callcount);
-	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(static_cast<int>(listener.backend().m_flags) == 0x3);
-}
-
-TEST(ListenerSet, readTwice)
-{
-	Listener<TestBackendSet> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable);
-	listener.set(s, Condition::Readable);
-
-	ASSERT_EQ(1U, listener.size());
-	ASSERT_EQ(1, listener.backend().m_callcount);
-	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::Readable);
-}
-
-TEST(ListenerSet, failure)
-{
-	Listener<TestBackendSetFail> listener;
-	Handle s = 0;
-
-	try {
-		listener.set(s, Condition::Readable);
-		FAIL() << "exception expected";
-	} catch (...) {
-	}
-
-	ASSERT_EQ(0U, listener.size());
-}
-
-/* --------------------------------------------------------
- * Listener: unset / remove functions
- * -------------------------------------------------------- */
-
-class TestBackendUnset {
-public:
-	bool m_isset{false};
-	bool m_isunset{false};
-	Condition m_flags{Condition::None};
-	bool m_removal{false};
-
-	inline void set(const ListenerTable &, Handle &, Condition flags, bool) noexcept
-	{
-		m_isset = true;
-		m_flags |= flags;
-	}
-
-	inline void unset(const ListenerTable &, Handle &, Condition flags, bool remove) noexcept
-	{
-		m_isunset = true;
-		m_flags &= ~(flags);
-		m_removal = remove;
-	}
-
-	std::vector<ListenerStatus> wait(const ListenerTable &, int) noexcept
-	{
-		return {};
-	}
-};
-
-class TestBackendUnsetFail {
-public:
-	inline void set(const ListenerTable &, Handle &, Condition, bool) noexcept
-	{
-	}
-
-	inline void unset(const ListenerTable &, Handle &, Condition, bool)
-	{
-		throw "fail";
-	}
-
-	std::vector<ListenerStatus> wait(const ListenerTable &, int)
-	{
-		return {};
-	}
-};
-
-TEST(ListenerUnsetRemove, unset)
-{
-	Listener<TestBackendUnset> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable);
-	listener.unset(s, Condition::Readable);
-
-	ASSERT_EQ(0U, listener.size());
-	ASSERT_TRUE(listener.backend().m_isset);
-	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
-	ASSERT_TRUE(listener.backend().m_removal);
-}
-
-TEST(ListenerUnsetRemove, unsetOne)
-{
-	Listener<TestBackendUnset> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable | Condition::Writable);
-	listener.unset(s, Condition::Readable);
-
-	ASSERT_EQ(1U, listener.size());
-	ASSERT_TRUE(listener.backend().m_isset);
-	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::Writable);
-	ASSERT_FALSE(listener.backend().m_removal);
-}
-
-TEST(ListenerUnsetRemove, unsetAll)
-{
-	Listener<TestBackendUnset> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable | Condition::Writable);
-	listener.unset(s, Condition::Readable);
-	listener.unset(s, Condition::Writable);
-
-	ASSERT_EQ(0U, listener.size());
-	ASSERT_TRUE(listener.backend().m_isset);
-	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
-	ASSERT_TRUE(listener.backend().m_removal);
-}
-
-TEST(ListenerUnsetRemove, remove)
-{
-	Listener<TestBackendUnset> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable | Condition::Writable);
-	listener.remove(s);
-
-	ASSERT_EQ(0U, listener.size());
-	ASSERT_TRUE(listener.backend().m_isset);
-	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
-	ASSERT_TRUE(listener.backend().m_removal);
-}
-
-TEST(ListenerUnsetRemove, failure)
-{
-	Listener<TestBackendUnsetFail> listener;
-	Handle s = 0;
-
-	listener.set(s, Condition::Readable | Condition::Writable);
-
-	try {
-		listener.remove(s);
-		FAIL() << "exception expected";
-	} catch (...) {
-	}
-
-	/* If fail, kept into the table */
-	ASSERT_EQ(1U, listener.size());
-}
-
-/* --------------------------------------------------------
- * Listener: system
- * -------------------------------------------------------- */
-
-class ListenerTest : public testing::Test {
-protected:
-	Listener<Select> m_listener;
-	SocketTcp<Ipv4> m_masterTcp;
-	SocketTcp<Ipv4> m_clientTcp;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	ListenerTest()
-	{
-		m_masterTcp.set(SockReuseAddress());
-		m_masterTcp.bind(Ipv4("*", 16000));
-		m_masterTcp.listen();
-	}
-
-	~ListenerTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(ListenerTest, accept)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp.handle(), Condition::Readable);
-			m_listener.wait();
-			m_masterTcp.accept(nullptr);
-			m_masterTcp.close();
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Ipv4("127.0.0.1", 16000));
-	});
-}
-
-TEST_F(ListenerTest, recv)
-{
-	m_tserver = std::thread([this] () {
-		try {
-			m_listener.set(m_masterTcp.handle(), Condition::Readable);
-			m_listener.wait();
-
-			SocketTcp<Ipv4> sc;
-
-			m_masterTcp.accept(sc);
-
-			ASSERT_EQ("hello", sc.recv(512));
-		} catch (const std::exception &ex) {
-			FAIL() << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_clientTcp.connect(Ipv4("127.0.0.1", 16000));
-		m_clientTcp.send("hello");
-	});
-}
-
-/* --------------------------------------------------------
- * Non-blocking connect
- * -------------------------------------------------------- */
-
-class NonBlockingConnectTest : public testing::Test {
-protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	NonBlockingConnectTest()
-	{
-		m_client.set(SockBlockMode(false));
-	}
-
-	~NonBlockingConnectTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-/* --------------------------------------------------------
- * TCP accept
- * -------------------------------------------------------- */
-
-class TcpAcceptTest : public testing::Test {
-protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpAcceptTest()
-	{
-		m_server.set(SockReuseAddress());
-		m_server.bind(Ipv4("*", 16000));
-		m_server.listen();
-	}
-
-	~TcpAcceptTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-/* --------------------------------------------------------
- * TCP recv
- * -------------------------------------------------------- */
-
-class TcpRecvTest : public testing::Test {
-protected:
-	SocketTcp<Ipv4> m_server;
-	SocketTcp<Ipv4> m_client;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TcpRecvTest()
-	{
-		m_server.set(SockReuseAddress());
-		m_server.bind(Ipv4("*", 16000));
-		m_server.listen();
-	}
-
-	~TcpRecvTest()
-	{
-		if (m_tserver.joinable())
-			m_tserver.join();
-		if (m_tclient.joinable())
-			m_tclient.join();
-	}
-};
-
-TEST_F(TcpRecvTest, blockingSuccess)
-{
-	m_tserver = std::thread([this] () {
-		SocketTcp<Ipv4> client;
-
-		m_server.accept(client);
-
-		ASSERT_EQ("hello", client.recv(32));
-	});
-
-	std::this_thread::sleep_for(100ms);
-
-	m_tclient = std::thread([this] () {
-		m_client.connect(Ipv4("127.0.0.1", 16000));
-		m_client.send("hello");
-		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;
-
-	std::thread m_tserver;
-	std::thread m_tclient;
-
-public:
-	TlsRecvTest()
-	{
-		Tls protocol;
-
-		protocol.setCertificate("sockets/test.crt");
-		protocol.setPrivateKey("sockets/test.key");
-		protocol.setVerify(false);
-
-		m_server = SocketTls<Ipv4>(std::move(protocol));
-		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(client);
-
-			ASSERT_EQ("hello", client.recv(32));
-
-			std::this_thread::sleep_for(500ms);
-		} catch (const net::Error &ex) {
-			FAIL() << ex.function() << ": " << ex.what();
-		}
-	});
-
-	std::this_thread::sleep_for(500ms);
-
-	m_tclient = std::thread([this] () {
-		try {
-			puts("OLOL");
-			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);
-
-	return RUN_ALL_TESTS();
-}