Commit 2f45f72d authored by Alexey Borzenkov's avatar Alexey Borzenkov Committed by Russ Cox

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
parent 98828f03
...@@ -274,19 +274,25 @@ func startServer() { ...@@ -274,19 +274,25 @@ func startServer() {
pollserver = p 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) onceStartServer.Do(startServer)
if e := syscall.SetNonblock(fd, true); e != 0 { if e := syscall.SetNonblock(fd, true); e != 0 {
return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)} return nil, os.Errno(e)
} }
f = &netFD{ f = &netFD{
sysfd: fd, sysfd: fd,
family: family, family: family,
proto: proto, proto: proto,
net: net, 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 var ls, rs string
if laddr != nil { if laddr != nil {
ls = laddr.String() ls = laddr.String()
...@@ -294,10 +300,31 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err ...@@ -294,10 +300,31 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err
if raddr != nil { if raddr != nil {
rs = raddr.String() rs = raddr.String()
} }
f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
f.cr = make(chan bool, 1) }
f.cw = make(chan bool, 1)
return f, nil 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. // Add a reference to this fd.
...@@ -593,10 +620,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. ...@@ -593,10 +620,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
syscall.CloseOnExec(s) syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock() 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) syscall.Close(s)
return nil, err return nil, err
} }
nfd.setAddr(fd.laddr, toAddr(sa))
return nfd, nil return nfd, nil
} }
......
...@@ -225,29 +225,48 @@ type netFD struct { ...@@ -225,29 +225,48 @@ type netFD struct {
wio sync.Mutex 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{ f = &netFD{
sysfd: fd, sysfd: fd,
family: family, family: family,
proto: proto, proto: proto,
net: net, net: net,
laddr: laddr,
raddr: raddr,
} }
runtime.SetFinalizer(f, (*netFD).Close) runtime.SetFinalizer(f, (*netFD).Close)
return f 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 { if initErr != nil {
return nil, initErr return nil, initErr
} }
onceStartServer.Do(startServer) onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp. // Associate our socket with resultsrv.iocp.
if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 { 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. // Add a reference to this fd.
...@@ -497,7 +516,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. ...@@ -497,7 +516,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
lsa, _ := lrsa.Sockaddr() lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.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. // Not implemeted functions.
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"syscall" "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()) fd, errno := syscall.Dup(f.Fd())
if errno != 0 { if errno != 0 {
return nil, os.NewSyscallError("dup", errno) return nil, os.NewSyscallError("dup", errno)
...@@ -50,7 +50,11 @@ func newFileFD(f *os.File) (*netFD, os.Error) { ...@@ -50,7 +50,11 @@ func newFileFD(f *os.File) (*netFD, os.Error) {
sa, _ = syscall.Getpeername(fd) sa, _ = syscall.Getpeername(fd)
raddr := toAddr(sa) 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 // FileConn returns a copy of the network connection corresponding to
......
...@@ -44,33 +44,22 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal ...@@ -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) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
} }
if la != nil { if fd, err = newFD(s, f, p, net); err != nil {
e = syscall.Bind(s, la) closesocket(s)
if e != 0 { return nil, err
closesocket(s)
return nil, os.Errno(e)
}
} }
if ra != nil { if err = fd.connect(la, ra); err != nil {
e = syscall.Connect(s, ra) closesocket(s)
if e != 0 { return nil, err
closesocket(s)
return nil, os.Errno(e)
}
} }
sa, _ := syscall.Getsockname(s) sa, _ := syscall.Getsockname(fd.sysfd)
laddr := toAddr(sa) laddr := toAddr(sa)
sa, _ = syscall.Getpeername(s) sa, _ = syscall.Getpeername(fd.sysfd)
raddr := toAddr(sa) raddr := toAddr(sa)
fd, err = newFD(s, f, p, net, laddr, raddr) fd.setAddr(laddr, raddr)
if err != nil {
closesocket(s)
return nil, err
}
return fd, nil return fd, nil
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment