Skip to content

Commit c0325f5

Browse files
committed
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 <[email protected]> Fixes #8276. Fixes #8426. LGTM=dvyukov R=dvyukov, golang-codereviews, adg, dave, iant, alex.brainman CC=golang-codereviews https://golang.org/cl/120820043
1 parent 9333fe8 commit c0325f5

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

src/pkg/net/fd_unix.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,19 @@ func (fd *netFD) name() string {
6868
return fd.net + ":" + ls + "->" + rs
6969
}
7070

71-
func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
71+
func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
7272
// Do not need to call fd.writeLock here,
7373
// because fd is not yet accessible to user,
7474
// so no concurrent operations are possible.
75-
if err := fd.pd.PrepareWrite(); err != nil {
76-
return err
77-
}
7875
switch err := syscall.Connect(fd.sysfd, ra); err {
7976
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
8077
case nil, syscall.EISCONN:
78+
if !deadline.IsZero() && deadline.Before(time.Now()) {
79+
return errTimeout
80+
}
81+
if err := fd.init(); err != nil {
82+
return err
83+
}
8184
return nil
8285
case syscall.EINVAL:
8386
// On Solaris we can see EINVAL if the socket has
@@ -92,6 +95,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
9295
default:
9396
return err
9497
}
98+
if err := fd.init(); err != nil {
99+
return err
100+
}
101+
if !deadline.IsZero() {
102+
fd.setWriteDeadline(deadline)
103+
defer fd.setWriteDeadline(noDeadline)
104+
}
95105
for {
96106
// Performing multiple connect system calls on a
97107
// non-blocking socket under Unix variants does not

src/pkg/net/fd_windows.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,17 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
313313
runtime.SetFinalizer(fd, (*netFD).Close)
314314
}
315315

316-
func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
316+
func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
317317
// Do not need to call fd.writeLock here,
318318
// because fd is not yet accessible to user,
319319
// so no concurrent operations are possible.
320+
if err := fd.init(); err != nil {
321+
return err
322+
}
323+
if !deadline.IsZero() {
324+
fd.setWriteDeadline(deadline)
325+
defer fd.setWriteDeadline(noDeadline)
326+
}
320327
if !canUseConnectEx(fd.net) {
321328
return syscall.Connect(fd.sysfd, ra)
322329
}

src/pkg/net/sock_posix.go

+8-14
Original file line numberDiff line numberDiff line change
@@ -107,24 +107,18 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(sys
107107
}
108108
}
109109
}
110-
if err := fd.init(); err != nil {
111-
return err
112-
}
113110
var rsa syscall.Sockaddr
114111
if raddr != nil {
115112
if rsa, err = raddr.sockaddr(fd.family); err != nil {
116113
return err
117-
} else if rsa != nil {
118-
if !deadline.IsZero() {
119-
fd.setWriteDeadline(deadline)
120-
}
121-
if err := fd.connect(lsa, rsa); err != nil {
122-
return err
123-
}
124-
fd.isConnected = true
125-
if !deadline.IsZero() {
126-
fd.setWriteDeadline(noDeadline)
127-
}
114+
}
115+
if err := fd.connect(lsa, rsa, deadline); err != nil {
116+
return err
117+
}
118+
fd.isConnected = true
119+
} else {
120+
if err := fd.init(); err != nil {
121+
return err
128122
}
129123
}
130124
lsa, _ = syscall.Getsockname(fd.sysfd)

0 commit comments

Comments
 (0)