changeset 437:378699c81257

Socket: massive cleanup, documentation
author David Demelier <markand@malikania.fr>
date Thu, 22 Oct 2015 21:38:28 +0200
parents 2dbaf2fb03ef
children 5f837e40b569
files C++/modules/Socket/SocketAddress.cpp C++/modules/Socket/SocketAddress.h C++/modules/Socket/SocketListener.cpp C++/modules/Socket/SocketListener.h C++/modules/Socket/SocketSsl.cpp C++/modules/Socket/SocketSsl.h C++/modules/Socket/Sockets.cpp C++/modules/Socket/Sockets.h C++/tests/Socket/main.cpp
diffstat 9 files changed, 440 insertions(+), 1880 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Socket/SocketAddress.cpp	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * SocketAddress.cpp -- socket addresses management
- *
- * 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 <algorithm>
-#include <cstring>
-
-#include "Socket.h"
-#include "SocketAddress.h"
-
-bool operator==(const SocketAddressAbstract &address1, const SocketAddressAbstract &address2) noexcept
-{
-	const char *addr1 = reinterpret_cast<const char *>(&address1.address());
-	const char *addr2 = reinterpret_cast<const char *>(&address2.address());
-
-	return std::equal(
-		addr1, addr1 + address1.length(),
-		addr2, addr2 + address2.length()
-	);
-}
-
-bool operator<(const SocketAddressAbstract &address1, const SocketAddressAbstract &address2) noexcept
-{
-	const char *addr1 = reinterpret_cast<const char *>(&address1.address());
-	const char *addr2 = reinterpret_cast<const char *>(&address2.address());
-
-	return std::lexicographical_compare(
-		addr1, addr1 + address1.length(),
-		addr2, addr2 + address2.length()
-	);
-}
-
-namespace address {
-
-/* --------------------------------------------------------
- * Ip implementation
- * -------------------------------------------------------- */
-
-Ip::Ip()
-{
-	// Default uses IPv4
-	std::memset(&m_sin, 0, sizeof (sockaddr_in));
-}
-
-Ip::Ip(const std::string &host, unsigned port, int domain)
-	: m_domain{domain}
-{
-	if (host == "*") {
-		if (m_domain == AF_INET6) {
-			std::memset(&m_sin6, 0, sizeof (sockaddr_in6));
-
-			m_sin6.sin6_addr = in6addr_any;
-			m_sin6.sin6_family = AF_INET6;
-			m_sin6.sin6_port = htons(port);
-		} else {
-			std::memset(&m_sin, 0, sizeof (sockaddr_in));
-
-			m_sin.sin_addr.s_addr = INADDR_ANY;
-			m_sin.sin_family = AF_INET;
-			m_sin.sin_port = htons(port);
-		}
-	} else {
-		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 SocketError{SocketError::System, "getaddrinfo", gai_strerror(error)};
-		}
-
-		if (m_domain == AF_INET6) {
-			std::memcpy(&m_sin6, res->ai_addr, sizeof (sockaddr_in6));
-		} else {
-			std::memcpy(&m_sin, res->ai_addr, sizeof (sockaddr_in));
-		}
-
-		freeaddrinfo(res);
-	}
-}
-
-Ip::Ip(const sockaddr_storage &ss, socklen_t length)
-	: m_domain{ss.ss_family}
-{
-	if (ss.ss_family == AF_INET6) {
-		std::memcpy(&m_sin6, &ss, length);
-	} else {
-		std::memcpy(&m_sin, &ss, length);
-	}
-}
-
-SocketAddressInfo Ip::info() const
-{
-	std::string type = (m_domain == AF_INET6) ? "ipv6" : "ipv4";
-	std::string port = std::to_string(m_domain == AF_INET6 ? ntohs(m_sin6.sin6_port) : ntohs(m_sin.sin_port));
-
-	// TODO: add IP here
-	return SocketAddressInfo{
-		{ "type",	type	},
-		{ "port",	port	}
-	};
-}
-
-/* --------------------------------------------------------
- * Unix implementation
- * -------------------------------------------------------- */
-
-#if !defined(_WIN32)
-
-Unix::Unix(std::string path, bool rm)
-	: 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_UNIX;
-}
-
-Unix::Unix(const sockaddr_storage &ss, socklen_t length)
-{
-	std::memcpy(&m_sun, &ss, length);
-
-	if (ss.ss_family == AF_UNIX) {
-		m_path = reinterpret_cast<const sockaddr_un &>(m_sun).sun_path;
-	}
-}
-
-SocketAddressInfo Unix::info() const
-{
-	return SocketAddressInfo{
-		{ "type",	"unix"	},
-		{ "path",	m_path	}
-	};
-}
-
-#endif // _WIN32
-
-} // !address
--- a/C++/modules/Socket/SocketAddress.h	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-/*
- * SocketAddress.h -- socket addresses management
- *
- * 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.
- */
-
-#ifndef _SOCKET_ADDRESS_NG_H_
-#define _SOCKET_ADDRESS_NG_H_
-
-/**
- * @file SocketAddress.h
- * @brief Describe addresses
- *
- * User may set the following variables before compiling these files:
- *
- * SOCKET_HAVE_SUN_LEN	- (bool) Some systems do not have SUN_LEN which is the preferred way to
- *			  compute the address size for a Unix address. Otherwise, sizeof is used.
- *
- * Addresses are used in many places such as bind, recvfrom, accept and such. They describe different
- * parameters depending on the families.
- *
- * For example, when using IPv4, one should use Ipv4 class.
- *
- * All addresses are used directly as template parameter for a stronger type security. To be compatible
- * with the sockets classes, an address must have the following requirements:
- *
- * - Default constructible
- * - Copyable or Moveable
- *
- * Constructors:
- *
- * # With a storage address
- *
- * @code
- * Address(const sockaddr_storage &ss, socklen_t size);
- * @endcode
- *
- * The address is free to use the storage.
- *
- * Member functions:
- *
- * # Address
- *
- * @code
- * inline const sockaddr &address() const noexcept
- * @endcode
- *
- * Return the address converted to the C sockaddr structure.
- *
- * # Length
- *
- * @code
- * inline socklen_t length() const noexcept
- * @endcode
- *
- * Return the length of an address.
- *
- * # Info
- *
- * @code
- * SocketAddressInfo info() const
- * @endcode
- *
- * Return an information table about the address.
- */
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#if defined(_WIN32)
-#  include <Winsock2.h>
-#  include <Ws2tcpip.h>
-#else
-#  include <sys/socket.h>
-#  include <sys/un.h>
-#  include <arpa/inet.h>
-#  include <netinet/in.h>
-#endif
-
-/**
- * Generic information table for an address.
- */
-using SocketAddressInfo = std::unordered_map<std::string, std::string>;
-
-/**
- * @class SocketAddressAbstract
- * @brief Generic base class for addresses
- */
-class SocketAddressAbstract {
-public:
-	/**
-	 * Get the address as base type.
-	 *
-	 * @return the base address reference
-	 */
-	virtual const sockaddr &address() const noexcept = 0;
-
-	/**
-	 * Get the address length.
-	 *
-	 * @return the length
-	 */
-	virtual socklen_t length() const noexcept = 0;
-};
-
-/**
- * Compare two socket addresses, std::equal is used.
- *
- * @param addr1 the first address
- * @param addr2 the second address
- * @return true if equals
- */
-bool operator==(const SocketAddressAbstract &addr1, const SocketAddressAbstract &addr2) noexcept;
-
-/**
- * Compare two socket addresses, std::lexicographical_compare is used.
- *
- * @param addr1 the first address
- * @param addr2 the second address
- * @return true if addr1 < addr2
- */
-bool operator<(const SocketAddressAbstract &addr1, const SocketAddressAbstract &addr2) noexcept;
-
-/**
- * @brief Predefined addresses.
- */
-namespace address {
-
-/**
- * @class Ip
- * @brief Generic internet protocol address
- *
- * Create a connect address for internet protocol,
- * using getaddrinfo(3).
- *
- * @see Ipv4
- * @see Ipv6
- */
-class Ip : public SocketAddressAbstract {
-private:
-	union {
-		sockaddr_in m_sin;
-		sockaddr_in6 m_sin6;
-	};
-
-	int m_domain{AF_INET};
-
-public:
-	/**
-	 * Default constructor.
-	 */
-	Ip();
-
-	/**
-	 * Create an IPv4 or IPV6 end point.
-	 *
-	 * @param host the hostname
-	 * @param port the port
-	 * @param domain AF_INET or AF_INET6
-	 * @throw SocketError on error
-	 */
-	Ip(const std::string &host, unsigned port, int domain);
-
-	/**
-	 * Construct an internet address from a storage address.
-	 *
-	 * @param ss the storage
-	 * @param length the length
-	 */
-	Ip(const sockaddr_storage &ss, socklen_t length);
-
-	/**
-	 * @copydoc SocketAddress::address
-	 */
-	const sockaddr &address() const noexcept override
-	{
-		// Can't get a ternary operator to work here.
-		if (m_domain == AF_INET6)
-			return reinterpret_cast<const sockaddr &>(m_sin6);
-
-		return reinterpret_cast<const sockaddr &>(m_sin);
-	}
-
-	/**
-	 * @copydoc SocketAddress::length
-	 */
-	socklen_t length() const noexcept override
-	{
-		return (m_domain == AF_INET6) ? sizeof (sockaddr_in6) : sizeof (sockaddr_in);
-	}
-
-	/**
-	 * @copydoc SocketAddress::info
-	 */
-	SocketAddressInfo info() const;
-};
-
-/**
- * @class Ipv6
- * @brief Convenient helper for IPv6 protocol
- */
-class Ipv6 : public Ip {
-public:
-	/**
-	 * Default constructor.
-	 */
-	Ipv6() = default;
-
-	/**
-	 * Construct an IPv6 address from storage.
-	 *
-	 * @param ss the storage
-	 * @param length the length
-	 */
-	inline Ipv6(const sockaddr_storage &ss, socklen_t length)
-		: Ip(ss, length)
-	{
-	}
-
-	/**
-	 * Construct an IPv6 address.
-	 *
-	 * @param host the host
-	 * @param port the port
-	 * @throw SocketError on error
-	 */
-	inline Ipv6(const std::string &host, unsigned port)
-		: Ip(host, port, AF_INET6)
-	{
-	}
-};
-
-/**
- * @class Ipv4
- * @brief Convenient helper for IPv4 protocol
- */
-class Ipv4 : public Ip {
-public:
-	/**
-	 * Default constructor.
-	 */
-	Ipv4() = default;
-
-	/**
-	 * Construct an IPv4 address from storage.
-	 *
-	 * @param ss the storage
-	 * @param length the length
-	 */
-	inline Ipv4(const sockaddr_storage &ss, socklen_t length)
-		: Ip(ss, length)
-	{
-	}
-
-	/**
-	 * Construct an IPv4 address.
-	 *
-	 * @param host the host
-	 * @param port the port
-	 * @throw SocketError on error
-	 */
-	inline Ipv4(const std::string &host, unsigned port)
-		: Ip(host, port, AF_INET)
-	{
-	}
-};
-
-
-} // !address
-
-#endif // !_SOCKET_ADDRESS_NG_H_
--- a/C++/modules/Socket/SocketListener.cpp	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,378 +0,0 @@
-/*
- * SocketListener.cpp -- portable select() wrapper
- *
- * 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 <algorithm>
-#include <set>
-
-#include "SocketListener.h"
-
-/* --------------------------------------------------------
- * Select implementation
- * -------------------------------------------------------- */
-
-namespace backend {
-
-std::vector<SocketStatus> Select::wait(const SocketTable &table, int ms)
-{
-	timeval maxwait, *towait;
-	fd_set readset;
-	fd_set writeset;
-
-	FD_ZERO(&readset);
-	FD_ZERO(&writeset);
-
-	SocketAbstract::Handle max = 0;
-
-	for (const auto &s : table) {
-		if (s.second.second & SocketListener::Read) {
-			FD_SET(s.first, &readset);
-		}
-		if (s.second.second & SocketListener::Write) {
-			FD_SET(s.first, &writeset);
-		}
-
-		if (s.first > max) {
-			max = s.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 == SocketAbstract::Error) {
-		throw SocketError(SocketError::System, "select");
-	}
-	if (error == 0) {
-		throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
-	}
-
-	std::vector<SocketStatus> sockets;
-
-	for (auto &c : table) {
-		if (FD_ISSET(c.first, &readset)) {
-			sockets.push_back(SocketStatus{*c.second.first, SocketListener::Read});
-		}
-		if (FD_ISSET(c.first, &writeset)) {
-			sockets.push_back(SocketStatus{*c.second.first, SocketListener::Write});
-		}
-	}
-
-	return sockets;
-}
-
-/* --------------------------------------------------------
- * Poll implementation
- * -------------------------------------------------------- */
-
-#if defined(SOCKET_HAVE_POLL)
-
-#if defined(_WIN32)
-#  define poll WSAPoll
-#endif
-
-short Poll::topoll(int flags) const noexcept
-{
-	short result(0);
-
-	if (flags & SocketListener::Read) {
-		result |= POLLIN;
-	}
-	if (flags & SocketListener::Write) {
-		result |= POLLOUT;
-	}
-
-	return result;
-}
-
-int Poll::toflags(short &event) const noexcept
-{
-	int flags = 0;
-
-	/*
-	 * 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)) {
-		flags |= SocketListener::Read;
-	}
-	if (event & POLLOUT) {
-		flags |= SocketListener::Write;
-	}
-
-	// Reset event for safety
-	event = 0;
-
-	return flags;
-}
-
-void Poll::set(const SocketTable &, SocketAbstract &s, int flags, bool add)
-{
-	if (add) {
-		m_fds.push_back(pollfd{s.handle(), topoll(flags), 0});
-	} else {
-		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const struct pollfd &pfd) {
-			return pfd.fd == s.handle();
-		});
-
-		it->events |= topoll(flags);
-	}
-}
-
-void Poll::unset(const SocketTable &, SocketAbstract &s, int flags, bool remove)
-{
-	auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const struct pollfd &pfd) {
-		return pfd.fd == s.handle();
-	});
-
-	if (remove) {
-		m_fds.erase(it);
-	} else {
-		it->events &= ~(topoll(flags));
-	}
-}
-
-std::vector<SocketStatus> Poll::wait(const SocketTable &table, int ms)
-{
-	auto result = poll(m_fds.data(), m_fds.size(), ms);
-	if (result == 0) {
-		throw SocketError(SocketError::Timeout, "select", "Timeout while listening");
-	}
-	if (result < 0) {
-		throw SocketError(SocketError::System, "poll");
-	}
-
-	std::vector<SocketStatus> sockets;
-	for (auto &fd : m_fds) {
-		if (fd.revents != 0) {
-			sockets.push_back(SocketStatus{*table.at(fd.fd).first, toflags(fd.revents)});
-		}
-	}
-
-	return sockets;
-}
-
-#endif // !SOCKET_HAVE_POLL
-
-/* --------------------------------------------------------
- * Epoll implementation
- * -------------------------------------------------------- */
-
-#if defined(SOCKET_HAVE_EPOLL)
-
-uint32_t Epoll::toepoll(int flags) const noexcept
-{
-	uint32_t events = 0;
-
-	if (flags & SocketListener::Read) {
-		events |= EPOLLIN;
-	}
-	if (flags & SocketListener::Write) {
-		events |= EPOLLOUT;
-	}
-
-	return events;
-}
-
-int Epoll::toflags(uint32_t events) const noexcept
-{
-	int flags = 0;
-
-	if ((events & EPOLLIN) || (events & EPOLLHUP)) {
-		flags |= SocketListener::Read;
-	}
-	if (events & EPOLLOUT) {
-		flags |= SocketListener::Write;
-	}
-
-	return flags;
-}
-
-void Epoll::update(SocketAbstract &sc, int op, int flags)
-{
-	struct epoll_event ev;
-
-	std::memset(&ev, 0, sizeof (struct epoll_event));
-
-	ev.events = flags;
-	ev.data.fd = sc.handle();
-
-	if (epoll_ctl(m_handle, op, sc.handle(), &ev) < 0) {
-		throw SocketError{SocketError::System, "epoll_ctl"};
-	}
-}
-
-Epoll::Epoll()
-	: m_handle(epoll_create1(0))
-{
-	if (m_handle < 0) {
-		throw SocketError(SocketError::System, "epoll_create");
-	}
-}
-
-Epoll::~Epoll()
-{
-	close(m_handle);
-}
-
-/*
- * Add a new epoll_event or just update it.
- */
-void Epoll::set(const SocketTable &, SocketAbstract &sc, int flags, bool add)
-{
-	update(sc, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, toepoll(flags));
-
-	if (add) {
-		m_events.resize(m_events.size() + 1);
-	}
-}
-
-/*
- * Unset is a bit complicated case because SocketListener 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 SocketTable &table, SocketAbstract &sc, int flags, bool remove)
-{
-	if (remove) {
-		update(sc, EPOLL_CTL_DEL, 0);
-		m_events.resize(m_events.size() - 1);
-	} else {
-		update(sc, EPOLL_CTL_MOD, table.at(sc.handle()).second & ~(toepoll(flags)));
-	}
-}
-
-std::vector<SocketStatus> Epoll::wait(const SocketTable &table, int ms)
-{
-	int ret = epoll_wait(m_handle, m_events.data(), m_events.size(), ms);
-	std::vector<SocketStatus> result;
-
-	if (ret == 0) {
-		throw SocketError(SocketError::Timeout, "epoll_wait");
-	}
-	if (ret < 0) {
-		throw SocketError(SocketError::System, "epoll_wait");
-	}
-
-	for (int i = 0; i < ret; ++i) {
-		result.push_back(SocketStatus{*table.at(m_events[i].data.fd).first, toflags(m_events[i].events)});
-	}
-
-	return result;
-}
-
-#endif // !SOCKET_HAVE_EPOLL
-
-/* --------------------------------------------------------
- * Kqueue implementation
- * -------------------------------------------------------- */
-
-#if defined(SOCKET_HAVE_KQUEUE)
-
-Kqueue::Kqueue()
-	: m_handle(kqueue())
-{
-	if (m_handle < 0) {
-		throw SocketError(SocketError::System, "kqueue");
-	}
-}
-
-Kqueue::~Kqueue()
-{
-	close(m_handle);
-}
-
-void Kqueue::update(SocketAbstract &sc, int filter, int flags)
-{
-	struct kevent ev;
-
-	EV_SET(&ev, sc.handle(), filter, flags, 0, 0, nullptr);
-
-	if (kevent(m_handle, &ev, 1, nullptr, 0, nullptr) < 0) {
-		throw SocketError(SocketError::System, "kevent");
-	}
-}
-
-void Kqueue::set(const SocketTable &, SocketAbstract &sc, int flags, bool add)
-{
-	if (flags & SocketListener::Read) {
-		update(sc, EVFILT_READ, EV_ADD | EV_ENABLE);
-	}
-	if (flags & SocketListener::Write) {
-		update(sc, EVFILT_WRITE, EV_ADD | EV_ENABLE);
-	}
-
-	if (add) {
-		m_result.resize(m_result.size() + 1);
-	}
-}
-
-void Kqueue::unset(const SocketTable &, SocketAbstract &sc, int flags, bool remove)
-{
-	if (flags & SocketListener::Read) {
-		update(sc, EVFILT_READ, EV_DELETE);
-	}
-	if (flags & SocketListener::Write) {
-		update(sc, EVFILT_WRITE, EV_DELETE);
-	}
-
-	if (remove) {
-		m_result.resize(m_result.size() - 1);
-	}
-}
-
-std::vector<SocketStatus> Kqueue::wait(const SocketTable &table, int ms)
-{
-	std::vector<SocketStatus> 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 SocketError(SocketError::Timeout, "kevent");
-	}
-	if (nevents < 0) {
-		throw SocketError(SocketError::System, "kevent");
-	}
-
-	for (int i = 0; i < nevents; ++i) {
-		SocketAbstract *sc = table.at(m_result[i].ident).first;
-		int flags = m_result[i].filter == EVFILT_READ ? SocketListener::Read : SocketListener::Write;
-
-		sockets.push_back(SocketStatus{*sc, flags});
-	}
-
-	return sockets;
-}
-
-#endif // !SOCKET_HAVE_KQUEUE
-
-} // !backend
--- a/C++/modules/Socket/SocketListener.h	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,592 +0,0 @@
-/*
- * SocketListener.h -- portable select() wrapper
- *
- * 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.
- */
-
-#ifndef _SOCKET_LISTENER_NG_H_
-#define _SOCKET_LISTENER_NG_H_
-
-/**
- * @file SocketListener.h
- * @brief Portable synchronous multiplexer
- *
- * 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.
- */
-#if defined(_WIN32)
-#  if _WIN32_WINNT >= 0x0600
-#    define SOCKET_HAVE_POLL
-#  endif
-#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
-#  define SOCKET_HAVE_KQUEUE
-#  define SOCKET_HAVE_POLL
-#elif defined(__linux__)
-#  define SOCKET_HAVE_EPOLL
-#  define SOCKET_HAVE_POLL
-#endif
-
-/**
- * This sets the default backend to use depending on the system. The following
- * table summaries.
- *
- * The preference priority is ordered from left to right.
- *
- * | System        | Backend                 |
- * |---------------|-------------------------|
- * | Linux         | epoll(7)                |
- * | *BSD          | kqueue(2)               |
- * | Windows       | poll(2), select(2)      |
- * | Mac OS X      | kqueue(2)               |
- */
-
-#if defined(_WIN32)
-#  if defined(SOCKET_HAVE_POLL)
-#    define SOCKET_DEFAULT_BACKEND backend::Poll
-#  else
-#    define SOCKET_DEFAULT_BACKEND backend::Select
-#  endif
-#elif defined(__linux__)
-#  include <sys/epoll.h>
-#  include <cstring>
-
-#  define SOCKET_DEFAULT_BACKEND backend::Epoll
-#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
-#  include <sys/types.h>
-#  include <sys/event.h>
-#  include <sys/time.h>
-
-#  define SOCKET_DEFAULT_BACKEND backend::Kqueue
-#else
-#  define SOCKET_DEFAULT_BACKEND backend::Select
-#endif
-
-#include <chrono>
-#include <functional>
-#include <initializer_list>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "Socket.h"
-
-#if defined(SOCKET_HAVE_POLL) && !defined(_WIN32)
-#  include <poll.h>
-#endif
-
-/**
- * @struct SocketStatus
- * @brief The SocketStatus class
- *
- * Result of a select call, returns the first ready socket found with its
- * flags.
- */
-class SocketStatus {
-public:
-	SocketAbstract &socket;		//!< which socket is ready
-	int flags;			//!< the flags
-};
-
-/**
- * Table used in the socket listener to store which sockets have been
- * set in which directions.
- */
-using SocketTable = std::map<SocketAbstract::Handle, std::pair<SocketAbstract *, int>>;
-
-/**
- * @brief Namespace for predefined backends
- */
-namespace backend {
-
-/**
- * @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:
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "select";
-	}
-
-	/**
-	 * No-op, uses the SocketTable directly.
-	 */
-	inline void set(const SocketTable &, SocketAbstract &, int, bool) noexcept {}
-
-	/**
-	 * No-op, uses the SocketTable directly.
-	 */
-	inline void unset(const SocketTable &, SocketAbstract &, int, bool) noexcept {}
-
-	/**
-	 * Return the sockets
-	 */
-	std::vector<SocketStatus> wait(const SocketTable &table, int ms);
-};
-
-#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(int flags) const noexcept;
-	int toflags(short &event) const noexcept;
-
-public:
-	void set(const SocketTable &, SocketAbstract &sc, int flags, bool add);
-	void unset(const SocketTable &, SocketAbstract &sc, int flags, bool remove);
-	std::vector<SocketStatus> wait(const SocketTable &, int ms);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "poll";
-	}
-};
-
-#endif
-
-#if defined(SOCKET_HAVE_EPOLL)
-
-class Epoll {
-private:
-	int m_handle;
-	std::vector<struct epoll_event> m_events;
-
-	Epoll(const Epoll &) = delete;
-	Epoll &operator=(const Epoll &) = delete;
-	Epoll(const Epoll &&) = delete;
-	Epoll &operator=(const Epoll &&) = delete;
-
-	uint32_t toepoll(int flags) const noexcept;
-	int toflags(uint32_t events) const noexcept;
-	void update(SocketAbstract &sc, int op, int flags);
-
-public:
-	Epoll();
-	~Epoll();
-	void set(const SocketTable &, SocketAbstract &sc, int flags, bool add);
-	void unset(const SocketTable &, SocketAbstract &sc, int flags, bool remove);
-	std::vector<SocketStatus> wait(const SocketTable &table, int ms);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "epoll";
-	}
-};
-
-#endif
-
-#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;
-	Kqueue(Kqueue &&) = delete;
-	Kqueue &operator=(Kqueue &&) = delete;
-
-	void update(SocketAbstract &sc, int filter, int flags);
-
-public:
-	Kqueue();
-	~Kqueue();
-
-	void set(const SocketTable &, SocketAbstract &sc, int flags, bool add);
-	void unset(const SocketTable &, SocketAbstract &sc, int flags, bool remove);
-	std::vector<SocketStatus> wait(const SocketTable &, int ms);
-
-	/**
-	 * Backend identifier
-	 */
-	inline const char *name() const noexcept
-	{
-		return "kqueue";
-	}
-};
-
-#endif
-
-} // !backend
-
-/**
- * @class SocketListenerAbstract
- * @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 SocketListener 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 SocketTable &, const SocketAbstract &sc, int flags, bool add);
- * @endcode
- *
- * This function, takes the socket to be added and the flags. The flags are
- * 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 SocketTable &, const SocketAbstract &sc, int flags, bool remove);
- * @endcode
- *
- * Like set, this function is only called if the flags are 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<SocketStatus> wait(const SocketTable &, int ms);
- * @encode
- *
- * Wait for the sockets to be ready with the specified milliseconds. Must return a list of SocketStatus,
- * 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 SocketListenerAbstract final {
-public:
-	/**
-	 * Mark the socket for read operation.
-	 */
-	static const int Read;
-
-	/**
-	 * Mark the socket for write operation.
-	 */
-	static const int Write;
-
-private:
-	Backend m_backend;
-	SocketTable m_table;
-
-public:
-	/**
-	 * Construct an empty listener.
-	 */
-	SocketListenerAbstract() = 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 SocketTable &table() const noexcept
-	{
-		return m_table;
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline SocketTable::const_iterator begin() const noexcept
-	{
-		return m_table.begin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline SocketTable::const_iterator cbegin() const noexcept
-	{
-		return m_table.cbegin();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline SocketTable::const_iterator end() const noexcept
-	{
-		return m_table.end();
-	}
-
-	/**
-	 * Overloaded function.
-	 *
-	 * @return the iterator
-	 */
-	inline SocketTable::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 flags (may be OR'ed)
-	 * @throw SocketError if the backend failed to set
-	 */
-	void set(SocketAbstract &sc, int flags);
-
-	/**
-	 * 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 flags the flags (may be OR'ed)
-	 * @see remove
-	 */
-	void unset(SocketAbstract &sc, int flags);
-
-	/**
-	 * Remove completely the socket from the listener.
-	 *
-	 * It is a shorthand for unset(sc, SocketListener::Read | SocketListener::Write);
-	 *
-	 * @param sc the socket
-	 */
-	inline void remove(SocketAbstract &sc)
-	{
-		unset(sc, Read | Write);
-	}
-
-	/**
-	 * Remove all sockets.
-	 */
-	inline void clear()
-	{
-		while (!m_table.empty()) {
-			remove(m_table.begin()->second.first);
-		}
-	}
-
-	/**
-	 * Get the number of sockets in the listener.
-	 */
-	inline SocketTable::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 SocketStatus 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 SocketStatus 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<SocketStatus> 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<SocketStatus> waitMultiple(int timeout = -1)
-	{
-		return waitMultiple(std::chrono::milliseconds(timeout));
-	}
-};
-
-template <typename Backend>
-void SocketListenerAbstract<Backend>::set(SocketAbstract &sc, int flags)
-{
-	/* Invalid or useless flags */
-	if (flags == 0 || flags > 0x3)
-		return;
-
-	auto it = m_table.find(sc.handle());
-
-	/*
-	 * Do not update the table if the backend failed to add
-	 * or update.
-	 */
-	if (it == m_table.end()) {
-		m_backend.set(m_table, sc, flags, true);
-		m_table.emplace(sc.handle(), std::make_pair(std::addressof(sc), flags));
-	} else {
-		if ((flags & Read) && (it->second.second & Read)) {
-			flags &= ~(Read);
-		}
-		if ((flags & Write) && (it->second.second & Write)) {
-			flags &= ~(Write);
-		}
-
-		/* Still need a call? */
-		if (flags != 0) {
-			m_backend.set(m_table, sc, flags, false);
-			it->second.second |= flags;
-		}
-	}
-}
-
-template <typename Backend>
-void SocketListenerAbstract<Backend>::unset(SocketAbstract &sc, int flags)
-{
-	auto it = m_table.find(sc.handle());
-
-	/* Invalid or useless flags */
-	if (flags == 0 || flags > 0x3 || it == m_table.end())
-		return;
-
-	/*
-	 * Like set, do not update if the socket is already at the appropriate
-	 * state.
-	 */
-	if ((flags & Read) && !(it->second.second & Read)) {
-		flags &= ~(Read);
-	}
-	if ((flags & Write) && !(it->second.second & Write)) {
-		flags &= ~(Write);
-	}
-
-	if (flags != 0) {
-		/* Determine if it's a complete removal */
-		bool removal = ((it->second.second) & ~(flags)) == 0;
-
-		m_backend.unset(m_table, sc, flags, removal);
-
-		if (removal) {
-			m_table.erase(it);
-		} else {
-			it->second.second &= ~(flags);
-		}
-	}
-}
-
-/**
- * Helper to use the default.
- */
-using SocketListener = SocketListenerAbstract<>;
-
-template <typename Backend>
-const int SocketListenerAbstract<Backend>::Read{1 << 0};
-
-template <typename Backend>
-const int SocketListenerAbstract<Backend>::Write{1 << 1};
-
-#endif // !_SOCKET_LISTENER_NG_H_
--- a/C++/modules/Socket/SocketSsl.cpp	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * SocketSsl.cpp -- OpenSSL extension for 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 "SocketAddress.h"
-#include "SocketSsl.h"
-
-namespace detail {
-
-std::mutex mutex;
-std::atomic<bool> initialized{false};
-
-void terminate()
-{
-	ERR_free_strings();
-}
-
-void initialize()
-{
-	std::lock_guard<std::mutex> lock(mutex);
-
-	if (!initialized) {
-		initialized = true;
-
-		SSL_library_init();
-		SSL_load_error_strings();
-
-		atexit(terminate);
-	}
-}
-
-} // !detail
--- a/C++/modules/Socket/SocketSsl.h	Thu Oct 22 20:00:51 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,342 +0,0 @@
-/*
- * SocketSsl.h -- OpenSSL extension for 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.
- */
-
-#ifndef _SOCKET_SSL_NG_H_
-#define _SOCKET_SSL_NG_H_
-
-/**
- * @file SocketSsl.h
- * @brief Bring SSL support to socket module
- * @note This code is considered experimental
- *
- * User may set the following variables before compiling these files:
- *
- * - **SOCKET_NO_SSL_INIT**: (bool) Set to false if you don't want OpenSSL to be
- * initialized when the first SocketSsl object is created.
- */
-
-#include <cstdint>
-#include <atomic>
-#include <memory>
-#include <mutex>
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-
-#include "Socket.h"
-
-/**
- * @class SocketSslOptions
- * @brief Options for SocketSsl
- */
-class SocketSslOptions {
-public:
-	/**
-	 * @brief Method
-	 *
-	 * It is highly recommended to only use TLSv1.
-	 */
-	enum {
-		SSLv3,
-		TLSv1
-	};
-
-	int method{TLSv1};		//!< The method
-	std::string certificate;	//!< The certificate path
-	std::string privateKey;		//!< The private key file
-	bool verify{false};		//!< Verify or not
-
-	/**
-	 * Default constructor.
-	 */
-	SocketSslOptions() = default;
-
-	/**
-	 * More advanced constructor.
-	 *
-	 * @param method the method requested
-	 * @param certificate the certificate file
-	 * @param key the key file
-	 * @param verify set to true to verify
-	 */
-	SocketSslOptions(std::string certificate, std::string key, int method = TLSv1, bool verify = false)
-		: method(method)
-		, certificate(std::move(certificate))
-		, privateKey(std::move(key))
-		, verify(verify)
-	{
-	}
-};
-
-/**
- * This namespace is private.
- */
-namespace detail {
-
-/**
- * Mutex for thread-safe initialization.
- */
-extern std::mutex mutex;
-
-/**
- * Boolean that marks the SSL module initialized.
- */
-extern std::atomic<bool> initialized;
-
-/**
- * Get the appropriate method.
- */
-inline auto method(int type) noexcept
-{
-	if (type == SocketSslOptions::SSLv3)
-		return SSLv3_method();
-	if (type == SocketSslOptions::TLSv1)
-		return TLSv1_method();
-
-	throw std::invalid_argument("unknown method selected");
-}
-
-/**
- * Get the error
- */
-inline std::string error(int error)
-{
-	return ERR_reason_error_string(error);
-}
-
-/**
- * Close OpenSSL library.
- */
-void terminate();
-
-/**
- * Open SSL library.
- */
-void initialize();
-
-} // !ssl
-
-/**
- * @class SocketSsl
- * @brief SSL interface for sockets
- *
- * This class derives from SocketAbstractTcp and provide SSL support through OpenSSL.
- */
-template <typename Address>
-class SocketSsl : public SocketAbstractTcp<Address> {
-private:
-	using ContextHandle = std::unique_ptr<SSL_CTX, void (*)(SSL_CTX *)>;
-	using SslHandle = std::unique_ptr<SSL, void (*)(SSL *)>;
-
-	ContextHandle m_context{nullptr, nullptr};
-	SslHandle m_ssl{nullptr, nullptr};
-	SocketSslOptions m_options;
-
-public:
-	/**
-	 * Create a SocketSsl from an already created one.
-	 *
-	 * @param sc the standard TCP socket
-	 * @param context the context
-	 * @param ssl the ssl object
-	 */
-	explicit SocketSsl(SocketTcp<Address> sc, SSL_CTX *context, SSL *ssl);
-
-	/**
-	 * Open a SSL socket with the specified family. Automatically
-	 * use SOCK_STREAM as the type.
-	 *
-	 * @param family the family
-	 * @param protocol the protocol
-	 * @param options the options
-	 */
-	SocketSsl(int family, int protocol, SocketSslOptions options = {});
-
-	/**
-	 * Accept a SSL TCP socket.
-	 *
-	 * @param info the client information
-	 * @return the socket
-	 * @throw SocketError on error
-	 */
-	SocketSsl accept(Address &info);
-
-	/**
-	 * Connect to an end point.
-	 *
-	 * @param address the address
-	 * @throw SocketError on error
-	 */
-	void connect(const Address &address);
-
-	/**
-	 * @copydoc SocketTcp::recv
-	 */
-	unsigned recv(void *data, unsigned length) override;
-
-	/**
-	 * @copydoc SocketTcp::recv
-	 */
-	unsigned send(const void *data, unsigned length) override;
-
-	/**
-	 * Bring back send overloads.
-	 */
-	using SocketAbstractTcp<Address>::send;
-
-	/**
-	 * Bring back recv overloads;
-	 */
-	using SocketAbstractTcp<Address>::recv;
-};
-
-template <typename Address>
-SocketSsl<Address>::SocketSsl(SocketTcp<Address> sc, SSL_CTX *context, SSL *ssl)
-	: SocketAbstractTcp<Address>{sc.handle()}
-	, m_context{context, SSL_CTX_free}
-	, m_ssl{ssl, SSL_free}
-{
-#if !defined(SOCKET_NO_SSL_INIT)
-	if (!detail::initialized) {
-		detail::initialize();
-	}
-#endif
-
-	// Invalid other
-	sc.m_handle = -1;
-}
-
-template <typename Address>
-SocketSsl<Address>::SocketSsl(int family, int protocol, SocketSslOptions options)
-	: SocketAbstractTcp<Address>{family, protocol}
-	, m_context{nullptr, nullptr}
-	, m_ssl{nullptr, nullptr}
-	, m_options{std::move(options)}
-{
-#if !defined(SOCKET_NO_SSL_INIT)
-	if (!detail::initialized) {
-		detail::initialize();
-	}
-#endif
-	m_context = ContextHandle{SSL_CTX_new(detail::method(m_options.method)), SSL_CTX_free};
-	m_ssl = SslHandle{SSL_new(m_context.get()), SSL_free};
-
-	SSL_set_fd(m_ssl.get(), SocketAbstract::m_handle);
-}
-
-
-template <typename Address>
-void SocketSsl<Address>::connect(const Address &address)
-{
-	// 1. Standard connect
-	SocketAbstractTcp<Address>::standardConnect(address);
-
-	// 2. OpenSSL handshake
-	auto ret = SSL_connect(m_ssl.get());
-
-	if (ret <= 0) {
-		auto error = SSL_get_error(m_ssl.get(), ret);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError{SocketError::WouldBlockRead, "connect", "Operation in progress"};
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError{SocketError::WouldBlockWrite, "connect", "Operation in progress"};
-		} else {
-			throw SocketError{SocketError::System, "connect", detail::error(error)};
-		}
-	}
-}
-
-template <typename Address>
-SocketSsl<Address> SocketSsl<Address>::accept(Address &info)
-{
-	auto client = SocketAbstractTcp<Address>::standardAccept(info);
-	auto context = SSL_CTX_new(detail::method(m_options.method));
-
-	if (m_options.certificate.size() > 0)
-		SSL_CTX_use_certificate_file(context, m_options.certificate.c_str(), SSL_FILETYPE_PEM);
-	if (m_options.privateKey.size() > 0)
-		SSL_CTX_use_PrivateKey_file(context, m_options.privateKey.c_str(), SSL_FILETYPE_PEM);
-	if (m_options.verify && !SSL_CTX_check_private_key(context)) {
-		throw SocketError(SocketError::System, "accept", "certificate failure");
-	}
-
-	// SSL object
-	auto ssl = SSL_new(context);
-
-	SSL_set_fd(ssl, client->handle());
-
-	auto ret = SSL_accept(ssl);
-
-	if (ret <= 0) {
-		auto error = SSL_get_error(ssl, ret);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError(SocketError::WouldBlockRead, "accept", "Operation would block");
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError(SocketError::WouldBlockWrite, "accept", "Operation would block");
-		} else {
-			throw SocketError(SocketError::System, "accept", detail::error(error));
-		}
-	}
-
-	return SocketSsl(std::move(client), context, ssl);
-}
-
-template <typename Address>
-unsigned SocketSsl<Address>::recv(void *data, unsigned len)
-{
-	auto nbread = SSL_read(m_ssl.get(), data, len);
-
-	if (nbread <= 0) {
-		auto error = SSL_get_error(m_ssl.get(), nbread);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError{SocketError::WouldBlockRead, "recv", "Operation would block"};
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError{SocketError::WouldBlockWrite, "recv", "Operation would block"};
-		} else {
-			throw SocketError{SocketError::System, "recv", detail::error(error)};
-		}
-	}
-
-	return nbread;
-}
-
-template <typename Address>
-unsigned SocketSsl<Address>::send(const void *data, unsigned len)
-{
-	auto nbread = SSL_write(m_ssl.get(), data, len);
-
-	if (nbread <= 0) {
-		auto error = SSL_get_error(m_ssl.get(), nbread);
-
-		if (error == SSL_ERROR_WANT_READ) {
-			throw SocketError{SocketError::WouldBlockRead, "send", "Operation would block"};
-		} else if (error == SSL_ERROR_WANT_WRITE) {
-			throw SocketError{SocketError::WouldBlockWrite, "send", "Operation would block"};
-		} else {
-			throw SocketError{SocketError::System, "send", detail::error(error)};
-		}
-	}
-
-	return nbread;
-}
-
-#endif // !_SOCKET_SSL_NG_H_
--- a/C++/modules/Socket/Sockets.cpp	Thu Oct 22 20:00:51 2015 +0200
+++ b/C++/modules/Socket/Sockets.cpp	Thu Oct 22 21:38:28 2015 +0200
@@ -16,13 +16,10 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#if defined(_WIN32)
-#  include <atomic>
-#  include <mutex>
-#endif
-
 #include <algorithm>
