]> git.lizzy.rs Git - rust.git/commitdiff
SGX target: implement networking
authorJethro Beekman <jethro@fortanix.com>
Wed, 19 Sep 2018 22:59:06 +0000 (15:59 -0700)
committerJethro Beekman <jethro@fortanix.com>
Fri, 7 Dec 2018 05:56:51 +0000 (11:26 +0530)
src/libstd/sys/sgx/abi/usercalls/mod.rs
src/libstd/sys/sgx/net.rs

index b8d739f4d2fa13ef2c1dc176acd9047025d989e7..3614e1293c11219cb4a9cfb1b988cc38d5d0f689 100644 (file)
@@ -55,6 +55,61 @@ pub fn close(fd: Fd) {
     unsafe { raw::close(fd) }
 }
 
+fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
+    String::from_utf8(copy_user_buffer(buf))
+        .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+}
+
+pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
+    unsafe {
+        let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
+        let mut local = alloc::User::<ByteBuffer>::uninitialized();
+        let fd = raw::bind_stream(
+            addr_user.as_ptr(),
+            addr_user.len(),
+            local.as_raw_mut_ptr()
+        ).from_sgx_result()?;
+        let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
+        Ok((fd, local))
+    }
+}
+
+pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
+    unsafe {
+        let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
+        let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
+                                                               // without forcing coercion?
+        let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
+        let fd = raw::accept_stream(
+            fd,
+            local.as_raw_mut_ptr(),
+            peer.as_raw_mut_ptr()
+        ).from_sgx_result()?;
+        let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
+        let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
+        Ok((fd, local, peer))
+    }
+}
+
+pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
+    unsafe {
+        let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
+        let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
+        let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
+                                                               // without forcing coercion?
+        let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
+        let fd = raw::connect_stream(
+            addr_user.as_ptr(),
+            addr_user.len(),
+            local.as_raw_mut_ptr(),
+            peer.as_raw_mut_ptr()
+        ).from_sgx_result()?;
+        let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
+        let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
+        Ok((fd, local, peer))
+    }
+}
+
 pub fn launch_thread() -> IoResult<()> {
     unsafe { raw::launch_thread().from_sgx_result() }
 }
index 094683e28b80d6ee91a6c10c6e642bdf83dc38f8..176d230846dc25b0a8d61ba8c9a7162ac99946bf 100644 (file)
 
 use fmt;
 use io;
-use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
 use time::Duration;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, sgx_ineffective};
+use sys::fd::FileDesc;
 use convert::TryFrom;
+use error;
+use sync::Arc;
 
-pub struct TcpStream(Void);
+use super::abi::usercalls;
+
+const DEFAULT_FAKE_TTL: u32 = 64;
+
+#[derive(Debug, Clone)]
+struct Socket {
+    inner: Arc<FileDesc>,
+    local_addr: String,
+}
+
+impl Socket {
+    fn new(fd: usercalls::Fd, local_addr: String) -> Socket {
+        Socket { inner: Arc::new(FileDesc::new(fd)), local_addr }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct TcpStream {
+    inner: Socket,
+    peer_addr: String,
+}
+
+fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
+    match result {
+        Ok(saddr) => Ok(saddr.to_string()),
+        // need to downcast twice because io::Error::into_inner doesn't return the original
+        // value if the conversion fails
+        Err(e) => if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
+            Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
+        } else {
+            Err(e)
+        }
+    }
+}
+
+fn addr_to_sockaddr(addr: &str) -> io::Result<SocketAddr> {
+    // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
+    addr.to_socket_addrs().map(|mut it| it.next().unwrap())
+}
 
 impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        unsupported()
+    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        let addr = io_err_to_addr(addr)?;
+        let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
+        Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr })
     }
 
-    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
-        unsupported()
+    pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        Self::connect(Ok(addr)) // FIXME: ignoring timeout
     }
 
     pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
+        sgx_ineffective(None)
     }
 
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
+        sgx_ineffective(None)
     }
 
     pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
+        Ok(0)
     }
 
-    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.inner.read(buf)
     }
 
-    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        match self.0 {}
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.inner.inner.write(buf)
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
+        addr_to_sockaddr(&self.peer_addr)
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
+        addr_to_sockaddr(&self.inner.local_addr)
     }
 
     pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn duplicate(&self) -> io::Result<TcpStream> {
-        match self.0 {}
+        Ok(self.clone())
     }
 
     pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn nodelay(&self) -> io::Result<bool> {
-        match self.0 {}
+        sgx_ineffective(false)
     }
 
     pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn ttl(&self) -> io::Result<u32> {
-        match self.0 {}
+        sgx_ineffective(DEFAULT_FAKE_TTL)
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match self.0 {}
+        Ok(None)
     }
 
     pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 }
 
-impl fmt::Debug for TcpStream {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
-        match self.0 {}
-    }
+#[derive(Debug, Clone)]
+pub struct TcpListener {
+    inner: Socket,
 }
 
-pub struct TcpListener(Void);
-
 impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        unsupported()
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        let addr = io_err_to_addr(addr)?;
+        let (fd, local_addr) = usercalls::bind_stream(&addr)?;
+        Ok(TcpListener { inner: Socket::new(fd, local_addr) })
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
+        addr_to_sockaddr(&self.inner.local_addr)
     }
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        match self.0 {}
+        let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?;
+        let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into());
+        Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer))
     }
 
     pub fn duplicate(&self) -> io::Result<TcpListener> {
-        match self.0 {}
+        Ok(self.clone())
     }
 
     pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn ttl(&self) -> io::Result<u32> {
-        match self.0 {}
+        sgx_ineffective(DEFAULT_FAKE_TTL)
     }
 
     pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
+        sgx_ineffective(())
     }
 
     pub fn only_v6(&self) -> io::Result<bool> {
-        match self.0 {}
+        sgx_ineffective(false)
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match self.0 {}
+        Ok(None)
     }
 
     pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for TcpListener {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
-        match self.0 {}
+        sgx_ineffective(())
     }
 }
 
@@ -285,9 +323,30 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+#[derive(Debug)]
+pub struct NonIpSockAddr {
+    host: String
+}
+
+impl error::Error for NonIpSockAddr {
+    fn description(&self) -> &str {
+        "Failed to convert address to SocketAddr"
+    }
+}
+
+impl fmt::Display for NonIpSockAddr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Failed to convert address to SocketAddr: {}", self.host)
+    }
+}
+
 pub struct LookupHost(Void);
 
 impl LookupHost {
+    fn new(host: String) -> io::Result<LookupHost> {
+        Err(io::Error::new(io::ErrorKind::Other, NonIpSockAddr { host }))
+    }
+
     pub fn port(&self) -> u16 {
         match self.0 {}
     }
@@ -303,16 +362,16 @@ fn next(&mut self) -> Option<SocketAddr> {
 impl<'a> TryFrom<&'a str> for LookupHost {
     type Error = io::Error;
 
-    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
-        unsupported()
+    fn try_from(v: &'a str) -> io::Result<LookupHost> {
+        LookupHost::new(v.to_owned())
     }
 }
 
 impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
     type Error = io::Error;
 
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
+    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+        LookupHost::new(format!("{}:{}", host, port))
     }
 }