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