[52/77] Use scalar_int_mode in extract/store_bit_field
[official-gcc.git] / libgo / go / net / dial_test.go
blob9919d72ce3b79b90500835e3a46ec3cf2b38d183
1 // 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.
5 package net
7 import (
8 "bufio"
9 "context"
10 "internal/testenv"
11 "io"
12 "net/internal/socktest"
13 "runtime"
14 "sync"
15 "testing"
16 "time"
19 var prohibitionaryDialArgTests = []struct {
20 network string
21 address string
23 {"tcp6", "127.0.0.1"},
24 {"tcp6", "::ffff:127.0.0.1"},
27 func TestProhibitionaryDialArg(t *testing.T) {
28 testenv.MustHaveExternalNetwork(t)
30 switch runtime.GOOS {
31 case "plan9":
32 t.Skipf("not supported on %s", runtime.GOOS)
34 if !supportsIPv4map {
35 t.Skip("mapping ipv4 address inside ipv6 address not supported")
38 ln, err := Listen("tcp", "[::]:0")
39 if err != nil {
40 t.Fatal(err)
42 defer ln.Close()
44 _, port, err := SplitHostPort(ln.Addr().String())
45 if err != nil {
46 t.Fatal(err)
49 for i, tt := range prohibitionaryDialArgTests {
50 c, err := Dial(tt.network, JoinHostPort(tt.address, port))
51 if err == nil {
52 c.Close()
53 t.Errorf("#%d: %v", i, err)
58 func TestDialLocal(t *testing.T) {
59 ln, err := newLocalListener("tcp")
60 if err != nil {
61 t.Fatal(err)
63 defer ln.Close()
64 _, port, err := SplitHostPort(ln.Addr().String())
65 if err != nil {
66 t.Fatal(err)
68 c, err := Dial("tcp", JoinHostPort("", port))
69 if err != nil {
70 t.Fatal(err)
72 c.Close()
75 func TestDialTimeoutFDLeak(t *testing.T) {
76 switch runtime.GOOS {
77 case "plan9":
78 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
79 case "openbsd":
80 testenv.SkipFlaky(t, 15157)
83 const T = 100 * time.Millisecond
85 switch runtime.GOOS {
86 case "plan9", "windows":
87 origTestHookDialChannel := testHookDialChannel
88 testHookDialChannel = func() { time.Sleep(2 * T) }
89 defer func() { testHookDialChannel = origTestHookDialChannel }()
90 if runtime.GOOS == "plan9" {
91 break
93 fallthrough
94 default:
95 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
96 time.Sleep(2 * T)
97 return nil, errTimeout
99 defer sw.Set(socktest.FilterConnect, nil)
102 // Avoid tracking open-close jitterbugs between netFD and
103 // socket that leads to confusion of information inside
104 // socktest.Switch.
105 // It may happen when the Dial call bumps against TCP
106 // simultaneous open. See selfConnect in tcpsock_posix.go.
107 defer func() { sw.Set(socktest.FilterClose, nil) }()
108 var mu sync.Mutex
109 var attempts int
110 sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
111 mu.Lock()
112 attempts++
113 mu.Unlock()
114 return nil, nil
117 const N = 100
118 var wg sync.WaitGroup
119 wg.Add(N)
120 for i := 0; i < N; i++ {
121 go func() {
122 defer wg.Done()
123 // This dial never starts to send any SYN
124 // segment because of above socket filter and
125 // test hook.
126 c, err := DialTimeout("tcp", "127.0.0.1:0", T)
127 if err == nil {
128 t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
129 c.Close()
133 wg.Wait()
134 if attempts < N {
135 t.Errorf("got %d; want >= %d", attempts, N)
139 func TestDialerDualStackFDLeak(t *testing.T) {
140 switch runtime.GOOS {
141 case "plan9":
142 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
143 case "windows":
144 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
145 case "openbsd":
146 testenv.SkipFlaky(t, 15157)
148 if !supportsIPv4 || !supportsIPv6 {
149 t.Skip("both IPv4 and IPv6 are required")
152 closedPortDelay, expectClosedPortDelay := dialClosedPort()
153 if closedPortDelay > expectClosedPortDelay {
154 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
157 before := sw.Sockets()
158 origTestHookLookupIP := testHookLookupIP
159 defer func() { testHookLookupIP = origTestHookLookupIP }()
160 testHookLookupIP = lookupLocalhost
161 handler := func(dss *dualStackServer, ln Listener) {
162 for {
163 c, err := ln.Accept()
164 if err != nil {
165 return
167 c.Close()
170 dss, err := newDualStackServer()
171 if err != nil {
172 t.Fatal(err)
174 if err := dss.buildup(handler); err != nil {
175 dss.teardown()
176 t.Fatal(err)
179 const N = 10
180 var wg sync.WaitGroup
181 wg.Add(N)
182 d := &Dialer{DualStack: true, Timeout: 100*time.Millisecond + closedPortDelay}
183 for i := 0; i < N; i++ {
184 go func() {
185 defer wg.Done()
186 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
187 if err != nil {
188 t.Error(err)
189 return
191 c.Close()
194 wg.Wait()
195 dss.teardown()
196 after := sw.Sockets()
197 if len(after) != len(before) {
198 t.Errorf("got %d; want %d", len(after), len(before))
202 // Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
203 // expected to hang until the timeout elapses. These addresses are reserved
204 // for benchmarking by RFC 6890.
205 const (
206 slowDst4 = "198.18.0.254"
207 slowDst6 = "2001:2::254"
210 // In some environments, the slow IPs may be explicitly unreachable, and fail
211 // more quickly than expected. This test hook prevents dialTCP from returning
212 // before the deadline.
213 func slowDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
214 c, err := doDialTCP(ctx, net, laddr, raddr)
215 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
216 // Wait for the deadline, or indefinitely if none exists.
217 <-ctx.Done()
219 return c, err
222 func dialClosedPort() (actual, expected time.Duration) {
223 // Estimate the expected time for this platform.
224 // On Windows, dialing a closed port takes roughly 1 second,
225 // but other platforms should be instantaneous.
226 if runtime.GOOS == "windows" {
227 expected = 1500 * time.Millisecond
228 } else {
229 expected = 95 * time.Millisecond
232 l, err := Listen("tcp", "127.0.0.1:0")
233 if err != nil {
234 return 999 * time.Hour, expected
236 addr := l.Addr().String()
237 l.Close()
238 // On OpenBSD, interference from TestSelfConnect is mysteriously
239 // causing the first attempt to hang for a few seconds, so we throw
240 // away the first result and keep the second.
241 for i := 1; ; i++ {
242 startTime := time.Now()
243 c, err := Dial("tcp", addr)
244 if err == nil {
245 c.Close()
247 elapsed := time.Now().Sub(startTime)
248 if i == 2 {
249 return elapsed, expected
254 func TestDialParallel(t *testing.T) {
255 testenv.MustHaveExternalNetwork(t)
257 if !supportsIPv4 || !supportsIPv6 {
258 t.Skip("both IPv4 and IPv6 are required")
261 closedPortDelay, expectClosedPortDelay := dialClosedPort()
262 if closedPortDelay > expectClosedPortDelay {
263 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
266 const instant time.Duration = 0
267 const fallbackDelay = 200 * time.Millisecond
269 // Some cases will run quickly when "connection refused" is fast,
270 // or trigger the fallbackDelay on Windows. This value holds the
271 // lesser of the two delays.
272 var closedPortOrFallbackDelay time.Duration
273 if closedPortDelay < fallbackDelay {
274 closedPortOrFallbackDelay = closedPortDelay
275 } else {
276 closedPortOrFallbackDelay = fallbackDelay
279 origTestHookDialTCP := testHookDialTCP
280 defer func() { testHookDialTCP = origTestHookDialTCP }()
281 testHookDialTCP = slowDialTCP
283 nCopies := func(s string, n int) []string {
284 out := make([]string, n)
285 for i := 0; i < n; i++ {
286 out[i] = s
288 return out
291 var testCases = []struct {
292 primaries []string
293 fallbacks []string
294 teardownNetwork string
295 expectOk bool
296 expectElapsed time.Duration
298 // These should just work on the first try.
299 {[]string{"127.0.0.1"}, []string{}, "", true, instant},
300 {[]string{"::1"}, []string{}, "", true, instant},
301 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
302 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
303 // Primary is slow; fallback should kick in.
304 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
305 // Skip a "connection refused" in the primary thread.
306 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
307 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
308 // Skip a "connection refused" in the fallback thread.
309 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
310 // Primary refused, fallback without delay.
311 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
312 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
313 // Everything is refused.
314 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
315 // Nothing to do; fail instantly.
316 {[]string{}, []string{}, "", false, instant},
317 // Connecting to tons of addresses should not trip the deadline.
318 {nCopies("::1", 1000), []string{}, "", true, instant},
321 handler := func(dss *dualStackServer, ln Listener) {
322 for {
323 c, err := ln.Accept()
324 if err != nil {
325 return
327 c.Close()
331 // Convert a list of IP strings into TCPAddrs.
332 makeAddrs := func(ips []string, port string) addrList {
333 var out addrList
334 for _, ip := range ips {
335 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
336 if err != nil {
337 t.Fatal(err)
339 out = append(out, addr)
341 return out
344 for i, tt := range testCases {
345 dss, err := newDualStackServer()
346 if err != nil {
347 t.Fatal(err)
349 defer dss.teardown()
350 if err := dss.buildup(handler); err != nil {
351 t.Fatal(err)
353 if tt.teardownNetwork != "" {
354 // Destroy one of the listening sockets, creating an unreachable port.
355 dss.teardownNetwork(tt.teardownNetwork)
358 primaries := makeAddrs(tt.primaries, dss.port)
359 fallbacks := makeAddrs(tt.fallbacks, dss.port)
360 d := Dialer{
361 FallbackDelay: fallbackDelay,
363 startTime := time.Now()
364 dp := &dialParam{
365 Dialer: d,
366 network: "tcp",
367 address: "?",
369 c, err := dialParallel(context.Background(), dp, primaries, fallbacks)
370 elapsed := time.Since(startTime)
372 if c != nil {
373 c.Close()
376 if tt.expectOk && err != nil {
377 t.Errorf("#%d: got %v; want nil", i, err)
378 } else if !tt.expectOk && err == nil {
379 t.Errorf("#%d: got nil; want non-nil", i)
382 expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
383 expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
384 if !(elapsed >= expectElapsedMin) {
385 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
386 } else if !(elapsed <= expectElapsedMax) {
387 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
390 // Repeat each case, ensuring that it can be canceled quickly.
391 ctx, cancel := context.WithCancel(context.Background())
392 var wg sync.WaitGroup
393 wg.Add(1)
394 go func() {
395 time.Sleep(5 * time.Millisecond)
396 cancel()
397 wg.Done()
399 startTime = time.Now()
400 c, err = dialParallel(ctx, dp, primaries, fallbacks)
401 if c != nil {
402 c.Close()
404 elapsed = time.Now().Sub(startTime)
405 if elapsed > 100*time.Millisecond {
406 t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed)
408 wg.Wait()
412 func lookupSlowFast(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
413 switch host {
414 case "slow6loopback4":
415 // Returns a slow IPv6 address, and a local IPv4 address.
416 return []IPAddr{
417 {IP: ParseIP(slowDst6)},
418 {IP: ParseIP("127.0.0.1")},
419 }, nil
420 default:
421 return fn(ctx, host)
425 func TestDialerFallbackDelay(t *testing.T) {
426 testenv.MustHaveExternalNetwork(t)
428 if !supportsIPv4 || !supportsIPv6 {
429 t.Skip("both IPv4 and IPv6 are required")
432 origTestHookLookupIP := testHookLookupIP
433 defer func() { testHookLookupIP = origTestHookLookupIP }()
434 testHookLookupIP = lookupSlowFast
436 origTestHookDialTCP := testHookDialTCP
437 defer func() { testHookDialTCP = origTestHookDialTCP }()
438 testHookDialTCP = slowDialTCP
440 var testCases = []struct {
441 dualstack bool
442 delay time.Duration
443 expectElapsed time.Duration
445 // Use a very brief delay, which should fallback immediately.
446 {true, 1 * time.Nanosecond, 0},
447 // Use a 200ms explicit timeout.
448 {true, 200 * time.Millisecond, 200 * time.Millisecond},
449 // The default is 300ms.
450 {true, 0, 300 * time.Millisecond},
453 handler := func(dss *dualStackServer, ln Listener) {
454 for {
455 c, err := ln.Accept()
456 if err != nil {
457 return
459 c.Close()
462 dss, err := newDualStackServer()
463 if err != nil {
464 t.Fatal(err)
466 defer dss.teardown()
467 if err := dss.buildup(handler); err != nil {
468 t.Fatal(err)
471 for i, tt := range testCases {
472 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
474 startTime := time.Now()
475 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
476 elapsed := time.Now().Sub(startTime)
477 if err == nil {
478 c.Close()
479 } else if tt.dualstack {
480 t.Error(err)
482 expectMin := tt.expectElapsed - 1*time.Millisecond
483 expectMax := tt.expectElapsed + 95*time.Millisecond
484 if !(elapsed >= expectMin) {
485 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
487 if !(elapsed <= expectMax) {
488 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
493 func TestDialParallelSpuriousConnection(t *testing.T) {
494 if !supportsIPv4 || !supportsIPv6 {
495 t.Skip("both IPv4 and IPv6 are required")
498 var wg sync.WaitGroup
499 wg.Add(2)
500 handler := func(dss *dualStackServer, ln Listener) {
501 // Accept one connection per address.
502 c, err := ln.Accept()
503 if err != nil {
504 t.Fatal(err)
506 // The client should close itself, without sending data.
507 c.SetReadDeadline(time.Now().Add(1 * time.Second))
508 var b [1]byte
509 if _, err := c.Read(b[:]); err != io.EOF {
510 t.Errorf("got %v; want %v", err, io.EOF)
512 c.Close()
513 wg.Done()
515 dss, err := newDualStackServer()
516 if err != nil {
517 t.Fatal(err)
519 defer dss.teardown()
520 if err := dss.buildup(handler); err != nil {
521 t.Fatal(err)
524 const fallbackDelay = 100 * time.Millisecond
526 origTestHookDialTCP := testHookDialTCP
527 defer func() { testHookDialTCP = origTestHookDialTCP }()
528 testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
529 // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation.
530 // This forces dialParallel to juggle two successful connections.
531 time.Sleep(fallbackDelay * 2)
533 // Now ignore the provided context (which will be canceled) and use a
534 // different one to make sure this completes with a valid connection,
535 // which we hope to be closed below:
536 return doDialTCP(context.Background(), net, laddr, raddr)
539 d := Dialer{
540 FallbackDelay: fallbackDelay,
542 dp := &dialParam{
543 Dialer: d,
544 network: "tcp",
545 address: "?",
548 makeAddr := func(ip string) addrList {
549 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
550 if err != nil {
551 t.Fatal(err)
553 return addrList{addr}
556 // dialParallel returns one connection (and closes the other.)
557 c, err := dialParallel(context.Background(), dp, makeAddr("127.0.0.1"), makeAddr("::1"))
558 if err != nil {
559 t.Fatal(err)
561 c.Close()
563 // The server should've seen both connections.
564 wg.Wait()
567 func TestDialerPartialDeadline(t *testing.T) {
568 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
569 var testCases = []struct {
570 now time.Time
571 deadline time.Time
572 addrs int
573 expectDeadline time.Time
574 expectErr error
576 // Regular division.
577 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
578 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
579 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
580 // Bump against the 2-second sane minimum.
581 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
582 // Total available is now below the sane minimum.
583 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
584 // Null deadline.
585 {now, noDeadline, 1, noDeadline, nil},
586 // Step the clock forward and cross the deadline.
587 {now.Add(-1 * time.Millisecond), now, 1, now, nil},
588 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
589 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
591 for i, tt := range testCases {
592 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
593 if err != tt.expectErr {
594 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
596 if deadline != tt.expectDeadline {
597 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
602 func TestDialerLocalAddr(t *testing.T) {
603 if !supportsIPv4 || !supportsIPv6 {
604 t.Skip("both IPv4 and IPv6 are required")
607 type test struct {
608 network, raddr string
609 laddr Addr
610 error
612 var tests = []test{
613 {"tcp4", "127.0.0.1", nil, nil},
614 {"tcp4", "127.0.0.1", &TCPAddr{}, nil},
615 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
616 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
617 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
618 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
619 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
620 {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
621 {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
622 {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
624 {"tcp6", "::1", nil, nil},
625 {"tcp6", "::1", &TCPAddr{}, nil},
626 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
627 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
628 {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
629 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
630 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
631 {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
632 {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
633 {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
635 {"tcp", "127.0.0.1", nil, nil},
636 {"tcp", "127.0.0.1", &TCPAddr{}, nil},
637 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
638 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
639 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
640 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
641 {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
642 {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
643 {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
645 {"tcp", "::1", nil, nil},
646 {"tcp", "::1", &TCPAddr{}, nil},
647 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
648 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
649 {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
650 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
651 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
652 {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
653 {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
654 {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
657 if supportsIPv4map {
658 tests = append(tests, test{
659 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
661 } else {
662 tests = append(tests, test{
663 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
667 origTestHookLookupIP := testHookLookupIP
668 defer func() { testHookLookupIP = origTestHookLookupIP }()
669 testHookLookupIP = lookupLocalhost
670 handler := func(ls *localServer, ln Listener) {
671 for {
672 c, err := ln.Accept()
673 if err != nil {
674 return
676 c.Close()
679 var err error
680 var lss [2]*localServer
681 for i, network := range []string{"tcp4", "tcp6"} {
682 lss[i], err = newLocalServer(network)
683 if err != nil {
684 t.Fatal(err)
686 defer lss[i].teardown()
687 if err := lss[i].buildup(handler); err != nil {
688 t.Fatal(err)
692 for _, tt := range tests {
693 d := &Dialer{LocalAddr: tt.laddr}
694 var addr string
695 ip := ParseIP(tt.raddr)
696 if ip.To4() != nil {
697 addr = lss[0].Listener.Addr().String()
699 if ip.To16() != nil && ip.To4() == nil {
700 addr = lss[1].Listener.Addr().String()
702 c, err := d.Dial(tt.network, addr)
703 if err == nil && tt.error != nil || err != nil && tt.error == nil {
704 t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
706 if err != nil {
707 if perr := parseDialError(err); perr != nil {
708 t.Error(perr)
710 continue
712 c.Close()
716 func TestDialerDualStack(t *testing.T) {
717 // This test is known to be flaky. Don't frighten regular
718 // users about it; only fail on the build dashboard.
719 if testenv.Builder() == "" {
720 testenv.SkipFlaky(t, 13324)
722 if !supportsIPv4 || !supportsIPv6 {
723 t.Skip("both IPv4 and IPv6 are required")
726 closedPortDelay, expectClosedPortDelay := dialClosedPort()
727 if closedPortDelay > expectClosedPortDelay {
728 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
731 origTestHookLookupIP := testHookLookupIP
732 defer func() { testHookLookupIP = origTestHookLookupIP }()
733 testHookLookupIP = lookupLocalhost
734 handler := func(dss *dualStackServer, ln Listener) {
735 for {
736 c, err := ln.Accept()
737 if err != nil {
738 return
740 c.Close()
744 var timeout = 150*time.Millisecond + closedPortDelay
745 for _, dualstack := range []bool{false, true} {
746 dss, err := newDualStackServer()
747 if err != nil {
748 t.Fatal(err)
750 defer dss.teardown()
751 if err := dss.buildup(handler); err != nil {
752 t.Fatal(err)
755 d := &Dialer{DualStack: dualstack, Timeout: timeout}
756 for range dss.lns {
757 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
758 if err != nil {
759 t.Error(err)
760 continue
762 switch addr := c.LocalAddr().(*TCPAddr); {
763 case addr.IP.To4() != nil:
764 dss.teardownNetwork("tcp4")
765 case addr.IP.To16() != nil && addr.IP.To4() == nil:
766 dss.teardownNetwork("tcp6")
768 c.Close()
773 func TestDialerKeepAlive(t *testing.T) {
774 handler := func(ls *localServer, ln Listener) {
775 for {
776 c, err := ln.Accept()
777 if err != nil {
778 return
780 c.Close()
783 ls, err := newLocalServer("tcp")
784 if err != nil {
785 t.Fatal(err)
787 defer ls.teardown()
788 if err := ls.buildup(handler); err != nil {
789 t.Fatal(err)
791 defer func() { testHookSetKeepAlive = func() {} }()
793 for _, keepAlive := range []bool{false, true} {
794 got := false
795 testHookSetKeepAlive = func() { got = true }
796 var d Dialer
797 if keepAlive {
798 d.KeepAlive = 30 * time.Second
800 c, err := d.Dial("tcp", ls.Listener.Addr().String())
801 if err != nil {
802 t.Fatal(err)
804 c.Close()
805 if got != keepAlive {
806 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
811 func TestDialCancel(t *testing.T) {
812 switch testenv.Builder() {
813 case "linux-arm64-buildlet":
814 t.Skip("skipping on linux-arm64-buildlet; incompatible network config? issue 15191")
815 case "":
816 testenv.MustHaveExternalNetwork(t)
819 if runtime.GOOS == "nacl" {
820 // nacl doesn't have external network access.
821 t.Skipf("skipping on %s", runtime.GOOS)
824 blackholeIPPort := JoinHostPort(slowDst4, "1234")
825 if !supportsIPv4 {
826 blackholeIPPort = JoinHostPort(slowDst6, "1234")
829 ticker := time.NewTicker(10 * time.Millisecond)
830 defer ticker.Stop()
832 const cancelTick = 5 // the timer tick we cancel the dial at
833 const timeoutTick = 100
835 var d Dialer
836 cancel := make(chan struct{})
837 d.Cancel = cancel
838 errc := make(chan error, 1)
839 connc := make(chan Conn, 1)
840 go func() {
841 if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
842 errc <- err
843 } else {
844 connc <- c
847 ticks := 0
848 for {
849 select {
850 case <-ticker.C:
851 ticks++
852 if ticks == cancelTick {
853 close(cancel)
855 if ticks == timeoutTick {
856 t.Fatal("timeout waiting for dial to fail")
858 case c := <-connc:
859 c.Close()
860 t.Fatal("unexpected successful connection")
861 case err := <-errc:
862 if perr := parseDialError(err); perr != nil {
863 t.Error(perr)
865 if ticks < cancelTick {
866 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
867 ticks, cancelTick-ticks, err)
869 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
870 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
872 return // success.
877 func TestCancelAfterDial(t *testing.T) {
878 if testing.Short() {
879 t.Skip("avoiding time.Sleep")
882 ln, err := newLocalListener("tcp")
883 if err != nil {
884 t.Fatal(err)
887 var wg sync.WaitGroup
888 wg.Add(1)
889 defer func() {
890 ln.Close()
891 wg.Wait()
894 // Echo back the first line of each incoming connection.
895 go func() {
896 for {
897 c, err := ln.Accept()
898 if err != nil {
899 break
901 rb := bufio.NewReader(c)
902 line, err := rb.ReadString('\n')
903 if err != nil {
904 t.Error(err)
905 c.Close()
906 continue
908 if _, err := c.Write([]byte(line)); err != nil {
909 t.Error(err)
911 c.Close()
913 wg.Done()
916 try := func() {
917 cancel := make(chan struct{})
918 d := &Dialer{Cancel: cancel}
919 c, err := d.Dial("tcp", ln.Addr().String())
921 // Immediately after dialing, request cancelation and sleep.
922 // Before Issue 15078 was fixed, this would cause subsequent operations
923 // to fail with an i/o timeout roughly 50% of the time.
924 close(cancel)
925 time.Sleep(10 * time.Millisecond)
927 if err != nil {
928 t.Fatal(err)
930 defer c.Close()
932 // Send some data to confirm that the connection is still alive.
933 const message = "echo!\n"
934 if _, err := c.Write([]byte(message)); err != nil {
935 t.Fatal(err)
938 // The server should echo the line, and close the connection.
939 rb := bufio.NewReader(c)
940 line, err := rb.ReadString('\n')
941 if err != nil {
942 t.Fatal(err)
944 if line != message {
945 t.Errorf("got %q; want %q", line, message)
947 if _, err := rb.ReadByte(); err != io.EOF {
948 t.Errorf("got %v; want %v", err, io.EOF)
952 // This bug manifested about 50% of the time, so try it a few times.
953 for i := 0; i < 10; i++ {
954 try()