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

Reply via email to