+#include <atomic>
 #include <cstring>
+#include <mutex>
 
 #include "Sockets.h"
 
@@ -58,9 +55,13 @@
 
 #if defined(_WIN32)
 
+namespace {
+
 static std::mutex s_mutex;
 static std::atomic<bool> s_initialized{false};
 
+} // !namespace
+
 #endif // !_WIN32
 
 void init() noexcept
@@ -608,4 +609,40 @@
 
 #endif // !SOCKET_HAVE_KQUEUE
 
+#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();
+
+#if !defined(SOCKET_NO_AUTO_SSL_INIT)
+		atexit(finish);
+#endif // SOCKET_NO_AUTO_SSL_INIT
+	}
+}
+
+#endif // SOCKET_NO_SSL
+
+} // !ssl
+
 } // !net
--- a/C++/modules/Socket/Sockets.h	Thu Oct 22 20:00:51 2015 +0200
+++ b/C++/modules/Socket/Sockets.h	Thu Oct 22 21:38:28 2015 +0200
@@ -23,12 +23,19 @@
  * @file Sockets.h
  * @brief Portable socket abstraction
  *
+ * This file is a portable network library.
+ *
+ * ### User definable options
+ *
  * User may set the following variables before compiling these files:
  *
- * - **SOCKET_NO_AUTO_INIT**:(bool) Set to false if you don't want Socket class to
+ * - **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.
  *
