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() }
}
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(())
}
}
}
}
+#[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 {}
}
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))
}
}