mirror of
https://github.com/golang/go.git
synced 2025-11-10 21:51:05 +00:00
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
This commit is contained in:
parent
98828f033a
commit
2f45f72dce
4 changed files with 83 additions and 41 deletions
|
|
@ -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
|
||||||
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.
|
||||||
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 {
|
||||||
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, laddr, raddr), nil
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.
|
||||||
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 (
|
||||||
"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) {
|
||||||
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
|
||||||
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)
|
|
||||||
if e != 0 {
|
|
||||||
closesocket(s)
|
|
||||||
return nil, os.Errno(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ra != nil {
|
|
||||||
e = syscall.Connect(s, ra)
|
|
||||||
if e != 0 {
|
|
||||||
closesocket(s)
|
|
||||||
return nil, os.Errno(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sa, _ := syscall.Getsockname(s)
|
|
||||||
laddr := toAddr(sa)
|
|
||||||
sa, _ = syscall.Getpeername(s)
|
|
||||||
raddr := toAddr(sa)
|
|
||||||
|
|
||||||
fd, err = newFD(s, f, p, net, laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
closesocket(s)
|
closesocket(s)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = fd.connect(la, ra); err != nil {
|
||||||
|
closesocket(s)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sa, _ := syscall.Getsockname(fd.sysfd)
|
||||||
|
laddr := toAddr(sa)
|
||||||
|
sa, _ = syscall.Getpeername(fd.sysfd)
|
||||||
|
raddr := toAddr(sa)
|
||||||
|
|
||||||
|
fd.setAddr(laddr, raddr)
|
||||||
return fd, nil
|
return fd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue