32 #include <gtest/gtest.h>
34 #include <system_error>
39 #include <condition_variable>
58 using std::unique_lock;
59 using std::lock_guard;
62 using std::condition_variable;
64 using std::stringstream;
65 using std::error_code;
79 static int find_interface(
int flag,
InetAddr* ad =
nullptr)
86 for (
auto& j : i.addrs())
89 if ((j.test_flags(flag)))
102 struct inet_networking :
public testing::Test
104 std::string snd, got, testgot;
106 InetAddr server_addr, client_addr, servfrom;
111 inet_networking() : snd(
"this is a test line\nthis is the second\nanother\n\nlast one")
117 virtual ~inet_networking()
122 tcp_serv_sock.
reset();
123 udp_serv_sock.
reset();
124 tcp_client_sock.
reset();
125 udp_client_sock.
reset();
130 void udp_readwrite_client()
132 auto fut = async(udp_readwrite_server, std::ref(startev), std::ref(udp_serv_sock), std::ref(server_addr), std::ref(servfrom), std::ref(quitev));
136 log <<
"started" << endl;
138 udp_writeread_test(udp_client_sock, client_addr);
143 log <<
"return code: " << res << endl;
147 void tcp_iostream_client()
149 auto fut = async(tcp_iostream_server, std::ref(startev), std::ref(tcp_serv_sock), std::ref(server_addr), std::ref(servfrom));
153 log <<
"connect" << endl;
154 tcp_client_sock.
connect(server_addr);
156 log <<
"connected to addr=" << server_addr.
str() << endl;
158 tcp_stream_test(tcp_client_sock);
160 tcp_client_sock.
close();
163 log <<
"return code: " << res << endl;
167 void tcp_readwrite_client()
169 auto fut = async(tcp_readwrite_server, std::ref(startev), std::ref(tcp_serv_sock), std::ref(server_addr), std::ref(servfrom));
171 log <<
"read start event" << endl;
175 log <<
"connect" << endl;
176 tcp_client_sock.
connect(server_addr);
178 log <<
"connected to addr=" << server_addr.
str() << endl;
180 tcp_writeread_test(tcp_client_sock);
182 tcp_client_sock.
close();
184 log <<
"return code: " << res << endl;
192 log.
id(
"inet tcp stream client");
195 stringstream testst(snd);
199 log <<
"sending " << snd.size() << endl;
200 ASSERT_TRUE(stream << snd << endl);
203 while (std::getline(testst, testgot))
205 ASSERT_TRUE(std::getline(stream, got));
206 log <<
"got reply " << got.size() << endl;
207 ASSERT_EQ(got, testgot);
212 ASSERT_TRUE(stream << snd << endl);
215 stringstream testst2(snd);
216 while (testst2 >> testgot)
218 ASSERT_TRUE(stream >> got);
219 log <<
"got reply " << got.size() << endl;
220 ASSERT_EQ(got, testgot);
223 log <<
"end" << endl;
230 log.
id(
"inet tcp readwrite client");
232 log <<
"sending " << snd.size() << endl;
233 ASSERT_EQ(
sock.send(snd.data(), snd.size()), snd.size());
235 char buf[snd.size()];
239 got =
sock.recv(buf+sz, snd.size()-sz);
240 log <<
"got reply " << got << endl;
244 while (sz < snd.size());
245 ASSERT_EQ(sz, snd.size());
246 ASSERT_EQ(memcmp(buf, snd.data(), sz), 0);
248 log <<
"end" << endl;
255 log.
id(
"inet udp client");
257 log <<
"sending " << snd.size() <<
" to " << addr.
str() << endl;
258 ASSERT_EQ(
sock.send(snd.data(), snd.size(), addr), snd.size());
260 char buf[snd.size()];
263 got =
sock.recv(buf, snd.size(), from);
264 log <<
"got reply " << got <<
" from " << from.
host() << endl;
265 ASSERT_EQ(got, snd.size());
266 ASSERT_EQ(memcmp(buf, snd.data(), snd.size()), 0);
268 log <<
"end" << endl;
275 log.
id(
"inet udp server");
279 log <<
"reuse_addr" << endl;
280 sock.reuse_addr(
true);
281 log <<
"bind to " << addr.
host() << endl;
288 pin.
set(
sock.fd(), Poller::input);
289 pin.
set(quitev.
fd(), Poller::input);
301 auto sz =
sock.recv_next();
303 sock.recv(buf, sz, from);
304 log <<
"got " << sz <<
" from " << from.
host() << endl;
305 sock.send(buf, sz, from);
309 catch (
const std::exception& e)
311 log <<
"exception: " << e.what() << endl;
323 log.
id(
"inet tcp stream server");
327 log <<
"reuse_addr" << endl;
328 sock.reuse_addr(
true);
329 log <<
"bind to " << addr.
host() << endl;
331 log <<
"listen" << endl;
336 auto conn =
sock.accept(from);
337 log <<
"connect from " << from << endl;
341 for (
string got; std::getline(stream, got);)
343 log <<
"got " << got.size() << endl;
344 stream << got << endl;
348 catch (
const std::exception& e)
350 log <<
"exception: " << e.what() << endl;
362 log.
id(
"inet tcp readwrite server");
366 log <<
"reuse_addr" << endl;
367 sock.reuse_addr(
true);
368 log <<
"bind to " << addr.
host() << endl;
370 log <<
"listen" << endl;
375 auto conn =
sock.accept(from);
376 log <<
"connect from " << from << endl;
380 while ((sz = conn.recv(buf, 16)) > 0)
382 log <<
"got " << sz << endl;
386 catch (
const std::exception& e)
388 log <<
"exception: " << e.what() << endl;
397 TEST_F(inet_networking, udp_readwrite_loopback)
399 server_addr.
host(
"::1");
400 server_addr.
port(9999);
402 client_addr.
host(
"::1");
403 client_addr.
port(9999);
405 udp_readwrite_client();
406 log <<
"server connect from " << servfrom << endl;
407 ASSERT_EQ(server_addr.
host(), servfrom.
host());
411 server_addr.
host(
"::ffff:127.0.0.1");
412 server_addr.
port(9999);
414 client_addr.
host(
"::ffff:127.0.0.1");
415 client_addr.
port(9999);
417 udp_readwrite_client();
418 log <<
"server connect from " << servfrom << endl;
419 ASSERT_EQ(server_addr.
host(), servfrom.
host());
422 TEST_F(inet_networking, udp_readwrite_unicast)
426 server_addr.
port(9999);
428 cout <<
"ipv4 server addr: " << server_addr << endl;
430 client_addr.
host(server_addr.
host());
431 client_addr.
port(9999);
433 udp_readwrite_client();
434 log <<
"server connect from " << servfrom << endl;
435 ASSERT_EQ(server_addr.
host(), servfrom.
host());
444 cout <<
"NOTE: no interface local address found, skipping" << endl;
448 cout <<
"ipv6 link local server addr: " << server_addr << endl;
450 server_addr.
port(9999);
452 client_addr.
host(server_addr.
host());
453 client_addr.
port(9999);
455 udp_readwrite_client();
456 log <<
"server connect from " << servfrom << endl;
457 ASSERT_EQ(server_addr.
host(), servfrom.
host());
466 cout <<
"NOTE: no interface local address found, skipping" << endl;
470 cout <<
"ipv6 global server addr: " << server_addr << endl;
472 server_addr.
port(9999);
474 client_addr.
host(server_addr.
host());
475 client_addr.
port(9999);
477 udp_readwrite_client();
478 log <<
"server connect from " << servfrom << endl;
479 ASSERT_EQ(server_addr.
host(), servfrom.
host());
482 TEST_F(inet_networking, tcp_iostream_loopback)
484 server_addr.
host(
"::1");
485 server_addr.
port(9999);
487 tcp_iostream_client();
488 log <<
"server connect from " << servfrom << endl;
489 ASSERT_EQ(server_addr.
host(), servfrom.
host());
493 server_addr.
host(
"::ffff:127.0.0.1");
494 server_addr.
port(9999);
496 tcp_iostream_client();
497 log <<
"server connect from " << servfrom << endl;
498 ASSERT_EQ(server_addr.
host(), servfrom.
host());
501 TEST_F(inet_networking, tcp_readwrite_loopback)
503 server_addr.
host(
"::1");
504 server_addr.
port(9999);
506 tcp_readwrite_client();
507 log <<
"server connect from " << servfrom << endl;
508 ASSERT_EQ(server_addr.
host(), servfrom.
host());
512 server_addr.
host(
"::ffff:127.0.0.1");
513 server_addr.
port(9999);
515 tcp_readwrite_client();
516 log <<
"server connect from " << servfrom << endl;
517 ASSERT_EQ(server_addr.
host(), servfrom.
host());
521 TEST(inet_example, client_server_stream_test)
525 log.
id(
"tcp client");
536 std::packaged_task<int(
void)> serv_task([&addr, &listening]()
540 log.
id(
"tcp server");
545 sock.reuse_addr(
true);
548 log <<
"server listening" << endl;
555 log <<
"signalling client" << endl;
559 auto conn = sock.accept(from);
560 log <<
"connection from " << from << endl;
565 for (
string got; std::getline(stream, got);)
567 log <<
"got " << got << endl;
569 stream << got << endl;
574 catch (exception& ex)
576 log << ex.what() << endl;
582 auto fut = serv_task.get_future();
583 std::thread serv(std::move(serv_task));
586 pin.
set(listening, Poller::input);
590 pin.wait(std::chrono::milliseconds(700));
591 if (pin.
event(listening))
595 log <<
"waiting for listener" << endl;
603 sock.non_blocking(
true);
605 sock.connect(addr, ec);
606 if (ec.value() != 0 && ec.value() != EINPROGRESS)
608 log <<
"Non blocking connect failed: " << ec.message() << endl;
609 ASSERT_EQ(ec.value(), 0);
612 log <<
"waiting for 200 ms seconds to connect" << endl;
614 pout.
set(sock, Poller::output);
615 pout.wait(std::chrono::milliseconds(200));
617 if (!pout.
event(sock))
619 log <<
"connect attempt timed out" << endl;
620 ASSERT_EQ(pout.
event(sock), 0);
623 sock.non_blocking(
false);
626 log <<
"connected, sending stuff" << endl;
628 string line1(
"first line");
629 string line2(
"second line");
634 ASSERT_TRUE(stream << line1 << endl);
635 ASSERT_TRUE(getline(stream, got));
636 ASSERT_EQ(got, line1);
637 ASSERT_TRUE(stream << line2 << endl);
638 ASSERT_TRUE(getline(stream, got));
639 ASSERT_EQ(got, line2);
645 log <<
"got result=" << res << endl;
646 ASSERT_EQ(res, line1.size()+line2.size());
651 TEST(inet_example, tcp_multiserver)
655 log.
id(
"tcp client");
663 condition_variable cv;
668 auto serv_task = [&addr, &mx, &listening, &cv, &shut](
int i)
672 log.
id(
string(
"tcp server ")+to_string(i));
677 sock.reuse_addr(
true);
678 sock.reuse_port(
true);
686 log <<
"server listening" << endl;
689 log <<
"telling the client I am listening" << endl;
691 lock_guard<mutex> lk(mx);
701 p.
set(sock, Poller::input);
702 p.
set(shut, Poller::input);
711 auto conn = sock.accept(from);
712 log <<
"connection from " << from << endl;
716 for (
string got; std::getline(stream, got);)
718 log <<
"got size " << got.size() <<
" : " << got << endl;
720 stream << got << endl;
726 catch (exception& ex)
728 log << ex.what() << endl;
729 lock_guard<mutex> lk(mx);
736 auto fut1 = async(serv_task, 1);
737 auto fut2 = async(serv_task, 2);
738 auto fut3 = async(serv_task, 3);
740 unique_lock<mutex> lk(mx);
741 cv.wait(lk, [&listening]
743 return listening == 3;
748 for (
int i = 0; i < 10; i++)
752 log <<
"connected #" << i <<
", sending stuff" << endl;
754 string line1(
"first line");
755 string line2(
"second line");
760 ASSERT_TRUE(stream << line1 << endl);
761 ASSERT_TRUE(getline(stream, got));
762 ASSERT_EQ(got, line1);
763 ASSERT_TRUE(stream << line2 << endl);
764 ASSERT_TRUE(getline(stream, got));
765 ASSERT_EQ(got, line2);
766 count += line1.size()+line2.size();
771 int res = fut1.get();
774 log <<
"got result=" << res << endl;
775 ASSERT_EQ(res, count);
unsigned port() const
Get the port.
virtual std::string host() const
Get host.
virtual std::string str() const
Readable address string.
Internet transmission control protocol (tcp) socket.
virtual void reset()
Close the connection and reset the socket.
Internet user datagram protocol (udp) socket.
virtual void reset()
Reset the socket.
static std::vector< NetIf > all_interfaces()
List network interfaces on the local system.
void close()
Close the socket.
void connect(SockaddrBase &)
Connect to a socket address.
Signaling kernel event counter.
uint64_t read()
Read from (decrement) the event counter.
void reset(int=-1)
Reset the event.
int fd() const
Return file descriptor.
void write(uint64_t)
Write to (increment) the event counter.
Input/output stream wrapper for reader/writer.
Thread-safe stream logger.
void id(const std::string &id="")
Set the id.
void add_cout()
Add std::cout console stream.
Poller which allows polling of generic file descriptors for various events.
void set(int, int)
Add a file desriptor to poller.
int event(int)
Return flags which were polled for this file descriptor.
Signaling kernel event counter.
NetIfFlag
Interface flags.
@ if_up
Interface is running.
InetAddrFlag
Internet address flags.
@ unicast
Unicast address.
@ link_local
Traffic is restricted to the local link.
@ global
Global traffic is allowed.
Internet tcp and udp networking.
Base input/output stream classes.
Internet network interface utility.
Linux kernel i/o event notification (poller).
TEST(inet_example, client_server_stream_test)
[Inet client server]
Unix domain tcp and udp networking.