net: avoid multiple calling of syscall connect on Unix variants

The previous fix CL 69340044 still leaves a possibility of it.
This CL prevents the kernel, especially DragonFly BSD, from
performing unpredictable asynchronous connection establishment
on stream-based transport layer protocol sockets.

Update #7541
Update #7474

LGTM=jsing
R=jsing
CC=golang-codereviews
https://golang.org/cl/75930043
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 9b0c615..3b67b79 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -75,51 +75,47 @@
 	if err := fd.pd.PrepareWrite(); err != nil {
 		return err
 	}
-	for {
-		err := syscall.Connect(fd.sysfd, ra)
-		if err == nil || err == syscall.EISCONN {
-			break
-		}
-
+	switch err := syscall.Connect(fd.sysfd, ra); err {
+	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+	case nil, syscall.EISCONN:
+		return nil
+	case syscall.EINVAL:
 		// On Solaris we can see EINVAL if the socket has
 		// already been accepted and closed by the server.
 		// Treat this as a successful connection--writes to
 		// the socket will see EOF.  For details and a test
 		// case in C see http://golang.org/issue/6828.
-		if runtime.GOOS == "solaris" && err == syscall.EINVAL {
-			break
+		if runtime.GOOS == "solaris" {
+			return nil
 		}
-
-		if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+		fallthrough
+	default:
+		return err
+	}
+	for {
+		// Performing multiple connect system calls on a
+		// non-blocking socket under Unix variants does not
+		// necessarily result in earlier errors being
+		// returned. Instead, once runtime-integrated network
+		// poller tells us that the socket is ready, get the
+		// SO_ERROR socket option to see if the connection
+		// succeeded or failed. See issue 7474 for further
+		// details.
+		if err := fd.pd.WaitWrite(); err != nil {
 			return err
 		}
-		if err = fd.pd.WaitWrite(); err != nil {
+		nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		if err != nil {
 			return err
 		}
-
-		// Performing multiple connect system calls on a non-blocking
-		// socket under DragonFly BSD does not necessarily result in
-		// earlier errors being returned, particularly if we are
-		// connecting to localhost. Instead, once netpoll tells us that
-		// the socket is ready, get the SO_ERROR socket option to see
-		// if the connection succeeded or failed. See issue 7474 for
-		// further details. At some point we may want to consider
-		// doing the same on other Unixes.
-		if runtime.GOOS == "dragonfly" {
-			nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
-			if err != nil {
-				return err
-			}
-			if nerr == 0 {
-				return nil
-			}
-			err = syscall.Errno(nerr)
-			if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
-				return err
-			}
+		switch err := syscall.Errno(nerr); err {
+		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+		case syscall.Errno(0), syscall.EISCONN:
+			return nil
+		default:
+			return err
 		}
 	}
-	return nil
 }
 
 func (fd *netFD) destroy() {