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,51 @@ 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.
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 ) ,
76106 }
77107 }
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+ } ,
78112 }
79113}
80114
@@ -86,17 +120,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
86120}
87121
88122impl 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+ } )
93128 }
94129
95130 pub fn connect_timeout ( addr : & SocketAddr , dur : Duration ) -> io:: Result < TcpStream > {
96131 if dur == Duration :: default ( ) {
97132 return Err ( io:: Error :: ZERO_TIMEOUT ) ;
98133 }
99- Self :: connect ( Ok ( addr) ) // FIXME: ignoring timeout
134+ Self :: connect ( addr) // FIXME: ignoring timeout
100135 }
101136
102137 pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
@@ -247,10 +282,11 @@ impl fmt::Debug for TcpListener {
247282}
248283
249284impl 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+ } )
254290 }
255291
256292 pub fn socket_addr ( & self ) -> io:: Result < SocketAddr > {
@@ -316,7 +352,7 @@ impl FromInner<Socket> for TcpListener {
316352pub struct UdpSocket ( !) ;
317353
318354impl UdpSocket {
319- pub fn bind ( _: io :: Result < & SocketAddr > ) -> io:: Result < UdpSocket > {
355+ pub fn bind < A : ToSocketAddrs > ( _: A ) -> io:: Result < UdpSocket > {
320356 unsupported ( )
321357 }
322358
@@ -436,7 +472,7 @@ impl UdpSocket {
436472 self . 0
437473 }
438474
439- pub fn connect ( & self , _: io :: Result < & SocketAddr > ) -> io:: Result < ( ) > {
475+ pub fn connect < A : ToSocketAddrs > ( & self , _: A ) -> io:: Result < ( ) > {
440476 self . 0
441477 }
442478}
0 commit comments