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.
12 "net/internal/socktest"
19 var prohibitionaryDialArgTests
= []struct {
23 {"tcp6", "127.0.0.1"},
24 {"tcp6", "::ffff:127.0.0.1"},
27 func TestProhibitionaryDialArg(t
*testing
.T
) {
28 testenv
.MustHaveExternalNetwork(t
)
32 t
.Skipf("not supported on %s", runtime
.GOOS
)
35 t
.Skip("mapping ipv4 address inside ipv6 address not supported")
38 ln
, err
:= Listen("tcp", "[::]:0")
44 _
, port
, err
:= SplitHostPort(ln
.Addr().String())
49 for i
, tt
:= range prohibitionaryDialArgTests
{
50 c
, err
:= Dial(tt
.network
, JoinHostPort(tt
.address
, port
))
53 t
.Errorf("#%d: %v", i
, err
)
58 func TestDialLocal(t
*testing
.T
) {
59 ln
, err
:= newLocalListener("tcp")
64 _
, port
, err
:= SplitHostPort(ln
.Addr().String())
68 c
, err
:= Dial("tcp", JoinHostPort("", port
))
75 func TestDialTimeoutFDLeak(t
*testing
.T
) {
78 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
80 testenv
.SkipFlaky(t
, 15157)
83 const T
= 100 * time
.Millisecond
86 case "plan9", "windows":
87 origTestHookDialChannel
:= testHookDialChannel
88 testHookDialChannel
= func() { time
.Sleep(2 * T
) }
89 defer func() { testHookDialChannel
= origTestHookDialChannel
}()
90 if runtime
.GOOS
== "plan9" {
95 sw
.Set(socktest
.FilterConnect
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
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
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) }()
110 sw
.Set(socktest
.FilterClose
, func(so
*socktest
.Status
) (socktest
.AfterFilter
, error
) {
118 var wg sync
.WaitGroup
120 for i
:= 0; i
< N
; i
++ {
123 // This dial never starts to send any SYN
124 // segment because of above socket filter and
126 c
, err
:= DialTimeout("tcp", "127.0.0.1:0", T
)
128 t
.Errorf("unexpectedly established: tcp:%s->%s", c
.LocalAddr(), c
.RemoteAddr())
135 t
.Errorf("got %d; want >= %d", attempts
, N
)
139 func TestDialerDualStackFDLeak(t
*testing
.T
) {
140 switch runtime
.GOOS
{
142 t
.Skipf("%s does not have full support of socktest", runtime
.GOOS
)
144 t
.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime
.GOOS
)
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
) {
163 c
, err
:= ln
.Accept()
170 dss
, err
:= newDualStackServer()
174 if err
:= dss
.buildup(handler
); err
!= nil {
180 var wg sync
.WaitGroup
182 d
:= &Dialer
{DualStack
: true, Timeout
: 100*time
.Millisecond
+ closedPortDelay
}
183 for i
:= 0; i
< N
; i
++ {
186 c
, err
:= d
.Dial("tcp", JoinHostPort("localhost", dss
.port
))
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.
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.
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
229 expected
= 95 * time
.Millisecond
232 l
, err
:= Listen("tcp", "127.0.0.1:0")
234 return 999 * time
.Hour
, expected
236 addr
:= l
.Addr().String()
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.
242 startTime
:= time
.Now()
243 c
, err
:= Dial("tcp", addr
)
247 elapsed
:= time
.Now().Sub(startTime
)
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
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
++ {
291 var testCases
= []struct {
294 teardownNetwork
string
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
) {
323 c
, err
:= ln
.Accept()
331 // Convert a list of IP strings into TCPAddrs.
332 makeAddrs
:= func(ips
[]string, port
string) addrList
{
334 for _
, ip
:= range ips
{
335 addr
, err
:= ResolveTCPAddr("tcp", JoinHostPort(ip
, port
))
339 out
= append(out
, addr
)
344 for i
, tt
:= range testCases
{
345 dss
, err
:= newDualStackServer()
350 if err
:= dss
.buildup(handler
); err
!= nil {
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
)
361 FallbackDelay
: fallbackDelay
,
363 startTime
:= time
.Now()
369 c
, err
:= dialParallel(context
.Background(), dp
, primaries
, fallbacks
)
370 elapsed
:= time
.Since(startTime
)
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
395 time
.Sleep(5 * time
.Millisecond
)
399 startTime
= time
.Now()
400 c
, err
= dialParallel(ctx
, dp
, primaries
, fallbacks
)
404 elapsed
= time
.Now().Sub(startTime
)
405 if elapsed
> 100*time
.Millisecond
{
406 t
.Errorf("#%d (cancel): got %v; want <= 100ms", i
, elapsed
)
412 func lookupSlowFast(ctx context
.Context
, fn
func(context
.Context
, string) ([]IPAddr
, error
), host
string) ([]IPAddr
, error
) {
414 case "slow6loopback4":
415 // Returns a slow IPv6 address, and a local IPv4 address.
417 {IP
: ParseIP(slowDst6
)},
418 {IP
: ParseIP("127.0.0.1")},
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 {
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
) {
455 c
, err
:= ln
.Accept()
462 dss
, err
:= newDualStackServer()
467 if err
:= dss
.buildup(handler
); err
!= nil {
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
)
479 } else if tt
.dualstack
{
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
500 handler
:= func(dss
*dualStackServer
, ln Listener
) {
501 // Accept one connection per address.
502 c
, err
:= ln
.Accept()
506 // The client should close itself, without sending data.
507 c
.SetReadDeadline(time
.Now().Add(1 * time
.Second
))
509 if _
, err
:= c
.Read(b
[:]); err
!= io
.EOF
{
510 t
.Errorf("got %v; want %v", err
, io
.EOF
)
515 dss
, err
:= newDualStackServer()
520 if err
:= dss
.buildup(handler
); err
!= nil {
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
)
540 FallbackDelay
: fallbackDelay
,
548 makeAddr
:= func(ip
string) addrList
{
549 addr
, err
:= ResolveTCPAddr("tcp", JoinHostPort(ip
, dss
.port
))
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"))
563 // The server should've seen both connections.
567 func TestDialerPartialDeadline(t
*testing
.T
) {
568 now
:= time
.Date(2000, time
.January
, 1, 0, 0, 0, 0, time
.UTC
)
569 var testCases
= []struct {
573 expectDeadline time
.Time
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},
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")
608 network
, raddr
string
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"}},
658 tests
= append(tests
, test
{
659 "tcp", "127.0.0.1", &TCPAddr
{IP
: ParseIP("::")}, nil,
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
) {
672 c
, err
:= ln
.Accept()
680 var lss
[2]*localServer
681 for i
, network
:= range []string{"tcp4", "tcp6"} {
682 lss
[i
], err
= newLocalServer(network
)
686 defer lss
[i
].teardown()
687 if err
:= lss
[i
].buildup(handler
); err
!= nil {
692 for _
, tt
:= range tests
{
693 d
:= &Dialer
{LocalAddr
: tt
.laddr
}
695 ip
:= ParseIP(tt
.raddr
)
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
)
707 if perr
:= parseDialError(err
); perr
!= nil {
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
) {
736 c
, err
:= ln
.Accept()
744 var timeout
= 150*time
.Millisecond
+ closedPortDelay
745 for _
, dualstack
:= range []bool{false, true} {
746 dss
, err
:= newDualStackServer()
751 if err
:= dss
.buildup(handler
); err
!= nil {
755 d
:= &Dialer
{DualStack
: dualstack
, Timeout
: timeout
}
757 c
, err
:= d
.Dial("tcp", JoinHostPort("localhost", dss
.port
))
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")
773 func TestDialerKeepAlive(t
*testing
.T
) {
774 handler
:= func(ls
*localServer
, ln Listener
) {
776 c
, err
:= ln
.Accept()
783 ls
, err
:= newLocalServer("tcp")
788 if err
:= ls
.buildup(handler
); err
!= nil {
791 defer func() { testHookSetKeepAlive
= func() {} }()
793 for _
, keepAlive
:= range []bool{false, true} {
795 testHookSetKeepAlive
= func() { got
= true }
798 d
.KeepAlive
= 30 * time
.Second
800 c
, err
:= d
.Dial("tcp", ls
.Listener
.Addr().String())
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")
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")
826 blackholeIPPort
= JoinHostPort(slowDst6
, "1234")
829 ticker
:= time
.NewTicker(10 * time
.Millisecond
)
832 const cancelTick
= 5 // the timer tick we cancel the dial at
833 const timeoutTick
= 100
836 cancel
:= make(chan struct{})
838 errc
:= make(chan error
, 1)
839 connc
:= make(chan Conn
, 1)
841 if c
, err
:= d
.Dial("tcp", blackholeIPPort
); err
!= nil {
852 if ticks
== cancelTick
{
855 if ticks
== timeoutTick
{
856 t
.Fatal("timeout waiting for dial to fail")
860 t
.Fatal("unexpected successful connection")
862 if perr
:= parseDialError(err
); perr
!= nil {
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
)
877 func TestCancelAfterDial(t
*testing
.T
) {
879 t
.Skip("avoiding time.Sleep")
882 ln
, err
:= newLocalListener("tcp")
887 var wg sync
.WaitGroup
894 // Echo back the first line of each incoming connection.
897 c
, err
:= ln
.Accept()
901 rb
:= bufio
.NewReader(c
)
902 line
, err
:= rb
.ReadString('\n')
908 if _
, err
:= c
.Write([]byte(line
)); err
!= nil {
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.
925 time
.Sleep(10 * time
.Millisecond
)
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 {
938 // The server should echo the line, and close the connection.
939 rb
:= bufio
.NewReader(c
)
940 line
, err
:= rb
.ReadString('\n')
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
++ {