1+ use crate :: error;
2+ use crate :: fmt:: { self , Write } ;
13use crate :: io:: { self , BorrowedCursor , IoSlice , IoSliceMut } ;
24use crate :: net:: { Ipv4Addr , Ipv6Addr , Shutdown , SocketAddr , ToSocketAddrs } ;
35use crate :: sync:: Arc ;
46use crate :: sys:: abi:: usercalls;
57use crate :: sys:: fd:: FileDesc ;
68use crate :: sys:: { AsInner , FromInner , IntoInner , TryIntoInner , sgx_ineffective, unsupported} ;
79use crate :: time:: Duration ;
8- use crate :: { error, fmt} ;
910
1011const DEFAULT_FAKE_TTL : u32 = 64 ;
1112
@@ -63,18 +64,52 @@ impl fmt::Debug for TcpStream {
6364 }
6465}
6566
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 ) ,
76107 }
77108 }
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+ } ,
78113 }
79114}
80115
@@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
86121}
87122
88123impl 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+ } )
93129 }
94130
95131 pub fn connect_timeout ( addr : & SocketAddr , dur : Duration ) -> io:: Result < TcpStream > {
96132 if dur == Duration :: default ( ) {
97133 return Err ( io:: Error :: ZERO_TIMEOUT ) ;
98134 }
99- Self :: connect ( Ok ( addr) ) // FIXME: ignoring timeout
135+ Self :: connect ( addr) // FIXME: ignoring timeout
100136 }
101137
102138 pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
@@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener {
247283}
248284
249285impl 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+ } )
254291 }
255292
256293 pub fn socket_addr ( & self ) -> io:: Result < SocketAddr > {
@@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener {
316353pub struct UdpSocket ( !) ;
317354
318355impl UdpSocket {
319- pub fn bind ( _: io :: Result < & SocketAddr > ) -> io:: Result < UdpSocket > {
356+ pub fn bind < A : ToSocketAddrs > ( _: A ) -> io:: Result < UdpSocket > {
320357 unsupported ( )
321358 }
322359
@@ -436,7 +473,7 @@ impl UdpSocket {
436473 self . 0
437474 }
438475
439- pub fn connect ( & self , _: io :: Result < & SocketAddr > ) -> io:: Result < ( ) > {
476+ pub fn connect < A : ToSocketAddrs > ( & self , _: A ) -> io:: Result < ( ) > {
440477 self . 0
441478 }
442479}
0 commit comments