Source file
src/net/dial_test.go
Documentation: net
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 handler := func(ls *localServer, ln Listener) {
694 for {
695 c, err := ln.Accept()
696 if err != nil {
697 return
698 }
699 c.Close()
700 }
701 }
702 ls := newLocalServer(t, "tcp")
703 defer ls.teardown()
704 if err := ls.buildup(handler); err != nil {
705 t.Fatal(err)
706 }
707 defer func() { testHookSetKeepAlive = func(time.Duration) {} }()
708
709 tests := []struct {
710 ka time.Duration
711 expected time.Duration
712 }{
713 {-1, -1},
714 {0, 15 * time.Second},
715 {5 * time.Second, 5 * time.Second},
716 {30 * time.Second, 30 * time.Second},
717 }
718
719 for _, test := range tests {
720 var got time.Duration = -1
721 testHookSetKeepAlive = func(d time.Duration) { got = d }
722 d := Dialer{KeepAlive: test.ka}
723 c, err := d.Dial("tcp", ls.Listener.Addr().String())
724 if err != nil {
725 t.Fatal(err)
726 }
727 c.Close()
728 if got != test.expected {
729 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected)
730 }
731 }
732 }
733
734 func TestDialCancel(t *testing.T) {
735 mustHaveExternalNetwork(t)
736
737 blackholeIPPort := JoinHostPort(slowDst4, "1234")
738 if !supportsIPv4() {
739 blackholeIPPort = JoinHostPort(slowDst6, "1234")
740 }
741
742 ticker := time.NewTicker(10 * time.Millisecond)
743 defer ticker.Stop()
744
745 const cancelTick = 5
746 const timeoutTick = 100
747
748 var d Dialer
749 cancel := make(chan struct{})
750 d.Cancel = cancel
751 errc := make(chan error, 1)
752 connc := make(chan Conn, 1)
753 go func() {
754 if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
755 errc <- err
756 } else {
757 connc <- c
758 }
759 }()
760 ticks := 0
761 for {
762 select {
763 case <-ticker.C:
764 ticks++
765 if ticks == cancelTick {
766 close(cancel)
767 }
768 if ticks == timeoutTick {
769 t.Fatal("timeout waiting for dial to fail")
770 }
771 case c := <-connc:
772 c.Close()
773 t.Fatal("unexpected successful connection")
774 case err := <-errc:
775 if perr := parseDialError(err); perr != nil {
776 t.Error(perr)
777 }
778 if ticks < cancelTick {
779
780
781 ignorable := []string{
782 "connection refused",
783 "unreachable",
784 "no route to host",
785 "invalid argument",
786 }
787 e := err.Error()
788 for _, ignore := range ignorable {
789 if strings.Contains(e, ignore) {
790 t.Skipf("connection to %v failed fast with %v", blackholeIPPort, err)
791 }
792 }
793
794 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
795 ticks, cancelTick-ticks, err)
796 }
797 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
798 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
799 }
800 return
801 }
802 }
803 }
804
805 func TestCancelAfterDial(t *testing.T) {
806 if testing.Short() {
807 t.Skip("avoiding time.Sleep")
808 }
809
810 ln := newLocalListener(t, "tcp")
811
812 var wg sync.WaitGroup
813 wg.Add(1)
814 defer func() {
815 ln.Close()
816 wg.Wait()
817 }()
818
819
820 go func() {
821 for {
822 c, err := ln.Accept()
823 if err != nil {
824 break
825 }
826 rb := bufio.NewReader(c)
827 line, err := rb.ReadString('\n')
828 if err != nil {
829 t.Error(err)
830 c.Close()
831 continue
832 }
833 if _, err := c.Write([]byte(line)); err != nil {
834 t.Error(err)
835 }
836 c.Close()
837 }
838 wg.Done()
839 }()
840
841 try := func() {
842 cancel := make(chan struct{})
843 d := &Dialer{Cancel: cancel}
844 c, err := d.Dial("tcp", ln.Addr().String())
845
846
847
848
849 close(cancel)
850 time.Sleep(10 * time.Millisecond)
851
852 if err != nil {
853 t.Fatal(err)
854 }
855 defer c.Close()
856
857
858 const message = "echo!\n"
859 if _, err := c.Write([]byte(message)); err != nil {
860 t.Fatal(err)
861 }
862
863
864 rb := bufio.NewReader(c)
865 line, err := rb.ReadString('\n')
866 if err != nil {
867 t.Fatal(err)
868 }
869 if line != message {
870 t.Errorf("got %q; want %q", line, message)
871 }
872 if _, err := rb.ReadByte(); err != io.EOF {
873 t.Errorf("got %v; want %v", err, io.EOF)
874 }
875 }
876
877
878 for i := 0; i < 10; i++ {
879 try()
880 }
881 }
882
883 func TestDialClosedPortFailFast(t *testing.T) {
884 if runtime.GOOS != "windows" {
885
886 t.Skip("skipping windows only test")
887 }
888 for _, network := range []string{"tcp", "tcp4", "tcp6"} {
889 t.Run(network, func(t *testing.T) {
890 if !testableNetwork(network) {
891 t.Skipf("skipping: can't listen on %s", network)
892 }
893
894
895
896 ln := newLocalListener(t, network)
897 addr := ln.Addr().String()
898 conn1, err := Dial(network, addr)
899 if err != nil {
900 ln.Close()
901 t.Fatal(err)
902 }
903 defer conn1.Close()
904
905
906
907 ln.Close()
908
909 maxElapsed := time.Second
910
911
912
913
914 for {
915 startTime := time.Now()
916 conn2, err := Dial(network, addr)
917 if err == nil {
918 conn2.Close()
919 t.Fatal("error expected")
920 }
921 elapsed := time.Since(startTime)
922 if elapsed < maxElapsed {
923 break
924 }
925 t.Logf("got %v; want < %v", elapsed, maxElapsed)
926 }
927 })
928 }
929 }
930
931
932
933
934
935 func TestDialListenerAddr(t *testing.T) {
936 if !testableNetwork("tcp4") {
937 t.Skipf("skipping: can't listen on tcp4")
938 }
939
940
941
942
943
944
945
946
947
948
949
950 ln, err := Listen("tcp4", "localhost:0")
951 if err != nil {
952 t.Fatal(err)
953 }
954 defer ln.Close()
955
956 t.Logf("listening on %q", ln.Addr())
957 _, port, err := SplitHostPort(ln.Addr().String())
958 if err != nil {
959 t.Fatal(err)
960 }
961
962
963
964
965
966
967
968
969
970
971 dialAddr := "[::]:" + port
972 c, err := Dial("tcp4", dialAddr)
973 if err != nil {
974 t.Fatalf(`Dial("tcp4", %q): %v`, dialAddr, err)
975 }
976 c.Close()
977 t.Logf(`Dial("tcp4", %q) succeeded`, dialAddr)
978 }
979
980 func TestDialerControl(t *testing.T) {
981 switch runtime.GOOS {
982 case "plan9":
983 t.Skipf("not supported on %s", runtime.GOOS)
984 case "js", "wasip1":
985 t.Skipf("skipping: fake net does not support Dialer.Control")
986 }
987
988 t.Run("StreamDial", func(t *testing.T) {
989 for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
990 if !testableNetwork(network) {
991 continue
992 }
993 ln := newLocalListener(t, network)
994 defer ln.Close()
995 d := Dialer{Control: controlOnConnSetup}
996 c, err := d.Dial(network, ln.Addr().String())
997 if err != nil {
998 t.Error(err)
999 continue
1000 }
1001 c.Close()
1002 }
1003 })
1004 t.Run("PacketDial", func(t *testing.T) {
1005 for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} {
1006 if !testableNetwork(network) {
1007 continue
1008 }
1009 c1 := newLocalPacketListener(t, network)
1010 if network == "unixgram" {
1011 defer os.Remove(c1.LocalAddr().String())
1012 }
1013 defer c1.Close()
1014 d := Dialer{Control: controlOnConnSetup}
1015 c2, err := d.Dial(network, c1.LocalAddr().String())
1016 if err != nil {
1017 t.Error(err)
1018 continue
1019 }
1020 c2.Close()
1021 }
1022 })
1023 }
1024
1025 func TestDialerControlContext(t *testing.T) {
1026 switch runtime.GOOS {
1027 case "plan9":
1028 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
1029 case "js", "wasip1":
1030 t.Skipf("skipping: fake net does not support Dialer.ControlContext")
1031 }
1032 t.Run("StreamDial", func(t *testing.T) {
1033 for i, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
1034 t.Run(network, func(t *testing.T) {
1035 if !testableNetwork(network) {
1036 t.Skipf("skipping: %s not available", network)
1037 }
1038
1039 ln := newLocalListener(t, network)
1040 defer ln.Close()
1041 var id int
1042 d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error {
1043 id = ctx.Value("id").(int)
1044 return controlOnConnSetup(network, address, c)
1045 }}
1046 c, err := d.DialContext(context.WithValue(context.Background(), "id", i+1), network, ln.Addr().String())
1047 if err != nil {
1048 t.Fatal(err)
1049 }
1050 if id != i+1 {
1051 t.Errorf("got id %d, want %d", id, i+1)
1052 }
1053 c.Close()
1054 })
1055 }
1056 })
1057 }
1058
1059
1060
1061
1062 func mustHaveExternalNetwork(t *testing.T) {
1063 t.Helper()
1064 definitelyHasLongtestBuilder := runtime.GOOS == "linux"
1065 mobile := runtime.GOOS == "android" || runtime.GOOS == "ios"
1066 fake := runtime.GOOS == "js" || runtime.GOOS == "wasip1"
1067 if testenv.Builder() != "" && !definitelyHasLongtestBuilder && !mobile && !fake {
1068
1069
1070
1071
1072 return
1073 }
1074 testenv.MustHaveExternalNetwork(t)
1075 }
1076
1077 type contextWithNonZeroDeadline struct {
1078 context.Context
1079 }
1080
1081 func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) {
1082
1083 return time.Unix(0, 0), false
1084 }
1085
1086 func TestDialWithNonZeroDeadline(t *testing.T) {
1087 ln := newLocalListener(t, "tcp")
1088 defer ln.Close()
1089 _, port, err := SplitHostPort(ln.Addr().String())
1090 if err != nil {
1091 t.Fatal(err)
1092 }
1093
1094 ctx := contextWithNonZeroDeadline{Context: context.Background()}
1095 var dialer Dialer
1096 c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port))
1097 if err != nil {
1098 t.Fatal(err)
1099 }
1100 c.Close()
1101 }
1102
View as plain text