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,52 @@ 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. Fixing this requires Fortanix to
84
+ // add a method for resolving addresses.
85
+ fn each_addr < A : ToSocketAddrs , F , T > ( addr : A , mut f : F ) -> io:: Result < T >
86
+ where
87
+ F : FnMut ( & str ) -> io:: Result < T > ,
88
+ {
89
+ match addr. to_socket_addrs ( ) {
90
+ Ok ( addrs) => {
91
+ let mut last_err = None ;
92
+ let mut encoded = String :: new ( ) ;
93
+ for addr in addrs {
94
+ // Format the IP address as a string, reusing the buffer.
95
+ encoded. clear ( ) ;
96
+ write ! ( encoded, "{}" , & addr) . unwrap ( ) ;
97
+
98
+ match f ( & encoded) {
99
+ Ok ( val) => return Ok ( val) ,
100
+ Err ( err) => last_err = Some ( err) ,
101
+ }
102
+ }
103
+
104
+ match last_err {
105
+ Some ( err) => Err ( err) ,
106
+ None => Err ( io:: Error :: NO_ADDRESSES ) ,
76
107
}
77
108
}
109
+ Err ( err) => match err. get_ref ( ) . and_then ( |e| e. downcast_ref :: < NonIpSockAddr > ( ) ) {
110
+ Some ( NonIpSockAddr { host } ) => f ( host) ,
111
+ None => Err ( err) ,
112
+ } ,
78
113
}
79
114
}
80
115
@@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
86
121
}
87
122
88
123
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) } )
124
+ pub fn connect < A : ToSocketAddrs > ( addr : A ) -> io:: Result < TcpStream > {
125
+ each_addr ( addr, |addr| {
126
+ let ( fd, local_addr, peer_addr) = usercalls:: connect_stream ( addr) ?;
127
+ Ok ( TcpStream { inner : Socket :: new ( fd, local_addr) , peer_addr : Some ( peer_addr) } )
128
+ } )
93
129
}
94
130
95
131
pub fn connect_timeout ( addr : & SocketAddr , dur : Duration ) -> io:: Result < TcpStream > {
96
132
if dur == Duration :: default ( ) {
97
133
return Err ( io:: Error :: ZERO_TIMEOUT ) ;
98
134
}
99
- Self :: connect ( Ok ( addr) ) // FIXME: ignoring timeout
135
+ Self :: connect ( addr) // FIXME: ignoring timeout
100
136
}
101
137
102
138
pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
@@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener {
247
283
}
248
284
249
285
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) } )
286
+ pub fn bind < A : ToSocketAddrs > ( addr : A ) -> io:: Result < TcpListener > {
287
+ each_addr ( addr, |addr| {
288
+ let ( fd, local_addr) = usercalls:: bind_stream ( addr) ?;
289
+ Ok ( TcpListener { inner : Socket :: new ( fd, local_addr) } )
290
+ } )
254
291
}
255
292
256
293
pub fn socket_addr ( & self ) -> io:: Result < SocketAddr > {
@@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener {
316
353
pub struct UdpSocket ( !) ;
317
354
318
355
impl UdpSocket {
319
- pub fn bind ( _: io :: Result < & SocketAddr > ) -> io:: Result < UdpSocket > {
356
+ pub fn bind < A : ToSocketAddrs > ( _: A ) -> io:: Result < UdpSocket > {
320
357
unsupported ( )
321
358
}
322
359
@@ -436,7 +473,7 @@ impl UdpSocket {
436
473
self . 0
437
474
}
438
475
439
- pub fn connect ( & self , _: io :: Result < & SocketAddr > ) -> io:: Result < ( ) > {
476
+ pub fn connect < A : ToSocketAddrs > ( & self , _: A ) -> io:: Result < ( ) > {
440
477
self . 0
441
478
}
442
479
}
0 commit comments