- * # For Listener objects
+ * ### Options for Listener class
  *
  * Feature detection, multiple implementations may be avaible, for example,
  * Linux has poll, select and epoll.
@@ -62,12 +69,12 @@
  *
  * The preference priority is ordered from left to right.
  *
- * | System        | Backend                 |
- * |---------------|-------------------------|
- * | Linux         | epoll(7)                |
- * | *BSD          | kqueue(2)               |
- * | Windows       | poll(2), select(2)      |
- * | Mac OS X      | kqueue(2)               |
+ * | 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)
@@ -116,6 +123,12 @@
 #  include <unistd.h>
 #endif
 
+#if !defined(SOCKET_NO_SSL)
+#  include <openssl/err.h>
+#  include <openssl/evp.h>
+#  include <openssl/ssl.h>
+#endif
+
 #include <chrono>
 #include <cstdlib>
 #include <cstring>
@@ -125,6 +138,9 @@
 #include <string>
 #include <vector>
 
+/**
+ * General network namespace.
+ */
 namespace net {
 
 /*
@@ -188,6 +204,28 @@
  */
 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.
@@ -372,19 +410,26 @@
 public:
 	/**
 	 * This tries to create a socket.
+	 *
+	 * @param type the type instance
 	 */
-	inline Socket() noexcept
+	inline Socket(Type type = Type{}) noexcept
 		: Socket{Address::domain(), Type::type(), 0}
 	{
+		/* Some implementation requires more things */
+		m_type = std::move(type);
+		m_type.create(*this);
 	}
 
 	/**
 	 * Construct a socket with an already created descriptor.
 	 *
 	 * @param handle the native descriptor
+	 * @param type the type of socket implementation
 	 */
-	explicit inline Socket(Handle handle) noexcept
-		: m_handle{handle}
+	explicit inline Socket(Handle handle, Type type = Type{}) noexcept
+		: m_type(std::move(type))
+		, m_handle{handle}
 	{
 	}
 
@@ -525,12 +570,12 @@
 	/**
 	 * Bind using a native address.
 	 *
-	 * @param addr the address
-	 * @param size the size
+	 * @param address the address
+	 * @param length the size
 	 */
-	inline void bind(const sockaddr *addr, socklen_t size)
+	inline void bind(const sockaddr *address, socklen_t length)
 	{
-		if (::bind(m_handle, addr, size) == Failure) {
+		if (::bind(m_handle, address, length) == Failure) {
 			throw Error{Error::System, "bind"};
 		}
 	}
@@ -1103,35 +1148,21 @@
  * @brief Clear TCP implementation.
  */
 class Tcp {
-public:
+protected:
 	/**
-	 * Socket type.
-	 *
-	 * @return SOCK_STREAM
-	 */
-	static inline int type() noexcept
-	{
-		return SOCK_STREAM;
-	}
-
-	/**
-	 * Accept a clear client. Wrapper of accept(2).
+	 * Standard accept.
 	 *
 	 * @param sc the socket
 	 * @param address the address destination
-	 * @return the socket
+	 * @param length the address initial length
+	 * @return the client handle
 	 * @throw Error on errors
 	 */
-	template <typename Address>
-	Socket<Address, Tcp> accept(Socket<Address, Tcp> &sc, Address &address)
+	Handle accept(Handle sc, sockaddr *address, socklen_t *length)
 	{
-		Handle handle;
-		sockaddr_storage storage;
-		socklen_t addrlen = sizeof (sockaddr_storage);
+		Handle client = ::accept(sc, address, length);
 
-		handle = ::accept(sc.handle(), reinterpret_cast<sockaddr *>(&storage), &addrlen);
-
-		if (handle == Invalid) {
+		if (client == Invalid) {
 #if defined(_WIN32)
 			int error = WSAGetLastError();
 
@@ -1149,22 +1180,19 @@
 #endif
 		}
 
-		address = Address{&storage, addrlen};
-
-		return Socket<Address, Tcp>{handle};
+		return client;
 	}
 
 	/**
-	 * Connect to the end point. Wrapper for connect(2).
+	 * Standard connect.
 	 *
 	 * @param sc the socket
 	 * @param address the address
-	 * @throw Error on errors
+	 * @param length the length
 	 */
-	template <typename Address>
-	void connect(Socket<Address, Tcp> &sc, const Address &address)
+	void connect(Handle sc, const sockaddr *address, socklen_t length)
 	{
-		if (::connect(sc.handle(), address.address(), address.length()) == Failure) {
+		if (::connect(sc, address, length) == Failure) {
 			/*
 			 * Determine if the error comes from a non-blocking connect that cannot be
 			 * accomplished yet.
@@ -1187,6 +1215,58 @@
 #endif
 	}
 
+public:
+	/**
+	 * Socket type.
+	 *
+	 * @return SOCK_STREAM
+	 */
+	static inline int type() noexcept
+	{
+		return SOCK_STREAM;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	template <typename Address>
+	inline void create(Socket<Address, Tcp> &) noexcept
+	{
+		/* No-op */
+	}
+
+	/**
+	 * Accept a clear client. Wrapper of accept(2).
+	 *
+	 * @param sc the socket
+	 * @param address the address destination
+	 * @return the socket
+	 * @throw Error on errors
+	 */
+	template <typename Address>
+	Socket<Address, Tcp> accept(Socket<Address, Tcp> &sc, Address &address)
+	{
+		sockaddr_storage ss;
+		socklen_t length = sizeof (sockaddr_storage);
+		Handle handle = accept(sc.handle(), reinterpret_cast<sockaddr *>(&ss), &length);
+		address = Address{&ss, length};
+
+		return Socket<Address, Tcp>{handle};
+	}
+
+	/**
+	 * Connect to the end point. Wrapper for connect(2).
+	 *
+	 * @param sc the socket
+	 * @param address the address
+	 * @throw Error on errors
+	 */
+	template <typename Address>
+	void connect(Socket<Address, Tcp> &sc, const Address &address)
+	{
+		connect(sc.handle(), address.address(), address.length());
+	}
+
 	/**
 	 * Receive data. Wrapper of recv(2).
 	 *
@@ -1283,6 +1363,15 @@
 	}
 
 	/**
+	 * Do nothing.
+	 */
+	template <typename Address>
+	inline void create(Socket<Address, Udp> &) noexcept
+	{
+		/* No-op */
+	}
+
+	/**
 	 * Receive data from an end point.
 	 *
 	 * @param sc the socket
@@ -1365,6 +1454,237 @@
 
 /* }}} */
 
+#if !defined(SOCKET_NO_SSL)
+
+/**
+ * @class Tls
+ * @brief OpenSSL secure layer for TCP
+ */
+class Tls : private Tcp {
+public:
+	/**
+	 * OpenSSL method to use.
+	 */
+	enum Method {
+		Tlsv1,	//!< Tlsv1 (recommended)
+		Sslv3	//!< SSL v3
+	};
+
+private:
+	using Context = std::unique_ptr<SSL_CTX, void (*)(SSL_CTX *)>;
+	using Ssl = std::unique_ptr<SSL, void (*)(SSL *)>;
+
+	/* OpenSSL objects */
+	Context m_context{nullptr, nullptr};
+	Ssl m_ssl{nullptr, nullptr};
+
+	/* Parameters */
+	Method m_method;
+	std::string m_key;
+	std::string m_certificate;
+	bool m_verify{false};
+
+	Tls(Context context, Ssl ssl)
+		: m_context{std::move(context)}
+		, m_ssl{std::move(ssl)}
+	{
+	}
+
+	inline std::string error(int error)
+	{
+		return ERR_reason_error_string(error);
+	}
+
+public:
+	/**
+	 * @copydoc Tcp::type
+	 */
+	static inline int type() noexcept
+	{
+		return SOCK_STREAM;
+	}
+
+	/**
+	 * Empty TLS constructor.
+	 */
+	Tls()
+	{
+#if !defined(SOCKET_NO_SSL_AUTO_INIT)
+		ssl::init();
+#endif
+	}
+
+	/**
+	 * Construct a specific Tls object.
+	 *
+	 * @param method the method to use
+	 * @param verify true to verify the certificate
+	 * @param key the private key
+	 * @param certificate the certificate file
+	 */
+	Tls(Method method, bool verify = true, std::string key = "", std::string certificate = "")
+		: Tls()
+	{
+		m_method = method;
+		m_verify = verify;
+		m_key = std::move(key);
+		m_certificate = std::move(certificate);
+	}
+
+	/**
+	 * Initialize the SSL objects after have created.
+	 *
+	 * @param sc the socket
+	 */
+	template <typename Address>
+	inline void create(Socket<Address, Tls> &sc)
+	{
+		auto method = (m_method == Tlsv1) ? TLSv1_method() : SSLv3_method();
+
+		m_context = {SSL_CTX_new(method), SSL_CTX_free};
+		m_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, "accept", "certificate failure");
+		}
+	}
+
+	/**
+	 * Connect to a secure host.
+	 *
+	 * @param sc the socket
+	 * @param address the address
+	 * @throw Error on errors
+	 */
+	template <typename Address>
+	void connect(Socket<Address, Tls> &sc, const Address &address)
+	{
+		// 1. Standard connect
+		Tcp::connect(sc.handle(), address.address(), address.length());
+
+		// 2. OpenSSL handshake
+		auto ret = SSL_connect(m_ssl.get());
+
+		if (ret <= 0) {
+			auto no = SSL_get_error(m_ssl.get(), ret);
+
+			if (no == SSL_ERROR_WANT_READ) {
+				throw Error{Error::WouldBlockRead, "connect", "Operation in progress"};
+			} else if (no == SSL_ERROR_WANT_WRITE) {
+				throw Error{Error::WouldBlockWrite, "connect", "Operation in progress"};
+			} else {
+				throw Error{Error::System, "connect", error(no)};
+			}
+		}
+	}
+
+	/**
+	 * Accept a secure client.
+	 *
+	 * @param sc the socket
+	 * @param address the address destination
+	 * @return the client
+	 */
+	template <typename Address>
+	Socket<Address, Tls> accept(Socket<Address, Tls> &sc, Address &address)
+	{
+		/* 1. Do standard accept */
+		sockaddr_storage ss;
+		socklen_t length = sizeof (sockaddr_storage);
+		Handle handle = Tcp::accept(sc.handle(), reinterpret_cast<sockaddr *>(&ss), &length);
+		address = Address{&ss, length};
+
+		/* 2. Create OpenSSL related stuff */
+		auto method = (m_method == Tlsv1) ? TLSv1_method() : SSLv3_method();
+		auto context = Context{SSL_CTX_new(method), SSL_CTX_free};
+		auto ssl = Ssl{SSL_new(context.get()), SSL_free};
+
+		SSL_set_fd(ssl.get(), handle);
+
+		/* 3. Do the OpenSSL accept */
+		auto ret = SSL_accept(ssl.get());
+
+		if (ret <= 0) {
+			auto no = SSL_get_error(ssl.get(), ret);
+
+			if (no == SSL_ERROR_WANT_READ) {
+				throw Error(Error::WouldBlockRead, "accept", "Operation would block");
+			} else if (no == SSL_ERROR_WANT_WRITE) {
+				throw Error(Error::WouldBlockWrite, "accept", "Operation would block");
+			} else {
+				throw Error(Error::System, "accept", error(no));
+			}
+		}
+
+		return Socket<Address, Tls>{handle, Tls{std::move(context), std::move(ssl)}};
+	}
+
+	/**
+	 * Receive some secure data.
+	 *
+	 * @param data the destination
+	 * @param len the buffer length
+	 * @return the number of bytes read
+	 * @throw Error on errors
+	 */
+	template <typename Address>
+	unsigned recv(Socket<Address, Tls> &, void *data, unsigned len)
+	{
+		auto nbread = SSL_read(m_ssl.get(), data, len);
+
+		if (nbread <= 0) {
+			auto no = SSL_get_error(m_ssl.get(), nbread);
+
+			if (no == SSL_ERROR_WANT_READ) {
+				throw Error{Error::WouldBlockRead, "recv", "Operation would block"};
+			} else if (no == SSL_ERROR_WANT_WRITE) {
+				throw Error{Error::WouldBlockWrite, "recv", "Operation would block"};
+			} else {
+				throw Error{Error::System, "recv", error(no)};
+			}
+		}
+
+		return nbread;
+	}
+
+	/**
+	 * Send some data.
+	 *
+	 * @param data the data to send
+	 * @param len the buffer length
+	 * @return the number of bytes sent
+	 * @throw Error on errors
+	 */
+	template <typename Address>
+	unsigned send(Socket<Address, Tls> &, const void *data, unsigned len)
+	{
+		auto nbread = SSL_write(m_ssl.get(), data, len);
+
+		if (nbread <= 0) {
+			auto no = SSL_get_error(m_ssl.get(), nbread);
+
+			if (no == SSL_ERROR_WANT_READ) {
+				throw Error{Error::WouldBlockRead, "send", "Operation would block"};
+			} else if (no == SSL_ERROR_WANT_WRITE) {
+				throw Error{Error::WouldBlockWrite, "send", "Operation would block"};
+			} else {
+				throw Error{Error::System, "send", error(no)};
+			}
+		}
+
+		return nbread;
+	}
+};
+
+#endif // !SOCKET_NO_SSL
+
 /* }}} */
 
 /*
@@ -1389,6 +1709,16 @@
 template <typename Address>
 using SocketUdp = Socket<Address, Udp>;
 
+#if !defined(SOCKET_NO_SSL)
+
+/**
+ * Helper to create OpenSSL TCP sockets.
+ */
+template <typename Address>
+using SocketTls = Socket<Address, Tls>;
+
+#endif
+
 /* }}} */
 
 /*
@@ -1576,7 +1906,7 @@
  * This class is implemented using a bridge pattern to allow different uses
  * of listener implementation.
  *
- * You should not reinstanciate a new SocketListener at each iteartion of your
+ * 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.
  *
@@ -1584,10 +1914,10 @@
  *
  * To implement the backend, the following functions must be available:
  *
- * # Set
+ * ### Set
  *
  * @code
- * void set(const ListenerTable &, const Handle &sc, int flags, bool add);
+ * void set(const ListenerTable &, Handle sc, int flags, bool add);
  * @endcode
  *
  * This function, takes the socket to be added and the flags. The flags are
@@ -1598,10 +1928,10 @@
  * 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
+ * ### Unset
  *
  * @code
- * void unset(const ListenerTable &, const Handle &sc, int flags, bool remove);
+ * void unset(const ListenerTable &, Handle sc, int flags, bool remove);
  * @endcode
  *
  * Like set, this function is only called if the flags are actually set and will
@@ -1610,16 +1940,16 @@
  * 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
+ * ### Wait
  *
  * @code
  * std::vector<ListenerStatus> wait(const ListenerTable &, int ms);
- * @encode
+ * @endcode
  *
  * Wait for the sockets to be ready with the specified milliseconds. Must return a list of ListenerStatus,
  * may throw any exceptions.
  *
- * # Name
+ * ### Name
  *
  * @code
  * inline const char *name() const noexcept
@@ -1711,7 +2041,7 @@
 	 *
 	 * @param sc the socket
 	 * @param flags (may be OR'ed)
-	 * @throw SocketError if the backend failed to set
+	 * @throw Error if the backend failed to set
 	 */
 	void set(Handle sc, int flags)
 	{
@@ -1783,7 +2113,7 @@
 			if (removal) {
 				m_table.erase(it);
 			} else {
-				it->second.second &= ~(flags);
+				it->second &= ~(flags);
 			}
 		}
 	}
--- a/C++/tests/Socket/main.cpp	Thu Oct 22 20:00:51 2015 +0200
+++ b/C++/tests/Socket/main.cpp	Thu Oct 22 21:38:28 2015 +0200
@@ -264,8 +264,6 @@
 	ASSERT_EQ(0U, listener.size());
 }
 
-#if 0
-
 /* --------------------------------------------------------
  * Listener: unset / remove functions
  * -------------------------------------------------------- */
@@ -397,7 +395,7 @@
 
 class ListenerTest : public testing::Test {
 protected:
-	Listener<backend::Select> m_listener;
+	Listener<Select> m_listener;
 	SocketTcp<Ipv4> m_masterTcp;
 	SocketTcp<Ipv4> m_clientTcp;
 
@@ -406,8 +404,6 @@
 
 public:
 	ListenerTest()
-		: m_masterTcp{AF_INET, 0}
-		, m_clientTcp{AF_INET, 0}
 	{
 		m_masterTcp.set(SOL_SOCKET, SO_REUSEADDR, 1);
 		m_masterTcp.bind(Ipv4{"*", 16000});
@@ -429,7 +425,7 @@
 {
 	m_tserver = std::thread([this] () {
 		try {
-			m_listener.set(m_masterTcp, FlagRead);
+			m_listener.set(m_masterTcp.handle(), FlagRead);
 			m_listener.wait();
 			m_masterTcp.accept();
 			m_masterTcp.close();
@@ -449,7 +445,7 @@
 {
 	m_tserver = std::thread([this] () {
 		try {
-			m_listener.set(m_masterTcp, FlagRead);
+			m_listener.set(m_masterTcp.handle(), FlagRead);
 			m_listener.wait();
 
 			auto sc = m_masterTcp.accept();
@@ -474,8 +470,8 @@
 
 class NonBlockingConnectTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server{AF_INET, 0};
-	SocketTcp<Ipv4> m_client{AF_INET, 0};
+	SocketTcp<Ipv4> m_server;
+	SocketTcp<Ipv4> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -501,8 +497,8 @@
 
 class TcpAcceptTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server{AF_INET, 0};
-	SocketTcp<Ipv4> m_client{AF_INET, 0};
+	SocketTcp<Ipv4> m_server;
+	SocketTcp<Ipv4> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -530,8 +526,8 @@
 
 class TcpRecvTest : public testing::Test {
 protected:
-	SocketTcp<Ipv4> m_server{AF_INET, 0};
-	SocketTcp<Ipv4> m_client{AF_INET, 0};
+	SocketTcp<Ipv4> m_server;
+	SocketTcp<Ipv4> m_client;
 
 	std::thread m_tserver;
 	std::thread m_tclient;
@@ -576,15 +572,14 @@
 
 class SslTest : public testing::Test {
 protected:
-	SocketSsl<Ipv4> client{AF_INET, 0};
+	SocketTls<Ipv4> client;
 };
 
 TEST_F(SslTest, connect)
 {
 	try {
 		client.connect(Ipv4{"google.fr", 443});
-		client.close();
-	} catch (const SocketError &error) {
+	} catch (const Error &error) {
 		FAIL() << error.what();
 	}
 }
@@ -599,13 +594,13 @@
 		std::string content = msg.substr(0, 18);
 
 		ASSERT_EQ("HTTP/1.0 302 Found", content);
-
-		client.close();
-	} catch (const SocketError &error) {
+	} catch (const Error &error) {
 		FAIL() << error.what();
 	}
 }
 
+#if 0
+
 /* --------------------------------------------------------
  * Operators
  * -------------------------------------------------------- */