// partialDeadline returns the deadline to use for a single address,
// when multiple addresses are pending.
-func (d *Dialer) partialDeadline(now time.Time, addrsRemaining int) (time.Time, error) {
- deadline := d.deadline(now)
+func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
if deadline.IsZero() {
return deadline, nil
}
type dialContext struct {
Dialer
network, address string
+ finalDeadline time.Time
}
// Dial connects to the address on the named network.
// See func Dial for a description of the network and address
// parameters.
func (d *Dialer) Dial(network, address string) (Conn, error) {
- addrs, err := resolveAddrList("dial", network, address, d.deadline(time.Now()))
+ finalDeadline := d.deadline(time.Now())
+ addrs, err := resolveAddrList("dial", network, address, finalDeadline)
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
}
ctx := &dialContext{
- Dialer: *d,
- network: network,
- address: address,
+ Dialer: *d,
+ network: network,
+ address: address,
+ finalDeadline: finalDeadline,
}
var primaries, fallbacks addrList
default:
}
- partialDeadline, err := ctx.partialDeadline(time.Now(), len(ras)-i)
+ partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i)
if err != nil {
// Ran out of time.
if firstErr == nil {
return c, err
}
-func dialClosedPort() time.Duration {
+func dialClosedPort() (actual, expected time.Duration) {
+ // Estimate the expected time for this platform.
+ // On Windows, dialing a closed port takes roughly 1 second,
+ // but other platforms should be instantaneous.
+ if runtime.GOOS == "windows" {
+ expected = 1095 * time.Millisecond
+ } else {
+ expected = 95 * time.Millisecond
+ }
+
l, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
- return 999 * time.Hour
+ return 999 * time.Hour, expected
}
addr := l.Addr().String()
l.Close()
}
elapsed := time.Now().Sub(startTime)
if i == 2 {
- return elapsed
+ return elapsed, expected
}
}
}
t.Skip("both IPv4 and IPv6 are required")
}
- // Determine the time required to dial a closed port.
- // On Windows, this takes roughly 1 second, but other platforms
- // are expected to be instantaneous.
- closedPortDelay := dialClosedPort()
- var expectClosedPortDelay time.Duration
- if runtime.GOOS == "windows" {
- expectClosedPortDelay = 1095 * time.Millisecond
- } else {
- expectClosedPortDelay = 95 * time.Millisecond
- }
+ closedPortDelay, expectClosedPortDelay := dialClosedPort()
if closedPortDelay > expectClosedPortDelay {
t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
}
{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
}
for i, tt := range testCases {
- d := Dialer{Deadline: tt.deadline}
- deadline, err := d.partialDeadline(tt.now, tt.addrs)
+ deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
if err != tt.expectErr {
t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
}
t.Skip("both IPv4 and IPv6 are required")
}
+ closedPortDelay, expectClosedPortDelay := dialClosedPort()
+ if closedPortDelay > expectClosedPortDelay {
+ t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
+ }
+
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
}
}
- const T = 100 * time.Millisecond
+ var timeout = 100*time.Millisecond + closedPortDelay
for _, dualstack := range []bool{false, true} {
dss, err := newDualStackServer([]streamListener{
{network: "tcp4", address: "127.0.0.1"},
t.Fatal(err)
}
- d := &Dialer{DualStack: dualstack, Timeout: T}
+ d := &Dialer{DualStack: dualstack, Timeout: timeout}
for range dss.lns {
c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
if err != nil {
c.Close()
}
}
- time.Sleep(2 * T) // wait for the dial racers to stop
+ time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
}
func TestDialerKeepAlive(t *testing.T) {