scclib
Stable Cloud Computing C++ Library
inet.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <net/inet.h>
32 #include <gtest/gtest.h>
33 #include <iostream>
34 #include <system_error>
35 #include <thread>
36 #include <future>
37 #include <sstream>
38 #include <chrono>
39 #include <condition_variable>
40 #include <mutex>
41 #include <util/event.h>
42 #include <util/poller.h>
43 #include <net/inet.h>
44 #include <net/unix.h>
45 #include <net/net_if.h>
46 #include <util/iostream.h>
47 #include <util/logger.h>
48 
55 using std::cout;
56 using std::endl;
57 using std::string;
58 using std::unique_lock;
59 using std::lock_guard;
60 using std::mutex;
61 using std::exception;
62 using std::condition_variable;
63 using std::async;
64 using std::stringstream;
65 using std::error_code;
66 using std::to_string;
68 using scc::util::Logger;
69 using scc::util::Event;
70 using scc::util::Poller;
73 using scc::net::InetAddr;
76 
77 // look for an address on a network interface that satisfies InetAddrFlag input flag
78 // Set the address if provided, and return the interface number
79 static int find_interface(int flag, InetAddr* ad = nullptr)
80 {
81  for (auto& i : scc::net::NetIf::all_interfaces())
82  {
83  //cout << "if=" << i << endl;
84  if (!i.test_flags(NetIfFlag::if_up)) continue;
85 
86  for (auto& j : i.addrs())
87  {
88  //cout << " addr=" << i << endl;
89  if ((j.test_flags(flag)))
90  {
91  if (ad)
92  {
93  *ad = j;
94  }
95  return i.index();
96  }
97  }
98  }
99  return 0;
100 }
101 
102 struct inet_networking : public testing::Test
103 {
104  std::string snd, got, testgot;
105  scc::util::Logger log;
106  InetAddr server_addr, client_addr, servfrom;
107  scc::util::Event startev, quitev;
108  InetTcpSock tcp_serv_sock, tcp_client_sock;
109  InetUdpSock udp_serv_sock, udp_client_sock;
110 
111  inet_networking() : snd("this is a test line\nthis is the second\nanother\n\nlast one")
112  {
113  Logger log;
114  log.add_cout();
115  log.id("test");
116  }
117  virtual ~inet_networking()
118  {
119  }
120  void reset()
121  {
122  tcp_serv_sock.reset();
123  udp_serv_sock.reset();
124  tcp_client_sock.reset();
125  udp_client_sock.reset();
126  startev.reset();
127  quitev.reset();
128  }
129 
130  void udp_readwrite_client()
131  {
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));
133 
134  startev.read(); // wait for the server to listen
135 
136  log << "started" << endl;
137 
138  udp_writeread_test(udp_client_sock, client_addr);
139 
140  quitev.write(1); // signal server to quit
141 
142  int res = fut.get();
143  log << "return code: " << res << endl;
144  ASSERT_EQ(res, 0);
145  };
146 
147  void tcp_iostream_client()
148  {
149  auto fut = async(tcp_iostream_server, std::ref(startev), std::ref(tcp_serv_sock), std::ref(server_addr), std::ref(servfrom));
150 
151  startev.read(); // wait for the server to listen
152 
153  log << "connect" << endl;
154  tcp_client_sock.connect(server_addr);
155 
156  log << "connected to addr=" << server_addr.str() << endl;
157 
158  tcp_stream_test(tcp_client_sock);
159 
160  tcp_client_sock.close(); // closed socket will stop the server
161 
162  int res = fut.get();
163  log << "return code: " << res << endl;
164  ASSERT_EQ(res, 0);
165  }
166 
167  void tcp_readwrite_client()
168  {
169  auto fut = async(tcp_readwrite_server, std::ref(startev), std::ref(tcp_serv_sock), std::ref(server_addr), std::ref(servfrom));
170 
171  log << "read start event" << endl;
172  startev.read(); // wait for the server to listen
173 
175  log << "connect" << endl;
176  tcp_client_sock.connect(server_addr);
177 
178  log << "connected to addr=" << server_addr.str() << endl;
179 
180  tcp_writeread_test(tcp_client_sock);
181 
182  tcp_client_sock.close();
183  int res = fut.get();
184  log << "return code: " << res << endl;
185  ASSERT_EQ(res, 0);
186  }
187 
188  void tcp_stream_test(InetTcpSock& sock)
189  {
190  Logger log;
191  log.add_cout();
192  log.id("inet tcp stream client");
193 
194  IoStream stream(sock, sock);
195  stringstream testst(snd);
196 
197  // first send and recieve using getline
198 
199  log << "sending " << snd.size() << endl;
200  ASSERT_TRUE(stream << snd << endl);
201  stream.flush();
202 
203  while (std::getline(testst, testgot))
204  {
205  ASSERT_TRUE(std::getline(stream, got));
206  log << "got reply " << got.size() << endl;
207  ASSERT_EQ(got, testgot);
208  }
209 
210  // now send and receive using stream operators
211 
212  ASSERT_TRUE(stream << snd << endl);
213  stream.flush();
214 
215  stringstream testst2(snd);
216  while (testst2 >> testgot)
217  {
218  ASSERT_TRUE(stream >> got);
219  log << "got reply " << got.size() << endl;
220  ASSERT_EQ(got, testgot);
221  }
222 
223  log << "end" << endl;
224  }
225 
226  void tcp_writeread_test(InetTcpSock& sock)
227  {
228  Logger log;
229  log.add_cout();
230  log.id("inet tcp readwrite client");
231 
232  log << "sending " << snd.size() << endl;
233  ASSERT_EQ(sock.send(snd.data(), snd.size()), snd.size());
234 
235  char buf[snd.size()];
236  size_t sz = 0, got;
237  do
238  {
239  got = sock.recv(buf+sz, snd.size()-sz);
240  log << "got reply " << got << endl;
241  ASSERT_GT(got, 0);
242  sz += got;
243  }
244  while (sz < snd.size());
245  ASSERT_EQ(sz, snd.size());
246  ASSERT_EQ(memcmp(buf, snd.data(), sz), 0);
247 
248  log << "end" << endl;
249  }
250 
251  void udp_writeread_test(InetUdpSock& sock, InetAddr& addr)
252  {
253  Logger log;
254  log.add_cout();
255  log.id("inet udp client");
256 
257  log << "sending " << snd.size() << " to " << addr.str() << endl;
258  ASSERT_EQ(sock.send(snd.data(), snd.size(), addr), snd.size());
259 
260  char buf[snd.size()];
261  size_t got;
262  InetAddr from;
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);
267 
268  log << "end" << endl;
269  }
270 
271  static int udp_readwrite_server(Event& startev, InetUdpSock& sock, InetAddr& addr, InetAddr& from, Event& quitev)
272  {
273  Logger log;
274  log.add_cout();
275  log.id("inet udp server");
276 
277  try
278  {
279  log << "reuse_addr" << endl;
280  sock.reuse_addr(true);
281  log << "bind to " << addr.host() << endl;
282  sock.bind(addr);
283 
284  startev.write(1); // signal the other thread it can start
285 
286  // now poll to see when we have new data (or are signalled to quit)
287  Poller pin;
288  pin.set(sock.fd(), Poller::input);
289  pin.set(quitev.fd(), Poller::input);
290 
291  while (1)
292  {
293  pin.wait();
294  if (pin.event(quitev.fd()))
295  {
296  startev.write(1); // no blocking allowed
297  return 0;
298  }
299  else if (pin.event(sock.fd()))
300  {
301  auto sz = sock.recv_next(); // how many bytes are waiting?
302  char buf[sz];
303  sock.recv(buf, sz, from);
304  log << "got " << sz << " from " << from.host() << endl;
305  sock.send(buf, sz, from);
306  }
307  }
308  }
309  catch (const std::exception& e)
310  {
311  log << "exception: " << e.what() << endl;
312  startev.write(1); // no blocking allowed
313  return errno;
314  }
315  startev.write(1); // no blocking allowed
316  return 0;
317  }
318 
319  static int tcp_iostream_server(Event& startev, InetTcpSock& sock, InetAddr& addr, InetAddr& from)
320  {
321  Logger log;
322  log.add_cout();
323  log.id("inet tcp stream server");
324 
325  try
326  {
327  log << "reuse_addr" << endl;
328  sock.reuse_addr(true);
329  log << "bind to " << addr.host() << endl;
330  sock.bind(addr);
331  log << "listen" << endl;
332  sock.listen();
333 
334  startev.write(1); // signal the other thread it can start
335 
336  auto conn = sock.accept(from);
337  log << "connect from " << from << endl;
338 
339  IoStream stream(conn, conn);
340 
341  for (string got; std::getline(stream, got);) // loop until eof (socket closed)
342  {
343  log << "got " << got.size() << endl;
344  stream << got << endl;
345  }
346 
347  }
348  catch (const std::exception& e)
349  {
350  log << "exception: " << e.what() << endl;
351  startev.write(1); // no blocking allowed
352  return errno;
353  }
354  startev.write(1); // no blocking allowed
355  return 0;
356  }
357 
358  static int tcp_readwrite_server(Event& startev, InetTcpSock& sock, InetAddr& addr, InetAddr& from)
359  {
360  Logger log;
361  log.add_cout();
362  log.id("inet tcp readwrite server");
363 
364  try
365  {
366  log << "reuse_addr" << endl;
367  sock.reuse_addr(true);
368  log << "bind to " << addr.host() << endl;
369  sock.bind(addr);
370  log << "listen" << endl;
371  sock.listen();
372 
373  startev.write(1); // signal the other thread it can start
374 
375  auto conn = sock.accept(from);
376  log << "connect from " << from << endl;
377 
378  char buf[16];
379  int sz;
380  while ((sz = conn.recv(buf, 16)) > 0) // loop until we get 0 (socket closed)
381  {
382  log << "got " << sz << endl;
383  conn.send(buf, sz);
384  }
385  }
386  catch (const std::exception& e)
387  {
388  log << "exception: " << e.what() << endl;
389  startev.write(1); // make sure we don't block
390  return errno;
391  }
392  startev.write(1);
393  return 0;
394  }
395 };
396 
397 TEST_F(inet_networking, udp_readwrite_loopback)
398 {
399  server_addr.host("::1");
400  server_addr.port(9999);
401 
402  client_addr.host("::1");
403  client_addr.port(9999);
404 
405  udp_readwrite_client();
406  log << "server connect from " << servfrom << endl;
407  ASSERT_EQ(server_addr.host(), servfrom.host()); // the port will be ephemeral, but the address will be the same
408 
409  reset();
410 
411  server_addr.host("::ffff:127.0.0.1");
412  server_addr.port(9999);
413 
414  client_addr.host("::ffff:127.0.0.1");
415  client_addr.port(9999);
416 
417  udp_readwrite_client();
418  log << "server connect from " << servfrom << endl;
419  ASSERT_EQ(server_addr.host(), servfrom.host());
420 }
421 
422 TEST_F(inet_networking, udp_readwrite_unicast)
423 {
424  // look for an ipv4 global interface (not the loopback)
425  ASSERT_GT(find_interface(InetAddrFlag::unicast|InetAddrFlag::ipv4|InetAddrFlag::global, &server_addr), 0);
426  server_addr.port(9999);
427 
428  cout << "ipv4 server addr: " << server_addr << endl;
429 
430  client_addr.host(server_addr.host());
431  client_addr.port(9999);
432 
433  udp_readwrite_client();
434  log << "server connect from " << servfrom << endl;
435  ASSERT_EQ(server_addr.host(), servfrom.host());
436 
437  reset();
438 
439  // look for interface with link local ipv6 address (any interface with ipv6 enabled)
440  int inum = find_interface(InetAddrFlag::unicast|InetAddrFlag::ipv6|InetAddrFlag::link_local, &server_addr);
441 
442  if (!inum)
443  {
444  cout << "NOTE: no interface local address found, skipping" << endl;
445  GTEST_SKIP();
446  }
447 
448  cout << "ipv6 link local server addr: " << server_addr << endl;
449 
450  server_addr.port(9999);
451 
452  client_addr.host(server_addr.host());
453  client_addr.port(9999);
454 
455  udp_readwrite_client();
456  log << "server connect from " << servfrom << endl;
457  ASSERT_EQ(server_addr.host(), servfrom.host());
458 
459  reset();
460 
461  // look for interface with global ipv6 address
462  inum = find_interface(InetAddrFlag::unicast|InetAddrFlag::ipv6|InetAddrFlag::global, &server_addr);
463 
464  if (!inum)
465  {
466  cout << "NOTE: no interface local address found, skipping" << endl;
467  GTEST_SKIP();
468  }
469 
470  cout << "ipv6 global server addr: " << server_addr << endl;
471 
472  server_addr.port(9999);
473 
474  client_addr.host(server_addr.host());
475  client_addr.port(9999);
476 
477  udp_readwrite_client();
478  log << "server connect from " << servfrom << endl;
479  ASSERT_EQ(server_addr.host(), servfrom.host());
480 }
481 
482 TEST_F(inet_networking, tcp_iostream_loopback)
483 {
484  server_addr.host("::1");
485  server_addr.port(9999);
486 
487  tcp_iostream_client();
488  log << "server connect from " << servfrom << endl;
489  ASSERT_EQ(server_addr.host(), servfrom.host());
490 
491  reset();
492 
493  server_addr.host("::ffff:127.0.0.1");
494  server_addr.port(9999);
495 
496  tcp_iostream_client();
497  log << "server connect from " << servfrom << endl;
498  ASSERT_EQ(server_addr.host(), servfrom.host());
499 }
500 
501 TEST_F(inet_networking, tcp_readwrite_loopback)
502 {
503  server_addr.host("::1");
504  server_addr.port(9999);
505 
506  tcp_readwrite_client();
507  log << "server connect from " << servfrom << endl;
508  ASSERT_EQ(server_addr.host(), servfrom.host());
509 
510  reset();
511 
512  server_addr.host("::ffff:127.0.0.1");
513  server_addr.port(9999);
514 
515  tcp_readwrite_client();
516  log << "server connect from " << servfrom << endl;
517  ASSERT_EQ(server_addr.host(), servfrom.host());
518 }
519 
521 TEST(inet_example, client_server_stream_test)
522 {
523  Logger log;
524  log.add_cout();
525  log.id("tcp client");
526 
527  // this test sets up a client and server & streams some data between them
528 
529  scc::net::InetAddr addr;
530  addr.host("::1"); // localhost
531  addr.port(9999);
532 
533  // listening event
534  scc::util::Event listening;
535 
536  std::packaged_task<int(void)> serv_task([&addr, &listening]()
537  {
538  Logger log;
539  log.add_cout();
540  log.id("tcp server");
541 
542  try
543  {
545  sock.reuse_addr(true);
546 
547  sock.bind(addr);
548  log << "server listening" << endl;
549  sock.listen();
550 
551  // can play around with timeouts and timing this way...
552  //log << "sleep for a second" << endl;
553  //std::this_thread::sleep_for(std::chrono::seconds(1));
554 
555  log << "signalling client" << endl;
556  listening.write(1);
557 
558  scc::net::InetAddr from;
559  auto conn = sock.accept(from);
560  log << "connection from " << from << endl;
561 
562  scc::util::IoStream stream(conn, conn);
563 
564  int count = 0;
565  for (string got; std::getline(stream, got);) // loop until eof (socket closed)
566  {
567  log << "got " << got << endl;
568  count += got.size();
569  stream << got << endl;
570  }
571 
572  return count;
573  }
574  catch (exception& ex)
575  {
576  log << ex.what() << endl;
577  listening.write(1);
578  return -1;
579  }
580  });
581 
582  auto fut = serv_task.get_future();
583  std::thread serv(std::move(serv_task)); // start server thread
584 
585  Poller pin;
586  pin.set(listening, Poller::input);
587 
588  while (1)
589  {
590  pin.wait(std::chrono::milliseconds(700));
591  if (pin.event(listening))
592  {
593  break;
594  }
595  log << "waiting for listener" << endl;
596  }
597 
598  listening.read();
599 
601 
602  // use a non-blocking approach to add a timeout to the connect
603  sock.non_blocking(true);
604  error_code ec;
605  sock.connect(addr, ec);
606  if (ec.value() != 0 && ec.value() != EINPROGRESS)
607  {
608  log << "Non blocking connect failed: " << ec.message() << endl;
609  ASSERT_EQ(ec.value(), 0);
610  }
611 
612  log << "waiting for 200 ms seconds to connect" << endl;
613  Poller pout;
614  pout.set(sock, Poller::output);
615  pout.wait(std::chrono::milliseconds(200));
616 
617  if (!pout.event(sock))
618  {
619  log << "connect attempt timed out" << endl;
620  ASSERT_EQ(pout.event(sock), 0);
621  }
622 
623  sock.non_blocking(false);
624  sock.connect(addr); // connect will either throw immediately or connect
625 
626  log << "connected, sending stuff" << endl;
627 
628  string line1("first line");
629  string line2("second line");
630 
631  scc::util::IoStream stream(sock, sock);
632 
633  string got;
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);
640  sock.close();
641 
642  serv.join();
643 
644  int res = fut.get();
645  log << "got result=" << res << endl;
646  ASSERT_EQ(res, line1.size()+line2.size());
647 }
649 
651 TEST(inet_example, tcp_multiserver)
652 {
653  Logger log;
654  log.add_cout();
655  log.id("tcp client");
656 
657  // this test sets up a client and server & streams some data between them
658 
659  scc::net::InetAddr addr;
660  addr.host("::1"); // localhost
661  addr.port(9999);
662 
663  condition_variable cv;
664  mutex mx;
665  int listening = 0; // how many threads are listening?
666  Event shut;
667 
668  auto serv_task = [&addr, &mx, &listening, &cv, &shut](int i)
669  {
670  Logger log;
671  log.add_cout();
672  log.id(string("tcp server ")+to_string(i));
673 
674  try
675  {
677  sock.reuse_addr(true);
678  sock.reuse_port(true);
679 
680  /*
681  Port and address reuse allows us to bind the same address to two distinct sockets and accept connections. This may
682  provide better performance than spawning a new thread from a single acceptor, or competing to accept from a single listening socket.
683  */
684 
685  sock.bind(addr);
686  log << "server listening" << endl;
687  sock.listen();
688 
689  log << "telling the client I am listening" << endl;
690  {
691  lock_guard<mutex> lk(mx);
692  listening++;
693  cv.notify_one();
694  }
695 
696  int count = 0;
697 
698  for (;;)
699  {
700  Poller p;
701  p.set(sock, Poller::input);
702  p.set(shut, Poller::input);
703  p.wait();
704 
705  if (p.event(shut))
706  {
707  return count;
708  }
709 
710  InetAddr from;
711  auto conn = sock.accept(from);
712  log << "connection from " << from << endl;
713 
714  IoStream stream(conn, conn);
715 
716  for (string got; std::getline(stream, got);) // loop until eof (socket closed)
717  {
718  log << "got size " << got.size() << " : " << got << endl;
719  count += got.size();
720  stream << got << endl;
721  }
722  }
723 
724  return count;
725  }
726  catch (exception& ex)
727  {
728  log << ex.what() << endl;
729  lock_guard<mutex> lk(mx); // just to make sure the client cannot block
730  listening++;
731  cv.notify_one();
732  return 0;
733  }
734  };
735 
736  auto fut1 = async(serv_task, 1);
737  auto fut2 = async(serv_task, 2);
738  auto fut3 = async(serv_task, 3);
739 
740  unique_lock<mutex> lk(mx);
741  cv.wait(lk, [&listening]
742  {
743  return listening == 3; // wait for all the threads to wake up
744  });
745 
746  int count = 0;
747 
748  for (int i = 0; i < 10; i++)
749  {
750  InetTcpSock sock;
751  sock.connect(addr);
752  log << "connected #" << i << ", sending stuff" << endl;
753 
754  string line1("first line");
755  string line2("second line");
756 
757  IoStream stream(sock, sock);
758 
759  string got;
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();
767  }
768 
769  shut.write(1);
770 
771  int res = fut1.get();
772  res += fut2.get();
773  res += fut3.get();
774  log << "got result=" << res << endl;
775  ASSERT_EQ(res, count);
776 }
Ipv6 internet address.
Definition: inet.h:120
unsigned port() const
Get the port.
Definition: inet.cc:159
virtual std::string host() const
Get host.
Definition: inet.cc:188
virtual std::string str() const
Readable address string.
Definition: inet.cc:325
Internet transmission control protocol (tcp) socket.
Definition: inet.h:251
virtual void reset()
Close the connection and reset the socket.
Definition: inet.cc:418
Internet user datagram protocol (udp) socket.
Definition: inet.h:295
virtual void reset()
Reset the socket.
Definition: inet.cc:484
static std::vector< NetIf > all_interfaces()
List network interfaces on the local system.
Definition: net_if.cc:105
void close()
Close the socket.
Definition: socket.cc:72
void connect(SockaddrBase &)
Connect to a socket address.
Definition: socket.cc:397
Signaling kernel event counter.
Definition: event.h:79
uint64_t read()
Read from (decrement) the event counter.
Definition: event.cc:82
void reset(int=-1)
Reset the event.
Definition: event.cc:63
int fd() const
Return file descriptor.
Definition: event.h:122
void write(uint64_t)
Write to (increment) the event counter.
Definition: event.cc:94
Input/output stream wrapper for reader/writer.
Definition: iostream.h:157
Thread-safe stream logger.
Definition: logger.h:86
void id(const std::string &id="")
Set the id.
Definition: logger.cc:425
void add_cout()
Add std::cout console stream.
Definition: logger.cc:418
Poller which allows polling of generic file descriptors for various events.
Definition: poller.h:66
void set(int, int)
Add a file desriptor to poller.
Definition: poller.cc:54
int event(int)
Return flags which were polled for this file descriptor.
Definition: poller.cc:171
Signaling kernel event counter.
NetIfFlag
Interface flags.
Definition: net_if.h:71
@ if_up
Interface is running.
Definition: net_if.h:72
InetAddrFlag
Internet address flags.
Definition: inet.h:74
@ unicast
Unicast address.
Definition: inet.h:82
@ link_local
Traffic is restricted to the local link.
Definition: inet.h:87
@ global
Global traffic is allowed.
Definition: inet.h:92
@ ipv4
IPv4.
Definition: inet.h:76
@ ipv6
IPv6.
Definition: inet.h:77
Internet tcp and udp networking.
Base input/output stream classes.
Thread safe logging.
Internet network interface utility.
Linux kernel i/o event notification (poller).
TEST(inet_example, client_server_stream_test)
[Inet client server]
Definition: inet.cc:521
Unix domain tcp and udp networking.