Hi, I am using netcat to write tests that send and receive UDP packets. Unfortunately I can terminate nc only with a timeout. This takes either too long or is unreliable.
So I implemented nc -W recvlimit. It works a bit like ping -c count. So I can quickly check for UDP responses. # echo request | nc -u -W 1 host port | grep reply Is this a useful addition? ok? bluhm Index: usr.bin/nc/nc.1 =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.bin/nc/nc.1,v retrieving revision 1.84 diff -u -p -r1.84 nc.1 --- usr.bin/nc/nc.1 5 Apr 2017 06:55:59 -0000 1.84 +++ usr.bin/nc/nc.1 10 May 2017 16:07:12 -0000 @@ -50,6 +50,7 @@ .Op Fl s Ar source .Op Fl T Ar keyword .Op Fl V Ar rtable +.Op Fl W Ar recvlimit .Op Fl w Ar timeout .Op Fl X Ar proxy_protocol .Op Fl x Ar proxy_address Ns Op : Ns Ar port @@ -288,6 +289,8 @@ Set the routing table to be used. Have .Nm give more verbose output. +.It Fl W Ar recvlimit +Terminate after receiving a number of packets from the network. .It Fl w Ar timeout Connections which cannot be established or are idle timeout after .Ar timeout Index: usr.bin/nc/netcat.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.bin/nc/netcat.c,v retrieving revision 1.181 diff -u -p -r1.181 netcat.c --- usr.bin/nc/netcat.c 16 Apr 2017 15:11:01 -0000 1.181 +++ usr.bin/nc/netcat.c 10 May 2017 15:52:47 -0000 @@ -108,6 +108,7 @@ char *tls_expectname; /* required name char *tls_expecthash; /* required hash of peer cert */ FILE *Zflag; /* file to save peer cert */ +int recvcount, recvlimit; int timeout = -1; int family = AF_UNSPEC; char *portlist[PORT_MAX+1]; @@ -167,7 +168,8 @@ main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); while ((ch = getopt(argc, argv, - "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vw:X:x:Z:z")) != -1) { + "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vW:w:X:x:Z:z")) + != -1) { switch (ch) { case '4': family = AF_INET; @@ -270,6 +272,11 @@ main(int argc, char *argv[]) case 'v': vflag = 1; break; + case 'W': + recvlimit = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr) + errx(1, "receive limit %s: %s", errstr, optarg); + break; case 'w': timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); if (errstr) @@ -1166,6 +1173,12 @@ readwrite(int net_fd, struct tls *tls_ct shutdown(pfd[POLL_NETIN].fd, SHUT_RD); pfd[POLL_NETIN].fd = -1; } + if (recvlimit > 0 && ++recvcount >= recvlimit) { + if (pfd[POLL_NETIN].fd != -1) + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; + pfd[POLL_STDIN].fd = -1; + } /* read something - poll stdout */ if (netinbufpos > 0) pfd[POLL_STDOUT].events = POLLOUT; @@ -1706,6 +1719,7 @@ help(void) \t-u UDP mode\n\ \t-V rtable Specify alternate routing table\n\ \t-v Verbose\n\ + \t-W recvlimit Terminate after receiving a number of packets\n\ \t-w timeout Timeout for connects and final net reads\n\ \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ \t-x addr[:port]\tSpecify proxy address and port\n\ @@ -1724,10 +1738,11 @@ usage(int ret) "\t [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O length]\n" "\t [-o staplefile] [-P proxy_username] [-p source_port] " "[-R CAfile]\n" - "\t [-s source] [-T keyword] [-V rtable] [-w timeout] " - "[-X proxy_protocol]\n" - "\t [-x proxy_address[:port]] [-Z peercertfile] " - "[destination] [port]\n"); + "\t [-s source] [-T keyword] [-V rtable] [-W recvlimit ] " + "[-w timeout]\n" + "\t [-X proxy_protocol] [-x proxy_address[:port]] " + "[-Z peercertfile]\n" + "\t [destination] [port]\n"); if (ret) exit(1); }