summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2014-08-13 13:18:02 +1000
committerAndrew Gerrand <adg@golang.org>2014-08-13 13:18:02 +1000
commite3338c848402d04b92de0477803a77a1de93605b (patch)
tree27eb83bd740df0a90ea38b4761e3be5ad2c366c2
parent585165a01ad6da64859da4b720605199b43928b4 (diff)
downloadgo-e3338c848402d04b92de0477803a77a1de93605b.tar.gz
[release-branch.go1.3] net: prevent spurious on-connect events via epoll on linuxgo1.3.1
??? CL 120820043 / 06a4b59c1393 net: prevent spurious on-connect events via epoll on linux 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 issue 8276. Fixes issue 8426. LGTM=dvyukov R=dvyukov, golang-codereviews, adg, dave, iant, alex.brainman CC=golang-codereviews https://codereview.appspot.com/120820043 ??? TBR=r, rsc CC=golang-codereviews https://codereview.appspot.com/128110045
-rw-r--r--src/pkg/net/fd_unix.go18
-rw-r--r--src/pkg/net/fd_windows.go9
-rw-r--r--src/pkg/net/sock_posix.go22
3 files changed, 30 insertions, 19 deletions
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index b82ecd11c..e22861abb 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -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
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index a1f6bc5f8..d1129dccc 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -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)
}
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index a6ef874c9..c80c7d6a2 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -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)