33 #include <system_error>
55 using std::runtime_error;
57 using std::chrono::milliseconds;
58 using std::chrono::seconds;
72 void print_available_addrs()
75 lout <<
"Any addrs:" << endl;
77 sa.
host(
"::ffff:0.0.0.0");
78 lout <<
" " << sa << endl;
80 lout <<
" " << sa << endl;
82 auto ifs = NetIf::all_interfaces();
85 lout <<
"Interface " << i.name() <<
" (index " << i.index() <<
"):" << endl;
86 for (
auto& s : i.addrs())
88 lout <<
" " << s << endl;
93 void print_interfaces()
96 lout <<
"Interfaces: " << endl;
97 auto ifs = NetIf::all_interfaces();
100 lout << i.str() << endl;
104 string resolve(
const string& host,
bool udp=
false)
106 auto hads = NetIf::host_addrs(host, udp ? NetIf::SocketType::udp_datagram : NetIf::SocketType::tcp_stream);
109 lout <<
"* " << host <<
" --> " << hads[0] << endl;
110 return hads[0].host();
115 void test_tcp(
const string& host,
int port,
unsigned scope,
int timeout)
126 lout <<
"* connecting with " << timeout <<
" second timeout..." << endl;
132 if (ec.value() != 0 && ec.value() != EINPROGRESS)
134 throw std::system_error(ec.value(), std::system_category());
138 pout.
set(s.
fd(), Poller::output);
139 pout.wait(seconds(timeout));
143 throw runtime_error(
"timed out");
152 lout <<
"* connecting with no timeout" << endl;
155 lout <<
"* connected OK" << endl;
159 void listen_tcp(
const string& host,
int port,
unsigned scope)
166 lout <<
"* server tcp address: " << addr << endl;
171 lout <<
"* tcp binding to address" << endl;
174 lout <<
"* tcp listening" << endl;
181 lout <<
"* tcp waiting for connection" << endl;
182 auto conn = s.
accept(from);
183 lout <<
"* connection from " << from << endl;
188 while (getline(st, got))
190 lout <<
"echo > " << got << endl;
193 lout <<
"* input stream failed: eof()=" << st.eof() << endl;
197 void connect_tcp(
const string& host,
int port,
unsigned scope)
204 lout <<
"* address: " << addr << endl;
209 lout <<
"* tcp connect..." << endl;
212 lout <<
"* connected, sending keyboard input to server" << endl;
216 thread t([&s, &done]()
224 pin.
set(done, Poller::input);
225 pin.
set(s.
fd(), Poller::input);
229 pin.wait(milliseconds(100));
232 tout <<
"* done signal, thread exit" << endl;
236 while (getline(st, got))
238 tout <<
"got > " << got << endl;
247 std::this_thread::sleep_for(milliseconds(100));
250 getline(std::cin, cmd);
252 if (!(st << cmd << endl))
254 lout <<
"* output stream failed, exit" << endl;
265 void listen_udp(
const string& host,
int port,
unsigned scope)
272 lout <<
"* server udp address: " << addr << endl;
277 lout <<
"* udp binding to address" << endl;
281 pin.
set(s.
fd(), Poller::input);
291 s.
recv(&got[0], sz, from);
294 lout <<
"echo to " << from.
host() <<
" > " << got;
295 s.
send(got.data(), sz, from);
299 void connect_udp(
const string& host,
int port,
unsigned scope)
306 lout <<
"* connect udp address: " << addr << endl;
313 thread t([&s, &done]()
319 pin.
set(s.
fd(), Poller::input);
320 pin.
set(done, Poller::input);
328 tout <<
"* done signal, thread exit" << endl;
333 auto sz = s.recv_next();
337 if (s.recv(&got[0], sz, from) <= 0)
339 tout <<
"* recv failed, thread exit" << endl;
344 tout <<
"got from " << from <<
" > " << got;
349 lout <<
"* sending keyboard input to server" << endl;
353 std::this_thread::sleep_for(milliseconds(100));
356 getline(std::cin, cmd);
360 if (s.
send(&cmd[0], cmd.size(), addr) <= 0)
362 lout <<
"* send failed, exit" << endl;
372 void test_connection(
const string& host,
int port,
unsigned scope,
int timeout)
376 test_tcp(resolve(host), port, scope, timeout);
378 catch (exception& ex)
380 lout <<
"* connection failed: " << ex.what() << endl;
386 void server(
const string& host,
int port,
bool udp,
unsigned scope)
392 listen_udp(resolve(host,
true), port, scope);
396 listen_tcp(resolve(host), port, scope);
399 catch (exception& ex)
401 lout <<
"* server failed: " << ex.what() << endl;
407 void client(
const string& host,
int port,
bool udp,
unsigned scope)
413 connect_udp(resolve(host,
true), port, scope);
417 connect_tcp(resolve(host), port, scope);
420 catch (exception& ex)
422 lout <<
"* client failed: " << ex.what() << endl;
427 int main(
int argc,
char **argv)
430 memset(&lo[0], 0, 32*
sizeof(option));
436 lo[2].name =
"addrs";
438 lo[3].name =
"listen";
444 lo[6].name =
"resolve";
446 lo[7].name =
"scope";
452 bool usage=
false, listen=
false, udp=
false, test=
false, resolve=
false;
457 int opt = getopt_long(argc, argv,
"?IAluTRs:", &lo[0],
nullptr);
472 print_available_addrs();
488 if (!optarg) usage =
true;
489 else scope = atoi(optarg);
497 int nargs = argc-optind;
501 if (nargs < 1) usage =
true;
505 if (nargs < 2) usage =
true;
511 cerr << argv[0] << endl;
512 cerr <<
" scclib net module example" << endl;
514 cerr <<
" For ipv4 addresses, use ipv4/6 syntax, e.g. ::ffff:192.168.1.1" << endl;
516 cerr <<
" Informational:" << endl;
517 cerr <<
" -I|--ifs print out interfaces and return" << endl;
518 cerr <<
" -A|--addrs print out addrs and return" << endl;
519 cerr <<
" -R|--resolve HOST1 HOST2 .. resolve host(s) and return" << endl;
520 cerr <<
" Test:" << endl;
521 cerr <<
" -T|--test HOST PORT [secs] perform tcp connection test and return" << endl;
522 cerr <<
" Client:" << endl;
523 cerr <<
" HOST PORT connect and send keyboard input" << endl;
524 cerr <<
" Server:" << endl;
525 cerr <<
" -l HOST PORT listen and echo" << endl;
526 cerr <<
" Common params for client/server:" << endl;
527 cerr <<
" -u|--udp udp mode" << endl;
528 cerr <<
" -s|--scope <NUM> set scope_id for address" << endl;
534 while (optind < argc)
536 lout <<
"* resolving " << argv[optind] << endl;
537 auto hads = NetIf::host_addrs(argv[optind], udp ? NetIf::SocketType::udp_datagram : NetIf::SocketType::tcp_stream);
540 lout <<
"* not resolved" << endl;
542 else for (
auto& i : hads)
544 lout <<
"* " << i << endl;
551 test_connection(argv[optind], atoi(argv[optind+1]), scope, optind+2 < argc ? atoi(argv[optind+2]) : -1);
555 server(argv[optind], atoi(argv[optind+1]), udp, scope);
559 client(argv[optind], atoi(argv[optind+1]), udp, scope);
unsigned port() const
Get the port.
void scope_id(uint32_t)
Set the scope id of the address.
virtual std::string host() const
Get host.
Internet transmission control protocol (tcp) socket.
InetTcpSock accept()
Accept a connection from an anonymous peer.
Internet user datagram protocol (udp) socket.
int fd() const
Return the underlying socket handle.
void non_blocking(bool b=true)
Set the socket non-blocking.
void bind(const SockaddrBase &)
Bind an address to the socket.
void reuse_addr(bool r=true)
Set address reusable.
void close()
Close the socket.
void listen(int maxConnections=10)
Set to accept connections.
void connect(SockaddrBase &)
Connect to a socket address.
size_t recv(void *loc, size_t len, SockaddrBase &s)
Receive bytes (a datagram), setting the socket address of the peer.
size_t send(const void *loc, size_t len, const SockaddrBase &d)
Send bytes (a datagram) to a peer address.
size_t recv_next()
Return the number of bytes available to read (the size of the next datagram).
Signaling kernel event counter.
void write(uint64_t)
Write to (increment) the event counter.
Input stream wrapper for reader.
Input/output stream wrapper for reader/writer.
Thread-safe stream logger.
void add_cout()
Add std::cout console stream.
Output stream wrapper for writer.
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.
Internet tcp and udp networking.
Base input/output stream classes.
Internet network interface utility.
Linux kernel i/o event notification (poller).