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