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