changeset 276:05f0a3e09cbf

Socket: * Improve exception message by adding the function prefix * Defaulted sockets are now initialized to INVALID_SOCKET * Socket::get() is more secure and do not require default value * Improved unit tests
author David Demelier <markand@malikania.fr>
date Thu, 23 Oct 2014 17:08:13 +0200
parents d945fa44f601
children b544a599e08e
files C++/Socket.cpp C++/Socket.h C++/SocketAddress.cpp C++/SocketListener.cpp C++/Tests/Sockets/main.cpp
diffstat 5 files changed, 532 insertions(+), 348 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Socket.cpp	Thu Oct 23 12:25:43 2014 +0200
+++ b/C++/Socket.cpp	Thu Oct 23 17:08:13 2014 +0200
@@ -27,19 +27,44 @@
 
 namespace error {
 
+Timeout::Timeout(std::string func)
+	: m_error(func + ": Timeout exception")
+{
+}
+
 const char *Timeout::what() const noexcept
 {
-	return "Timeout exception";
+	return m_error.c_str();
+}
+
+InProgress::InProgress(std::string func)
+	: m_error(func + ": Operation in progress")
+{
 }
 
 const char *InProgress::what() const noexcept
 {
-	return "Operation in progress";
+	return m_error.c_str();
+}
+
+WouldBlock::WouldBlock(std::string func)
+	: m_error(func + ": Operation would block")
+{
 }
 
 const char *WouldBlock::what() const noexcept
 {
-	return "Operation would block";
+	return m_error.c_str();
+}
+
+Failure::Failure(std::string func, std::string message)
+	: m_error(func + ": " + message)
+{
+}
+
+const char *Failure::what() const noexcept
+{
+	return m_error.c_str();
 }
 
 } // !error
@@ -133,7 +158,7 @@
 	auto addrlen = addr.length();
 
 	if (::bind(s.handle(), (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("bind", Socket::syserror());
 }
 
 void Standard::connect(Socket &s, const SocketAddress &addr)
@@ -148,14 +173,14 @@
 		 */
 #if defined(_WIN32)
 		if (WSAGetLastError() == WSAEWOULDBLOCK)
-			throw error::InProgress();
+			throw error::InProgress("connect");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("connect", Socket::syserror());
 #else
 		if (errno == EINPROGRESS)
-			throw error::InProgress();
+			throw error::InProgress("connect");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("connect", Socket::syserror());
 #endif
 	}
 }
@@ -172,7 +197,7 @@
 	handle = ::accept(s.handle(), (sockaddr *)&address, &addrlen);
 
 	if (handle == INVALID_SOCKET)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("accept", Socket::syserror());
 
 	// Usually accept works only with SOCK_STREAM
 	info = SocketAddress(address, addrlen);
@@ -183,7 +208,7 @@
 void Standard::listen(Socket &s, int max)
 {
 	if (::listen(s.handle(), max) == SOCKET_ERROR)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("listen", Socket::syserror());
 }
 
 unsigned Standard::recv(Socket &s, void *data, unsigned dataLen)
@@ -194,14 +219,14 @@
 	if (nbread == SOCKET_ERROR) {
 #if defined(_WIN32)
 		if (WSAGetLastError() == WSAEWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("recv");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("recv", Socket::syserror());
 #else
 		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("recv");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("recv", Socket::syserror());
 #endif
 	}
 
@@ -216,14 +241,14 @@
 	if (nbsent == SOCKET_ERROR) {
 #if defined(_WIN32)
 		if (WSAGetLastError() == WSAEWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("send");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("send", Socket::syserror());
 #else
 		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("send");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("send", Socket::syserror());
 #endif
 	}
 
@@ -246,14 +271,14 @@
 	if (nbread == SOCKET_ERROR) {
 #if defined(_WIN32)
 		if (WSAGetLastError() == WSAEWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("recvfrom");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("recvfrom", Socket::syserror());
 #else
 		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("recvfrom");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("recvfrom", Socket::syserror());
 #endif
 	}
 
@@ -268,14 +293,14 @@
 	if (nbsent == SOCKET_ERROR) {
 #if defined(_WIN32)
 		if (WSAGetLastError() == WSAEWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("sendto");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("sendto", Socket::syserror());
 #else
 		if (errno == EAGAIN || errno == EWOULDBLOCK)
-			throw error::WouldBlock();
+			throw error::WouldBlock("sendto");
 
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("sendto", Socket::syserror());
 #endif
 	}
 
@@ -297,7 +322,7 @@
 	m_handle = socket(domain, type, protocol);
 
 	if (m_handle == INVALID_SOCKET)
-		throw error::Failure(syserror());
+		throw error::Failure("socket", syserror());
 }
 
 Socket::Socket(Handle handle)
@@ -325,12 +350,12 @@
 		flags |= O_NONBLOCK;
 
 	if (fcntl(m_handle, F_SETFL, flags) == -1)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("blockMode", Socket::syserror());
 #else
 	unsigned long flags = (block) ? 0 : 1;
 
 	if (ioctlsocket(m_handle, FIONBIO, &flags) == SOCKET_ERROR)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("blockMode", Socket::syserror());
 #endif
 }
 
--- a/C++/Socket.h	Thu Oct 23 12:25:43 2014 +0200
+++ b/C++/Socket.h	Thu Oct 23 17:08:13 2014 +0200
@@ -19,6 +19,7 @@
 #ifndef _SOCKET_H_
 #define _SOCKET_H_
 
+#include <cstring>
 #include <exception>
 #include <memory>
 #include <string>
@@ -60,7 +61,11 @@
  * Usually thrown on timeout in SocketListener::select.
  */
 class Timeout final : public std::exception {
+private:
+	std::string m_error;
+
 public:
+	Timeout(std::string func);
 	const char *what() const noexcept override;
 };
 
@@ -71,7 +76,11 @@
  * Usually thrown in a non-blocking connect call.
  */
 class InProgress final : public std::exception {
+private:
+	std::string m_error;
+
 public:
+	InProgress(std::string func);
 	const char *what() const noexcept override;
 };
 
@@ -82,7 +91,11 @@
  * Usually thrown in a non-blocking connect send or receive.
  */
 class WouldBlock final : public std::exception {
+private:
+	std::string m_error;
+
 public:
+	WouldBlock(std::string func);
 	const char *what() const noexcept override;
 };
 
@@ -94,18 +107,11 @@
  */
 class Failure final : public std::exception {
 private:
-	std::string m_message;
+	std::string m_error;
 
 public:
-	inline Failure(std::string message)
-		: m_message(std::move(message))
-	{
-	}
-
-	inline const char *what() const noexcept override
-	{
-		return m_message.c_str();
-	}
+	Failure(std::string func, std::string message);
+	const char *what() const noexcept override;
 };
 
 } // !error
@@ -240,8 +246,8 @@
 	using Iface	= std::shared_ptr<SocketInterface>;
 
 protected:
-	Iface	m_interface;		//!< the interface
-	Handle	m_handle;		//!< the socket shared pointer
+	Iface	m_interface;				//!< the interface
+	Handle	m_handle { INVALID_SOCKET };		//!< the socket shared pointer
 
 public:
 	/**
@@ -316,7 +322,7 @@
 	void set(int level, int name, const Argument &arg)
 	{
 		if (setsockopt(m_handle, level, name, (Socket::ConstArg)&arg, sizeof (arg)) == SOCKET_ERROR)
-			throw error::Failure(syserror());
+			throw error::Failure("set", syserror());
 	}
 
 	/**
@@ -324,20 +330,20 @@
 	 *
 	 * @param level the setting level
 	 * @param name the name
-	 * @param def the default value
-	 * @note since getsockopt return the real size of the argument, it is recommended to set integer and such to 0
 	 * @throw error::Failure on error
 	 */
 	template <typename Argument>
-	Argument get(int level, int name, const Argument &def = Argument())
+	Argument get(int level, int name)
 	{
-		Argument arg(def);
-		socklen_t size = sizeof (arg);
+		Argument desired, result{};
+		socklen_t size = sizeof (result);
 
-		if (getsockopt(m_handle, level, name, (Socket::Arg)&level, &size) == SOCKET_ERROR)
-			throw error::Failure(syserror());
+		if (getsockopt(m_handle, level, name, (Socket::Arg)&desired, &size) == SOCKET_ERROR)
+			throw error::Failure("get", syserror());
 
-		return arg;
+		std::memcpy(&result, &desired, size);
+
+		return result;
 	}
 
 	/**
--- a/C++/SocketAddress.cpp	Thu Oct 23 12:25:43 2014 +0200
+++ b/C++/SocketAddress.cpp	Thu Oct 23 17:08:13 2014 +0200
@@ -56,7 +56,7 @@
 
 		auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
 		if (error != 0)
-			throw std::runtime_error(gai_strerror(error));
+			throw error::Failure("getaddrinfo", gai_strerror(error));
 
 		std::memcpy(&m_addr, res->ai_addr, res->ai_addrlen);
 		m_addrlen = res->ai_addrlen;
--- a/C++/SocketListener.cpp	Thu Oct 23 12:25:43 2014 +0200
+++ b/C++/SocketListener.cpp	Thu Oct 23 17:08:13 2014 +0200
@@ -133,7 +133,7 @@
 	auto result = selectMultiple(ms);
 
 	if (result.size() == 0)
-		throw error::Failure("No socket found");
+		throw error::Failure("select", "No socket found");
 
 	return result[0];
 }
@@ -150,9 +150,9 @@
 
 	auto error = ::select(m_max + 1, &m_readset, &m_writeset, NULL, towait);
 	if (error == SOCKET_ERROR)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("select", Socket::syserror());
 	if (error == 0)
-		throw error::Timeout();
+		throw error::Timeout("select");
 
 	std::vector<SocketStatus> sockets;
 	for (auto &c : m_lookup)
@@ -221,7 +221,6 @@
 
 void PollMethod::add(Socket &&s, SocketDirection direction)
 {
-	bool found(false);
 	auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const auto &pfd) { return pfd.fd == s.handle(); });
 
 	// If found, add the new direction, otherwise add a new socket
@@ -271,24 +270,24 @@
 {
 	auto result = poll(m_fds.data(), m_fds.size(), ms);
 	if (result == 0)
-		throw error::Timeout();
+		throw error::Timeout("select");
 	if (result < 0)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("select", Socket::syserror());
 
 	for (auto &fd : m_fds)
 		if (fd.revents != 0)
 			return { m_lookup[fd.fd], todirection(fd.revents) };
 
-	throw error::Failure("no socket found");
+	throw error::Failure("select", "No socket found");
 }
 
 std::vector<SocketStatus> PollMethod::selectMultiple(int ms)
 {
 	auto result = poll(m_fds.data(), m_fds.size(), ms);
 	if (result == 0)
-		throw error::Timeout();
+		throw error::Timeout("select");
 	if (result < 0)
-		throw error::Failure(Socket::syserror());
+		throw error::Failure("select", Socket::syserror());
 
 	std::vector<SocketStatus> sockets;
 	for (auto &fd : m_fds)
--- a/C++/Tests/Sockets/main.cpp	Thu Oct 23 12:25:43 2014 +0200
+++ b/C++/Tests/Sockets/main.cpp	Thu Oct 23 17:08:13 2014 +0200
@@ -1,4 +1,23 @@
+/*
+ * main.cpp -- test sockets
+ *
+ * Copyright (c) 2013, 2014 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>
@@ -19,16 +38,21 @@
 
 TEST(Misc, set)
 {
+	Socket s;
+
 	try {
-		Socket s(AF_INET6, SOCK_STREAM, 0);
+		s = { AF_INET6, SOCK_STREAM, 0 };
+
+		s.set(IPPROTO_IPV6, IPV6_V6ONLY, 0);
+		ASSERT_EQ(0, s.get<int>(IPPROTO_IPV6, IPV6_V6ONLY));
 
-		s.set(IPPROTO_IPV6, IPV6_V6ONLY, false);
-		ASSERT_FALSE(s.get<bool>(IPPROTO_IPV6, IPV6_V6ONLY));
+		s.set(IPPROTO_IPV6, IPV6_V6ONLY, 1);
+		ASSERT_EQ(1, s.get<int>(IPPROTO_IPV6, IPV6_V6ONLY));
+	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
+	}
 
-		s.set(IPPROTO_IPV6, IPV6_V6ONLY, true);
-		ASSERT_TRUE(s.get<bool>(IPPROTO_IPV6, IPV6_V6ONLY));
-	} catch (const std::exception &ex) {
-	}
+	s.close();
 }
 
 /* --------------------------------------------------------
@@ -37,9 +61,11 @@
 
 TEST(ListenerMethodSelect, add)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Select);
 
 		listener.add(s, SocketDirection::Read);
@@ -47,14 +73,20 @@
 
 		ASSERT_EQ(2UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 TEST(ListenerMethodSelect, remove)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Select);
 
 		listener.add(s, SocketDirection::Read);
@@ -64,7 +96,11 @@
 
 		ASSERT_EQ(0UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 /*
@@ -73,9 +109,11 @@
  */
 TEST(ListenerMethodSelect, inOut)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Select);
 
 		listener.add(s, SocketDirection::Read | SocketDirection::Write);
@@ -101,13 +139,19 @@
 
 		ASSERT_EQ(0UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 TEST(ListenerMethodSelect, addSame)
 {
+	Socket s;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Select);
 
 		listener.add(s, SocketDirection::Read);
@@ -135,7 +179,10 @@
 			ASSERT_EQ(0x03, static_cast<int>(dir));
 		});
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
 }
 
 /* --------------------------------------------------------
@@ -144,9 +191,11 @@
 
 TEST(ListenerMethodPoll, add)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Poll);
 
 		listener.add(s, SocketDirection::Read);
@@ -154,14 +203,20 @@
 
 		ASSERT_EQ(2UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 TEST(ListenerMethodPoll, remove)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Poll);
 
 		listener.add(s, SocketDirection::Read);
@@ -171,14 +226,20 @@
 
 		ASSERT_EQ(0UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 TEST(ListenerMethodPoll, inOut)
 {
+	Socket s, s2;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
+		s2 = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Poll);
 
 		listener.add(s, SocketDirection::Read | SocketDirection::Write);
@@ -204,13 +265,19 @@
 
 		ASSERT_EQ(0UL, listener.size());
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
+	s2.close();
 }
 
 TEST(ListenerMethodPoll, addSame)
 {
+	Socket s;
+
 	try {
-		Socket s(AF_INET, SOCK_STREAM, 0);
+		s = { AF_INET, SOCK_STREAM, 0 };
 		SocketListener listener(SocketMethod::Poll);
 
 		listener.add(s, SocketDirection::Read);
@@ -238,7 +305,10 @@
 			ASSERT_EQ(0x03, static_cast<int>(dir));
 		});
 	} catch (const std::exception &ex) {
+		std::cerr << "warning: " << ex.what() << std::endl;
 	}
+
+	s.close();
 }
 
 /* --------------------------------------------------------
@@ -247,135 +317,116 @@
 
 TEST(Listener, connection)
 {
+	std::thread server([] () {
+		Socket s;
+		SocketListener listener;
+
+		try {
+			s = { AF_INET, SOCK_STREAM, 0 };
+
+			s.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			s.bind(Internet{"*", 10000, AF_INET});
+			s.listen(8);
+
+			listener.add(s, SocketDirection::Read);
+
+			auto client = listener.select(10s);
+
+			ASSERT_TRUE(client.direction == SocketDirection::Read);
+			ASSERT_TRUE(client.socket == s);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		s.close();
+	});
+
 	std::thread client([] () {
 		Socket client;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 
 		try {
-			client = Socket(AF_INET, SOCK_STREAM, 0);
-			client.connect(Internet("localhost", 10000, AF_INET));
+			client = { AF_INET, SOCK_STREAM, 0 };
+			client.connect(Internet{"localhost", 10000, AF_INET});
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		client.close();
 	});
 
-	Socket s;
-	SocketListener listener;
-
-	try {
-		s = Socket(AF_INET, SOCK_STREAM, 0);
-
-		s.bind(Internet("localhost", 10000, AF_INET));
-		s.listen(8);
-
-		listener.add(s, SocketDirection::Read);
-
-		auto client = listener.select(10s);
-
-		ASSERT_TRUE(client.direction == SocketDirection::Read);
-		ASSERT_TRUE(client.socket == s);
-	} catch (const std::exception &ex) {
-	}
-
-	s.close();
+	server.join();
 	client.join();
 }
 
 TEST(Listener, connectionAndRead)
 {
-	std::thread thread([] () {
+	std::thread server([] () {
+		Socket s;
+		SocketListener listener;
+
+		try {
+			s = { AF_INET, SOCK_STREAM, 0 };
+
+			s.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			s.bind(Internet("*", 10000, AF_INET));
+			s.listen(8);
+
+			// Read for master
+			listener.add(s, SocketDirection::Read);
+
+			auto result = listener.select(10s);
+
+			ASSERT_TRUE(result.direction == SocketDirection::Read);
+			ASSERT_TRUE(result.socket == s);
+
+			// Wait for client
+			auto client = s.accept();
+			listener.add(client, SocketDirection::Read);
+
+			result = listener.select(10s);
+
+			ASSERT_TRUE(result.direction == SocketDirection::Read);
+			ASSERT_TRUE(result.socket == client);
+
+			char data[512];
+			auto nb = client.recv(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			client.close();
+			ASSERT_STREQ("hello world", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		s.close();
+	});
+
+	std::thread client([] () {
 		Socket client;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 
 		try {
 			client = Socket(AF_INET, SOCK_STREAM, 0);
 			client.connect(Internet("localhost", 10000, AF_INET));
 			client.send("hello world");
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		client.close();
 	});
 
-	Socket s;
-	SocketListener listener;
-
-	try {
-		s = Socket(AF_INET, SOCK_STREAM, 0);
-
-		s.bind(Internet("localhost", 10000, AF_INET));
-		s.listen(8);
-
-		// Read for master
-		listener.add(s, SocketDirection::Read);
-
-		auto result = listener.select(10s);
-
-		ASSERT_TRUE(result.direction == SocketDirection::Read);
-		ASSERT_TRUE(result.socket == s);
-
-		// Wait for client
-		auto client = s.accept();
-		listener.add(client, SocketDirection::Read);
-
-		result = listener.select(10s);
-
-		ASSERT_TRUE(result.direction == SocketDirection::Read);
-		ASSERT_TRUE(result.socket == client);
-
-		char data[512];
-		auto nb = client.recv(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		client.close();
-		ASSERT_STREQ("hello world", data);
-	} catch (const std::exception &ex) {
-	}
-
-	s.close();
-	thread.join();
+	server.join();
+	client.join();
 }
 
 TEST(Listener, bigData)
 {
-	auto producer = [] () {
-		std::string data;
-
-		data.reserve(9000000);
-		for (int i = 0; i < 9000000; ++i)
-			data.push_back('a');
-
-		data.push_back('\r');
-		data.push_back('\n');
-
-		std::this_thread::sleep_for(3s);
-
-		Socket client;
-		SocketListener listener;
-
-		try {
-			client = Socket(AF_INET, SOCK_STREAM, 0);
-
-			client.connect(Internet("localhost", 10000, AF_INET));
-			client.blockMode(false);
-			listener.add(client, SocketDirection::Write);
-
-			while (data.size() > 0) {
-				auto s = listener.select(30s).socket;
-				auto nb = s.send(data.data(), data.size());
-				data.erase(0, nb);
-			}
-		} catch (const std::exception &ex) {
-		}
-
-		client.close();
-	};
-
-	auto consumer = [] () {
+	std::thread server([] () {
 		std::ostringstream out;
 
 		Socket server;
@@ -383,9 +434,10 @@
 		bool finished(false);
 
 		try {
-			server = Socket(AF_INET, SOCK_STREAM, 0);
+			server = { AF_INET, SOCK_STREAM, 0 };
 
-			server.bind(Internet("*", 10000, AF_INET));
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Internet{"*", 10000, AF_INET});
 			server.listen(10);
 			listener.add(server, SocketDirection::Read);
 
@@ -409,16 +461,48 @@
 
 			ASSERT_EQ(9000002UL, out.str().size());
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		server.close();
-	};
+	});
+
+	std::thread client([] () {
+		std::string data;
+
+		data.reserve(9000000);
+		for (int i = 0; i < 9000000; ++i)
+			data.push_back('a');
+
+		data.push_back('\r');
+		data.push_back('\n');
+
+		std::this_thread::sleep_for(500ms);
+
+		Socket client;
+		SocketListener listener;
 
-	std::thread tconsumer(consumer);
-	std::thread tproducer(producer);
+		try {
+			client = { AF_INET, SOCK_STREAM, 0 };
+
+			client.connect(Internet{"localhost", 10000, AF_INET});
+			client.blockMode(false);
+			listener.add(client, SocketDirection::Write);
 
-	tconsumer.join();
-	tproducer.join();
+			while (data.size() > 0) {
+				auto s = listener.select(30s).socket;
+				auto nb = s.send(data.data(), data.size());
+				data.erase(0, nb);
+			}
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		client.close();
+	});
+
+	server.join();
+	client.join();
 }
 
 /* --------------------------------------------------------
@@ -431,50 +515,60 @@
 	 * Normally, 3 sockets added for writing should be marked ready immediately
 	 * as there are no data being currently queued to be sent.
 	 */
