From: Jethro Beekman Date: Wed, 19 Sep 2018 22:59:06 +0000 (-0700) Subject: SGX target: implement networking X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=59b79f71e98fa96ce632d87dfb8cad0d9707bf9d;p=rust.git SGX target: implement networking --- diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index b8d739f4d2f..3614e1293c1 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -55,6 +55,61 @@ pub fn close(fd: Fd) { unsafe { raw::close(fd) } } +fn string_from_bytebuffer(buf: &alloc::UserRef, 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::::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() } } diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index 094683e28b8..176d230846d 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -10,144 +10,182 @@ 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, + 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 { + 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::()).is_some() { + Ok(e.into_inner().unwrap().downcast::().unwrap().host) + } else { + Err(e) + } + } +} + +fn addr_to_sockaddr(addr: &str) -> io::Result { + // 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 { - unsupported() + pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { + 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 { - unsupported() + pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result { + Self::connect(Ok(addr)) // FIXME: ignoring timeout } pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} + sgx_ineffective(()) } pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} + sgx_ineffective(()) } pub fn read_timeout(&self) -> io::Result> { - match self.0 {} + sgx_ineffective(None) } pub fn write_timeout(&self) -> io::Result> { - match self.0 {} + sgx_ineffective(None) } pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} + Ok(0) } - pub fn read(&self, _: &mut [u8]) -> io::Result { - match self.0 {} + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.inner.inner.read(buf) } - pub fn write(&self, _: &[u8]) -> io::Result { - match self.0 {} + pub fn write(&self, buf: &[u8]) -> io::Result { + self.inner.inner.write(buf) } pub fn peer_addr(&self) -> io::Result { - match self.0 {} + addr_to_sockaddr(&self.peer_addr) } pub fn socket_addr(&self) -> io::Result { - 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 { - 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 { - 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 { - match self.0 {} + sgx_ineffective(DEFAULT_FAKE_TTL) } pub fn take_error(&self) -> io::Result> { - 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 { - unsupported() + pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { + 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 { - 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 { - 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 { - 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 { - match self.0 {} + sgx_ineffective(false) } pub fn take_error(&self) -> io::Result> { - 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 { + 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 { impl<'a> TryFrom<&'a str> for LookupHost { type Error = io::Error; - fn try_from(_v: &'a str) -> io::Result { - unsupported() + fn try_from(v: &'a str) -> io::Result { + 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 { - unsupported() + fn try_from((host, port): (&'a str, u16)) -> io::Result { + LookupHost::new(format!("{}:{}", host, port)) } }