net: fix non-blocking connect handling on dragonfly
Performing multiple connect system calls on a non-blocking socket
under DragonFly BSD does not necessarily result in errors from earlier
connect calls 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.
Fixes #7474
LGTM=mikioh.mikioh
R=mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/69340044
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 54aeaeb..9b0c615 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -96,6 +96,28 @@
if err = fd.pd.WaitWrite(); 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
+ }
+ }
}
return nil
}