Hi,

When running my pf regression tests, I triggered netcat hanging in
write(2).  This is bit strange as poll(2) should check that the socket
is writeable.  However making the network socket non-blocking
keeps the data flowing.  Note that the code to handle EAGAIN is
already there.

To trigger the blocking write(2) I use:
openssl rand 200000 | nc -N tcp-echo-server 7 | wc -c | grep 200000$

Ktrace shows that it happens from time to time:
 11789 nc       CALL  poll(0x7f7ffffbd5e0,4,INFTIM)
 11789 nc       RET   poll 2
 11789 nc       CALL  write(3,0x7f7ffffbd610,0x4000)
 11789 nc       RET   write -1 errno 35 Resource temporarily unavailable
 11789 nc       CALL  read(3,0x7f7ffffc1610,0x4000)
 11789 nc       GIO   fd 3 read 2048 bytes

ok?

bluhm

Index: usr.bin/nc/netcat.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.130
diff -u -p -r1.130 netcat.c
--- usr.bin/nc/netcat.c 26 Jul 2015 19:12:28 -0000      1.130
+++ usr.bin/nc/netcat.c 17 Aug 2015 07:25:30 -0000
@@ -95,7 +95,7 @@ int   Sflag;                                  /* TCP MD5 
signature opti
 int    Tflag = -1;                             /* IP Type of Service */
 int    rtableid = -1;
 
-int timeout = -1;
+int timeout = INFTIM;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
 char *unix_dg_tmp_socket;
@@ -397,8 +397,8 @@ main(int argc, char *argv[])
                                readwrite(s);
                        } else {
                                len = sizeof(cliaddr);
-                               connfd = accept(s, (struct sockaddr *)&cliaddr,
-                                   &len);
+                               connfd = accept4(s, (struct sockaddr *)&cliaddr,
+                                   &len, SOCK_NONBLOCK);
                                if (connfd == -1) {
                                        /* For now, all errnos are fatal */
                                        err(1, "accept");
@@ -594,8 +594,8 @@ remote_connect(const char *host, const c
 
        res0 = res;
        do {
-               if ((s = socket(res0->ai_family, res0->ai_socktype,
-                   res0->ai_protocol)) < 0)
+               if ((s = socket(res0->ai_family, res0->ai_socktype |
+                   SOCK_NONBLOCK, res0->ai_protocol)) < 0)
                        continue;
 
                if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
@@ -644,15 +644,9 @@ timeout_connect(int s, const struct sock
 {
        struct pollfd pfd;
        socklen_t optlen;
-       int flags, optval;
+       int optval;
        int ret;
 
-       if (timeout != -1) {
-               flags = fcntl(s, F_GETFL, 0);
-               if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
-                       err(1, "set non-blocking mode");
-       }
-
        if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
                pfd.fd = s;
                pfd.events = POLLOUT;
@@ -669,9 +663,6 @@ timeout_connect(int s, const struct sock
                } else
                        err(1, "poll failed");
        }
-
-       if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
-               err(1, "restoring flags");
 
        return (ret);
 }

Reply via email to