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 "os"
15 "runtime"
16 "strings"
17 "sync"
18 "syscall"
19 "testing"
20 "time"
21 )
22
23 var prohibitionaryDialArgTests = []struct {
24 network string
25 address string
26 }{
27 {"tcp6", "127.0.0.1"},
28 {"tcp6", "::ffff:127.0.0.1"},
29 }
30
31 func TestProhibitionaryDialArg(t *testing.T) {
32 testenv.MustHaveExternalNetwork(t)
33
34 switch runtime.GOOS {
35 case "plan9":
36 t.Skipf("not supported on %s", runtime.GOOS)
37 }
38 if !supportsIPv4map() {
39 t.Skip("mapping ipv4 address inside ipv6 address not supported")
40 }
41
42 ln, err := Listen("tcp", "[::]:0")
43 if err != nil {
44 t.Fatal(err)
45 }
46 defer ln.Close()
47
48 _, port, err := SplitHostPort(ln.Addr().String())
49 if err != nil {
50 t.Fatal(err)
51 }
52
53 for i, tt := range prohibitionaryDialArgTests {
54 c, err := Dial(tt.network, JoinHostPort(tt.address, port))
55 if err == nil {
56 c.Close()
57 t.Errorf("#%d: %v", i, err)
58 }
59 }
60 }
61
62 func TestDialLocal(t *testing.T) {
63 ln := newLocalListener(t, "tcp")
64 defer ln.Close()
65 _, port, err := SplitHostPort(ln.Addr().String())
66 if err != nil {
67 t.Fatal(err)
68 }
69 c, err := Dial("tcp", JoinHostPort("", port))
70 if err != nil {
71 t.Fatal(err)
72 }
73 c.Close()
74 }
75
76 func TestDialerDualStackFDLeak(t *testing.T) {
77 switch runtime.GOOS {
78 case "plan9":
79 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
80 case "windows":
81 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
82 case "openbsd":
83 testenv.SkipFlaky(t, 15157)
84 }
85 if !supportsIPv4() || !supportsIPv6() {
86 t.Skip("both IPv4 and IPv6 are required")
87 }
88
89 before := sw.Sockets()
90 origTestHookLookupIP := testHookLookupIP
91 defer func() { testHookLookupIP = origTestHookLookupIP }()
92 testHookLookupIP = lookupLocalhost
93 handler := func(dss *dualStackServer, ln Listener) {
94 for {
95 c, err := ln.Accept()
96 if err != nil {
97 return
98 }
99 c.Close()
100 }
101 }
102 dss, err := newDualStackServer()
103 if err != nil {
104 t.Fatal(err)
105 }
106 if err := dss.buildup(handler); err != nil {
107 dss.teardown()
108 t.Fatal(err)
109 }
110
111 const N = 10
112 var wg sync.WaitGroup
113 wg.Add(N)
114 d := &Dialer{DualStack: true, Timeout: 5 * time.Second}
115 for i := 0; i < N; i++ {
116 go func() {
117 defer wg.Done()
118 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
119 if err != nil {
120 t.Error(err)
121 return
122 }
123 c.Close()
124 }()
125 }
126 wg.Wait()
127 dss.teardown()
128 after := sw.Sockets()
129 if len(after) != len(before) {
130 t.Errorf("got %d; want %d", len(after), len(before))
131 }
132 }
133
134
135
136
137 const (
138 slowDst4 = "198.18.0.254"
139 slowDst6 = "2001:2::254"
140 )
141
142
143
144
145 func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
146 sd := &sysDialer{network: network, address: raddr.String()}
147 c, err := sd.doDialTCP(ctx, laddr, raddr)
148 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
149
150 <-ctx.Done()
151 }
152 return c, err
153 }
154
155 func dialClosedPort(t *testing.T) (dialLatency time.Duration) {
156
157
158
159
160
161 l, err := Listen("tcp", "127.0.0.1:0")
162 if err != nil {
163 t.Fatalf("dialClosedPort: Listen failed: %v", err)
164 }
165 addr := l.Addr().String()
166 l.Close()
167
168 startTime := time.Now()
169 c, err := Dial("tcp", addr)
170 if err == nil {
171 c.Close()
172 }
173 elapsed := time.Since(startTime)
174 t.Logf("dialClosedPort: measured delay %v", elapsed)
175 return elapsed
176 }
177
178 func TestDialParallel(t *testing.T) {
179 const instant time.Duration = 0
180 const fallbackDelay = 200 * time.Millisecond
181
182 nCopies := func(s string, n int) []string {
183 out := make([]string, n)
184 for i := 0; i < n; i++ {
185 out[i] = s
186 }
187 return out
188 }
189
190 var testCases = []struct {
191 primaries []string
192 fallbacks []string
193 teardownNetwork string
194 expectOk bool
195 expectElapsed time.Duration
196 }{
197
198 {[]string{"127.0.0.1"}, []string{}, "", true, instant},
199 {[]string{"::1"}, []string{}, "", true, instant},
200 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
201 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
202
203 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
204
205 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, instant},
206 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, instant},
207
208 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay},
209
210 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, instant},
211 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, instant},
212
213 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, instant},
214
215 {[]string{}, []string{}, "", false, instant},
216
217 {nCopies("::1", 1000), []string{}, "", true, instant},
218 }
219
220
221 makeAddrs := func(ips []string, port string) addrList {
222 var out addrList
223 for _, ip := range ips {
224 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
225 if err != nil {
226 t.Fatal(err)
227 }
228 out = append(out, addr)
229 }
230 return out
231 }
232
233 for i, tt := range testCases {
234 i, tt := i, tt
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
1068
1069
1070 func mustHaveExternalNetwork(t *testing.T) {
1071 t.Helper()
1072 definitelyHasLongtestBuilder := runtime.GOOS == "linux"
1073 mobile := runtime.GOOS == "android" || runtime.GOOS == "ios"
1074 fake := runtime.GOOS == "js" || runtime.GOOS == "wasip1"
1075 if testenv.Builder() != "" && !definitelyHasLongtestBuilder && !mobile && !fake {
1076
1077
1078
1079
1080 return
1081 }
1082 testenv.MustHaveExternalNetwork(t)
1083 }
1084
1085 type contextWithNonZeroDeadline struct {
1086 context.Context
1087 }
1088
1089 func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) {
1090
1091 return time.Unix(0, 0), false
1092 }
1093
1094 func TestDialWithNonZeroDeadline(t *testing.T) {
1095 ln := newLocalListener(t, "tcp")
1096 defer ln.Close()
1097 _, port, err := SplitHostPort(ln.Addr().String())
1098 if err != nil {
1099 t.Fatal(err)
1100 }
1101
1102 ctx := contextWithNonZeroDeadline{Context: context.Background()}
1103 var dialer Dialer
1104 c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port))
1105 if err != nil {
1106 t.Fatal(err)
1107 }
1108 c.Close()
1109 }
1110
View as plain text