blob: 98433067751a1672aba5688e23e11005d27c2bf2 [file] [log] [blame]
Brad Fitzpatrick964309e2011-12-20 13:17:39 -08001// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package net
6
7import (
Paul Marks0d8366e2015-04-10 14:15:54 -07008 "io"
Mikio Hara167562f2015-04-01 22:01:24 +09009 "net/internal/socktest"
Brad Fitzpatrick964309e2011-12-20 13:17:39 -080010 "runtime"
Mikio Hara89b26762013-09-11 10:48:53 -040011 "sync"
Brad Fitzpatrick964309e2011-12-20 13:17:39 -080012 "testing"
13 "time"
14)
15
Mikio Hara9b184fd2015-05-01 07:49:12 +090016var prohibitionaryDialArgTests = []struct {
17 network string
18 address string
19}{
20 {"tcp6", "127.0.0.1"},
21 {"tcp6", "::ffff:127.0.0.1"},
22}
23
24func TestProhibitionaryDialArg(t *testing.T) {
25 switch runtime.GOOS {
26 case "plan9":
27 t.Skipf("not supported on %s", runtime.GOOS)
28 }
29 if testing.Short() || !*testExternal {
30 t.Skip("avoid external network")
31 }
32 if !supportsIPv4map {
33 t.Skip("mapping ipv4 address inside ipv6 address not supported")
34 }
35
36 ln, err := Listen("tcp", "[::]:0")
37 if err != nil {
38 t.Fatal(err)
39 }
40 defer ln.Close()
41
42 _, port, err := SplitHostPort(ln.Addr().String())
43 if err != nil {
44 t.Fatal(err)
45 }
46
47 for i, tt := range prohibitionaryDialArgTests {
48 c, err := Dial(tt.network, JoinHostPort(tt.address, port))
49 if err == nil {
50 c.Close()
51 t.Errorf("#%d: %v", i, err)
52 }
53 }
54}
55
Russ Coxcbe7d8d2012-02-12 23:25:55 -050056func TestSelfConnect(t *testing.T) {
Alex Brainman07a29892012-02-14 13:51:38 +110057 if runtime.GOOS == "windows" {
58 // TODO(brainman): do not know why it hangs.
Mikio Haraf77e10f2015-05-01 12:38:42 +090059 t.Skip("known-broken test on windows")
Alex Brainman07a29892012-02-14 13:51:38 +110060 }
Russ Cox95c899f2014-09-16 14:02:59 -040061
Russ Coxcbe7d8d2012-02-12 23:25:55 -050062 // Test that Dial does not honor self-connects.
63 // See the comment in DialTCP.
64
65 // Find a port that would be used as a local address.
66 l, err := Listen("tcp", "127.0.0.1:0")
67 if err != nil {
68 t.Fatal(err)
69 }
70 c, err := Dial("tcp", l.Addr().String())
71 if err != nil {
72 t.Fatal(err)
73 }
74 addr := c.LocalAddr().String()
75 c.Close()
76 l.Close()
77
78 // Try to connect to that address repeatedly.
79 n := 100000
80 if testing.Short() {
81 n = 1000
82 }
Russ Cox5e4e3d82012-02-14 00:40:37 -050083 switch runtime.GOOS {
Aram Hăvărneanu50df1362014-02-24 22:31:01 -050084 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
Russ Cox5e4e3d82012-02-14 00:40:37 -050085 // Non-Linux systems take a long time to figure
86 // out that there is nothing listening on localhost.
87 n = 100
88 }
Russ Coxcbe7d8d2012-02-12 23:25:55 -050089 for i := 0; i < n; i++ {
Ian Lance Taylor4aa521a2013-12-27 08:49:47 -080090 c, err := DialTimeout("tcp", addr, time.Millisecond)
Russ Coxcbe7d8d2012-02-12 23:25:55 -050091 if err == nil {
Russ Cox95c899f2014-09-16 14:02:59 -040092 if c.LocalAddr().String() == addr {
93 t.Errorf("#%d: Dial %q self-connect", i, addr)
94 } else {
95 t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
96 }
Russ Coxcbe7d8d2012-02-12 23:25:55 -050097 c.Close()
Russ Coxcbe7d8d2012-02-12 23:25:55 -050098 }
99 }
100}
Mikio Hara705ebf12012-02-24 11:58:30 +0900101
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600102func TestDialTimeoutFDLeak(t *testing.T) {
Mikio Hara167562f2015-04-01 22:01:24 +0900103 switch runtime.GOOS {
104 case "plan9":
105 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600106 }
107
Mikio Hara167562f2015-04-01 22:01:24 +0900108 const T = 100 * time.Millisecond
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600109
Mikio Hara167562f2015-04-01 22:01:24 +0900110 switch runtime.GOOS {
111 case "plan9", "windows":
112 origTestHookDialChannel := testHookDialChannel
113 testHookDialChannel = func() { time.Sleep(2 * T) }
114 defer func() { testHookDialChannel = origTestHookDialChannel }()
115 if runtime.GOOS == "plan9" {
116 break
117 }
118 fallthrough
119 default:
120 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
121 time.Sleep(2 * T)
122 return nil, errTimeout
123 })
124 defer sw.Set(socktest.FilterConnect, nil)
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600125 }
Mikio Hara167562f2015-04-01 22:01:24 +0900126
Mikio Hara68557de2015-07-27 12:19:00 +0900127 // Avoid tracking open-close jitterbugs between netFD and
128 // socket that leads to confusion of information inside
129 // socktest.Switch.
130 // It may happen when the Dial call bumps against TCP
131 // simultaneous open. See selfConnect in tcpsock_posix.go.
132 defer func() {
133 sw.Set(socktest.FilterClose, nil)
134 forceCloseSockets()
135 }()
136 var mu sync.Mutex
137 var attempts int
138 sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
139 mu.Lock()
140 attempts++
141 mu.Unlock()
142 return nil, errTimedout
143 })
144
Mikio Hara167562f2015-04-01 22:01:24 +0900145 const N = 100
146 var wg sync.WaitGroup
147 wg.Add(N)
148 for i := 0; i < N; i++ {
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600149 go func() {
Mikio Hara167562f2015-04-01 22:01:24 +0900150 defer wg.Done()
151 // This dial never starts to send any SYN
152 // segment because of above socket filter and
153 // test hook.
154 c, err := DialTimeout("tcp", "127.0.0.1:0", T)
155 if err == nil {
156 t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
157 c.Close()
158 }
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600159 }()
160 }
Mikio Hara167562f2015-04-01 22:01:24 +0900161 wg.Wait()
Mikio Hara68557de2015-07-27 12:19:00 +0900162 if attempts < N {
163 t.Errorf("got %d; want >= %d", attempts, N)
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600164 }
165}
166
Mikio Hara5a83f062015-04-05 17:00:14 +0900167func TestDialerDualStackFDLeak(t *testing.T) {
168 switch runtime.GOOS {
169 case "plan9":
170 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
171 case "windows":
172 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
Mikio Hara89b26762013-09-11 10:48:53 -0400173 }
Mikio Hara89b26762013-09-11 10:48:53 -0400174 if !supportsIPv4 || !supportsIPv6 {
Mikio Haraf963cb72015-05-07 08:20:42 +0900175 t.Skip("both IPv4 and IPv6 are required")
Mikio Hara89b26762013-09-11 10:48:53 -0400176 }
177
Mikio Hara5a83f062015-04-05 17:00:14 +0900178 origTestHookLookupIP := testHookLookupIP
179 defer func() { testHookLookupIP = origTestHookLookupIP }()
180 testHookLookupIP = lookupLocalhost
Mikio Haraf0775052015-04-02 23:11:39 +0900181 handler := func(dss *dualStackServer, ln Listener) {
Mikio Hara89b26762013-09-11 10:48:53 -0400182 for {
Mikio Hara5a83f062015-04-05 17:00:14 +0900183 c, err := ln.Accept()
184 if err != nil {
Mikio Hara89b26762013-09-11 10:48:53 -0400185 return
Mikio Hara89b26762013-09-11 10:48:53 -0400186 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900187 c.Close()
Mikio Hara89b26762013-09-11 10:48:53 -0400188 }
189 }
190 dss, err := newDualStackServer([]streamListener{
Mikio Haraf0775052015-04-02 23:11:39 +0900191 {network: "tcp4", address: "127.0.0.1"},
192 {network: "tcp6", address: "::1"},
Mikio Hara89b26762013-09-11 10:48:53 -0400193 })
194 if err != nil {
Mikio Hara5a83f062015-04-05 17:00:14 +0900195 t.Fatal(err)
Mikio Hara89b26762013-09-11 10:48:53 -0400196 }
197 defer dss.teardown()
Mikio Haraf0775052015-04-02 23:11:39 +0900198 if err := dss.buildup(handler); err != nil {
Mikio Hara5a83f062015-04-05 17:00:14 +0900199 t.Fatal(err)
Mikio Hara89b26762013-09-11 10:48:53 -0400200 }
201
Mikio Hara5a83f062015-04-05 17:00:14 +0900202 before := sw.Sockets()
203 const T = 100 * time.Millisecond
Mikio Hara89b26762013-09-11 10:48:53 -0400204 const N = 10
Mikio Hara5a83f062015-04-05 17:00:14 +0900205 var wg sync.WaitGroup
206 wg.Add(N)
207 d := &Dialer{DualStack: true, Timeout: T}
Mikio Hara89b26762013-09-11 10:48:53 -0400208 for i := 0; i < N; i++ {
Mikio Hara89b26762013-09-11 10:48:53 -0400209 go func() {
210 defer wg.Done()
Mikio Hara5a83f062015-04-05 17:00:14 +0900211 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
212 if err != nil {
213 t.Error(err)
214 return
Mikio Hara89b26762013-09-11 10:48:53 -0400215 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900216 c.Close()
Mikio Hara89b26762013-09-11 10:48:53 -0400217 }()
218 }
219 wg.Wait()
Mikio Hara5a83f062015-04-05 17:00:14 +0900220 time.Sleep(2 * T) // wait for the dial racers to stop
221 after := sw.Sockets()
222 if len(after) != len(before) {
223 t.Errorf("got %d; want %d", len(after), len(before))
Mikio Hara89b26762013-09-11 10:48:53 -0400224 }
225}
226
Paul Marks0d8366e2015-04-10 14:15:54 -0700227// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
228// expected to hang until the timeout elapses. These addresses are reserved
229// for benchmarking by RFC 6890.
230const (
231 slowDst4 = "192.18.0.254"
232 slowDst6 = "2001:2::254"
233 slowTimeout = 1 * time.Second
234)
235
236// In some environments, the slow IPs may be explicitly unreachable, and fail
237// more quickly than expected. This test hook prevents dialTCP from returning
238// before the deadline.
239func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
240 c, err := dialTCP(net, laddr, raddr, deadline)
241 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
242 time.Sleep(deadline.Sub(time.Now()))
243 }
244 return c, err
245}
246
Paul Marksdcc905e2015-07-20 16:04:25 -0700247func dialClosedPort() (actual, expected time.Duration) {
248 // Estimate the expected time for this platform.
249 // On Windows, dialing a closed port takes roughly 1 second,
250 // but other platforms should be instantaneous.
251 if runtime.GOOS == "windows" {
Russ Cox48b42632015-07-30 10:39:07 -0400252 expected = 1500 * time.Millisecond
Paul Marksdcc905e2015-07-20 16:04:25 -0700253 } else {
254 expected = 95 * time.Millisecond
255 }
256
Paul Marks0d8366e2015-04-10 14:15:54 -0700257 l, err := Listen("tcp", "127.0.0.1:0")
258 if err != nil {
Paul Marksdcc905e2015-07-20 16:04:25 -0700259 return 999 * time.Hour, expected
Paul Marks0d8366e2015-04-10 14:15:54 -0700260 }
261 addr := l.Addr().String()
262 l.Close()
263 // On OpenBSD, interference from TestSelfConnect is mysteriously
264 // causing the first attempt to hang for a few seconds, so we throw
265 // away the first result and keep the second.
266 for i := 1; ; i++ {
267 startTime := time.Now()
268 c, err := Dial("tcp", addr)
269 if err == nil {
270 c.Close()
271 }
272 elapsed := time.Now().Sub(startTime)
273 if i == 2 {
Paul Marksdcc905e2015-07-20 16:04:25 -0700274 return elapsed, expected
Paul Marks0d8366e2015-04-10 14:15:54 -0700275 }
276 }
277}
278
279func TestDialParallel(t *testing.T) {
280 if testing.Short() || !*testExternal {
281 t.Skip("avoid external network")
282 }
283 if !supportsIPv4 || !supportsIPv6 {
284 t.Skip("both IPv4 and IPv6 are required")
285 }
286
Paul Marksdcc905e2015-07-20 16:04:25 -0700287 closedPortDelay, expectClosedPortDelay := dialClosedPort()
Paul Marks0d8366e2015-04-10 14:15:54 -0700288 if closedPortDelay > expectClosedPortDelay {
289 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
290 }
291
292 const instant time.Duration = 0
293 const fallbackDelay = 200 * time.Millisecond
294
295 // Some cases will run quickly when "connection refused" is fast,
296 // or trigger the fallbackDelay on Windows. This value holds the
297 // lesser of the two delays.
298 var closedPortOrFallbackDelay time.Duration
299 if closedPortDelay < fallbackDelay {
300 closedPortOrFallbackDelay = closedPortDelay
301 } else {
302 closedPortOrFallbackDelay = fallbackDelay
303 }
304
305 origTestHookDialTCP := testHookDialTCP
306 defer func() { testHookDialTCP = origTestHookDialTCP }()
307 testHookDialTCP = slowDialTCP
308
309 nCopies := func(s string, n int) []string {
310 out := make([]string, n)
311 for i := 0; i < n; i++ {
312 out[i] = s
313 }
314 return out
315 }
316
317 var testCases = []struct {
318 primaries []string
319 fallbacks []string
320 teardownNetwork string
321 expectOk bool
322 expectElapsed time.Duration
323 }{
324 // These should just work on the first try.
325 {[]string{"127.0.0.1"}, []string{}, "", true, instant},
326 {[]string{"::1"}, []string{}, "", true, instant},
327 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
328 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
329 // Primary is slow; fallback should kick in.
330 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
331 // Skip a "connection refused" in the primary thread.
332 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
333 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
334 // Skip a "connection refused" in the fallback thread.
335 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
336 // Primary refused, fallback without delay.
337 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
338 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
339 // Everything is refused.
340 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
341 // Nothing to do; fail instantly.
342 {[]string{}, []string{}, "", false, instant},
343 // Connecting to tons of addresses should not trip the deadline.
344 {nCopies("::1", 1000), []string{}, "", true, instant},
345 }
346
347 handler := func(dss *dualStackServer, ln Listener) {
348 for {
349 c, err := ln.Accept()
350 if err != nil {
351 return
352 }
353 c.Close()
354 }
355 }
356
357 // Convert a list of IP strings into TCPAddrs.
358 makeAddrs := func(ips []string, port string) addrList {
359 var out addrList
360 for _, ip := range ips {
361 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
362 if err != nil {
363 t.Fatal(err)
364 }
365 out = append(out, addr)
366 }
367 return out
368 }
369
370 for i, tt := range testCases {
371 dss, err := newDualStackServer([]streamListener{
372 {network: "tcp4", address: "127.0.0.1"},
373 {network: "tcp6", address: "::1"},
374 })
375 if err != nil {
376 t.Fatal(err)
377 }
378 defer dss.teardown()
379 if err := dss.buildup(handler); err != nil {
380 t.Fatal(err)
381 }
382 if tt.teardownNetwork != "" {
383 // Destroy one of the listening sockets, creating an unreachable port.
384 dss.teardownNetwork(tt.teardownNetwork)
385 }
386
387 primaries := makeAddrs(tt.primaries, dss.port)
388 fallbacks := makeAddrs(tt.fallbacks, dss.port)
Paul Marks85a5fce2015-07-27 14:39:32 -0700389 d := Dialer{
390 FallbackDelay: fallbackDelay,
391 Timeout: slowTimeout,
392 }
Paul Marks0d8366e2015-04-10 14:15:54 -0700393 ctx := &dialContext{
Paul Marks85a5fce2015-07-27 14:39:32 -0700394 Dialer: d,
395 network: "tcp",
396 address: "?",
397 finalDeadline: d.deadline(time.Now()),
Paul Marks0d8366e2015-04-10 14:15:54 -0700398 }
399 startTime := time.Now()
400 c, err := dialParallel(ctx, primaries, fallbacks)
401 elapsed := time.Now().Sub(startTime)
402
403 if c != nil {
404 c.Close()
405 }
406
407 if tt.expectOk && err != nil {
408 t.Errorf("#%d: got %v; want nil", i, err)
409 } else if !tt.expectOk && err == nil {
410 t.Errorf("#%d: got nil; want non-nil", i)
411 }
412
413 expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
414 expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
415 if !(elapsed >= expectElapsedMin) {
416 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
417 } else if !(elapsed <= expectElapsedMax) {
418 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
419 }
420 }
421 // Wait for any slowDst4/slowDst6 connections to timeout.
422 time.Sleep(slowTimeout * 3 / 2)
423}
424
425func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
426 switch host {
427 case "slow6loopback4":
428 // Returns a slow IPv6 address, and a local IPv4 address.
429 return []IPAddr{
430 {IP: ParseIP(slowDst6)},
431 {IP: ParseIP("127.0.0.1")},
432 }, nil
433 default:
434 return fn(host)
435 }
436}
437
438func TestDialerFallbackDelay(t *testing.T) {
439 if testing.Short() || !*testExternal {
440 t.Skip("avoid external network")
441 }
442 if !supportsIPv4 || !supportsIPv6 {
443 t.Skip("both IPv4 and IPv6 are required")
444 }
445
446 origTestHookLookupIP := testHookLookupIP
447 defer func() { testHookLookupIP = origTestHookLookupIP }()
448 testHookLookupIP = lookupSlowFast
449
450 origTestHookDialTCP := testHookDialTCP
451 defer func() { testHookDialTCP = origTestHookDialTCP }()
452 testHookDialTCP = slowDialTCP
453
454 var testCases = []struct {
455 dualstack bool
456 delay time.Duration
457 expectElapsed time.Duration
458 }{
459 // Use a very brief delay, which should fallback immediately.
460 {true, 1 * time.Nanosecond, 0},
461 // Use a 200ms explicit timeout.
462 {true, 200 * time.Millisecond, 200 * time.Millisecond},
463 // The default is 300ms.
464 {true, 0, 300 * time.Millisecond},
465 // This case is last, in order to wait for hanging slowDst6 connections.
466 {false, 0, slowTimeout},
467 }
468
469 handler := func(dss *dualStackServer, ln Listener) {
470 for {
471 c, err := ln.Accept()
472 if err != nil {
473 return
474 }
475 c.Close()
476 }
477 }
478 dss, err := newDualStackServer([]streamListener{
479 {network: "tcp", address: "127.0.0.1"},
480 })
481 if err != nil {
482 t.Fatal(err)
483 }
484 defer dss.teardown()
485 if err := dss.buildup(handler); err != nil {
486 t.Fatal(err)
487 }
488
489 for i, tt := range testCases {
490 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
491
492 startTime := time.Now()
493 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
494 elapsed := time.Now().Sub(startTime)
495 if err == nil {
496 c.Close()
497 } else if tt.dualstack {
498 t.Error(err)
499 }
500 expectMin := tt.expectElapsed - 1*time.Millisecond
501 expectMax := tt.expectElapsed + 95*time.Millisecond
502 if !(elapsed >= expectMin) {
503 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
504 }
505 if !(elapsed <= expectMax) {
506 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
507 }
508 }
509}
510
511func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
512 ln, err := newLocalListener("tcp")
513 if err != nil {
514 t.Fatal(err)
515 }
516 defer ln.Close()
517
Paul Marks85a5fce2015-07-27 14:39:32 -0700518 d := Dialer{}
Paul Marks0d8366e2015-04-10 14:15:54 -0700519 ctx := &dialContext{
Paul Marks85a5fce2015-07-27 14:39:32 -0700520 Dialer: d,
521 network: "tcp",
522 address: "?",
523 finalDeadline: d.deadline(time.Now()),
Paul Marks0d8366e2015-04-10 14:15:54 -0700524 }
525
526 results := make(chan dialResult)
527 cancel := make(chan struct{})
528
529 // Spawn a connection in the background.
530 go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
531
532 // Receive it at the server.
533 c, err := ln.Accept()
534 if err != nil {
535 t.Fatal(err)
536 }
537 defer c.Close()
538
539 // Tell dialSerialAsync that someone else won the race.
540 close(cancel)
541
542 // The connection should close itself, without sending data.
543 c.SetReadDeadline(time.Now().Add(1 * time.Second))
544 var b [1]byte
545 if _, err := c.Read(b[:]); err != io.EOF {
546 t.Errorf("got %v; want %v", err, io.EOF)
547 }
548}
549
550func TestDialerPartialDeadline(t *testing.T) {
551 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
552 var testCases = []struct {
553 now time.Time
554 deadline time.Time
555 addrs int
556 expectDeadline time.Time
557 expectErr error
558 }{
559 // Regular division.
560 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
561 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
562 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
563 // Bump against the 2-second sane minimum.
564 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
565 // Total available is now below the sane minimum.
566 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
567 // Null deadline.
568 {now, noDeadline, 1, noDeadline, nil},
569 // Step the clock forward and cross the deadline.
570 {now.Add(-1 * time.Millisecond), now, 1, now, nil},
571 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
572 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
573 }
574 for i, tt := range testCases {
Paul Marksdcc905e2015-07-20 16:04:25 -0700575 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
Paul Marks0d8366e2015-04-10 14:15:54 -0700576 if err != tt.expectErr {
577 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
578 }
579 if deadline != tt.expectDeadline {
580 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
581 }
582 }
583}
584
Mikio Haraf0775052015-04-02 23:11:39 +0900585func TestDialerLocalAddr(t *testing.T) {
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700586 ch := make(chan error, 1)
Mikio Haraf0775052015-04-02 23:11:39 +0900587 handler := func(ls *localServer, ln Listener) {
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700588 c, err := ln.Accept()
589 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900590 ch <- err
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700591 return
592 }
593 defer c.Close()
594 ch <- nil
Mikio Haraf0775052015-04-02 23:11:39 +0900595 }
596 ls, err := newLocalServer("tcp")
597 if err != nil {
598 t.Fatal(err)
599 }
600 defer ls.teardown()
601 if err := ls.buildup(handler); err != nil {
602 t.Fatal(err)
603 }
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700604
Mikio Haraf0775052015-04-02 23:11:39 +0900605 laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700606 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900607 t.Fatal(err)
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700608 }
Mikio Haraf0775052015-04-02 23:11:39 +0900609 laddr.Port = 0
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700610 d := &Dialer{LocalAddr: laddr}
Mikio Haraf0775052015-04-02 23:11:39 +0900611 c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700612 if err != nil {
Mikio Haraf77e10f2015-05-01 12:38:42 +0900613 t.Fatal(err)
Alex Brainmanca6b1f32013-04-30 17:47:39 -0700614 }
615 defer c.Close()
616 c.Read(make([]byte, 1))
617 err = <-ch
618 if err != nil {
619 t.Error(err)
620 }
621}
Mikio Hara89b26762013-09-11 10:48:53 -0400622
Mikio Haraf0775052015-04-02 23:11:39 +0900623func TestDialerDualStack(t *testing.T) {
Mikio Hara5a83f062015-04-05 17:00:14 +0900624 if !supportsIPv4 || !supportsIPv6 {
Mikio Haraf963cb72015-05-07 08:20:42 +0900625 t.Skip("both IPv4 and IPv6 are required")
Mikio Hara484cc672014-09-18 19:17:55 +0900626 }
627
Paul Marksdcc905e2015-07-20 16:04:25 -0700628 closedPortDelay, expectClosedPortDelay := dialClosedPort()
629 if closedPortDelay > expectClosedPortDelay {
630 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
631 }
632
Mikio Hara5a83f062015-04-05 17:00:14 +0900633 origTestHookLookupIP := testHookLookupIP
634 defer func() { testHookLookupIP = origTestHookLookupIP }()
635 testHookLookupIP = lookupLocalhost
Mikio Haraf0775052015-04-02 23:11:39 +0900636 handler := func(dss *dualStackServer, ln Listener) {
Mikio Hara89b26762013-09-11 10:48:53 -0400637 for {
Mikio Hara5a83f062015-04-05 17:00:14 +0900638 c, err := ln.Accept()
639 if err != nil {
Mikio Hara89b26762013-09-11 10:48:53 -0400640 return
Mikio Hara89b26762013-09-11 10:48:53 -0400641 }
Mikio Hara5a83f062015-04-05 17:00:14 +0900642 c.Close()
Mikio Hara89b26762013-09-11 10:48:53 -0400643 }
644 }
Mikio Hara89b26762013-09-11 10:48:53 -0400645
Paul Marks754d4c02015-08-31 13:30:22 -0700646 var timeout = 150*time.Millisecond + closedPortDelay
Paul Marks0d8366e2015-04-10 14:15:54 -0700647 for _, dualstack := range []bool{false, true} {
648 dss, err := newDualStackServer([]streamListener{
649 {network: "tcp4", address: "127.0.0.1"},
650 {network: "tcp6", address: "::1"},
651 })
Mikio Hara5a83f062015-04-05 17:00:14 +0900652 if err != nil {
Paul Marks0d8366e2015-04-10 14:15:54 -0700653 t.Fatal(err)
Mikio Hara89b26762013-09-11 10:48:53 -0400654 }
Paul Marks0d8366e2015-04-10 14:15:54 -0700655 defer dss.teardown()
656 if err := dss.buildup(handler); err != nil {
657 t.Fatal(err)
Mikio Hara5a83f062015-04-05 17:00:14 +0900658 }
Paul Marks0d8366e2015-04-10 14:15:54 -0700659
Paul Marksdcc905e2015-07-20 16:04:25 -0700660 d := &Dialer{DualStack: dualstack, Timeout: timeout}
Paul Marks0d8366e2015-04-10 14:15:54 -0700661 for range dss.lns {
662 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
663 if err != nil {
664 t.Error(err)
665 continue
666 }
667 switch addr := c.LocalAddr().(*TCPAddr); {
668 case addr.IP.To4() != nil:
669 dss.teardownNetwork("tcp4")
670 case addr.IP.To16() != nil && addr.IP.To4() == nil:
671 dss.teardownNetwork("tcp6")
672 }
673 c.Close()
674 }
Mikio Hara89b26762013-09-11 10:48:53 -0400675 }
Paul Marksdcc905e2015-07-20 16:04:25 -0700676 time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
Mikio Hara89b26762013-09-11 10:48:53 -0400677}
Brad Fitzpatrickfdfbb402014-02-24 13:14:48 -0800678
679func TestDialerKeepAlive(t *testing.T) {
Mikio Haraf0775052015-04-02 23:11:39 +0900680 handler := func(ls *localServer, ln Listener) {
Brad Fitzpatrickfdfbb402014-02-24 13:14:48 -0800681 for {
682 c, err := ln.Accept()
683 if err != nil {
684 return
685 }
686 c.Close()
687 }
Mikio Haraf0775052015-04-02 23:11:39 +0900688 }
689 ls, err := newLocalServer("tcp")
690 if err != nil {
691 t.Fatal(err)
692 }
693 defer ls.teardown()
694 if err := ls.buildup(handler); err != nil {
695 t.Fatal(err)
696 }
Mikio Haraf77e10f2015-05-01 12:38:42 +0900697 defer func() { testHookSetKeepAlive = func() {} }()
Mikio Haraf0775052015-04-02 23:11:39 +0900698
Brad Fitzpatrickfdfbb402014-02-24 13:14:48 -0800699 for _, keepAlive := range []bool{false, true} {
700 got := false
701 testHookSetKeepAlive = func() { got = true }
702 var d Dialer
703 if keepAlive {
704 d.KeepAlive = 30 * time.Second
705 }
Mikio Haraf0775052015-04-02 23:11:39 +0900706 c, err := d.Dial("tcp", ls.Listener.Addr().String())
Brad Fitzpatrickfdfbb402014-02-24 13:14:48 -0800707 if err != nil {
708 t.Fatal(err)
709 }
710 c.Close()
711 if got != keepAlive {
712 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
713 }
714 }
715}