connect_sync looks like it could be a useful piece of code in other places.
however, putting the loop in the function means that ^C may not work... ftp
has disgusting signal handlers and longjmps, but i don't think that's how we
want other programs to be written.

i've rewritten the function slightly to return an error code. if the error is
EAGAIN, then the caller should call it again. or not, if a signal flag has
been set. thus we don't get stuck in a loop.

the changes required to the callers in ftp are minimal but this is a more
useful "recipe". thoughts?


Index: fetch.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/fetch.c,v
retrieving revision 1.148
diff -u -p -r1.148 fetch.c
--- fetch.c     18 Aug 2016 16:23:06 -0000      1.148
+++ fetch.c     19 Aug 2016 21:03:01 -0000
@@ -558,7 +558,10 @@ noslash:
 #endif /* !SMALL */
 
 again:
-               if (connect_sync(s, res->ai_addr, res->ai_addrlen) < 0) {
+               while ((error = connect_sync(s, res->ai_addr, res->ai_addrlen))
+                   == EAGAIN)
+                       continue;
+               if (error) {
                        save_errno = errno;
                        close(s);
                        errno = save_errno;
Index: ftp.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
retrieving revision 1.98
diff -u -p -r1.98 ftp.c
--- ftp.c       18 Aug 2016 16:23:06 -0000      1.98
+++ ftp.c       19 Aug 2016 21:04:43 -0000
@@ -219,7 +219,9 @@ hookup(char *host, char *port)
                        }
                }
 #endif /* !SMALL */
-               error = connect_sync(s, res->ai_addr, res->ai_addrlen);
+               while ((error = connect_sync(s, res->ai_addr, res->ai_addrlen))
+                   == EAGAIN)
+                       continue;
                if (error) {
                        /* this "if" clause is to prevent print warning twice */
                        if (verbose && res->ai_next) {
@@ -1514,8 +1516,10 @@ reinit:
                } else
                        goto bad;
 
-               if (connect_sync(data, (struct sockaddr *)&data_addr,
-                           data_addr.su_len) < 0) {
+               while ((error = connect_sync(data, (struct sockaddr 
*)&data_addr,
+                           data_addr.su_len)) == EAGAIN)
+                       continue;
+               if (error) {
                        if (activefallback) {
                                (void)close(data);
                                data = -1;
Index: util.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/util.c,v
retrieving revision 1.80
diff -u -p -r1.80 util.c
--- util.c      18 Aug 2016 16:23:06 -0000      1.80
+++ util.c      19 Aug 2016 21:00:31 -0000
@@ -1076,29 +1076,29 @@ controlediting(void)
 int
 connect_sync(int s, const struct sockaddr *name, socklen_t namelen)
 {
-       struct pollfd pfd[1];
-       int error = 0;
-       socklen_t len = sizeof(error);
+       int error;
 
-       if (connect(s, name, namelen) < 0) {
-               if (errno != EINTR)
-                       return -1;
-       }
+       if (connect(s, name, namelen) == 0)
+               return 0;
+       if (errno == EINTR)
+               return EAGAIN;
+       if (errno == EALREADY) {
+               /* An interrupted connect(2) continues asyncronously. */
+               struct pollfd pfd[1];
+               socklen_t len = sizeof(error);
 
-       /* An interrupted connect(2) continues asyncronously. */
-       pfd[0].fd = s;
-       pfd[0].events = POLLOUT;
-       for (;;) {
+               pfd[0].fd = s;
+               pfd[0].events = POLLOUT;
                if (poll(pfd, 1, -1) == -1) {
-                       if (errno != EINTR)
-                               return -1;
-                       continue;
+                       if (errno == EINTR)
+                               return EAGAIN;
+                       return errno;
                }
                if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
-                       return -1;
+                       return errno;
                if (error != 0)
-                       errno = error;
-               break;
+                       return error;
        }
-       return (error ? -1 : 0);
+
+       return errno;
 }

Reply via email to