net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package net
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
import (
|
2015-04-30 16:49:12 -06:00
|
|
|
"errors"
|
2015-04-02 08:11:39 -06:00
|
|
|
"fmt"
|
2015-04-19 08:42:11 -06:00
|
|
|
"io/ioutil"
|
2015-04-02 08:11:39 -06:00
|
|
|
"os"
|
|
|
|
"sync"
|
2015-04-28 06:17:46 -06:00
|
|
|
"testing"
|
2015-04-19 08:42:11 -06:00
|
|
|
"time"
|
2015-04-02 08:11:39 -06:00
|
|
|
)
|
|
|
|
|
2015-04-19 08:42:11 -06:00
|
|
|
// testUnixAddr uses ioutil.TempFile to get a name that is unique.
|
|
|
|
// It also uses /tmp directory in case it is prohibited to create UNIX
|
|
|
|
// sockets in TMPDIR.
|
|
|
|
func testUnixAddr() string {
|
2015-05-05 19:41:01 -06:00
|
|
|
f, err := ioutil.TempFile("", "go-nettest")
|
2015-04-19 08:42:11 -06:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
addr := f.Name()
|
|
|
|
f.Close()
|
|
|
|
os.Remove(addr)
|
|
|
|
return addr
|
|
|
|
}
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
func newLocalListener(network string) (Listener, error) {
|
|
|
|
switch network {
|
|
|
|
case "tcp", "tcp4", "tcp6":
|
|
|
|
if supportsIPv4 {
|
|
|
|
return Listen("tcp4", "127.0.0.1:0")
|
|
|
|
}
|
|
|
|
if supportsIPv6 {
|
|
|
|
return Listen("tcp6", "[::1]:0")
|
|
|
|
}
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
return Listen(network, testUnixAddr())
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("%s is not supported", network)
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:49:12 -06:00
|
|
|
func newDualStackListener() (lns []*TCPListener, err error) {
|
|
|
|
var args = []struct {
|
|
|
|
network string
|
|
|
|
TCPAddr
|
|
|
|
}{
|
|
|
|
{"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}},
|
|
|
|
{"tcp6", TCPAddr{IP: IPv6loopback}},
|
|
|
|
}
|
|
|
|
for i := 0; i < 64; i++ {
|
|
|
|
var port int
|
|
|
|
var lns []*TCPListener
|
|
|
|
for _, arg := range args {
|
|
|
|
arg.TCPAddr.Port = port
|
|
|
|
ln, err := ListenTCP(arg.network, &arg.TCPAddr)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
port = ln.Addr().(*TCPAddr).Port
|
|
|
|
lns = append(lns, ln)
|
|
|
|
}
|
|
|
|
if len(lns) != len(args) {
|
|
|
|
for _, ln := range lns {
|
|
|
|
ln.Close()
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return lns, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("no dualstack port available")
|
|
|
|
}
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
type localServer struct {
|
|
|
|
lnmu sync.RWMutex
|
|
|
|
Listener
|
|
|
|
done chan bool // signal that indicates server stopped
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localServer) buildup(handler func(*localServer, Listener)) error {
|
|
|
|
go func() {
|
|
|
|
handler(ls, ls.Listener)
|
|
|
|
close(ls.done)
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localServer) teardown() error {
|
|
|
|
ls.lnmu.Lock()
|
|
|
|
if ls.Listener != nil {
|
|
|
|
network := ls.Listener.Addr().Network()
|
|
|
|
address := ls.Listener.Addr().String()
|
|
|
|
ls.Listener.Close()
|
|
|
|
<-ls.done
|
|
|
|
ls.Listener = nil
|
|
|
|
switch network {
|
|
|
|
case "unix", "unixpacket":
|
|
|
|
os.Remove(address)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ls.lnmu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newLocalServer(network string) (*localServer, error) {
|
|
|
|
ln, err := newLocalListener(network)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &localServer{Listener: ln, done: make(chan bool)}, nil
|
|
|
|
}
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
|
|
|
|
type streamListener struct {
|
2015-04-02 08:11:39 -06:00
|
|
|
network, address string
|
|
|
|
Listener
|
|
|
|
done chan bool // signal that indicates server stopped
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sl *streamListener) newLocalServer() (*localServer, error) {
|
|
|
|
return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type dualStackServer struct {
|
|
|
|
lnmu sync.RWMutex
|
|
|
|
lns []streamListener
|
|
|
|
port string
|
|
|
|
|
|
|
|
cmu sync.RWMutex
|
|
|
|
cs []Conn // established connections at the passive open side
|
|
|
|
}
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error {
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
for i := range dss.lns {
|
2015-04-02 08:11:39 -06:00
|
|
|
go func(i int) {
|
|
|
|
handler(dss, dss.lns[i].Listener)
|
|
|
|
close(dss.lns[i].done)
|
|
|
|
}(i)
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dss *dualStackServer) putConn(c Conn) error {
|
|
|
|
dss.cmu.Lock()
|
|
|
|
dss.cs = append(dss.cs, c)
|
|
|
|
dss.cmu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-02 08:11:39 -06:00
|
|
|
func (dss *dualStackServer) teardownNetwork(network string) error {
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
dss.lnmu.Lock()
|
|
|
|
for i := range dss.lns {
|
2015-04-02 08:11:39 -06:00
|
|
|
if network == dss.lns[i].network && dss.lns[i].Listener != nil {
|
|
|
|
dss.lns[i].Listener.Close()
|
|
|
|
<-dss.lns[i].done
|
|
|
|
dss.lns[i].Listener = nil
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
dss.lnmu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dss *dualStackServer) teardown() error {
|
|
|
|
dss.lnmu.Lock()
|
|
|
|
for i := range dss.lns {
|
2015-04-02 08:11:39 -06:00
|
|
|
if dss.lns[i].Listener != nil {
|
|
|
|
dss.lns[i].Listener.Close()
|
|
|
|
<-dss.lns[i].done
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
}
|
|
|
|
}
|
2015-04-02 08:11:39 -06:00
|
|
|
dss.lns = dss.lns[:0]
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
dss.lnmu.Unlock()
|
|
|
|
dss.cmu.Lock()
|
|
|
|
for _, c := range dss.cs {
|
|
|
|
c.Close()
|
|
|
|
}
|
2015-04-02 08:11:39 -06:00
|
|
|
dss.cs = dss.cs[:0]
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
dss.cmu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
|
|
|
|
dss := &dualStackServer{lns: lns, port: "0"}
|
|
|
|
for i := range dss.lns {
|
2015-04-02 08:11:39 -06:00
|
|
|
ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
if err != nil {
|
2015-05-21 20:55:47 -06:00
|
|
|
for _, ln := range dss.lns[:i] {
|
2015-04-02 08:11:39 -06:00
|
|
|
ln.Listener.Close()
|
|
|
|
}
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-04-02 08:11:39 -06:00
|
|
|
dss.lns[i].Listener = ln
|
|
|
|
dss.lns[i].done = make(chan bool)
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
if dss.port == "0" {
|
|
|
|
if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil {
|
2015-04-02 08:11:39 -06:00
|
|
|
for _, ln := range dss.lns {
|
|
|
|
ln.Listener.Close()
|
|
|
|
}
|
net: implement TCP connection setup with fast failover
This CL adds minimal support of Happy Eyeballs-like TCP connection
setup to Dialer API. Happy Eyeballs and derivation techniques are
described in the following:
- Happy Eyeballs: Success with Dual-Stack Hosts
http://tools.ietf.org/html/rfc6555
- Analysing Dual Stack Behaviour and IPv6 Quality
http://www.potaroo.net/presentations/2012-04-17-dual-stack-quality.pdf
Usually, the techniques consist of three components below.
- DNS query racers, that run A and AAAA queries in parallel or series
- A short list of destination addresses
- TCP SYN racers, that run IPv4 and IPv6 transport in parallel or series
This CL implements only the latter two. The existing DNS query
component gathers together A and AAAA records in series, so we don't
touch it here. This CL just uses extended resolveInternetAddr and makes
it possible to run multiple Dial racers in parallel.
For example, when the given destination is a DNS name and the name has
multiple address family A and AAAA records, and it happens on the TCP
wildcard network "tcp" with DualStack=true like the following:
(&net.Dialer{DualStack: true}).Dial("tcp", "www.example.com:80")
The function will return a first established connection either TCP over
IPv4 or TCP over IPv6, and close the other connection internally.
Fixes #3610.
Fixes #5267.
Benchmark results on freebsd/amd64 virtual machine, tip vs. tip+12416043:
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot 50696 52141 +2.85%
BenchmarkTCP4OneShotTimeout 65775 66426 +0.99%
BenchmarkTCP4Persistent 10986 10457 -4.82%
BenchmarkTCP4PersistentTimeout 11207 10445 -6.80%
BenchmarkTCP6OneShot 62009 63718 +2.76%
BenchmarkTCP6OneShotTimeout 78351 79138 +1.00%
BenchmarkTCP6Persistent 14695 14659 -0.24%
BenchmarkTCP6PersistentTimeout 15032 14646 -2.57%
BenchmarkTCP4ConcurrentReadWrite 7215 6217 -13.83%
BenchmarkTCP6ConcurrentReadWrite 7528 7493 -0.46%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot 36 36 0.00%
BenchmarkTCP4OneShotTimeout 36 36 0.00%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 37 37 0.00%
BenchmarkTCP6OneShotTimeout 37 37 0.00%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot 2500 2503 0.12%
BenchmarkTCP4OneShotTimeout 2508 2505 -0.12%
BenchmarkTCP4Persistent 0 0 n/a%
BenchmarkTCP4PersistentTimeout 0 0 n/a%
BenchmarkTCP6OneShot 2713 2707 -0.22%
BenchmarkTCP6OneShotTimeout 2722 2720 -0.07%
BenchmarkTCP6Persistent 0 0 n/a%
BenchmarkTCP6PersistentTimeout 0 0 n/a%
BenchmarkTCP4ConcurrentReadWrite 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite 0 0 n/a%
R=golang-dev, bradfitz, nightlyone, rsc
CC=golang-dev
https://golang.org/cl/12416043
2013-09-11 08:48:53 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dss, nil
|
|
|
|
}
|
2015-04-19 08:42:11 -06:00
|
|
|
|
|
|
|
func transponder(ln Listener, ch chan<- error) {
|
|
|
|
defer close(ch)
|
|
|
|
|
|
|
|
switch ln := ln.(type) {
|
|
|
|
case *TCPListener:
|
|
|
|
ln.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
case *UnixListener:
|
|
|
|
ln.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
}
|
|
|
|
c, err := ln.Accept()
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseAcceptError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
network := ln.Addr().Network()
|
|
|
|
if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
|
|
|
|
ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
|
|
|
|
|
|
|
b := make([]byte, 256)
|
|
|
|
n, err := c.Read(b)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseReadError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if _, err := c.Write(b[:n]); err != nil {
|
|
|
|
if perr := parseWriteError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func transceiver(c Conn, wb []byte, ch chan<- error) {
|
|
|
|
defer close(ch)
|
|
|
|
|
|
|
|
c.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
|
|
|
|
|
|
|
n, err := c.Write(wb)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseWriteError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if n != len(wb) {
|
|
|
|
ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
|
|
|
|
}
|
|
|
|
rb := make([]byte, len(wb))
|
|
|
|
n, err = c.Read(rb)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseReadError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if n != len(wb) {
|
|
|
|
ch <- fmt.Errorf("read %d; want %d", n, len(wb))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-28 06:17:46 -06:00
|
|
|
func timeoutReceiver(c Conn, d, min, max time.Duration, ch chan<- error) {
|
|
|
|
var err error
|
|
|
|
defer func() { ch <- err }()
|
|
|
|
|
|
|
|
t0 := time.Now()
|
|
|
|
if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
b := make([]byte, 256)
|
|
|
|
var n int
|
|
|
|
n, err = c.Read(b)
|
|
|
|
t1 := time.Now()
|
|
|
|
if n != 0 || err == nil || !err.(Error).Timeout() {
|
|
|
|
err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
|
|
|
|
err = fmt.Errorf("Read took %s; expected %s", dt, d)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
|
|
|
|
var err error
|
|
|
|
defer func() { ch <- err }()
|
|
|
|
|
|
|
|
t0 := time.Now()
|
|
|
|
if err = c.SetWriteDeadline(time.Now().Add(d)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var n int
|
|
|
|
for {
|
|
|
|
n, err = c.Write([]byte("TIMEOUT TRANSMITTER"))
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t1 := time.Now()
|
|
|
|
if err == nil || !err.(Error).Timeout() {
|
|
|
|
err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
|
|
|
|
err = fmt.Errorf("Write took %s; expected %s", dt, d)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-19 08:42:11 -06:00
|
|
|
func newLocalPacketListener(network string) (PacketConn, error) {
|
|
|
|
switch network {
|
|
|
|
case "udp", "udp4", "udp6":
|
|
|
|
if supportsIPv4 {
|
|
|
|
return ListenPacket("udp4", "127.0.0.1:0")
|
|
|
|
}
|
|
|
|
if supportsIPv6 {
|
|
|
|
return ListenPacket("udp6", "[::1]:0")
|
|
|
|
}
|
|
|
|
case "unixgram":
|
|
|
|
return ListenPacket(network, testUnixAddr())
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("%s is not supported", network)
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:49:12 -06:00
|
|
|
func newDualStackPacketListener() (cs []*UDPConn, err error) {
|
|
|
|
var args = []struct {
|
|
|
|
network string
|
|
|
|
UDPAddr
|
|
|
|
}{
|
|
|
|
{"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}},
|
|
|
|
{"udp6", UDPAddr{IP: IPv6loopback}},
|
|
|
|
}
|
|
|
|
for i := 0; i < 64; i++ {
|
|
|
|
var port int
|
|
|
|
var cs []*UDPConn
|
|
|
|
for _, arg := range args {
|
|
|
|
arg.UDPAddr.Port = port
|
|
|
|
c, err := ListenUDP(arg.network, &arg.UDPAddr)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
port = c.LocalAddr().(*UDPAddr).Port
|
|
|
|
cs = append(cs, c)
|
|
|
|
}
|
|
|
|
if len(cs) != len(args) {
|
|
|
|
for _, c := range cs {
|
|
|
|
c.Close()
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return cs, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("no dualstack port available")
|
|
|
|
}
|
|
|
|
|
2015-04-19 08:42:11 -06:00
|
|
|
type localPacketServer struct {
|
|
|
|
pcmu sync.RWMutex
|
|
|
|
PacketConn
|
|
|
|
done chan bool // signal that indicates server stopped
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
|
|
|
|
go func() {
|
|
|
|
handler(ls, ls.PacketConn)
|
|
|
|
close(ls.done)
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localPacketServer) teardown() error {
|
|
|
|
ls.pcmu.Lock()
|
|
|
|
if ls.PacketConn != nil {
|
|
|
|
network := ls.PacketConn.LocalAddr().Network()
|
|
|
|
address := ls.PacketConn.LocalAddr().String()
|
|
|
|
ls.PacketConn.Close()
|
|
|
|
<-ls.done
|
|
|
|
ls.PacketConn = nil
|
|
|
|
switch network {
|
|
|
|
case "unixgram":
|
|
|
|
os.Remove(address)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ls.pcmu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newLocalPacketServer(network string) (*localPacketServer, error) {
|
|
|
|
c, err := newLocalPacketListener(network)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type packetListener struct {
|
|
|
|
PacketConn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pl *packetListener) newLocalServer() (*localPacketServer, error) {
|
|
|
|
return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packetTransponder(c PacketConn, ch chan<- error) {
|
|
|
|
defer close(ch)
|
|
|
|
|
|
|
|
c.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
|
|
|
|
|
|
|
b := make([]byte, 256)
|
|
|
|
n, peer, err := c.ReadFrom(b)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseReadError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if peer == nil { // for connected-mode sockets
|
|
|
|
switch c.LocalAddr().Network() {
|
|
|
|
case "udp":
|
|
|
|
peer, err = ResolveUDPAddr("udp", string(b[:n]))
|
|
|
|
case "unixgram":
|
|
|
|
peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if _, err := c.WriteTo(b[:n], peer); err != nil {
|
|
|
|
if perr := parseWriteError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
|
|
|
|
defer close(ch)
|
|
|
|
|
|
|
|
c.SetDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
|
|
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
|
|
|
|
|
|
|
n, err := c.WriteTo(wb, dst)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseWriteError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if n != len(wb) {
|
|
|
|
ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
|
|
|
|
}
|
|
|
|
rb := make([]byte, len(wb))
|
|
|
|
n, _, err = c.ReadFrom(rb)
|
|
|
|
if err != nil {
|
|
|
|
if perr := parseReadError(err); perr != nil {
|
|
|
|
ch <- perr
|
|
|
|
}
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if n != len(wb) {
|
|
|
|
ch <- fmt.Errorf("read %d; want %d", n, len(wb))
|
|
|
|
}
|
|
|
|
}
|
2015-04-28 06:17:46 -06:00
|
|
|
|
|
|
|
func timeoutPacketReceiver(c PacketConn, d, min, max time.Duration, ch chan<- error) {
|
|
|
|
var err error
|
|
|
|
defer func() { ch <- err }()
|
|
|
|
|
|
|
|
t0 := time.Now()
|
|
|
|
if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
b := make([]byte, 256)
|
|
|
|
var n int
|
|
|
|
n, _, err = c.ReadFrom(b)
|
|
|
|
t1 := time.Now()
|
|
|
|
if n != 0 || err == nil || !err.(Error).Timeout() {
|
|
|
|
err = fmt.Errorf("ReadFrom did not return (0, timeout): (%d, %v)", n, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
|
|
|
|
err = fmt.Errorf("ReadFrom took %s; expected %s", dt, d)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|