-	std::thread tester([] () {
+	std::thread server([] () {
+		Socket master;
+
 		try {
 			SocketListener masterListener, clientListener;
-			Socket master(AF_INET, SOCK_STREAM, 0);
+			master = { AF_INET, SOCK_STREAM, 0 };
 
-			master.bind(Internet("*", 10000, AF_INET));
+			master.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			master.bind(Internet{"*", 10000, AF_INET});
 			master.listen(8);
 
 			masterListener.add(master, SocketDirection::Read);
 
 			while (clientListener.size() != 3) {
-				masterListener.select(3s);
+				masterListener.select(500ms);
 				clientListener.add(master.accept(), SocketDirection::Write);
 			}
 
 			// Now do the test of writing
-			auto result = clientListener.selectMultiple(3s);
+			auto result = clientListener.selectMultiple(1s);
 			ASSERT_EQ(3UL, result.size());
 
 			clientListener.list([] (auto s, auto) {
 				s.close();
 			});
-	
-			master.close();
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
+
+		master.close();
 	});
-	
-	try {
-		Socket s1(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
-		Socket s3(AF_INET, SOCK_STREAM, 0);
+
+	std::thread client([] () {
+		Socket s1, s2, s3;
 
-		s1.connect(Internet("localhost", 10000, AF_INET));
-		s2.connect(Internet("localhost", 10000, AF_INET));
-		s3.connect(Internet("localhost", 10000, AF_INET));
+		try {
+			s1 = { AF_INET, SOCK_STREAM, 0 };
+			s2 = { AF_INET, SOCK_STREAM, 0 };
+			s3 = { AF_INET, SOCK_STREAM, 0 };
+
+			s1.connect(Internet("localhost", 10000, AF_INET));
+			s2.connect(Internet("localhost", 10000, AF_INET));
+			s3.connect(Internet("localhost", 10000, AF_INET));
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
 
 		s1.close();
 		s2.close();
 		s3.close();
-	} catch (const std::exception &ex) {
-	}
+	});
 
-	tester.join();
+	server.join();
+	client.join();
 }
 
 #if defined(SOCKET_LISTENER_HAVE_POLL)
@@ -485,50 +579,60 @@
 	 * Normally, 3 sockets added for writing should be marked ready immediately
 	 * as there are no data being currently queued to be sent.
 	 */
-	std::thread tester([] () {
+	std::thread server([] () {
+		Socket master;
+
 		try {
 			SocketListener masterListener(SocketMethod::Poll), clientListener(SocketMethod::Poll);
-			Socket master(AF_INET, SOCK_STREAM, 0);
+			master = { AF_INET, SOCK_STREAM, 0 };
 
-			master.bind(Internet("*", 10000, AF_INET));
+			master.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			master.bind(Internet{"*", 10000, AF_INET});
 			master.listen(8);
 
 			masterListener.add(master, SocketDirection::Read);
 
 			while (clientListener.size() != 3) {
-				masterListener.select(3s);
+				masterListener.select(1s);
 				clientListener.add(master.accept(), SocketDirection::Write);
 			}
 
 			// Now do the test of writing
-			auto result = clientListener.selectMultiple(3s);
+			auto result = clientListener.selectMultiple(500ms);
 			ASSERT_EQ(3UL, result.size());
 
 			clientListener.list([] (auto s, auto) {
 				s.close();
 			});
-	
-			master.close();
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
+
+		master.close();
 	});
 
-	try {
-		Socket s1(AF_INET, SOCK_STREAM, 0);
-		Socket s2(AF_INET, SOCK_STREAM, 0);
-		Socket s3(AF_INET, SOCK_STREAM, 0);
+	std::thread client([] () {
+		Socket s1, s2, s3;
 
-		s1.connect(Internet("localhost", 10000, AF_INET));
-		s2.connect(Internet("localhost", 10000, AF_INET));
-		s3.connect(Internet("localhost", 10000, AF_INET));
+		try {
+			s1 = { AF_INET, SOCK_STREAM, 0 };
+			s2 = { AF_INET, SOCK_STREAM, 0 };
+			s3 = { AF_INET, SOCK_STREAM, 0 };
+
+			s1.connect(Internet("localhost", 10000, AF_INET));
+			s2.connect(Internet("localhost", 10000, AF_INET));
+			s3.connect(Internet("localhost", 10000, AF_INET));
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
 
 		s1.close();
 		s2.close();
 		s3.close();
-	} catch (const std::exception &ex) {
-	}
+	});
 
-	tester.join();
+	server.join();
+	client.join();
 }
 
 #endif
@@ -538,230 +642,280 @@
  * -------------------------------------------------------- */
 
 TEST(BasicTcp, sendipv4) {
+	std::thread server([] () {
+		Socket server, client;
+
+		try {
+			server = { AF_INET, SOCK_STREAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Internet{"*", 10000, AF_INET});
+			server.listen(8);
+
+			client = server.accept();
+
+			char data[512];
+			auto nb = client.recv(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+		client.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_INET, SOCK_STREAM, 0);
+			s = { AF_INET, SOCK_STREAM, 0 };
 
-			s.connect(Internet("localhost", 10000, AF_INET));
+			s.connect(Internet{"localhost", 10000, AF_INET});
 			s.send("hello");
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_INET, SOCK_STREAM, 0);
-
-		server.bind(Internet("*", 10000, SOCK_STREAM));
-		server.listen(8);
-
-		auto client = server.accept();
-
-		char data[512];
-		auto nb = client.recv(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }
 
 TEST(BasicTcp, sendipv6) {
+	std::thread server([] () {
+		Socket server, client;
+
+		try {
+			server = { AF_INET6, SOCK_STREAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Internet("*", 10000, AF_INET6));
+			server.listen(8);
+
+			client = server.accept();
+
+			char data[512];
+			auto nb = client.recv(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+		client.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_INET6, SOCK_STREAM, 0);
+			s = { AF_INET6, SOCK_STREAM, 0 };
 
-			s.connect(Internet("localhost", 10000, AF_INET6));
+			s.connect(Internet{"ip6-localhost", 10000, AF_INET6});
 			s.send("hello");
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_INET6, SOCK_STREAM, 0);
-
-		server.bind(Internet("*", 10000, SOCK_STREAM));
-		server.listen(8);
-
-		auto client = server.accept();
-
-		char data[512];
-		auto nb = client.recv(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }
 
 #if !defined(_WIN32)
 
 TEST(BasicTcp, sendunix) {
+	std::thread server([] () {
+		Socket server, client;
+
+		try {
+			server = { AF_UNIX, SOCK_STREAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Unix("/tmp/gtest-send-tcp-unix.sock", true));
+			server.listen(8);
+
+			client = server.accept();
+
+			char data[512];
+			auto nb = client.recv(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+		client.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_UNIX, SOCK_STREAM, 0);
+			s = { AF_UNIX, SOCK_STREAM, 0 };
 
-			s.connect(Unix("/tmp/gtest-send-tcp-unix.sock"));
+			s.connect(Unix{"/tmp/gtest-send-tcp-unix.sock"});
 			s.send("hello");
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_UNIX, SOCK_STREAM, 0);
-
-		server.bind(Unix("/tmp/gtest-send-tcp-unix.sock", true));
-		server.listen(8);
-
-		auto client = server.accept();
-
-		char data[512];
-		auto nb = client.recv(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }
 
 #endif
 
+/* --------------------------------------------------------
+ * Basic UDP tests
+ * -------------------------------------------------------- */
+
 TEST(BasicUdp, sendipv4) {
+	std::thread server([] () {
+		Socket server;
+
+		try {
+			server = { AF_INET, SOCK_DGRAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Internet("*", 10000, AF_INET));
+
+			char data[512];
+			auto nb = server.recvfrom(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_INET, SOCK_DGRAM, 0);
+			s = { AF_INET, SOCK_DGRAM, 0 };
 
-			s.sendto("hello", Internet("localhost", 10000, AF_INET));
+			s.sendto("hello", Internet{"localhost", 10000, AF_INET});
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_INET, SOCK_DGRAM, 0);
-
-		server.bind(Internet("*", 10000, SOCK_DGRAM));
-
-		char data[512];
-		auto nb = server.recvfrom(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }
 
 TEST(BasicUdp, sendipv6) {
+	std::thread server([] () {
+		Socket server;
+
+		try {
+			server = { AF_INET6, SOCK_DGRAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.set(IPPROTO_IPV6, IPV6_V6ONLY, 1);
+			server.bind(Internet{"*", 10000, AF_INET6});
+
+			char data[512];
+			auto nb = server.recvfrom(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_INET6, SOCK_DGRAM, 0);
+			s = { AF_INET6, SOCK_DGRAM, 0 };
 
-			s.sendto("hello", Internet("localhost", 10000, AF_INET6));
+			s.sendto("hello", Internet{"ip6-localhost", 10000, AF_INET6});
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_INET6, SOCK_DGRAM, 0);
-
-		server.bind(Internet("*", 10000, SOCK_DGRAM));
-
-		char data[512];
-		auto nb = server.recvfrom(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }
 
 #if !defined(_WIN32)
 
 TEST(BasicUdp, sendunix) {
+	std::thread server([] () {
+		Socket server;
+
+		try {
+			server = { AF_UNIX, SOCK_DGRAM, 0 };
+
+			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+			server.bind(Unix{"/tmp/gtest-send-udp-unix.sock", true});
+
+			char data[512];
+			auto nb = server.recvfrom(data, sizeof (data) - 1);
+
+			data[nb] = '\0';
+
+			ASSERT_STREQ("hello", data);
+		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
+		}
+
+		server.close();
+	});
+
 	std::thread client([] () {
 		Socket s;
 
-		std::this_thread::sleep_for(3s);
+		std::this_thread::sleep_for(500ms);
 		try {
-			s = Socket(AF_UNIX, SOCK_DGRAM, 0);
+			s = { AF_UNIX, SOCK_DGRAM, 0 };
 
-			s.sendto("hello", Unix("/tmp/gtest-send-udp-unix.sock"));
+			s.sendto("hello", Unix{"/tmp/gtest-send-udp-unix.sock"});
 		} catch (const std::exception &ex) {
+			std::cerr << "warning: " << ex.what() << std::endl;
 		}
 
 		s.close();
 	});
 
-	Socket server;
-
-	try {
-		server = Socket(AF_UNIX, SOCK_DGRAM, 0);
-
-		server.bind(Unix("/tmp/gtest-send-udp-unix.sock", true));
-
-		char data[512];
-		auto nb = server.recvfrom(data, sizeof (data) - 1);
-
-		data[nb] = '\0';
-
-		ASSERT_STREQ("hello", data);
-	} catch (const std::exception &ex) {
-	}
-
-	server.close();
+	server.join();
 	client.join();
 }