diff options
Diffstat (limited to 'src/pkg/net/fd_unix.go')
-rw-r--r-- | src/pkg/net/fd_unix.go | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go index 9ed4f7536..b82ecd11c 100644 --- a/src/pkg/net/fd_unix.go +++ b/src/pkg/net/fd_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package net @@ -75,19 +75,47 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error { 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: + 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" { + return nil + } + fallthrough + default: + return err + } for { - err := syscall.Connect(fd.sysfd, ra) - if err == nil || err == syscall.EISCONN { - break + // 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 != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR { + nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) + if err != nil { return err } - if err = fd.pd.WaitWrite(); err != nil { + 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() { @@ -180,11 +208,11 @@ func (fd *netFD) shutdown(how int) error { return nil } -func (fd *netFD) CloseRead() error { +func (fd *netFD) closeRead() error { return fd.shutdown(syscall.SHUT_RD) } -func (fd *netFD) CloseWrite() error { +func (fd *netFD) closeWrite() error { return fd.shutdown(syscall.SHUT_WR) } @@ -215,7 +243,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) { return } -func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { if err := fd.readLock(); err != nil { return 0, nil, err } @@ -242,7 +270,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { return } -func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { if err := fd.readLock(); err != nil { return 0, 0, 0, nil, err } @@ -313,7 +341,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) { return nn, err } -func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { +func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { if err := fd.writeLock(); err != nil { return 0, err } @@ -338,7 +366,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { return } -func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { +func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { if err := fd.writeLock(); err != nil { return 0, 0, err } @@ -347,7 +375,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob return 0, 0, &OpError{"write", fd.net, fd.raddr, err} } for { - err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) + n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0) if err == syscall.EAGAIN { if err = fd.pd.WaitWrite(); err == nil { continue @@ -356,7 +384,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob break } if err == nil { - n = len(p) oobn = len(oob) } else { err = &OpError{"write", fd.net, fd.raddr, err} @@ -455,7 +482,6 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) { func (fd *netFD) dup() (f *os.File, err error) { ns, err := dupCloseOnExec(fd.sysfd) if err != nil { - syscall.ForkLock.RUnlock() return nil, &OpError{"dup", fd.net, fd.laddr, err} } |