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