From 2f45f72dce309e4afb8d1279a157ae1ad865ec8f Mon Sep 17 00:00:00 2001 From: Alexey Borzenkov Date: Mon, 28 Mar 2011 23:40:01 -0400 Subject: [PATCH] net: implement non-blocking connect Refactored bind/connect from sock.go into netFD.connect(), as a consequence newFD() doesn't accept laddr/raddr anymore, and expects an (optional) call to netFD.connect() followed by a call to netFD.setAddr(). Windows code is updated, but still uses blocking connect, since otherwise it needs support for ConnectEx syscall. R=brainman, rsc CC=golang-dev https://golang.org/cl/4303060 --- src/pkg/net/fd.go | 46 +++++++++++++++++++++++++++++++-------- src/pkg/net/fd_windows.go | 35 +++++++++++++++++++++++------ src/pkg/net/file.go | 8 +++++-- src/pkg/net/sock.go | 29 ++++++++---------------- 4 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go index df4dbce1cf..3e8780083d 100644 --- a/src/pkg/net/fd.go +++ b/src/pkg/net/fd.go @@ -274,19 +274,25 @@ func startServer() { pollserver = p } -func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { +func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) { onceStartServer.Do(startServer) if e := syscall.SetNonblock(fd, true); e != 0 { - return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)} + return nil, os.Errno(e) } f = &netFD{ sysfd: fd, family: family, proto: proto, net: net, - laddr: laddr, - raddr: raddr, } + f.cr = make(chan bool, 1) + f.cw = make(chan bool, 1) + return f, nil +} + +func (fd *netFD) setAddr(laddr, raddr Addr) { + fd.laddr = laddr + fd.raddr = raddr var ls, rs string if laddr != nil { ls = laddr.String() @@ -294,10 +300,31 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err if raddr != nil { rs = raddr.String() } - f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) - f.cr = make(chan bool, 1) - f.cw = make(chan bool, 1) - return f, nil + fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs) +} + +func (fd *netFD) connect(la, ra syscall.Sockaddr) (err os.Error) { + if la != nil { + e := syscall.Bind(fd.sysfd, la) + if e != 0 { + return os.Errno(e) + } + } + if ra != nil { + e := syscall.Connect(fd.sysfd, ra) + if e == syscall.EINPROGRESS { + var errno int + pollserver.WaitWrite(fd) + e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) + if errno != 0 { + return os.NewSyscallError("getsockopt", errno) + } + } + if e != 0 { + return os.Errno(e) + } + } + return nil } // Add a reference to this fd. @@ -593,10 +620,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() - if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil { + if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil { syscall.Close(s) return nil, err } + nfd.setAddr(fd.laddr, toAddr(sa)) return nfd, nil } diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index 63a8fbc448..0abf230ce1 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -225,29 +225,48 @@ type netFD struct { wio sync.Mutex } -func allocFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD) { +func allocFD(fd, family, proto int, net string) (f *netFD) { f = &netFD{ sysfd: fd, family: family, proto: proto, net: net, - laddr: laddr, - raddr: raddr, } runtime.SetFinalizer(f, (*netFD).Close) return f } -func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { +func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) { if initErr != nil { return nil, initErr } onceStartServer.Do(startServer) // Associate our socket with resultsrv.iocp. if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 { - return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)} + return nil, os.Errno(e) + } + return allocFD(fd, family, proto, net), nil +} + +func (fd *netFD) setAddr(laddr, raddr Addr) { + fd.laddr = laddr + fd.raddr = raddr +} + +func (fd *netFD) connect(la, ra syscall.Sockaddr) (err os.Error) { + if la != nil { + e := syscall.Bind(fd.sysfd, la) + if e != 0 { + return os.Errno(e) + } } - return allocFD(fd, family, proto, net, laddr, raddr), nil + if ra != nil { + e := syscall.Connect(fd.sysfd, ra) + if e != 0 { + return os.Errno(e) + } + } + return nil } // Add a reference to this fd. @@ -497,7 +516,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. lsa, _ := lrsa.Sockaddr() rsa, _ := rrsa.Sockaddr() - return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil + nfd = allocFD(s, fd.family, fd.proto, fd.net) + nfd.setAddr(toAddr(lsa), toAddr(rsa)) + return nfd, nil } // Not implemeted functions. diff --git a/src/pkg/net/file.go b/src/pkg/net/file.go index 5439ed994f..0e411a192f 100644 --- a/src/pkg/net/file.go +++ b/src/pkg/net/file.go @@ -9,7 +9,7 @@ import ( "syscall" ) -func newFileFD(f *os.File) (*netFD, os.Error) { +func newFileFD(f *os.File) (nfd *netFD, err os.Error) { fd, errno := syscall.Dup(f.Fd()) if errno != 0 { return nil, os.NewSyscallError("dup", errno) @@ -50,7 +50,11 @@ func newFileFD(f *os.File) (*netFD, os.Error) { sa, _ = syscall.Getpeername(fd) raddr := toAddr(sa) - return newFD(fd, 0, proto, laddr.Network(), laddr, raddr) + if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil { + return nil, err + } + nfd.setAddr(laddr, raddr) + return nfd, nil } // FileConn returns a copy of the network connection corresponding to diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go index 26816264c3..9b99ad58f8 100644 --- a/src/pkg/net/sock.go +++ b/src/pkg/net/sock.go @@ -44,33 +44,22 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) } - if la != nil { - e = syscall.Bind(s, la) - if e != 0 { - closesocket(s) - return nil, os.Errno(e) - } + if fd, err = newFD(s, f, p, net); err != nil { + closesocket(s) + return nil, err } - if ra != nil { - e = syscall.Connect(s, ra) - if e != 0 { - closesocket(s) - return nil, os.Errno(e) - } + if err = fd.connect(la, ra); err != nil { + closesocket(s) + return nil, err } - sa, _ := syscall.Getsockname(s) + sa, _ := syscall.Getsockname(fd.sysfd) laddr := toAddr(sa) - sa, _ = syscall.Getpeername(s) + sa, _ = syscall.Getpeername(fd.sysfd) raddr := toAddr(sa) - fd, err = newFD(s, f, p, net, laddr, raddr) - if err != nil { - closesocket(s) - return nil, err - } - + fd.setAddr(laddr, raddr) return fd, nil } -- 2.50.0