]> Cypherpunks repositories - gostls13.git/commitdiff
net: implement non-blocking connect
authorAlexey Borzenkov <snaury@gmail.com>
Tue, 29 Mar 2011 03:40:01 +0000 (23:40 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 29 Mar 2011 03:40:01 +0000 (23:40 -0400)
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
src/pkg/net/fd_windows.go
src/pkg/net/file.go
src/pkg/net/sock.go

index df4dbce1cfb5de596bc28e2f09885b7d9cfdcc26..3e8780083d5c2e2707ddc943a5984a8c1a8498f6 100644 (file)
@@ -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
 }
 
index 63a8fbc44898a202ee57613f8d64443d3074b21b..0abf230ce1cd9c4e55e64d1dc2987de998c2b3b4 100644 (file)
@@ -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.
index 5439ed994f3df0c64ba1ba023d23f55e5d259fba..0e411a192f2393715e6b03e9ccc7a4c12a68446c 100644 (file)
@@ -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
index 26816264c323175ceac49f6ebf2b5b47d9483706..9b99ad58f8c01221fad065ce64e510635c2a11ec 100644 (file)
@@ -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
 }