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.
22 var prohibitionaryDialArgTests = []struct {
26 {"tcp6", "127.0.0.1"},
27 {"tcp6", "::ffff:127.0.0.1"},
30 func TestProhibitionaryDialArg(t *testing.T) {
31 testenv.MustHaveExternalNetwork(t)
35 t.Skipf("not supported on %s", runtime.GOOS)
37 if !supportsIPv4map() {
38 t.Skip("mapping ipv4 address inside ipv6 address not supported")
41 ln, err := Listen("tcp", "[::]:0")
47 _, port, err := SplitHostPort(ln.Addr().String())
52 for i, tt := range prohibitionaryDialArgTests {
53 c, err := Dial(tt.network, JoinHostPort(tt.address, port))
56 t.Errorf("#%d: %v", i, err)
61 func TestDialLocal(t *testing.T) {
62 ln, err := newLocalListener("tcp")
67 _, port, err := SplitHostPort(ln.Addr().String())
71 c, err := Dial("tcp", JoinHostPort("", port))
78 func TestDialerDualStackFDLeak(t *testing.T) {
81 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
83 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
85 testenv.SkipFlaky(t, 15157)
87 if !supportsIPv4() || !supportsIPv6() {
88 t.Skip("both IPv4 and IPv6 are required")
91 before := sw.Sockets()
92 origTestHookLookupIP := testHookLookupIP
93 defer func() { testHookLookupIP = origTestHookLookupIP }()
94 testHookLookupIP = lookupLocalhost
95 handler := func(dss *dualStackServer, ln Listener) {
104 dss, err := newDualStackServer()
108 if err := dss.buildup(handler); err != nil {
114 var wg sync.WaitGroup
116 d := &Dialer{DualStack: true, Timeout: 5 * time.Second}
117 for i := 0; i < N; i++ {
120 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
130 after := sw.Sockets()
131 if len(after) != len(before) {
132 t.Errorf("got %d; want %d", len(after), len(before))
136 // Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
137 // expected to hang until the timeout elapses. These addresses are reserved
138 // for benchmarking by RFC 6890.
140 slowDst4 = "198.18.0.254"
141 slowDst6 = "2001:2::254"
144 // In some environments, the slow IPs may be explicitly unreachable, and fail
145 // more quickly than expected. This test hook prevents dialTCP from returning
146 // before the deadline.
147 func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
148 sd := &sysDialer{network: network, address: raddr.String()}
149 c, err := sd.doDialTCP(ctx, laddr, raddr)
150 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
151 // Wait for the deadline, or indefinitely if none exists.
157 func dialClosedPort() (actual, expected time.Duration) {
158 // Estimate the expected time for this platform.
159 // On Windows, dialing a closed port takes roughly 1 second,
160 // but other platforms should be instantaneous.
161 if runtime.GOOS == "windows" {
162 expected = 1500 * time.Millisecond
163 } else if runtime.GOOS == "darwin" {
164 expected = 150 * time.Millisecond
166 expected = 95 * time.Millisecond
169 l, err := Listen("tcp", "127.0.0.1:0")
171 return 999 * time.Hour, expected
173 addr := l.Addr().String()
175 // On OpenBSD, interference from TestSelfConnect is mysteriously
176 // causing the first attempt to hang for a few seconds, so we throw
177 // away the first result and keep the second.
179 startTime := time.Now()
180 c, err := Dial("tcp", addr)
184 elapsed := time.Now().Sub(startTime)
186 return elapsed, expected
191 func TestDialParallel(t *testing.T) {
192 testenv.MustHaveExternalNetwork(t)
194 if !supportsIPv4() || !supportsIPv6() {
195 t.Skip("both IPv4 and IPv6 are required")
198 closedPortDelay, expectClosedPortDelay := dialClosedPort()
199 if closedPortDelay > expectClosedPortDelay {
200 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
203 const instant time.Duration = 0
204 const fallbackDelay = 200 * time.Millisecond
206 // Some cases will run quickly when "connection refused" is fast,
207 // or trigger the fallbackDelay on Windows. This value holds the
208 // lesser of the two delays.
209 var closedPortOrFallbackDelay time.Duration
210 if closedPortDelay < fallbackDelay {
211 closedPortOrFallbackDelay = closedPortDelay
213 closedPortOrFallbackDelay = fallbackDelay
216 origTestHookDialTCP := testHookDialTCP
217 defer func() { testHookDialTCP = origTestHookDialTCP }()
218 testHookDialTCP = slowDialTCP
220 nCopies := func(s string, n int) []string {
221 out := make([]string, n)
222 for i := 0; i < n; i++ {
228 var testCases = []struct {
231 teardownNetwork string
233 expectElapsed time.Duration
235 // These should just work on the first try.
236 {[]string{"127.0.0.1"}, []string{}, "", true, instant},
237 {[]string{"::1"}, []string{}, "", true, instant},
238 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
239 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
240 // Primary is slow; fallback should kick in.
241 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
242 // Skip a "connection refused" in the primary thread.
243 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
244 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
245 // Skip a "connection refused" in the fallback thread.
246 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
247 // Primary refused, fallback without delay.
248 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
249 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
250 // Everything is refused.
251 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
252 // Nothing to do; fail instantly.
253 {[]string{}, []string{}, "", false, instant},
254 // Connecting to tons of addresses should not trip the deadline.
255 {nCopies("::1", 1000), []string{}, "", true, instant},
258 handler := func(dss *dualStackServer, ln Listener) {
260 c, err := ln.Accept()
268 // Convert a list of IP strings into TCPAddrs.
269 makeAddrs := func(ips []string, port string) addrList {
271 for _, ip := range ips {
272 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
276 out = append(out, addr)
281 for i, tt := range testCases {
282 dss, err := newDualStackServer()
287 if err := dss.buildup(handler); err != nil {
290 if tt.teardownNetwork != "" {
291 // Destroy one of the listening sockets, creating an unreachable port.
292 dss.teardownNetwork(tt.teardownNetwork)
295 primaries := makeAddrs(tt.primaries, dss.port)
296 fallbacks := makeAddrs(tt.fallbacks, dss.port)
298 FallbackDelay: fallbackDelay,
300 startTime := time.Now()
306 c, err := sd.dialParallel(context.Background(), primaries, fallbacks)
307 elapsed := time.Since(startTime)
313 if tt.expectOk && err != nil {
314 t.Errorf("#%d: got %v; want nil", i, err)
315 } else if !tt.expectOk && err == nil {
316 t.Errorf("#%d: got nil; want non-nil", i)
319 expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
320 expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
321 if elapsed < expectElapsedMin {
322 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
323 } else if elapsed > expectElapsedMax {
324 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
327 // Repeat each case, ensuring that it can be canceled quickly.
328 ctx, cancel := context.WithCancel(context.Background())
329 var wg sync.WaitGroup
332 time.Sleep(5 * time.Millisecond)
336 startTime = time.Now()
337 c, err = sd.dialParallel(ctx, primaries, fallbacks)
341 elapsed = time.Now().Sub(startTime)
342 if elapsed > 100*time.Millisecond {
343 t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed)
349 func lookupSlowFast(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
351 case "slow6loopback4":
352 // Returns a slow IPv6 address, and a local IPv4 address.
354 {IP: ParseIP(slowDst6)},
355 {IP: ParseIP("127.0.0.1")},
358 return fn(ctx, network, host)
362 func TestDialerFallbackDelay(t *testing.T) {
363 testenv.MustHaveExternalNetwork(t)
365 if !supportsIPv4() || !supportsIPv6() {
366 t.Skip("both IPv4 and IPv6 are required")
369 origTestHookLookupIP := testHookLookupIP
370 defer func() { testHookLookupIP = origTestHookLookupIP }()
371 testHookLookupIP = lookupSlowFast
373 origTestHookDialTCP := testHookDialTCP
374 defer func() { testHookDialTCP = origTestHookDialTCP }()
375 testHookDialTCP = slowDialTCP
377 var testCases = []struct {
380 expectElapsed time.Duration
382 // Use a very brief delay, which should fallback immediately.
383 {true, 1 * time.Nanosecond, 0},
384 // Use a 200ms explicit timeout.
385 {true, 200 * time.Millisecond, 200 * time.Millisecond},
386 // The default is 300ms.
387 {true, 0, 300 * time.Millisecond},
390 handler := func(dss *dualStackServer, ln Listener) {
392 c, err := ln.Accept()
399 dss, err := newDualStackServer()
404 if err := dss.buildup(handler); err != nil {
408 for i, tt := range testCases {
409 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
411 startTime := time.Now()
412 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
413 elapsed := time.Now().Sub(startTime)
416 } else if tt.dualstack {
419 expectMin := tt.expectElapsed - 1*time.Millisecond
420 expectMax := tt.expectElapsed + 95*time.Millisecond
421 if elapsed < expectMin {
422 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
424 if elapsed > expectMax {
425 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
430 func TestDialParallelSpuriousConnection(t *testing.T) {
431 if !supportsIPv4() || !supportsIPv6() {
432 t.Skip("both IPv4 and IPv6 are required")
435 var wg sync.WaitGroup
437 handler := func(dss *dualStackServer, ln Listener) {
438 // Accept one connection per address.
439 c, err := ln.Accept()
443 // The client should close itself, without sending data.
444 c.SetReadDeadline(time.Now().Add(1 * time.Second))
446 if _, err := c.Read(b[:]); err != io.EOF {
447 t.Errorf("got %v; want %v", err, io.EOF)
452 dss, err := newDualStackServer()
457 if err := dss.buildup(handler); err != nil {
461 const fallbackDelay = 100 * time.Millisecond
463 origTestHookDialTCP := testHookDialTCP
464 defer func() { testHookDialTCP = origTestHookDialTCP }()
465 testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
466 // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancellation.
467 // This forces dialParallel to juggle two successful connections.
468 time.Sleep(fallbackDelay * 2)
470 // Now ignore the provided context (which will be canceled) and use a
471 // different one to make sure this completes with a valid connection,
472 // which we hope to be closed below:
473 sd := &sysDialer{network: net, address: raddr.String()}
474 return sd.doDialTCP(context.Background(), laddr, raddr)
478 FallbackDelay: fallbackDelay,
486 makeAddr := func(ip string) addrList {
487 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
491 return addrList{addr}
494 // dialParallel returns one connection (and closes the other.)
495 c, err := sd.dialParallel(context.Background(), makeAddr("127.0.0.1"), makeAddr("::1"))
501 // The server should've seen both connections.
505 func TestDialerPartialDeadline(t *testing.T) {
506 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
507 var testCases = []struct {
511 expectDeadline time.Time
515 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
516 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
517 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
518 // Bump against the 2-second sane minimum.
519 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
520 // Total available is now below the sane minimum.
521 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
523 {now, noDeadline, 1, noDeadline, nil},
524 // Step the clock forward and cross the deadline.
525 {now.Add(-1 * time.Millisecond), now, 1, now, nil},
526 {now.Add(0 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
527 {now.Add(1 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
529 for i, tt := range testCases {
530 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
531 if err != tt.expectErr {
532 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
534 if !deadline.Equal(tt.expectDeadline) {
535 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
540 func TestDialerLocalAddr(t *testing.T) {
541 if !supportsIPv4() || !supportsIPv6() {
542 t.Skip("both IPv4 and IPv6 are required")
546 network, raddr string
551 {"tcp4", "127.0.0.1", nil, nil},
552 {"tcp4", "127.0.0.1", &TCPAddr{}, nil},
553 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
554 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
555 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
556 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
557 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
558 {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
559 {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
560 {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
562 {"tcp6", "::1", nil, nil},
563 {"tcp6", "::1", &TCPAddr{}, nil},
564 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
565 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
566 {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
567 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
568 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
569 {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
570 {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
571 {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
573 {"tcp", "127.0.0.1", nil, nil},
574 {"tcp", "127.0.0.1", &TCPAddr{}, nil},
575 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
576 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
577 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
578 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
579 {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
580 {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
581 {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
583 {"tcp", "::1", nil, nil},
584 {"tcp", "::1", &TCPAddr{}, nil},
585 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
586 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
587 {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
588 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
589 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
590 {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
591 {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
592 {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
595 if supportsIPv4map() {
596 tests = append(tests, test{
597 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
600 tests = append(tests, test{
601 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
605 origTestHookLookupIP := testHookLookupIP
606 defer func() { testHookLookupIP = origTestHookLookupIP }()
607 testHookLookupIP = lookupLocalhost
608 handler := func(ls *localServer, ln Listener) {
610 c, err := ln.Accept()
618 var lss [2]*localServer
619 for i, network := range []string{"tcp4", "tcp6"} {
620 lss[i], err = newLocalServer(network)
624 defer lss[i].teardown()
625 if err := lss[i].buildup(handler); err != nil {
630 for _, tt := range tests {
631 d := &Dialer{LocalAddr: tt.laddr}
633 ip := ParseIP(tt.raddr)
635 addr = lss[0].Listener.Addr().String()
637 if ip.To16() != nil && ip.To4() == nil {
638 addr = lss[1].Listener.Addr().String()
640 c, err := d.Dial(tt.network, addr)
641 if err == nil && tt.error != nil || err != nil && tt.error == nil {
642 // On Darwin this occasionally times out.
643 // We don't know why. Issue #22019.
644 if runtime.GOOS == "darwin" && tt.error == nil && os.IsTimeout(err) {
645 t.Logf("ignoring timeout error on Darwin; see https://golang.org/issue/22019")
647 t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
651 if perr := parseDialError(err); perr != nil {
660 func TestDialerDualStack(t *testing.T) {
661 testenv.SkipFlaky(t, 13324)
663 if !supportsIPv4() || !supportsIPv6() {
664 t.Skip("both IPv4 and IPv6 are required")
667 closedPortDelay, expectClosedPortDelay := dialClosedPort()
668 if closedPortDelay > expectClosedPortDelay {
669 t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
672 origTestHookLookupIP := testHookLookupIP
673 defer func() { testHookLookupIP = origTestHookLookupIP }()
674 testHookLookupIP = lookupLocalhost
675 handler := func(dss *dualStackServer, ln Listener) {
677 c, err := ln.Accept()
685 var timeout = 150*time.Millisecond + closedPortDelay
686 for _, dualstack := range []bool{false, true} {
687 dss, err := newDualStackServer()
692 if err := dss.buildup(handler); err != nil {
696 d := &Dialer{DualStack: dualstack, Timeout: timeout}
698 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
703 switch addr := c.LocalAddr().(*TCPAddr); {
704 case addr.IP.To4() != nil:
705 dss.teardownNetwork("tcp4")
706 case addr.IP.To16() != nil && addr.IP.To4() == nil:
707 dss.teardownNetwork("tcp6")
714 func TestDialerKeepAlive(t *testing.T) {
715 handler := func(ls *localServer, ln Listener) {
717 c, err := ln.Accept()
724 ls, err := newLocalServer("tcp")
729 if err := ls.buildup(handler); err != nil {
732 defer func() { testHookSetKeepAlive = func(time.Duration) {} }()
736 expected time.Duration
739 {0, 15 * time.Second},
740 {5 * time.Second, 5 * time.Second},
741 {30 * time.Second, 30 * time.Second},
744 for _, test := range tests {
745 var got time.Duration = -1
746 testHookSetKeepAlive = func(d time.Duration) { got = d }
747 d := Dialer{KeepAlive: test.ka}
748 c, err := d.Dial("tcp", ls.Listener.Addr().String())
753 if got != test.expected {
754 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected)
759 func TestDialCancel(t *testing.T) {
760 switch testenv.Builder() {
761 case "linux-arm64-buildlet":
762 t.Skip("skipping on linux-arm64-buildlet; incompatible network config? issue 15191")
764 mustHaveExternalNetwork(t)
766 if runtime.GOOS == "nacl" {
767 // nacl doesn't have external network access.
768 t.Skipf("skipping on %s", runtime.GOOS)
771 blackholeIPPort := JoinHostPort(slowDst4, "1234")
773 blackholeIPPort = JoinHostPort(slowDst6, "1234")
776 ticker := time.NewTicker(10 * time.Millisecond)
779 const cancelTick = 5 // the timer tick we cancel the dial at
780 const timeoutTick = 100
783 cancel := make(chan struct{})
785 errc := make(chan error, 1)
786 connc := make(chan Conn, 1)
788 if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
799 if ticks == cancelTick {
802 if ticks == timeoutTick {
803 t.Fatal("timeout waiting for dial to fail")
807 t.Fatal("unexpected successful connection")
809 if perr := parseDialError(err); perr != nil {
812 if ticks < cancelTick {
813 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
814 ticks, cancelTick-ticks, err)
816 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
817 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
824 func TestCancelAfterDial(t *testing.T) {
826 t.Skip("avoiding time.Sleep")
829 ln, err := newLocalListener("tcp")
834 var wg sync.WaitGroup
841 // Echo back the first line of each incoming connection.
844 c, err := ln.Accept()
848 rb := bufio.NewReader(c)
849 line, err := rb.ReadString('\n')
855 if _, err := c.Write([]byte(line)); err != nil {
864 cancel := make(chan struct{})
865 d := &Dialer{Cancel: cancel}
866 c, err := d.Dial("tcp", ln.Addr().String())
868 // Immediately after dialing, request cancellation and sleep.
869 // Before Issue 15078 was fixed, this would cause subsequent operations
870 // to fail with an i/o timeout roughly 50% of the time.
872 time.Sleep(10 * time.Millisecond)
879 // Send some data to confirm that the connection is still alive.
880 const message = "echo!\n"
881 if _, err := c.Write([]byte(message)); err != nil {
885 // The server should echo the line, and close the connection.
886 rb := bufio.NewReader(c)
887 line, err := rb.ReadString('\n')
892 t.Errorf("got %q; want %q", line, message)
894 if _, err := rb.ReadByte(); err != io.EOF {
895 t.Errorf("got %v; want %v", err, io.EOF)
899 // This bug manifested about 50% of the time, so try it a few times.
900 for i := 0; i < 10; i++ {
905 // Issue 18806: it should always be possible to net.Dial a
906 // net.Listener().Addr().String when the listen address was ":n", even
907 // if the machine has halfway configured IPv6 such that it can bind on
908 // "::" not connect back to that same address.
909 func TestDialListenerAddr(t *testing.T) {
910 mustHaveExternalNetwork(t)
911 ln, err := Listen("tcp", ":0")
916 addr := ln.Addr().String()
917 c, err := Dial("tcp", addr)
919 t.Fatalf("for addr %q, dial error: %v", addr, err)
924 func TestDialerControl(t *testing.T) {
925 switch runtime.GOOS {
926 case "nacl", "plan9":
927 t.Skipf("not supported on %s", runtime.GOOS)
930 t.Run("StreamDial", func(t *testing.T) {
931 for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
932 if !testableNetwork(network) {
935 ln, err := newLocalListener(network)
941 d := Dialer{Control: controlOnConnSetup}
942 c, err := d.Dial(network, ln.Addr().String())
950 t.Run("PacketDial", func(t *testing.T) {
951 for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} {
952 if !testableNetwork(network) {
955 c1, err := newLocalPacketListener(network)
960 if network == "unixgram" {
961 defer os.Remove(c1.LocalAddr().String())
964 d := Dialer{Control: controlOnConnSetup}
965 c2, err := d.Dial(network, c1.LocalAddr().String())
975 // mustHaveExternalNetwork is like testenv.MustHaveExternalNetwork
976 // except that it won't skip testing on non-mobile builders.
977 func mustHaveExternalNetwork(t *testing.T) {
979 mobile := runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
980 if testenv.Builder() == "" || mobile {
981 testenv.MustHaveExternalNetwork(t)