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