]> Cypherpunks repositories - gostls13.git/commitdiff
net: prevent spurious on-connect events via epoll on linux
authorMikio Hara <mikioh.mikioh@gmail.com>
Tue, 29 Jul 2014 07:48:11 +0000 (16:48 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 29 Jul 2014 07:48:11 +0000 (16:48 +0900)
On Linux, adding a socket descriptor to epoll instance before getting
the EINPROGRESS return value from connect system call could be a root
cause of spurious on-connect events.

See golang.org/issue/8276, golang.org/issue/8426 for further information.

All credit to Jason Eggleston <jason@eggnet.com>

Fixes #8276.
Fixes #8426.

LGTM=dvyukov
R=dvyukov, golang-codereviews, adg, dave, iant, alex.brainman
CC=golang-codereviews
https://golang.org/cl/120820043

src/pkg/net/fd_unix.go
src/pkg/net/fd_windows.go
src/pkg/net/sock_posix.go

index b82ecd11c1abce64705833054fc18ecf4311a0e7..e22861abbda9912b6e3ca7910c1cc90d6782cff3 100644 (file)
@@ -68,16 +68,19 @@ func (fd *netFD) name() string {
        return fd.net + ":" + ls + "->" + rs
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
+func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
-       if err := fd.pd.PrepareWrite(); err != nil {
-               return err
-       }
        switch err := syscall.Connect(fd.sysfd, ra); err {
        case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
        case nil, syscall.EISCONN:
+               if !deadline.IsZero() && deadline.Before(time.Now()) {
+                       return errTimeout
+               }
+               if err := fd.init(); err != nil {
+                       return err
+               }
                return nil
        case syscall.EINVAL:
                // On Solaris we can see EINVAL if the socket has
@@ -92,6 +95,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
        default:
                return err
        }
+       if err := fd.init(); err != nil {
+               return err
+       }
+       if !deadline.IsZero() {
+               fd.setWriteDeadline(deadline)
+               defer fd.setWriteDeadline(noDeadline)
+       }
        for {
                // Performing multiple connect system calls on a
                // non-blocking socket under Unix variants does not
index a1f6bc5f8148cb40fcbf45c7507da707dd5c89dd..d1129dccc47d8a857d038cf5758b794f5dacd80b 100644 (file)
@@ -313,10 +313,17 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
        runtime.SetFinalizer(fd, (*netFD).Close)
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
+func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
+       if err := fd.init(); err != nil {
+               return err
+       }
+       if !deadline.IsZero() {
+               fd.setWriteDeadline(deadline)
+               defer fd.setWriteDeadline(noDeadline)
+       }
        if !canUseConnectEx(fd.net) {
                return syscall.Connect(fd.sysfd, ra)
        }
index a6ef874c9fda0b3304dd503f2c1b836d2b5e200f..c80c7d6a2f1242f9a105d63b2cae59cad68adeec 100644 (file)
@@ -107,24 +107,18 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(sys
                        }
                }
        }
-       if err := fd.init(); err != nil {
-               return err
-       }
        var rsa syscall.Sockaddr
        if raddr != nil {
                if rsa, err = raddr.sockaddr(fd.family); err != nil {
                        return err
-               } else if rsa != nil {
-                       if !deadline.IsZero() {
-                               fd.setWriteDeadline(deadline)
-                       }
-                       if err := fd.connect(lsa, rsa); err != nil {
-                               return err
-                       }
-                       fd.isConnected = true
-                       if !deadline.IsZero() {
-                               fd.setWriteDeadline(noDeadline)
-                       }
+               }
+               if err := fd.connect(lsa, rsa, deadline); err != nil {
+                       return err
+               }
+               fd.isConnected = true
+       } else {
+               if err := fd.init(); err != nil {
+                       return err
                }
        }
        lsa, _ = syscall.Getsockname(fd.sysfd)