Source file
src/net/dial_test.go
1
2
3
4
5 package net
6
7 import (
8 "bufio"
9 "context"
10 "errors"
11 "fmt"
12 "internal/testenv"
13 "io"
14 "net/netip"
15 "os"
16 "runtime"
17 "strings"
18 "sync"
19 "syscall"
20 "testing"
21 "time"
22 )
23
24 var prohibitionaryDialArgTests = []struct {
25 network string
26 address string
27 }{
28 {"tcp6", "127.0.0.1"},
29 {"tcp6", "::ffff:127.0.0.1"},
30 }
31
32 func TestProhibitionaryDialArg(t *testing.T) {
33 testenv.MustHaveExternalNetwork(t)
34
35 switch runtime.GOOS {
36 case "plan9":
37 t.Skipf("not supported on %s", runtime.GOOS)
38 }
39 if !supportsIPv4map() {
40 t.Skip("mapping ipv4 address inside ipv6 address not supported")
41 }
42
43 ln, err := Listen("tcp", "[::]:0")
44 if err != nil {
45 t.Fatal(err)
46 }
47 defer ln.Close()
48
49 _, port, err := SplitHostPort(ln.Addr().String())
50 if err != nil {
51 t.Fatal(err)
52 }
53
54 for i, tt := range prohibitionaryDialArgTests {
55 c, err := Dial(tt.network, JoinHostPort(tt.address, port))
56 if err == nil {
57 c.Close()
58 t.Errorf("#%d: %v", i, err)
59 }
60 }
61 }
62
63 func TestDialLocal(t *testing.T) {
64 ln := newLocalListener(t, "tcp")
65 defer ln.Close()
66 _, port, err := SplitHostPort(ln.Addr().String())
67 if err != nil {
68 t.Fatal(err)
69 }
70 c, err := Dial("tcp", JoinHostPort("", port))
71 if err != nil {
72 t.Fatal(err)
73 }
74 c.Close()
75 }
76
77 func TestDialerDualStackFDLeak(t *testing.T) {
78 switch runtime.GOOS {
79 case "plan9":
80 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
81 case "windows":
82 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
83 case "openbsd":
84 testenv.SkipFlaky(t, 15157)
85 }
86 if !supportsIPv4() || !supportsIPv6() {
87 t.Skip("both IPv4 and IPv6 are required")
88 }
89
90 before := sw.Sockets()
91 origTestHookLookupIP := testHookLookupIP
92 defer func() { testHookLookupIP = origTestHookLookupIP }()
93 testHookLookupIP = lookupLocalhost
94 handler := func(dss *dualStackServer, ln Listener) {
95 for {
96 c, err := ln.Accept()
97 if err != nil {
98 return
99 }
100 c.Close()
101 }
102 }
103 dss, err := newDualStackServer()
104 if err != nil {
105 t.Fatal(err)
106 }
107 if err := dss.buildup(handler); err != nil {
108 dss.teardown()
109 t.Fatal(err)
110 }
111
112 const N = 10
113 var wg sync.WaitGroup
114 wg.Add(N)
115 d := &Dialer{DualStack: true, Timeout: 5 * time.Second}
116 for i := 0; i < N; i++ {
117 go func() {
118 defer wg.Done()
119 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
120 if err != nil {
121 t.Error(err)
122 return
123 }
124 c.Close()
125 }()
126 }
127 wg.Wait()
128 dss.teardown()
129 after := sw.Sockets()
130 if len(after) != len(before) {
131 t.Errorf("got %d; want %d", len(after), len(before))
132 }
133 }
134
135
136
137
138 const (
139 slowDst4 = "198.18.0.254"
140 slowDst6 = "2001:2::254"
141 )
142
143
144
145
146 func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
147 sd := &sysDialer{network: network, address: raddr.String()}
148 c, err := sd.doDialTCP(ctx, laddr, raddr)
149 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
150
151 <-ctx.Done()
152 }
153 return c, err
154 }
155
156 func dialClosedPort(t *testing.T) (dialLatency time.Duration) {
157
158
159
160
161
162 l, err := Listen("tcp", "127.0.0.1:0")
163 if err != nil {
164 t.Fatalf("dialClosedPort: Listen failed: %v", err)
165 }
166 addr := l.Addr().String()
167 l.Close()
168
169 startTime := time.Now()
170 c, err := Dial("tcp", addr)
171 if err == nil {
172 c.Close()
173 }
174 elapsed := time.Since(startTime)
175 t.Logf("dialClosedPort: measured delay %v", elapsed)
176 return elapsed
177 }
178
179 func TestDialParallel(t *testing.T) {
180 const instant time.Duration = 0
181 const fallbackDelay = 200 * time.Millisecond
182
183 nCopies := func(s string, n int) []string {
184 out := make([]string, n)
185 for i := 0; i < n; i++ {
186 out[i] = s
187 }
188 return out
189 }
190
191 var testCases = []struct {
192 primaries []string
193 fallbacks []string
194 teardownNetwork string
195 expectOk bool
196 expectElapsed time.Duration
197 }{
198
199 {[]string{"127.0.0.1"}, []string{}, "", true, instant},
200 {[]string{"::1"}, []string{}, "", true, instant},
201 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
202 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
203
204 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
205
206 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, instant},
207 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, instant},
208
209 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay},
210
211 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, instant},
212 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, instant},
213
214 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, instant},
215
216 {[]string{}, []string{}, "", false, instant},
217
218 {nCopies("::1", 1000), []string{}, "", true, instant},
219 }
220
221
222 makeAddrs := func(ips []string, port string) addrList {
223 var out addrList
224 for _, ip := range ips {
225 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
226 if err != nil {
227 t.Fatal(err)
228 }
229 out = append(out, addr)
230 }
231 return out
232 }
233
234 for i, tt := range testCases {
235 t.Run(fmt.Sprint(i), func(t *testing.T) {
236 dialTCP := func(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
237 n := "tcp6"
238 if raddr.IP.To4() != nil {
239 n = "tcp4"
240 }
241 if n == tt.teardownNetwork {
242 return nil, errors.New("unreachable")
243 }
244 if r := raddr.IP.String(); r == slowDst4 || r == slowDst6 {
245 <-ctx.Done()
246 return nil, ctx.Err()
247 }
248 return &TCPConn{}, nil
249 }
250
251 primaries := makeAddrs(tt.primaries, "80")
252 fallbacks := makeAddrs(tt.fallbacks, "80")
253 d := Dialer{
254 FallbackDelay: fallbackDelay,
255 }
256 const forever = 60 * time.Minute
257 if tt.expectElapsed == instant {
258 d.FallbackDelay = forever
259 }
260 startTime := time.Now()
261 sd := &sysDialer{
262 Dialer: d,
263 network: "tcp",
264 address: "?",
265 testHookDialTCP: dialTCP,
266 }
267 c, err := sd.dialParallel(context.Background(), primaries, fallbacks)
268 elapsed := time.Since(startTime)
269
270 if c != nil {
271 c.Close()
272 }
273
274 if tt.expectOk && err != nil {
275 t.Errorf("#%d: got %v; want nil", i, err)
276 } else if !tt.expectOk && err == nil {
277 t.Errorf("#%d: got nil; want non-nil", i)
278 }
279
280 if elapsed < tt.expectElapsed || elapsed >= forever {
281 t.Errorf("#%d: got %v; want >= %v, < forever", i, elapsed, tt.expectElapsed)
282 }
283
284
285 ctx, cancel := context.WithCancel(context.Background())
286 var wg sync.WaitGroup
287 wg.Add(1)
288 go func() {
289 time.Sleep(5 * time.Millisecond)
290 cancel()
291 wg.Done()
292 }()
293
294
295 c, _ = sd.dialParallel(ctx, primaries, fallbacks)
296 if c != nil {
297 c.Close()
298 }
299 wg.Wait()
300 })
301 }
302 }
303
304 func lookupSlowFast(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
305 switch host {
306 case "slow6loopback4":
307
308 return []IPAddr{
309 {IP: ParseIP(slowDst6)},
310 {IP: ParseIP("127.0.0.1")},
311 }, nil
312 default:
313 return fn(ctx, network, host)
314 }
315 }
316
317 func TestDialerFallbackDelay(t *testing.T) {
318 testenv.MustHaveExternalNetwork(t)
319
320 if !supportsIPv4() || !supportsIPv6() {
321 t.Skip("both IPv4 and IPv6 are required")
322 }
323
324 origTestHookLookupIP := testHookLookupIP
325 defer func() { testHookLookupIP = origTestHookLookupIP }()
326 testHookLookupIP = lookupSlowFast
327
328 origTestHookDialTCP := testHookDialTCP
329 defer func() { testHookDialTCP = origTestHookDialTCP }()
330 testHookDialTCP = slowDialTCP
331
332 var testCases = []struct {
333 dualstack bool
334 delay time.Duration
335 expectElapsed time.Duration
336 }{
337
338 {true, 1 * time.Nanosecond, 0},
339
340 {true, 200 * time.Millisecond, 200 * time.Millisecond},
341
342 {true, 0, 300 * time.Millisecond},
343 }
344
345 handler := func(dss *dualStackServer, ln Listener) {
346 for {
347 c, err := ln.Accept()
348 if err != nil {
349 return
350 }
351 c.Close()
352 }
353 }
354 dss, err := newDualStackServer()
355 if err != nil {
356 t.Fatal(err)
357 }
358 defer dss.teardown()
359 if err := dss.buildup(handler); err != nil {
360 t.Fatal(err)
361 }
362
363 for i, tt := range testCases {
364 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
365
366 startTime := time.Now()
367 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
368 elapsed := time.Since(startTime)
369 if err == nil {
370 c.Close()
371 } else if tt.dualstack {
372 t.Error(err)
373 }
374 expectMin := tt.expectElapsed - 1*time.Millisecond
375 expectMax := tt.expectElapsed + 95*time.Millisecond
376 if elapsed < expectMin {
377 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
378 }
379 if elapsed > expectMax {
380 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
381 }
382 }
383 }
384
385 func TestDialParallelSpuriousConnection(t *testing.T) {
386 if !supportsIPv4() || !supportsIPv6() {
387 t.Skip("both IPv4 and IPv6 are required")
388 }
389
390 var readDeadline time.Time
391 if td, ok := t.Deadline(); ok {
392 const arbitraryCleanupMargin = 1 * time.Second
393 readDeadline = td.Add(-arbitraryCleanupMargin)
394 } else {
395 readDeadline = time.Now().Add(5 * time.Second)
396 }
397
398 var closed sync.WaitGroup
399 closed.Add(2)
400 handler := func(dss *dualStackServer, ln Listener) {
401
402 c, err := ln.Accept()
403 if err != nil {
404 t.Fatal(err)
405 }
406
407
408
409
410
411
412
413 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
414 time.Sleep(10 * time.Millisecond)
415 }
416
417
418 c.SetReadDeadline(readDeadline)
419 var b [1]byte
420 if _, err := c.Read(b[:]); err != io.EOF {
421 t.Errorf("got %v; want %v", err, io.EOF)
422 }
423 c.Close()
424 closed.Done()
425 }
426 dss, err := newDualStackServer()
427 if err != nil {
428 t.Fatal(err)
429 }
430 defer dss.teardown()
431 if err := dss.buildup(handler); err != nil {
432 t.Fatal(err)
433 }
434
435 const fallbackDelay = 100 * time.Millisecond
436
437 var dialing sync.WaitGroup
438 dialing.Add(2)
439 origTestHookDialTCP := testHookDialTCP
440 defer func() { testHookDialTCP = origTestHookDialTCP }()
441 testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
442
443
444
445 dialing.Done()
446 dialing.Wait()
447
448
449
450
451 sd := &sysDialer{network: net, address: raddr.String()}
452 return sd.doDialTCP(context.Background(), laddr, raddr)
453 }
454
455 d := Dialer{
456 FallbackDelay: fallbackDelay,
457 }
458 sd := &sysDialer{
459 Dialer: d,
460 network: "tcp",
461 address: "?",
462 }
463
464 makeAddr := func(ip string) addrList {
465 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
466 if err != nil {
467 t.Fatal(err)
468 }
469 return addrList{addr}
470 }
471
472
473 c, err := sd.dialParallel(context.Background(), makeAddr("127.0.0.1"), makeAddr("::1"))
474 if err != nil {
475 t.Fatal(err)
476 }
477 c.Close()
478
479
480 closed.Wait()
481 }
482
483 func TestDialerPartialDeadline(t *testing.T) {
484 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
485 var testCases = []struct {
486 now time.Time
487 deadline time.Time
488 addrs int
489 expectDeadline time.Time
490 expectErr error
491 }{
492
493 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
494 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
495 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
496
497 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
498
499 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
500
501 {now, noDeadline, 1, noDeadline, nil},
502
503 {now.Add(-1 * time.Millisecond), now, 1, now, nil},
504 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
505 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
506 }
507 for i, tt := range testCases {
508 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
509 if err != tt.expectErr {
510 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
511 }
512 if !deadline.Equal(tt.expectDeadline) {
513 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
514 }
515 }
516 }
517
518
519 var isEADDRINUSE = func(err error) bool { return false }
520
521 func TestDialerLocalAddr(t *testing.T) {
522 if !supportsIPv4() || !supportsIPv6() {
523 t.Skip("both IPv4 and IPv6 are required")
524 }
525
526 type test struct {
527 network, raddr string
528 laddr Addr
529 error
530 }
531 var tests = []test{
532 {"tcp4", "127.0.0.1", nil, nil},
533 {"tcp4", "127.0.0.1", &TCPAddr{}, nil},
534 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
535 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
536 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
537 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
538 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
539 {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
540 {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
541 {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
542
543 {"tcp6", "::1", nil, nil},
544 {"tcp6", "::1", &TCPAddr{}, nil},
545 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
546 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
547 {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
548 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
549 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
550 {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
551 {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
552 {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
553
554 {"tcp", "127.0.0.1", nil, nil},
555 {"tcp", "127.0.0.1", &TCPAddr{}, nil},
556 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
557 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
558 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
559 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
560 {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
561 {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
562 {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
563
564 {"tcp", "::1", nil, nil},
565 {"tcp", "::1", &TCPAddr{}, nil},
566 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
567 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
568 {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
569 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
570 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
571 {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
572 {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
573 {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
574 }
575
576 issue34264Index := -1
577 if supportsIPv4map() {
578 issue34264Index = len(tests)
579 tests = append(tests, test{
580 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
581 })
582 } else {
583 tests = append(tests, test{
584 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
585 })
586 }
587
588 origTestHookLookupIP := testHookLookupIP
589 defer func() { testHookLookupIP = origTestHookLookupIP }()
590 testHookLookupIP = lookupLocalhost
591 handler := func(ls *localServer, ln Listener) {
592 for {
593 c, err := ln.Accept()
594 if err != nil {
595 return
596 }
597 c.Close()
598 }
599 }
600 var lss [2]*localServer
601 for i, network := range []string{"tcp4", "tcp6"} {
602 lss[i] = newLocalServer(t, network)
603 defer lss[i].teardown()
604 if err := lss[i].buildup(handler); err != nil {
605 t.Fatal(err)
606 }
607 }
608
609 for i, tt := range tests {
610 d := &Dialer{LocalAddr: tt.laddr}
611 var addr string
612 ip := ParseIP(tt.raddr)
613 if ip.To4() != nil {
614 addr = lss[0].Listener.Addr().String()
615 }
616 if ip.To16() != nil && ip.To4() == nil {
617 addr = lss[1].Listener.Addr().String()
618 }
619 c, err := d.Dial(tt.network, addr)
620 if err == nil && tt.error != nil || err != nil && tt.error == nil {
621 if i == issue34264Index && runtime.GOOS == "freebsd" && isEADDRINUSE(err) {
622
623
624
625 t.Logf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
626 t.Logf("(spurious EADDRINUSE ignored on freebsd: see https://golang.org/issue/34264)")
627 } else {
628 t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
629 }
630 }
631 if err != nil {
632 if perr := parseDialError(err); perr != nil {
633 t.Error(perr)
634 }
635 continue
636 }
637 c.Close()
638 }
639 }
640
641 func TestDialerDualStack(t *testing.T) {
642 testenv.SkipFlaky(t, 13324)
643
644 if !supportsIPv4() || !supportsIPv6() {
645 t.Skip("both IPv4 and IPv6 are required")
646 }
647
648 closedPortDelay := dialClosedPort(t)
649
650 origTestHookLookupIP := testHookLookupIP
651 defer func() { testHookLookupIP = origTestHookLookupIP }()
652 testHookLookupIP = lookupLocalhost
653 handler := func(dss *dualStackServer, ln Listener) {
654 for {
655 c, err := ln.Accept()
656 if err != nil {
657 return
658 }
659 c.Close()
660 }
661 }
662
663 var timeout = 150*time.Millisecond + closedPortDelay
664 for _, dualstack := range []bool{false, true} {
665 dss, err := newDualStackServer()
666 if err != nil {
667 t.Fatal(err)
668 }
669 defer dss.teardown()
670 if err := dss.buildup(handler); err != nil {
671 t.Fatal(err)
672 }
673
674 d := &Dialer{DualStack: dualstack, Timeout: timeout}
675 for range dss.lns {
676 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
677 if err != nil {
678 t.Error(err)
679 continue
680 }
681 switch addr := c.LocalAddr().(*TCPAddr); {
682 case addr.IP.To4() != nil:
683 dss.teardownNetwork("tcp4")
684 case addr.IP.To16() != nil && addr.IP.To4() == nil:
685 dss.teardownNetwork("tcp6")
686 }
687 c.Close()
688 }
689 }
690 }
691
692 func TestDialerKeepAlive(t *testing.T) {
693 t.Cleanup(func() {
694 testHookSetKeepAlive = func(KeepAliveConfig) {}
695 })
696
697 handler := func(ls *localServer, ln Listener) {
698 for {
699 c, err := ln.Accept()
700 if err != nil {
701 return
702 }
703 c.Close()
704 }
705 }
706 ln := newLocalListener(t, "tcp", &ListenConfig{
707 KeepAlive: -1,
708 })
709 ls := (&streamListener{Listener: ln}).newLocalServer()
710 defer ls.teardown()
711 if err := ls.buildup(handler); err != nil {
712 t.Fatal(err)
713 }
714
715 tests := []struct {
716 ka time.Duration
717 expected time.Duration
718 }{
719 {-1, -1},
720 {0, 0},
721 {5 * time.Second, 5 * time.Second},
722 {30 * time.Second, 30 * time.Second},
723 }
724
725 var got time.Duration = -1
726 testHookSetKeepAlive = func(cfg KeepAliveConfig) { got = cfg.Idle }
727
728 for _, test := range tests {
729 got = -1
730 d := Dialer{KeepAlive: test.ka}
731 c, err := d.Dial("tcp", ls.Listener.Addr().String())
732 if err != nil {
733 t.Fatal(err)
734 }
735 c.Close()
736 if got != test.expected {
737 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected)
738 }
739 }
740 }
741
742 func TestDialCancel(t *testing.T) {
743 mustHaveExternalNetwork(t)
744
745 blackholeIPPort := JoinHostPort(slowDst4, "1234")
746 if !supportsIPv4() {
747 blackholeIPPort = JoinHostPort(slowDst6, "1234")
748 }
749
750 ticker := time.NewTicker(10 * time.Millisecond)
751 defer ticker.Stop()
752
753 const cancelTick = 5
754 const timeoutTick = 100
755
756 var d Dialer
757 cancel := make(chan struct{})
758 d.Cancel = cancel
759 errc := make(chan error, 1)
760 connc := make(chan Conn, 1)
761 go func() {
762 if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
763 errc <- err
764 } else {
765 connc <- c
766 }
767 }()
768 ticks := 0
769 for {
770 select {
771 case <-ticker.C:
772 ticks++
773 if ticks == cancelTick {
774 close(cancel)
775 }
776 if ticks == timeoutTick {
777 t.Fatal("timeout waiting for dial to fail")
778 }
779 case c := <-connc:
780 c.Close()
781 t.Fatal("unexpected successful connection")
782 case err := <-errc:
783 if perr := parseDialError(err); perr != nil {
784 t.Error(perr)
785 }
786 if ticks < cancelTick {
787
788
789 ignorable := []string{
790 "connection refused",
791 "unreachable",
792 "no route to host",
793 "invalid argument",
794 }
795 e := err.Error()
796 for _, ignore := range ignorable {
797 if strings.Contains(e, ignore) {
798 t.Skipf("connection to %v failed fast with %v", blackholeIPPort, err)
799 }
800 }
801
802 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
803 ticks, cancelTick-ticks, err)
804 }
805 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
806 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
807 }
808 return
809 }
810 }
811 }
812
813 func TestCancelAfterDial(t *testing.T) {
814 if testing.Short() {
815 t.Skip("avoiding time.Sleep")
816 }
817
818 ln := newLocalListener(t, "tcp")
819
820 var wg sync.WaitGroup
821 wg.Add(1)
822 defer func() {
823 ln.Close()
824 wg.Wait()
825 }()
826
827
828 go func() {
829 for {
830 c, err := ln.Accept()
831 if err != nil {
832 break
833 }
834 rb := bufio.NewReader(c)
835 line, err := rb.ReadString('\n')
836 if err != nil {
837 t.Error(err)
838 c.Close()
839 continue
840 }
841 if _, err := c.Write([]byte(line)); err != nil {
842 t.Error(err)
843 }
844 c.Close()
845 }
846 wg.Done()
847 }()
848
849 try := func() {
850 cancel := make(chan struct{})
851 d := &Dialer{Cancel: cancel}
852 c, err := d.Dial("tcp", ln.Addr().String())
853
854
855
856
857 close(cancel)
858 time.Sleep(10 * time.Millisecond)
859
860 if err != nil {
861 t.Fatal(err)
862 }
863 defer c.Close()
864
865
866 const message = "echo!\n"
867 if _, err := c.Write([]byte(message)); err != nil {
868 t.Fatal(err)
869 }
870
871
872 rb := bufio.NewReader(c)
873 line, err := rb.ReadString('\n')
874 if err != nil {
875 t.Fatal(err)
876 }
877 if line != message {
878 t.Errorf("got %q; want %q", line, message)
879 }
880 if _, err := rb.ReadByte(); err != io.EOF {
881 t.Errorf("got %v; want %v", err, io.EOF)
882 }
883 }
884
885
886 for i := 0; i < 10; i++ {
887 try()
888 }
889 }
890
891 func TestDialClosedPortFailFast(t *testing.T) {
892 if runtime.GOOS != "windows" {
893
894 t.Skip("skipping windows only test")
895 }
896 for _, network := range []string{"tcp", "tcp4", "tcp6"} {
897 t.Run(network, func(t *testing.T) {
898 if !testableNetwork(network) {
899 t.Skipf("skipping: can't listen on %s", network)
900 }
901
902
903
904 ln := newLocalListener(t, network)
905 addr := ln.Addr().String()
906 conn1, err := Dial(network, addr)
907 if err != nil {
908 ln.Close()
909 t.Fatal(err)
910 }
911 defer conn1.Close()
912
913
914
915 ln.Close()
916
917 maxElapsed := time.Second
918
919
920
921
922 for {
923 startTime := time.Now()
924 conn2, err := Dial(network, addr)
925 if err == nil {
926 conn2.Close()
927 t.Fatal("error expected")
928 }
929 elapsed := time.Since(startTime)
930 if elapsed < maxElapsed {
931 break
932 }
933 t.Logf("got %v; want < %v", elapsed, maxElapsed)
934 }
935 })
936 }
937 }
938
939
940
941
942
943 func TestDialListenerAddr(t *testing.T) {
944 if !testableNetwork("tcp4") {
945 t.Skipf("skipping: can't listen on tcp4")
946 }
947
948
949
950
951
952
953
954
955
956
957
958 ln, err := Listen("tcp4", "localhost:0")
959 if err != nil {
960 t.Fatal(err)
961 }
962 defer ln.Close()
963
964 t.Logf("listening on %q", ln.Addr())
965 _, port, err := SplitHostPort(ln.Addr().String())
966 if err != nil {
967 t.Fatal(err)
968 }
969
970
971
972
973
974
975
976
977
978
979 dialAddr := "[::]:" + port
980 c, err := Dial("tcp4", dialAddr)
981 if err != nil {
982 t.Fatalf(`Dial("tcp4", %q): %v`, dialAddr, err)
983 }
984 c.Close()
985 t.Logf(`Dial("tcp4", %q) succeeded`, dialAddr)
986 }
987
988 func TestDialerControl(t *testing.T) {
989 switch runtime.GOOS {
990 case "plan9":
991 t.Skipf("not supported on %s", runtime.GOOS)
992 case "js", "wasip1":
993 t.Skipf("skipping: fake net does not support Dialer.Control")
994 }
995
996 t.Run("StreamDial", func(t *testing.T) {
997 for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
998 if !testableNetwork(network) {
999 continue
1000 }
1001 ln := newLocalListener(t, network)
1002 defer ln.Close()
1003 d := Dialer{Control: controlOnConnSetup}
1004 c, err := d.Dial(network, ln.Addr().String())
1005 if err != nil {
1006 t.Error(err)
1007 continue
1008 }
1009 c.Close()
1010 }
1011 })
1012 t.Run("PacketDial", func(t *testing.T) {
1013 for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} {
1014 if !testableNetwork(network) {
1015 continue
1016 }
1017 c1 := newLocalPacketListener(t, network)
1018 if network == "unixgram" {
1019 defer os.Remove(c1.LocalAddr().String())
1020 }
1021 defer c1.Close()
1022 d := Dialer{Control: controlOnConnSetup}
1023 c2, err := d.Dial(network, c1.LocalAddr().String())
1024 if err != nil {
1025 t.Error(err)
1026 continue
1027 }
1028 c2.Close()
1029 }
1030 })
1031 }
1032
1033 func TestDialerControlContext(t *testing.T) {
1034 switch runtime.GOOS {
1035 case "plan9":
1036 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
1037 case "js", "wasip1":
1038 t.Skipf("skipping: fake net does not support Dialer.ControlContext")
1039 }
1040 t.Run("StreamDial", func(t *testing.T) {
1041 for i, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
1042 t.Run(network, func(t *testing.T) {
1043 if !testableNetwork(network) {
1044 t.Skipf("skipping: %s not available", network)
1045 }
1046
1047 ln := newLocalListener(t, network)
1048 defer ln.Close()
1049 var id int
1050 d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error {
1051 id = ctx.Value("id").(int)
1052 return controlOnConnSetup(network, address, c)
1053 }}
1054 c, err := d.DialContext(context.WithValue(context.Background(), "id", i+1), network, ln.Addr().String())
1055 if err != nil {
1056 t.Fatal(err)
1057 }
1058 if id != i+1 {
1059 t.Errorf("got id %d, want %d", id, i+1)
1060 }
1061 c.Close()
1062 })
1063 }
1064 })
1065 }
1066
1067 func TestDialContext(t *testing.T) {
1068 switch runtime.GOOS {
1069 case "plan9":
1070 t.Skipf("not supported on %s", runtime.GOOS)
1071 case "js", "wasip1":
1072 t.Skipf("skipping: fake net does not support Dialer.ControlContext")
1073 }
1074
1075 t.Run("StreamDial", func(t *testing.T) {
1076 var err error
1077 for i, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
1078 if !testableNetwork(network) {
1079 continue
1080 }
1081 ln := newLocalListener(t, network)
1082 defer ln.Close()
1083 var id int
1084 d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error {
1085 id = ctx.Value("id").(int)
1086 return controlOnConnSetup(network, address, c)
1087 }}
1088 var c Conn
1089 switch network {
1090 case "tcp", "tcp4", "tcp6":
1091 raddr, err := netip.ParseAddrPort(ln.Addr().String())
1092 if err != nil {
1093 t.Error(err)
1094 continue
1095 }
1096 c, err = d.DialTCP(context.WithValue(context.Background(), "id", i+1), network, (*TCPAddr)(nil).AddrPort(), raddr)
1097 case "unix", "unixpacket":
1098 raddr, err := ResolveUnixAddr(network, ln.Addr().String())
1099 if err != nil {
1100 t.Error(err)
1101 continue
1102 }
1103 c, err = d.DialUnix(context.WithValue(context.Background(), "id", i+1), network, nil, raddr)
1104 }
1105 if err != nil {
1106 t.Error(err)
1107 continue
1108 }
1109 if id != i+1 {
1110 t.Errorf("%s: got id %d, want %d", network, id, i+1)
1111 }
1112 c.Close()
1113 }
1114 })
1115 t.Run("PacketDial", func(t *testing.T) {
1116 var err error
1117 for i, network := range []string{"udp", "udp4", "udp6", "unixgram"} {
1118 if !testableNetwork(network) {
1119 continue
1120 }
1121 c1 := newLocalPacketListener(t, network)
1122 if network == "unixgram" {
1123 defer os.Remove(c1.LocalAddr().String())
1124 }
1125 defer c1.Close()
1126 var id int
1127 d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error {
1128 id = ctx.Value("id").(int)
1129 return controlOnConnSetup(network, address, c)
1130 }}
1131 var c2 Conn
1132 switch network {
1133 case "udp", "udp4", "udp6":
1134 raddr, err := netip.ParseAddrPort(c1.LocalAddr().String())
1135 if err != nil {
1136 t.Error(err)
1137 continue
1138 }
1139 c2, err = d.DialUDP(context.WithValue(context.Background(), "id", i+1), network, (*UDPAddr)(nil).AddrPort(), raddr)
1140 case "unixgram":
1141 raddr, err := ResolveUnixAddr(network, c1.LocalAddr().String())
1142 if err != nil {
1143 t.Error(err)
1144 continue
1145 }
1146 c2, err = d.DialUnix(context.WithValue(context.Background(), "id", i+1), network, nil, raddr)
1147 }
1148 if err != nil {
1149 t.Error(err)
1150 continue
1151 }
1152 if id != i+1 {
1153 t.Errorf("%s: got id %d, want %d", network, id, i+1)
1154 }
1155 c2.Close()
1156 }
1157 })
1158 }
1159
1160
1161
1162
1163 func mustHaveExternalNetwork(t *testing.T) {
1164 t.Helper()
1165 definitelyHasLongtestBuilder := runtime.GOOS == "linux"
1166 mobile := runtime.GOOS == "android" || runtime.GOOS == "ios"
1167 fake := runtime.GOOS == "js" || runtime.GOOS == "wasip1"
1168 if testenv.Builder() != "" && !definitelyHasLongtestBuilder && !mobile && !fake {
1169
1170
1171
1172
1173 return
1174 }
1175 testenv.MustHaveExternalNetwork(t)
1176 }
1177
1178 type contextWithNonZeroDeadline struct {
1179 context.Context
1180 }
1181
1182 func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) {
1183
1184 return time.Unix(0, 0), false
1185 }
1186
1187 func TestDialWithNonZeroDeadline(t *testing.T) {
1188 ln := newLocalListener(t, "tcp")
1189 defer ln.Close()
1190 _, port, err := SplitHostPort(ln.Addr().String())
1191 if err != nil {
1192 t.Fatal(err)
1193 }
1194
1195 ctx := contextWithNonZeroDeadline{Context: context.Background()}
1196 var dialer Dialer
1197 c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port))
1198 if err != nil {
1199 t.Fatal(err)
1200 }
1201 c.Close()
1202 }
1203
View as plain text