1
1
use std:: {
2
2
io:: { self , Read , Write } ,
3
- net:: { TcpStream , ToSocketAddrs } ,
3
+ net:: { SocketAddr , TcpStream , ToSocketAddrs } ,
4
4
sync:: Arc ,
5
5
time:: Duration ,
6
6
} ;
@@ -10,7 +10,7 @@ use derivative::Derivative;
10
10
use webpki:: DNSNameRef ;
11
11
12
12
use crate :: {
13
- error:: Result ,
13
+ error:: { ErrorKind , Result } ,
14
14
options:: { StreamAddress , TlsOptions } ,
15
15
} ;
16
16
@@ -38,27 +38,52 @@ pub(super) enum Stream {
38
38
) ,
39
39
}
40
40
41
+ fn try_connect ( address : & SocketAddr , timeout : Duration ) -> Result < TcpStream > {
42
+ // The URI options spec requires that the default connect timeout is 10 seconds, but that 0
43
+ // should indicate no timeout.
44
+ let stream = if timeout == Duration :: from_secs ( 0 ) {
45
+ TcpStream :: connect ( address) ?
46
+ } else {
47
+ TcpStream :: connect_timeout ( address, timeout) ?
48
+ } ;
49
+
50
+ Ok ( stream)
51
+ }
52
+
53
+ fn connect_stream ( address : & StreamAddress , connect_timeout : Option < Duration > ) -> Result < TcpStream > {
54
+ let timeout = connect_timeout. unwrap_or ( DEFAULT_CONNECT_TIMEOUT ) ;
55
+
56
+ let mut socket_addrs: Vec < _ > = address. to_socket_addrs ( ) ?. collect ( ) ;
57
+
58
+ if socket_addrs. is_empty ( ) {
59
+ return Err ( ErrorKind :: NoDnsResults ( address. clone ( ) ) . into ( ) ) ;
60
+ }
61
+
62
+ // After considering various approaches, we decided to do what other drivers do, namely try each
63
+ // of the addresses in sequence with a preference for IPv4.
64
+ socket_addrs. sort_by_key ( |addr| if addr. is_ipv4 ( ) { 0 } else { 1 } ) ;
65
+
66
+ let mut connect_error = None ;
67
+
68
+ for address in & socket_addrs {
69
+ connect_error = match try_connect ( address, timeout) {
70
+ Ok ( stream) => return Ok ( stream) ,
71
+ Err ( err) => Some ( err) ,
72
+ } ;
73
+ }
74
+
75
+ Err ( connect_error. unwrap_or_else ( || ErrorKind :: NoDnsResults ( address. clone ( ) ) . into ( ) ) )
76
+ }
77
+
41
78
impl Stream {
42
79
/// Creates a new stream connected to `address`.
43
80
pub ( super ) fn connect (
44
81
host : StreamAddress ,
45
82
connect_timeout : Option < Duration > ,
46
83
tls_options : Option < TlsOptions > ,
47
84
) -> Result < Self > {
48
- let timeout = connect_timeout. unwrap_or ( DEFAULT_CONNECT_TIMEOUT ) ;
49
-
50
- // The URI options spec requires that the default is 10 seconds, but that 0 should indicate
51
- // no timeout.
52
- let inner = if timeout == Duration :: from_secs ( 0 ) {
53
- TcpStream :: connect ( & host) ?
54
- } else {
55
- let mut socket_addrs: Vec < _ > = host. to_socket_addrs ( ) ?. collect ( ) ;
56
- socket_addrs. sort_by_key ( |addr| if addr. is_ipv4 ( ) { 0 } else { 1 } ) ;
57
-
58
- TcpStream :: connect_timeout ( & socket_addrs[ 0 ] , timeout) ?
59
- } ;
85
+ let inner = connect_stream ( & host, connect_timeout) ?;
60
86
inner. set_nodelay ( true ) ?;
61
- let inner = inner;
62
87
63
88
match tls_options {
64
89
Some ( cfg) => {
0 commit comments