SGX target: implement networking
This commit is contained in:
parent
1a894f135e
commit
59b79f71e9
@ -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() }
|
||||
}
|
||||
|
@ -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<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))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user