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