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