POSIX says connect(2) does not restart so we need to do the same
kind of dance as async connect(2).

 - todd

Index: usr.bin/ftp/ftp.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
retrieving revision 1.96
diff -u -p -u -r1.96 ftp.c
--- usr.bin/ftp/ftp.c   16 Mar 2016 15:41:11 -0000      1.96
+++ usr.bin/ftp/ftp.c   8 Aug 2016 18:56:33 -0000
@@ -108,6 +108,36 @@ off_t      restart_point = 0;
 
 FILE   *cin, *cout;
 
+static int
+connect_sync(int s, const struct sockaddr *name, socklen_t namelen)
+{
+       struct pollfd pfd[1];
+       int error = 0;
+       socklen_t len = sizeof(error);
+
+       if (connect(s, name, namelen) < 0) {
+               if (errno != EINTR)
+                       return -1;
+       }
+
+       /* An interrupted connect(2) continues asyncronously. */
+       pfd[0].fd = s;
+       pfd[0].events = POLLOUT;
+       for (;;) {
+               if (poll(pfd, 1, -1) == -1) {
+                       if (errno != EINTR)
+                               return -1;
+                       continue;
+               }
+               if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+                       return -1;
+               if (error != 0)
+                       errno = error;
+               break;
+       }
+       return (error ? -1 : 0);
+}
+
 char *
 hookup(char *host, char *port)
 {
@@ -219,10 +249,7 @@ hookup(char *host, char *port)
                        }
                }
 #endif /* !SMALL */
-               while ((error = connect(s, res->ai_addr, res->ai_addrlen)) < 0
-                               && errno == EINTR) {
-                       ;
-               }
+               error = connect_sync(s, res->ai_addr, res->ai_addrlen);
                if (error) {
                        /* this "if" clause is to prevent print warning twice */
                        if (verbose && res->ai_next) {
@@ -1517,10 +1544,8 @@ reinit:
                } else
                        goto bad;
 
-               while (connect(data, (struct sockaddr *)&data_addr,
+               if (connect_sync(data, (struct sockaddr *)&data_addr,
                            data_addr.su_len) < 0) {
-                       if (errno == EINTR)
-                               continue;
                        if (activefallback) {
                                (void)close(data);
                                data = -1;

Reply via email to