1
+ use crate :: error;
2
+ use crate :: fmt:: { self , Write } ;
1
3
use crate :: io:: { self , BorrowedCursor , IoSlice , IoSliceMut } ;
2
4
use crate :: net:: { Ipv4Addr , Ipv6Addr , Shutdown , SocketAddr , ToSocketAddrs } ;
3
5
use crate :: sync:: Arc ;
4
6
use crate :: sys:: abi:: usercalls;
5
7
use crate :: sys:: fd:: FileDesc ;
6
8
use crate :: sys:: { AsInner , FromInner , IntoInner , TryIntoInner , sgx_ineffective, unsupported} ;
7
9
use crate :: time:: Duration ;
8
- use crate :: { error, fmt} ;
9
10
10
11
const DEFAULT_FAKE_TTL : u32 = 64 ;
11
12
@@ -63,18 +64,51 @@ impl fmt::Debug for TcpStream {
63
64
}
64
65
}
65
66
66
- fn io_err_to_addr ( result : io:: Result < & SocketAddr > ) -> io:: Result < String > {
67
- match result {
68
- Ok ( saddr) => Ok ( saddr. to_string ( ) ) ,
69
- // need to downcast twice because io::Error::into_inner doesn't return the original
70
- // value if the conversion fails
71
- Err ( e) => {
72
- if e. get_ref ( ) . and_then ( |e| e. downcast_ref :: < NonIpSockAddr > ( ) ) . is_some ( ) {
73
- Ok ( e. into_inner ( ) . unwrap ( ) . downcast :: < NonIpSockAddr > ( ) . unwrap ( ) . host )
74
- } else {
75
- Err ( e)
67
+ /// Converts each address in `addr` into a hostname.
68
+ ///
69
+ /// SGX doesn't support DNS resolution but rather accepts hostnames in
70
+ /// the same place as socket addresses. So, to make e.g.
71
+ /// ```rust
72
+ /// TcpStream::connect("example.com:80")`
73
+ /// ```
74
+ /// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead,
75
+ /// which contains the hostname being looked up. When `.to_socket_addrs()`
76
+ /// fails, we inspect the error and try recover the hostname from it. If that
77
+ /// succeeds, we thus continue with the hostname.
78
+ ///
79
+ /// This is a terrible hack and leads to buggy code. For instance, when users
80
+ /// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs`
81
+ /// implementation to select from a list of possible URLs, the only URL used
82
+ /// will be that of the last item tried.
83
+ // FIXME: This is a terrible, terrible hack.
84
+ fn each_addr < A : ToSocketAddrs , F , T > ( addr : A , mut f : F ) -> io:: Result < T >
85
+ where
86
+ F : FnMut ( & str ) -> io:: Result < T > ,
87
+ {
88
+ match addr. to_socket_addrs ( ) {
89
+ Ok ( addrs) => {
90
+ let mut last_err = None ;
91
+ let mut encoded = String :: new ( ) ;
92
+ for addr in addrs {
93
+ write ! ( encoded, "{}" , & addr) . unwrap ( ) ;
94
+ match f ( & encoded) {
95
+ Ok ( val) => return Ok ( val) ,
96
+ Err ( err) => {
97
+ last_err = Some ( err) ;
98
+ encoded. clear ( ) ;
99
+ }
100
+ }
101
+ }
102
+
103
+ match last_err {
104
+ Some ( err) => Err ( err) ,
105
+ None => Err ( io:: Error :: NO_ADDRESSES ) ,
76
106
}
77
107
}
108
+ Err ( err) => match err. get_ref ( ) . and_then ( |e| e. downcast_ref :: < NonIpSockAddr > ( ) ) {
109
+ Some ( NonIpSockAddr { host } ) => f ( host) ,
110
+ None => Err ( err) ,
111
+ } ,
78
112
}
79
113
}
80
114
@@ -86,17 +120,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
86
120
}
87
121
88
122
impl TcpStream {
89
- pub fn connect ( addr : io:: Result < & SocketAddr > ) -> io:: Result < TcpStream > {
90
- let addr = io_err_to_addr ( addr) ?;
91
- let ( fd, local_addr, peer_addr) = usercalls:: connect_stream ( & addr) ?;
92
- Ok ( TcpStream { inner : Socket :: new ( fd, local_addr) , peer_addr : Some ( peer_addr) } )
123
+ pub fn connect < A : ToSocketAddrs > ( addr : A ) -> io:: Result < TcpStream > {
124
+ each_addr ( addr, |addr| {
125
+ let ( fd, local_addr, peer_addr) = usercalls:: connect_stream ( addr) ?;
126
+ Ok ( TcpStream { inner : Socket :: new ( fd, local_addr) , peer_addr : Some ( peer_addr) } )
127
+ } )
93
128
}
94
129
95
130
pub fn connect_timeout ( addr : & SocketAddr , dur : Duration ) -> io:: Result < TcpStream > {
96
131
if dur == Duration :: default ( ) {
97
132
return Err ( io:: Error :: ZERO_TIMEOUT ) ;
98
133
}
99
- Self :: connect ( Ok ( addr) ) // FIXME: ignoring timeout
134
+ Self :: connect ( addr) // FIXME: ignoring timeout
100
135
}
101
136
102
137
pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
@@ -247,10 +282,11 @@ impl fmt::Debug for TcpListener {
247
282
}
248
283
249
284
impl TcpListener {
250
- pub fn bind ( addr : io:: Result < & SocketAddr > ) -> io:: Result < TcpListener > {
251
- let addr = io_err_to_addr ( addr) ?;
252
- let ( fd, local_addr) = usercalls:: bind_stream ( & addr) ?;
253
- Ok ( TcpListener { inner : Socket :: new ( fd, local_addr) } )
285
+ pub fn bind < A : ToSocketAddrs > ( addr : A ) -> io:: Result < TcpListener > {
286
+ each_addr ( addr, |addr| {
287
+ let ( fd, local_addr) = usercalls:: bind_stream ( addr) ?;
288
+ Ok ( TcpListener { inner : Socket :: new ( fd, local_addr) } )
289
+ } )
254
290
}
255
291
256
292
pub fn socket_addr ( & self ) -> io:: Result < SocketAddr > {
@@ -316,7 +352,7 @@ impl FromInner<Socket> for TcpListener {
316
352
pub struct UdpSocket ( !) ;
317
353
318
354
impl UdpSocket {
319
- pub fn bind ( _: io :: Result < & SocketAddr > ) -> io:: Result < UdpSocket > {
355
+ pub fn bind < A : ToSocketAddrs > ( _: A ) -> io:: Result < UdpSocket > {
320
356
unsupported ( )
321
357
}
322
358
@@ -436,7 +472,7 @@ impl UdpSocket {
436
472
self . 0
437
473
}
438
474
439
- pub fn connect ( & self , _: io :: Result < & SocketAddr > ) -> io:: Result < ( ) > {
475
+ pub fn connect < A : ToSocketAddrs > ( & self , _: A ) -> io:: Result < ( ) > {
440
476
self . 0
441
477
}
442
478
}
0 commit comments