diff C++/Tests/Sockets/main.cpp @ 318:68ae6d7dea1f

Sockets: improve errors
author David Demelier <markand@malikania.fr>
date Fri, 06 Mar 2015 17:30:16 +0100
parents 4c0af1143fc4
children cba77da58496
line wrap: on
line diff
--- a/C++/Tests/Sockets/main.cpp	Wed Mar 04 13:45:56 2015 +0100
+++ b/C++/Tests/Sockets/main.cpp	Fri Mar 06 17:30:16 2015 +0100
@@ -415,1150 +415,255 @@
 	});
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-#if 0
-
-#include <Socket.h>
-#include <SocketListener.h>
-#include <SocketAddress.h>
-
-using namespace std::literals::chrono_literals;
-
-using namespace error;
-using namespace address;
-
 /* --------------------------------------------------------
- * Miscellaneous
- * -------------------------------------------------------- */
-
-TEST(Misc, set)
-{
-	Socket s;
-
-	try {
-		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, 1);
-		ASSERT_EQ(1, s.get<int>(IPPROTO_IPV6, IPV6_V6ONLY));
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-
-	s.close();
-}
-
-TEST(Misc, initializer)
-{
-	Socket s1, s2;
-
-	try {
-		s1 = { AF_INET6, SOCK_STREAM, 0 };
-		s2 = { AF_INET6, SOCK_STREAM, 0 };
-
-		SocketListener listener {
-			{ s1, direction::Read	},
-			{ s2, direction::Read	},
-		};
-
-		ASSERT_EQ(2UL, listener.size());
-
-		listener.list([&] (const auto &so, auto direction) {
-			ASSERT_TRUE(so == s1 || so == s2);
-			ASSERT_EQ(direction::Read, direction);
-		});
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-
-	s1.close();
-	s2.close();
-}
-
-/* --------------------------------------------------------
- * Select tests
- * -------------------------------------------------------- */
-
-TEST(ListenerMethodSelect, timeout)
-{
-	std::thread server([] () {
-		Socket s, client;
-		SocketListener listener(Select);
-		bool running = true;
-		int tries = 0;
-
-		try {
-			s = { AF_INET, SOCK_STREAM, 0 };
-			s.set(SOL_SOCKET, SO_REUSEADDR, 1);
-			s.bind(Internet{"*", 10000, AF_INET});
-			s.listen(10);
-
-			listener.add(s, direction::Read);
-
-			while (running) {
-				try {
-					listener.select(500ms);
-					client = s.accept();
-					running = false;
-
-					// Abort if no client connected
-					if (tries >= 10)
-						running = false;
-				} catch (const Timeout &) {
-				}
-			}
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-		client.close();
-	});
-
-	std::thread client([] () {
-		std::this_thread::sleep_for(2s);
-
-		Socket s;
-
-		try {
-			s = { AF_INET, SOCK_STREAM, 0 };
-			s.connect(Internet{"localhost", 10000, AF_INET});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-	});
-
-	server.join();
-	client.join();
-}
-
-TEST(ListenerMethodSelect, add)
-{
-	Socket s, s2;
-
-	try {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Select);
-
-		listener.add(s, direction::Read);
-		listener.add(s2, direction::Read);
-
-		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 {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Select);
-
-		listener.add(s, direction::Read);
-		listener.add(s2, direction::Read);
-		listener.remove(s, direction::Read);
-		listener.remove(s2, direction::Read);
-
-		ASSERT_EQ(0UL, listener.size());
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-
-	s.close();
-	s2.close();
-}
-
-/*
- * Add two sockets for both direction::Reading and writing, them remove only direction::Reading and then
- * move only writing.
- */
-TEST(ListenerMethodSelect, inOut)
-{
-	Socket s, s2;
-
-	try {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Select);
-
-		listener.add(s, direction::Read | direction::Write);
-		listener.add(s2, direction::Read | direction::Write);
-
-		listener.list([&] (Socket &si, int dir) {
-			ASSERT_TRUE(si == s || si == s2);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-
-		listener.remove(s, direction::Write);
-		listener.remove(s2, direction::Write);
-
-		ASSERT_EQ(2UL, listener.size());
-
-		listener.list([&] (Socket &si, int dir) {
-			ASSERT_TRUE(si == s || si == s2);
-			ASSERT_EQ(direction::Read, dir);
-		});
-
-		listener.remove(s, direction::Read);
-		listener.remove(s2, direction::Read);
-
-		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 {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Select);
-
-		listener.add(s, direction::Read);
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(direction::Read, dir);
-		});
-
-		listener.add(s, direction::Write);
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-
-		// Oops, added the same
-		listener.add(s, direction::Read);
-		listener.add(s, direction::Write);
-		listener.add(s, direction::Read | direction::Write);
-
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
-
-	s.close();
-}
-
-/* --------------------------------------------------------
- * Poll tests
+ * Non-blocking connect
  * -------------------------------------------------------- */
 
-TEST(ListenerMethodPoll, timeout)
-{
-	std::thread server([] () {
-		Socket s, client;
-		SocketListener listener(Poll);
-		bool running = true;
-		int tries = 0;
-
-		try {
-			s = { AF_INET, SOCK_STREAM, 0 };
-			s.set(SOL_SOCKET, SO_REUSEADDR, 1);
-			s.bind(Internet{"*", 10000, AF_INET});
-			s.listen(10);
-
-			listener.add(s, direction::Read);
-
-			while (running) {
-				try {
-					listener.select(500ms);
-					client = s.accept();
-					running = false;
-
-					// Abort if no client connected
-					if (tries >= 10)
-						running = false;
-				} catch (const Timeout &) {
-				}
-			}
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-		client.close();
-	});
-
-	std::thread client([] () {
-		std::this_thread::sleep_for(2s);
-
-		Socket s;
-
-		try {
-			s = { AF_INET, SOCK_STREAM, 0 };
-			s.connect(Internet{"localhost", 10000, AF_INET});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-	});
-
-	server.join();
-	client.join();
-}
-
-TEST(ListenerMethodPoll, add)
-{
-	Socket s, s2;
-
-	try {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Poll);
+class NonBlockingConnectTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
 
-		listener.add(s, direction::Read);
-		listener.add(s2, direction::Read);
-
-		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 {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Poll);
-
-		listener.add(s, direction::Read);
-		listener.add(s2, direction::Read);
-		listener.remove(s, direction::Read);
-		listener.remove(s2, direction::Read);
-
-		ASSERT_EQ(0UL, listener.size());
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-	}
+	std::thread m_tserver;
+	std::thread m_tclient;
 
-	s.close();
-	s2.close();
-}
-
-TEST(ListenerMethodPoll, inOut)
-{
-	Socket s, s2;
-
-	try {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		s2 = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Poll);
-
-		listener.add(s, direction::Read | direction::Write);
-		listener.add(s2, direction::Read | direction::Write);
-
-		listener.list([&] (Socket &si, int dir) {
-			ASSERT_TRUE(si == s || si == s2);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-
-		listener.remove(s, direction::Write);
-		listener.remove(s2, direction::Write);
-
-		ASSERT_EQ(2UL, listener.size());
-
-		listener.list([&] (Socket &si, int dir) {
-			ASSERT_TRUE(si == s || si == s2);
-			ASSERT_EQ(direction::Read, dir);
-		});
-
-		listener.remove(s, direction::Read);
-		listener.remove(s2, direction::Read);
-
-		ASSERT_EQ(0UL, listener.size());
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
+public:
+	NonBlockingConnectTest()
+	{
+		m_client.setBlockMode(false);
 	}
 
-	s.close();
-	s2.close();
-}
-
-TEST(ListenerMethodPoll, addSame)
-{
-	Socket s;
-
-	try {
-		s = { AF_INET, SOCK_STREAM, 0 };
-		SocketListener listener(Poll);
-
-		listener.add(s, direction::Read);
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(direction::Read, dir);
-		});
-
-		listener.add(s, direction::Write);
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-
-		// Oops, added the same
-		listener.add(s, direction::Read);
-		listener.add(s, direction::Write);
-		listener.add(s, direction::Read | direction::Write);
-
-		ASSERT_EQ(1UL, listener.size());
-		listener.list([&] (const Socket &si, int dir) {
-			ASSERT_TRUE(si == s);
-			ASSERT_EQ(0x03, static_cast<int>(dir));
-		});
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
+	~NonBlockingConnectTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
 	}
-
-	s.close();
-}
-
-/* --------------------------------------------------------
- * Socket listener class
- * -------------------------------------------------------- */
-
-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, direction::Read);
-
-			auto client = listener.select(10s);
-
-			ASSERT_TRUE(client.direction == direction::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(500ms);
-
-		try {
-			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();
-	});
-
-	server.join();
-	client.join();
-}
-
-TEST(Listener, connectionAndRead)
+TEST_F(NonBlockingConnectTest, success)
 {
-	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);
-
-			// direction::Read for master
-			listener.add(s, direction::Read);
-
-			auto result = listener.select(10s);
+	m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+	m_server.bind(Internet("*", 16000, AF_INET));
+	m_server.listen();
 
-			ASSERT_TRUE(result.direction == direction::Read);
-			ASSERT_TRUE(result.socket == s);
-
-			// Wait for client
-			auto client = s.accept();
-			listener.add(client, direction::Read);
-
-			result = listener.select(10s);
-
-			ASSERT_TRUE(result.direction == direction::Read);
-			ASSERT_TRUE(result.socket == client);
-
-			char data[512];
-			auto nb = client.recv(data, sizeof (data) - 1);
-
-			data[nb] = '\0';
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
 
-			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(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;
-		}
-
+		m_server.close();
 		client.close();
 	});
 
