Source file
src/net/dial.go
Documentation: net
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "internal/bytealg"
10 "internal/godebug"
11 "internal/nettrace"
12 "syscall"
13 "time"
14 )
15
16 const (
17
18
19 defaultTCPKeepAlive = 15 * time.Second
20
21
22
23 defaultMPTCPEnabled = false
24 )
25
26 var multipathtcp = godebug.New("multipathtcp")
27
28
29 type mptcpStatus uint8
30
31 const (
32
33 mptcpUseDefault mptcpStatus = iota
34 mptcpEnabled
35 mptcpDisabled
36 )
37
38 func (m *mptcpStatus) get() bool {
39 switch *m {
40 case mptcpEnabled:
41 return true
42 case mptcpDisabled:
43 return false
44 }
45
46
47 if multipathtcp.Value() == "1" {
48 multipathtcp.IncNonDefault()
49
50 return true
51 }
52
53 return defaultMPTCPEnabled
54 }
55
56 func (m *mptcpStatus) set(use bool) {
57 if use {
58 *m = mptcpEnabled
59 } else {
60 *m = mptcpDisabled
61 }
62 }
63
64
65
66
67
68
69
70
71 type Dialer struct {
72
73
74
75
76
77
78
79
80
81
82
83
84 Timeout time.Duration
85
86
87
88
89
90 Deadline time.Time
91
92
93
94
95
96 LocalAddr Addr
97
98
99
100
101
102
103
104
105 DualStack bool
106
107
108
109
110
111
112
113
114
115 FallbackDelay time.Duration
116
117
118
119
120
121
122
123
124 KeepAlive time.Duration
125
126
127 Resolver *Resolver
128
129
130
131
132
133
134 Cancel <-chan struct{}
135
136
137
138
139
140
141
142
143
144 Control func(network, address string, c syscall.RawConn) error
145
146
147
148
149
150
151
152
153
154 ControlContext func(ctx context.Context, network, address string, c syscall.RawConn) error
155
156
157
158
159 mptcpStatus mptcpStatus
160 }
161
162 func (d *Dialer) dualStack() bool { return d.FallbackDelay >= 0 }
163
164 func minNonzeroTime(a, b time.Time) time.Time {
165 if a.IsZero() {
166 return b
167 }
168 if b.IsZero() || a.Before(b) {
169 return a
170 }
171 return b
172 }
173
174
175
176
177
178
179
180 func (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Time) {
181 if d.Timeout != 0 {
182 earliest = now.Add(d.Timeout)
183 }
184 if d, ok := ctx.Deadline(); ok {
185 earliest = minNonzeroTime(earliest, d)
186 }
187 return minNonzeroTime(earliest, d.Deadline)
188 }
189
190 func (d *Dialer) resolver() *Resolver {
191 if d.Resolver != nil {
192 return d.Resolver
193 }
194 return DefaultResolver
195 }
196
197
198
199 func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
200 if deadline.IsZero() {
201 return deadline, nil
202 }
203 timeRemaining := deadline.Sub(now)
204 if timeRemaining <= 0 {
205 return time.Time{}, errTimeout
206 }
207
208 timeout := timeRemaining / time.Duration(addrsRemaining)
209
210 const saneMinimum = 2 * time.Second
211 if timeout < saneMinimum {
212 if timeRemaining < saneMinimum {
213 timeout = timeRemaining
214 } else {
215 timeout = saneMinimum
216 }
217 }
218 return now.Add(timeout), nil
219 }
220
221 func (d *Dialer) fallbackDelay() time.Duration {
222 if d.FallbackDelay > 0 {
223 return d.FallbackDelay
224 } else {
225 return 300 * time.Millisecond
226 }
227 }
228
229 func parseNetwork(ctx context.Context, network string, needsProto bool) (afnet string, proto int, err error) {
230 i := bytealg.LastIndexByteString(network, ':')
231 if i < 0 {
232 switch network {
233 case "tcp", "tcp4", "tcp6":
234 case "udp", "udp4", "udp6":
235 case "ip", "ip4", "ip6":
236 if needsProto {
237 return "", 0, UnknownNetworkError(network)
238 }
239 case "unix", "unixgram", "unixpacket":
240 default:
241 return "", 0, UnknownNetworkError(network)
242 }
243 return network, 0, nil
244 }
245 afnet = network[:i]
246 switch afnet {
247 case "ip", "ip4", "ip6":
248 protostr := network[i+1:]
249 proto, i, ok := dtoi(protostr)
250 if !ok || i != len(protostr) {
251 proto, err = lookupProtocol(ctx, protostr)
252 if err != nil {
253 return "", 0, err
254 }
255 }
256 return afnet, proto, nil
257 }
258 return "", 0, UnknownNetworkError(network)
259 }
260
261
262
263
264 func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
265 afnet, _, err := parseNetwork(ctx, network, true)
266 if err != nil {
267 return nil, err
268 }
269 if op == "dial" && addr == "" {
270 return nil, errMissingAddress
271 }
272 switch afnet {
273 case "unix", "unixgram", "unixpacket":
274 addr, err := ResolveUnixAddr(afnet, addr)
275 if err != nil {
276 return nil, err
277 }
278 if op == "dial" && hint != nil && addr.Network() != hint.Network() {
279 return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
280 }
281 return addrList{addr}, nil
282 }
283 addrs, err := r.internetAddrList(ctx, afnet, addr)
284 if err != nil || op != "dial" || hint == nil {
285 return addrs, err
286 }
287 var (
288 tcp *TCPAddr
289 udp *UDPAddr
290 ip *IPAddr
291 wildcard bool
292 )
293 switch hint := hint.(type) {
294 case *TCPAddr:
295 tcp = hint
296 wildcard = tcp.isWildcard()
297 case *UDPAddr:
298 udp = hint
299 wildcard = udp.isWildcard()
300 case *IPAddr:
301 ip = hint
302 wildcard = ip.isWildcard()
303 }
304 naddrs := addrs[:0]
305 for _, addr := range addrs {
306 if addr.Network() != hint.Network() {
307 return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
308 }
309 switch addr := addr.(type) {
310 case *TCPAddr:
311 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(tcp.IP) {
312 continue
313 }
314 naddrs = append(naddrs, addr)
315 case *UDPAddr:
316 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(udp.IP) {
317 continue
318 }
319 naddrs = append(naddrs, addr)
320 case *IPAddr:
321 if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(ip.IP) {
322 continue
323 }
324 naddrs = append(naddrs, addr)
325 }
326 }
327 if len(naddrs) == 0 {
328 return nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: hint.String()}
329 }
330 return naddrs, nil
331 }
332
333
334
335
336
337 func (d *Dialer) MultipathTCP() bool {
338 return d.mptcpStatus.get()
339 }
340
341
342
343
344
345
346
347 func (d *Dialer) SetMultipathTCP(use bool) {
348 d.mptcpStatus.set(use)
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399 func Dial(network, address string) (Conn, error) {
400 var d Dialer
401 return d.Dial(network, address)
402 }
403
404
405
406
407
408
409
410
411
412
413
414 func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
415 d := Dialer{Timeout: timeout}
416 return d.Dial(network, address)
417 }
418
419
420 type sysDialer struct {
421 Dialer
422 network, address string
423 testHookDialTCP func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error)
424 }
425
426
427
428
429
430
431
432
433 func (d *Dialer) Dial(network, address string) (Conn, error) {
434 return d.DialContext(context.Background(), network, address)
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455 func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
456 if ctx == nil {
457 panic("nil context")
458 }
459 deadline := d.deadline(ctx, time.Now())
460 if !deadline.IsZero() {
461 testHookStepTime()
462 if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
463 subCtx, cancel := context.WithDeadline(ctx, deadline)
464 defer cancel()
465 ctx = subCtx
466 }
467 }
468 if oldCancel := d.Cancel; oldCancel != nil {
469 subCtx, cancel := context.WithCancel(ctx)
470 defer cancel()
471 go func() {
472 select {
473 case <-oldCancel:
474 cancel()
475 case <-subCtx.Done():
476 }
477 }()
478 ctx = subCtx
479 }
480
481
482 resolveCtx := ctx
483 if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil {
484 shadow := *trace
485 shadow.ConnectStart = nil
486 shadow.ConnectDone = nil
487 resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
488 }
489
490 addrs, err := d.resolver().resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
491 if err != nil {
492 return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
493 }
494
495 sd := &sysDialer{
496 Dialer: *d,
497 network: network,
498 address: address,
499 }
500
501 var primaries, fallbacks addrList
502 if d.dualStack() && network == "tcp" {
503 primaries, fallbacks = addrs.partition(isIPv4)
504 } else {
505 primaries = addrs
506 }
507
508 return sd.dialParallel(ctx, primaries, fallbacks)
509 }
510
511
512
513
514
515 func (sd *sysDialer) dialParallel(ctx context.Context, primaries, fallbacks addrList) (Conn, error) {
516 if len(fallbacks) == 0 {
517 return sd.dialSerial(ctx, primaries)
518 }
519
520 returned := make(chan struct{})
521 defer close(returned)
522
523 type dialResult struct {
524 Conn
525 error
526 primary bool
527 done bool
528 }
529 results := make(chan dialResult)
530
531 startRacer := func(ctx context.Context, primary bool) {
532 ras := primaries
533 if !primary {
534 ras = fallbacks
535 }
536 c, err := sd.dialSerial(ctx, ras)
537 select {
538 case results <- dialResult{Conn: c, error: err, primary: primary, done: true}:
539 case <-returned:
540 if c != nil {
541 c.Close()
542 }
543 }
544 }
545
546 var primary, fallback dialResult
547
548
549 primaryCtx, primaryCancel := context.WithCancel(ctx)
550 defer primaryCancel()
551 go startRacer(primaryCtx, true)
552
553
554 fallbackTimer := time.NewTimer(sd.fallbackDelay())
555 defer fallbackTimer.Stop()
556
557 for {
558 select {
559 case <-fallbackTimer.C:
560 fallbackCtx, fallbackCancel := context.WithCancel(ctx)
561 defer fallbackCancel()
562 go startRacer(fallbackCtx, false)
563
564 case res := <-results:
565 if res.error == nil {
566 return res.Conn, nil
567 }
568 if res.primary {
569 primary = res
570 } else {
571 fallback = res
572 }
573 if primary.done && fallback.done {
574 return nil, primary.error
575 }
576 if res.primary && fallbackTimer.Stop() {
577
578
579
580
581 fallbackTimer.Reset(0)
582 }
583 }
584 }
585 }
586
587
588
589 func (sd *sysDialer) dialSerial(ctx context.Context, ras addrList) (Conn, error) {
590 var firstErr error
591
592 for i, ra := range ras {
593 select {
594 case <-ctx.Done():
595 return nil, &OpError{Op: "dial", Net: sd.network, Source: sd.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())}
596 default:
597 }
598
599 dialCtx := ctx
600 if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
601 partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i)
602 if err != nil {
603
604 if firstErr == nil {
605 firstErr = &OpError{Op: "dial", Net: sd.network, Source: sd.LocalAddr, Addr: ra, Err: err}
606 }
607 break
608 }
609 if partialDeadline.Before(deadline) {
610 var cancel context.CancelFunc
611 dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
612 defer cancel()
613 }
614 }
615
616 c, err := sd.dialSingle(dialCtx, ra)
617 if err == nil {
618 return c, nil
619 }
620 if firstErr == nil {
621 firstErr = err
622 }
623 }
624
625 if firstErr == nil {
626 firstErr = &OpError{Op: "dial", Net: sd.network, Source: nil, Addr: nil, Err: errMissingAddress}
627 }
628 return nil, firstErr
629 }
630
631
632
633 func (sd *sysDialer) dialSingle(ctx context.Context, ra Addr) (c Conn, err error) {
634 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
635 if trace != nil {
636 raStr := ra.String()
637 if trace.ConnectStart != nil {
638 trace.ConnectStart(sd.network, raStr)
639 }
640 if trace.ConnectDone != nil {
641 defer func() { trace.ConnectDone(sd.network, raStr, err) }()
642 }
643 }
644 la := sd.LocalAddr
645 switch ra := ra.(type) {
646 case *TCPAddr:
647 la, _ := la.(*TCPAddr)
648 if sd.MultipathTCP() {
649 c, err = sd.dialMPTCP(ctx, la, ra)
650 } else {
651 c, err = sd.dialTCP(ctx, la, ra)
652 }
653 case *UDPAddr:
654 la, _ := la.(*UDPAddr)
655 c, err = sd.dialUDP(ctx, la, ra)
656 case *IPAddr:
657 la, _ := la.(*IPAddr)
658 c, err = sd.dialIP(ctx, la, ra)
659 case *UnixAddr:
660 la, _ := la.(*UnixAddr)
661 c, err = sd.dialUnix(ctx, la, ra)
662 default:
663 return nil, &OpError{Op: "dial", Net: sd.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: sd.address}}
664 }
665 if err != nil {
666 return nil, &OpError{Op: "dial", Net: sd.network, Source: la, Addr: ra, Err: err}
667 }
668 return c, nil
669 }
670
671
672 type ListenConfig struct {
673
674
675
676
677
678
679 Control func(network, address string, c syscall.RawConn) error
680
681
682
683
684
685
686
687 KeepAlive time.Duration
688
689
690
691
692 mptcpStatus mptcpStatus
693 }
694
695
696
697
698
699 func (lc *ListenConfig) MultipathTCP() bool {
700 return lc.mptcpStatus.get()
701 }
702
703
704
705
706
707
708
709 func (lc *ListenConfig) SetMultipathTCP(use bool) {
710 lc.mptcpStatus.set(use)
711 }
712
713
714
715
716
717 func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (Listener, error) {
718 addrs, err := DefaultResolver.resolveAddrList(ctx, "listen", network, address, nil)
719 if err != nil {
720 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
721 }
722 sl := &sysListener{
723 ListenConfig: *lc,
724 network: network,
725 address: address,
726 }
727 var l Listener
728 la := addrs.first(isIPv4)
729 switch la := la.(type) {
730 case *TCPAddr:
731 if sl.MultipathTCP() {
732 l, err = sl.listenMPTCP(ctx, la)
733 } else {
734 l, err = sl.listenTCP(ctx, la)
735 }
736 case *UnixAddr:
737 l, err = sl.listenUnix(ctx, la)
738 default:
739 return nil, &OpError{Op: "listen", Net: sl.network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
740 }
741 if err != nil {
742 return nil, &OpError{Op: "listen", Net: sl.network, Source: nil, Addr: la, Err: err}
743 }
744 return l, nil
745 }
746
747
748
749
750
751 func (lc *ListenConfig) ListenPacket(ctx context.Context, network, address string) (PacketConn, error) {
752 addrs, err := DefaultResolver.resolveAddrList(ctx, "listen", network, address, nil)
753 if err != nil {
754 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
755 }
756 sl := &sysListener{
757 ListenConfig: *lc,
758 network: network,
759 address: address,
760 }
761 var c PacketConn
762 la := addrs.first(isIPv4)
763 switch la := la.(type) {
764 case *UDPAddr:
765 c, err = sl.listenUDP(ctx, la)
766 case *IPAddr:
767 c, err = sl.listenIP(ctx, la)
768 case *UnixAddr:
769 c, err = sl.listenUnixgram(ctx, la)
770 default:
771 return nil, &OpError{Op: "listen", Net: sl.network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
772 }
773 if err != nil {
774 return nil, &OpError{Op: "listen", Net: sl.network, Source: nil, Addr: la, Err: err}
775 }
776 return c, nil
777 }
778
779
780 type sysListener struct {
781 ListenConfig
782 network, address string
783 }
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806 func Listen(network, address string) (Listener, error) {
807 var lc ListenConfig
808 return lc.Listen(context.Background(), network, address)
809 }
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836 func ListenPacket(network, address string) (PacketConn, error) {
837 var lc ListenConfig
838 return lc.ListenPacket(context.Background(), network, address)
839 }
840
View as plain text