Hi, I need a shell utility for sending udp datagrams. Of course netcat is the tool of choice for this purpose. But our netcat won't ever terminate when used for sending an udp datagram:
$ echo 'Hello, World!' |nc -Nu 8.8.8.8 53 also our netcat shows undefined behavior when started with closed stdin or stdout: $ nc -l 2000 <&- >&- & [1] 30593 $ echo 'Hello, World!' |nc localhost 2000 Hello, World! that's bizarre. The nc -l is dual-using its network socket as stdout or stdin by accident. I think the most natural behavior for netcat would be to terminate when stdout and stdin are closed and to switch to half-duplex when only one of them is closed. I believe the two diffs I provide will accomplish this without changing the current defined behavior of netcat. I split the diff in two. The first one contains all the code changes and will apply and compile just fine. The second one contains a reordering of the main loop which would have made the first diff unreadable. As a cosmetic change reordered the indices on pfd to match the filedescriptors. Don't let this confuse you. I'm not 100% sure whether the new close(lfd); I added is without bad sideeffects. I added it because the shutdown(lfd, SHUT_WR) only works for sockets. OK? comments? Christopher --- netcat.c.orig Sun Mar 30 23:05:14 2014 +++ netcat.c Mon Mar 31 19:21:53 2014 @@ -66,7 +66,8 @@ #define UNIX_DG_TMP_SOCKET_SIZE 19 /* Command Line Options */ -int dflag; /* detached, no stdin */ +int nostdin; /* detached, no stdin */ +int nostdout; /* no stdout */ int Fflag; /* fdpass sock to stdout */ unsigned int iflag; /* Interval Flag */ int kflag; /* More than one connect */ @@ -157,7 +158,7 @@ errx(1, "unsupported proxy protocol"); break; case 'd': - dflag = 1; + nostdin = 1; break; case 'F': Fflag = 1; @@ -286,6 +287,13 @@ if (!lflag && kflag) errx(1, "must use -l with -k"); + if (nostdin) Nflag = 0; + /* check if stdin / stdout are open */ + if (dup2(STDIN_FILENO, STDIN_FILENO) == -1 && errno == EBADF) + nostdin = 1; + if (dup2(STDOUT_FILENO, STDOUT_FILENO) == -1 && errno == EBADF) + nostdout = 1; + /* Get name of temporary socket for unix datagram client */ if ((family == AF_UNIX) && uflag && !lflag) { if (sflag) { @@ -732,27 +740,34 @@ void readwrite(int nfd) { - struct pollfd pfd[2]; + struct pollfd pfd[3]; unsigned char buf[16384]; - int n, wfd = fileno(stdin); + int n, wfd = nostdin ? -1 : STDIN_FILENO; - int lfd = fileno(stdout); + int lfd = nostdout ? -1 : STDOUT_FILENO; int plen; plen = 2048; /* Setup Network FD */ - pfd[0].fd = nfd; + pfd[2].fd = nfd; - pfd[0].events = POLLIN; + pfd[2].events = POLLIN; /* Set up STDIN FD. */ - pfd[1].fd = wfd; + pfd[0].fd = wfd; - pfd[1].events = POLLIN; + pfd[0].events = POLLIN; + /* Set up STDOUT FD. */ + pfd[1].fd = lfd; + pfd[1].events = POLLHUP; + + if (nostdin && Nflag) shutdown(nfd, SHUT_WR); + if (nostdout) shutdown(nfd, SHUT_RD); + - while (pfd[0].fd != -1) { + while (pfd[0].fd != -1 || pfd[1].fd != -1) { if (iflag) sleep(iflag); - if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { + if ((n = poll(pfd, 3, timeout)) < 0) { close(nfd); err(1, "Polling Error"); } @@ -760,13 +775,16 @@ if (n == 0) return; - if (pfd[0].revents & POLLIN) { + if (pfd[2].revents & POLLIN) { if ((n = read(nfd, buf, plen)) < 0) return; else if (n == 0) { shutdown(nfd, SHUT_RD); + shutdown(lfd, SHUT_WR); + close(lfd); + /*if (!Nflag)*/ return; - pfd[0].fd = -1; - pfd[0].events = 0; + pfd[1].fd = -1; + pfd[2].events = POLLHUP; } else { if (tflag) atelnet(nfd, buf, n); @@ -775,18 +793,30 @@ } } - if (!dflag && pfd[1].revents & POLLIN) { + if (pfd[0].revents & POLLIN) { if ((n = read(wfd, buf, plen)) < 0) return; else if (n == 0) { if (Nflag) shutdown(nfd, SHUT_WR); + shutdown(wfd, SHUT_RD); - pfd[1].fd = -1; - pfd[1].events = 0; + pfd[0].fd = -1; } else { if (atomicio(vwrite, nfd, buf, n) != n) return; } + } + + if (pfd[2].revents & POLLHUP) { + shutdown(wfd, SHUT_RD); + close(wfd); + pfd[2].fd = -1; + pfd[0].fd = -1; + } + + if (pfd[1].revents & POLLHUP) { + shutdown(nfd, SHUT_RD); + pfd[1].fd = -1; } } } --- netcat.c.1 Mon Mar 31 19:21:53 2014 +++ netcat.c Mon Mar 31 19:25:37 2014 @@ -748,10 +748,6 @@ plen = 2048; - /* Setup Network FD */ - pfd[2].fd = nfd; - pfd[2].events = POLLIN; - /* Set up STDIN FD. */ pfd[0].fd = wfd; pfd[0].events = POLLIN; @@ -760,6 +756,10 @@ pfd[1].fd = lfd; pfd[1].events = POLLHUP; + /* Setup Network FD */ + pfd[2].fd = nfd; + pfd[2].events = POLLIN; + if (nostdin && Nflag) shutdown(nfd, SHUT_WR); if (nostdout) shutdown(nfd, SHUT_RD); @@ -775,6 +775,20 @@ if (n == 0) return; + if (pfd[0].revents & POLLIN) { + if ((n = read(wfd, buf, plen)) < 0) + return; + else if (n == 0) { + if (Nflag) + shutdown(nfd, SHUT_WR); + shutdown(wfd, SHUT_RD); + pfd[0].fd = -1; + } else { + if (atomicio(vwrite, nfd, buf, n) != n) + return; + } + } + if (pfd[2].revents & POLLIN) { if ((n = read(nfd, buf, plen)) < 0) return; @@ -789,20 +803,6 @@ if (tflag) atelnet(nfd, buf, n); if (atomicio(vwrite, lfd, buf, n) != n) - return; - } - } - - if (pfd[0].revents & POLLIN) { - if ((n = read(wfd, buf, plen)) < 0) - return; - else if (n == 0) { - if (Nflag) - shutdown(nfd, SHUT_WR); - shutdown(wfd, SHUT_RD); - pfd[0].fd = -1; - } else { - if (atomicio(vwrite, nfd, buf, n) != n) return; } } -- http://gmerlin.de OpenPGP: http://gmerlin.de/christopher.pub F190 D013 8F01 AA53 E080 3F3C F17F B0A1 D44E 4FEE