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