-	server.join();
-	client.join();
+	std::this_thread::sleep_for(100ms);
+
+	m_tclient = std::thread([this] () {
+		try {
+			m_client.waitConnect(Internet("127.0.0.1", 16000, AF_INET), 3000);
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
+		}
+
+		ASSERT_EQ(SocketState::Connected, m_client.state());
+
+		m_client.close();
+	});
 }
 
-TEST(Listener, bigData)
+TEST_F(NonBlockingConnectTest, fail)
 {
-	std::thread server([] () {
-		std::ostringstream out;
-
-		Socket server;
-		SocketListener listener;
-		bool finished(false);
-
+	/*
+	 * /!\ If you find a way to test this locally please tell me /!\
+	 */
+	m_tclient = std::thread([this] () {
 		try {
-			server = { AF_INET, SOCK_STREAM, 0 };
-
-			server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-			server.bind(Internet{"*", 10000, AF_INET});
-			server.listen(10);
-			listener.add(server, direction::Read);
+			m_client.waitConnect(Internet("google.fr", 9000, AF_INET), 100);
 
-			while (!finished) {
-				auto s = listener.select(60s).socket;
-
-				if (s == server) {
-					listener.add(s.accept(), direction::Read);
-				} else {
-					char data[512];
-					auto nb = s.recv(data, sizeof (data) - 1);
-
-					if (nb == 0)
-						finished = true;
-					else {
-						data[nb] = '\0';
-						out << data;
-					}
-				}
-			}
-
-			ASSERT_EQ(9000002UL, out.str().size());
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
+			FAIL() << "Expected exception, got success";
+		} catch (const SocketError &error) {
+			ASSERT_EQ(SocketError::Timeout, error.code());
 		}
 
-		server.close();
+		m_client.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;
-
-		try {
-			client = { AF_INET, SOCK_STREAM, 0 };
-
-			client.connect(Internet{"localhost", 10000, AF_INET});
-			client.blockMode(false);
-			listener.add(client, direction::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) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		client.close();
-	});
-
-	server.join();
-	client.join();
 }
 
 /* --------------------------------------------------------
- * Multiple selection tests
+ * TCP accept
  * -------------------------------------------------------- */
 
-TEST(MultipleSelection, select)
-{
-	/*
-	 * Normally, 3 sockets added for writing should be marked direction::Ready immediately
-	 * as there are no data being currently queued to be sent.
-	 */
-	std::thread server([] () {
-		Socket master;
+class TcpAcceptTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 0};
+
+	std::thread m_tserver;
+	std::thread m_tclient;
 
-		try {
-			SocketListener masterListener, clientListener;
-			master = { AF_INET, SOCK_STREAM, 0 };
-
-			master.set(SOL_SOCKET, SO_REUSEADDR, 1);
-			master.bind(Internet{"*", 10000, AF_INET});
-			master.listen(8);
+public:
+	TcpAcceptTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_server.bind(Internet("*", 16000, AF_INET));
+		m_server.listen();
+	}
 
-			masterListener.add(master, direction::Read);
-
-			while (clientListener.size() != 3) {
-				masterListener.select(3s);
-				clientListener.add(master.accept(), direction::Write);
-			}
+	~TcpAcceptTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
 
-			// Now do the test of writing
-			auto result = clientListener.selectMultiple(3s);
-			ASSERT_EQ(3UL, result.size());
-
-			clientListener.list([] (auto s, auto) {
-				s.close();
-			});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
+TEST_F(TcpAcceptTest, blockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		try {
+			m_server.waitAccept(3000).close();
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
 		}
 
-		master.close();
-	});
-
-	std::thread client([] () {
-		Socket s1, s2, s3;
-
-		try {
-			s1 = { AF_INET, SOCK_STREAM, 0 };
-			s2 = { AF_INET, SOCK_STREAM, 0 };
-			s3 = { AF_INET, SOCK_STREAM, 0 };
-
-			std::this_thread::sleep_for(1s);
-
-			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();
-	});
-
-	server.join();
-	client.join();
-}
-
-#if defined(SOCKET_LISTENER_HAVE_POLL)
-
-TEST(MultipleSelection, poll)
-{
-	/*
-	 * Normally, 3 sockets added for writing should be marked direction::Ready immediately
-	 * as there are no data being currently queued to be sent.
-	 */
-	std::thread server([] () {
-		Socket master;
-
-		try {
-			SocketListener masterListener(Poll), clientListener(Poll);
-			master = { AF_INET, SOCK_STREAM, 0 };
-
-			master.set(SOL_SOCKET, SO_REUSEADDR, 1);
-			master.bind(Internet{"*", 10000, AF_INET});
-			master.listen(8);
-
-			masterListener.add(master, direction::Read);
-
-			while (clientListener.size() != 3) {
-				masterListener.select(3s);
-				clientListener.add(master.accept(), direction::Write);
-			}
-
-			// Now do the test of writing
-			auto result = clientListener.selectMultiple(3s);
-			ASSERT_EQ(3UL, result.size());
-
-			clientListener.list([] (auto s, auto) {
-				s.close();
-			});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		master.close();
+		m_server.close();
 	});
 
-	std::thread client([] () {
-		Socket s1, s2, s3;
-
-		try {
-			s1 = { AF_INET, SOCK_STREAM, 0 };
-			s2 = { AF_INET, SOCK_STREAM, 0 };
-			s3 = { AF_INET, SOCK_STREAM, 0 };
-
-			std::this_thread::sleep_for(1s);
+	std::this_thread::sleep_for(100ms);
 
-			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();
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.close();
 	});
-
-	server.join();
-	client.join();
 }
 
-#endif
-
-/* --------------------------------------------------------
- * Basic TCP tests
- * -------------------------------------------------------- */
-
-TEST(BasicTcp, sendipv4) {
-	std::thread server([] () {
-		Socket server, client;
-
+TEST_F(TcpAcceptTest, nonBlockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
 		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;
+			m_server.setBlockMode(false);
+			m_server.waitAccept(3000).close();
+		} catch (const SocketError &error) {
+			FAIL() << error.what();
 		}
 
-		server.close();
-		client.close();
+		m_server.close();
 	});
 
-	std::thread client([] () {
-		Socket s;
-
-		std::this_thread::sleep_for(500ms);
-		try {
-			s = { AF_INET, SOCK_STREAM, 0 };
+	std::this_thread::sleep_for(100ms);
 
-			s.connect(Internet{"localhost", 10000, AF_INET});
-			s.send("hello");
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.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;
-		}
+TEST_F(TcpAcceptTest, nonBlockingWaitFail)
+{
+	// No client, no accept
+	try {
+		m_server.setBlockMode(false);
+		m_server.waitAccept(100).close();
 
-		server.close();
-		client.close();
-	});
-
-	std::thread client([] () {
-		Socket s;
-
-		std::this_thread::sleep_for(500ms);
-		try {
-			s = { AF_INET6, SOCK_STREAM, 0 };
+		FAIL() << "Expected exception, got success";
+	} catch (const SocketError &error) {
+		ASSERT_EQ(SocketError::Timeout, error.code());
+	}
 
-			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();
-	});
-
-	server.join();
-	client.join();
+	m_server.close();
 }
 
-#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(500ms);
-		try {
-			s = { AF_UNIX, SOCK_STREAM, 0 };
-
-			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();
-	});
-
-	server.join();
-	client.join();
-}
-
-#endif
-
 /* --------------------------------------------------------
- * Basic UDP tests
+ * TCP recv
  * -------------------------------------------------------- */
 
-TEST(BasicUdp, sendipv4) {
-	std::thread server([] () {
-		Socket server;
-
-		try {
-			server = { AF_INET, SOCK_DGRAM, 0 };
+class TcpRecvTest : public testing::Test {
+protected:
+	SocketTcp m_server{AF_INET, 0};
+	SocketTcp m_client{AF_INET, 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';
+	std::thread m_tserver;
+	std::thread m_tclient;
 
-			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(500ms);
-		try {
-			s = { AF_INET, SOCK_DGRAM, 0 };
-
-			s.sendto("hello", Internet{"localhost", 10000, AF_INET});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-	});
+public:
+	TcpRecvTest()
+	{
+		m_server.set(SOL_SOCKET, SO_REUSEADDR, 1);
+		m_server.bind(Internet("*", 16000, AF_INET));
+		m_server.listen();
+	}
 
-	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';
+	~TcpRecvTest()
+	{
+		if (m_tserver.joinable())
+			m_tserver.join();
+		if (m_tclient.joinable())
+			m_tclient.join();
+	}
+};
 
-			ASSERT_STREQ("hello", data);
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		server.close();
-	});
-
-	std::thread client([] () {
-		Socket s;
+TEST_F(TcpRecvTest, blockingSuccess)
+{
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
 
-		std::this_thread::sleep_for(500ms);
-		try {
-			s = { AF_INET6, SOCK_DGRAM, 0 };
+		ASSERT_EQ("hello", client.recv(32));
 
-			s.sendto("hello", Internet{"ip6-localhost", 10000, AF_INET6});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
+		client.close();
+		m_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';
+	std::this_thread::sleep_for(100ms);
 
-			ASSERT_STREQ("hello", data);
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		server.close();
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
 	});
-
-	std::thread client([] () {
-		Socket s;
-
-		std::this_thread::sleep_for(500ms);
-		try {
-			s = { AF_UNIX, SOCK_DGRAM, 0 };
-
-			s.sendto("hello", Unix{"/tmp/gtest-send-udp-unix.sock"});
-		} catch (const std::exception &ex) {
-			std::cerr << "warning: " << ex.what() << std::endl;
-		}
-
-		s.close();
-	});
-
-	server.join();
-	client.join();
 }
 
-#endif
+TEST_F(TcpRecvTest, blockingWaitSuccess)
+{
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
 
-/* --------------------------------------------------------
- * Non-blocking functions failures
- * -------------------------------------------------------- */
-
-TEST(NonBlockingFailures, connect)
-{
-	Socket s;
+		ASSERT_EQ("hello", client.waitRecv(32, 3000));
 
-	try {
-		s = {AF_INET, SOCK_STREAM, 0};
-		s.blockMode(false);
-	} catch (const std::exception &ex) {
-		std::cerr << ex.what() << std::endl;
-		return;
-	}
+		client.close();
+		m_server.close();
+	});
 
-	auto time1 = std::chrono::system_clock::now();
+	std::this_thread::sleep_for(100ms);
 
-	try {
-		s.tryConnect(Internet{"google.fr", 9000, AF_INET}, 1000);
-
-		FAIL() << "unexpected code path";
-	} catch (const std::exception &ex) {}
-
-	auto time2 = std::chrono::system_clock::now();
-	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(time2 - time1).count();
-
-	// Assert between 0,9 and 1,1 seconds
-	ASSERT_GT(duration, 900);
-	ASSERT_LT(duration, 1100);
-
-	s.close();
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
+	});
 }
 
-TEST(NonBlockingFailures, recv)
+TEST_F(TcpRecvTest, nonBlockingWaitSuccess)
 {
-	Socket s;
-	Socket server;
-	bool ready{false};
-
-	try {
-		s = {AF_INET, SOCK_STREAM, 0};
+	m_tserver = std::thread([this] () {
+		SocketTcp client = m_server.accept();
 
-		server = {AF_INET, SOCK_STREAM, 0};
-		server.set(SOL_SOCKET, SO_REUSEADDR, 1);
-		server.bind(Internet{"localhost", 10000, AF_INET});
-		server.listen(10);
+		client.setBlockMode(false);
 
-		ready = true;
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
-		return;
-	}
-
-	if (!ready) {
-		s.close();
-		server.close();
-	}
+		ASSERT_EQ("hello", client.waitRecv(32, 3000));
 
-	try {
-		s.connect(Internet{"localhost", 10000, AF_INET});
-		s.blockMode(false);
-	} catch (const std::exception &ex) {
-		std::cerr << "warning: " << ex.what() << std::endl;
+		client.close();
+		m_server.close();
+	});
 
-		s.close();
-		server.close();
-
-		return;
-	}
-
-	auto time1 = std::chrono::system_clock::now();
+	std::this_thread::sleep_for(100ms);
 
-	try {
-		s.tryRecv(100, 1000);
-
-		FAIL() << "unexpected code path";
-	} catch (const std::exception &) {}
-
-	auto time2 = std::chrono::system_clock::now();
-	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(time2 - time1).count();
-
-	// Assert between 0,9 and 1,1 seconds
-	ASSERT_GT(duration, 900);
-	ASSERT_LT(duration, 1100);
-
-	s.close();
+	m_tclient = std::thread([this] () {
+		m_client.connect(Internet("127.0.0.1", 16000, AF_INET));
+		m_client.send("hello");
+		m_client.close();
+	});
 }
 
-#endif
-
 int main(int argc, char **argv)
 {
 	testing::InitGoogleTest(&argc, argv);