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