diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index f0de3087..719c07e0 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -64,7 +64,7 @@ fn parse_arguments( // TODO: make sure do_boot can only be called once fn do_boot(path_str: &str, argv: &Vec) -> Result<(), Error> { - info!("boot: path: {:?}, argv: {:?}", path_str, argv); +// info!("boot: path: {:?}, argv: {:?}", path_str, argv); util::mpx_util::mpx_enable()?; let envp = std::vec::Vec::new(); diff --git a/src/libos/src/errno.rs b/src/libos/src/errno.rs index 9957fd1a..3abfec08 100644 --- a/src/libos/src/errno.rs +++ b/src/libos/src/errno.rs @@ -39,6 +39,7 @@ impl fmt::Display for Error { } #[derive(Clone, Copy, Debug, PartialEq)] +#[repr(u8)] pub enum Errno { EUNDEF = 0, EPERM = 1, @@ -86,6 +87,14 @@ impl Errno { pub fn as_retval(&self) -> i32 { -(*self as i32) } + pub fn from_retval(ret: i32) -> Self { + let ret = if ret <= 0 && ret >= -39 { + (-ret) as u8 + } else { + 0 + }; + unsafe { core::mem::transmute(ret) } + } } impl fmt::Display for Errno { diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 79d0e415..3dbb71ad 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -3,8 +3,9 @@ use std; use std::borrow::BorrowMut; use std::fmt; use std::io::SeekFrom; +use std::any::Any; -pub trait File: Debug + Sync + Send { +pub trait File: Debug + Sync + Send + Any { fn read(&self, buf: &mut [u8]) -> Result; fn write(&self, buf: &[u8]) -> Result; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result; @@ -17,6 +18,7 @@ pub trait File: Debug + Sync + Send { fn sync_all(&self) -> Result<(), Error>; fn sync_data(&self) -> Result<(), Error>; fn read_entry(&self) -> Result; + fn as_any(&self) -> &Any { unimplemented!() } } pub type FileRef = Arc>; diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 162f7062..cdaff66d 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -9,12 +9,14 @@ use super::*; pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; pub use self::file_table::{FileDesc, FileTable}; pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; +pub use self::socket_file::SocketFile; use self::inode_file::OpenOptions; pub use self::pipe::Pipe; mod file; mod file_table; mod inode_file; +mod socket_file; mod pipe; mod sgx_impl; @@ -206,6 +208,7 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result { } pub fn do_close(fd: FileDesc) -> Result<(), Error> { + info!("close: fd: {}", fd); let current_ref = process::get_current(); let current_process = current_ref.lock().unwrap(); let file_table_ref = current_process.get_files(); diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs new file mode 100644 index 00000000..97471e94 --- /dev/null +++ b/src/libos/src/fs/socket_file.rs @@ -0,0 +1,110 @@ +use super::*; +use std::any::Any; + +/// Native Linux socket +#[derive(Debug)] +pub struct SocketFile { + fd: c_int, +} + +impl SocketFile { + pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { + let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(SocketFile { fd: ret }) + } + } + + pub fn accept( + &self, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, + flags: c_int, + ) -> Result { + let ret = unsafe { libc::ocall::accept4(self.fd, addr, addr_len, flags) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(SocketFile { fd: ret }) + } + } + + pub fn fd(&self) -> c_int { + self.fd + } +} + +impl Drop for SocketFile { + fn drop(&mut self) { + let ret = unsafe { libc::ocall::close(self.fd) }; + if ret < 0 { + warn!("socket (host fd: {}) close failed", self.fd); + } + } +} + +impl File for SocketFile { + fn read(&self, buf: &mut [u8]) -> Result { + let ret = unsafe { libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(ret as usize) + } + } + + fn write(&self, buf: &[u8]) -> Result { + let ret = unsafe { libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len()) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(ret as usize) + } + } + + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + unimplemented!() + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + unimplemented!() + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + unimplemented!() + } + + fn seek(&self, pos: SeekFrom) -> Result { + Err(Error::new(Errno::ESPIPE, "Socket does not support seek")) + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + unimplemented!() + } + + fn sync_all(&self) -> Result<(), Error> { + unimplemented!() + } + + fn sync_data(&self) -> Result<(), Error> { + unimplemented!() + } + + fn read_entry(&self) -> Result { + unimplemented!() + } + + fn as_any(&self) -> &Any { + self + } +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index fe6ef772..1293aba5 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,8 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::File; -use fs::{off_t, FileDesc}; +use fs::{File, SocketFile, off_t, FileDesc, FileRef}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; @@ -21,6 +20,7 @@ use {fs, process, std, vm}; use super::*; use self::consts::*; +use std::any::Any; // Use the internal syscall wrappers from sgx_tstd //use std::libc_fs as fs; @@ -177,6 +177,22 @@ pub extern "C" fn dispatch_syscall( arg3 as *mut c_void, arg4 as *mut libc::socklen_t, ), + SYS_SENDTO => do_sendto( + arg0 as c_int, + arg1 as *const c_void, + arg2 as size_t, + arg3 as c_int, + arg4 as *const libc::sockaddr, + arg5 as libc::socklen_t, + ), + SYS_RECVFROM => do_recvfrom( + arg0 as c_int, + arg1 as *mut c_void, + arg2 as size_t, + arg3 as c_int, + arg4 as *mut libc::sockaddr, + arg5 as *mut libc::socklen_t, + ), _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; @@ -654,6 +670,7 @@ fn do_gettimeofday(tv_u: *mut timeval_t) -> Result { const MAP_FAILED: *const c_void = ((-1) as i64) as *const c_void; fn do_exit(status: i32) -> ! { + info!("exit: {}", status); extern "C" { fn do_exit_task() -> !; } @@ -749,8 +766,15 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result> = Arc::new(Box::new(socket)); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + + let fd = proc.get_files().lock().unwrap().put(file_ref, false); + Ok(fd as isize) } fn do_connect( @@ -762,7 +786,12 @@ fn do_connect( "connect: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len ); - let ret = unsafe { libc::ocall::connect(fd, addr, addr_len) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::connect(socket.fd(), addr, addr_len) }; Ok(ret as isize) } @@ -776,13 +805,26 @@ fn do_accept( "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", fd, addr, addr_len, flags ); - let ret = unsafe { libc::ocall::accept4(fd, addr, addr_len, flags) }; - Ok(ret as isize) + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let new_socket = socket.accept(addr, addr_len, flags)?; + let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); + let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); + + Ok(new_fd as isize) } fn do_shutdown(fd: c_int, how: c_int) -> Result { info!("shutdown: fd: {}, how: {}", fd, how); - let ret = unsafe { libc::ocall::shutdown(fd, how) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::shutdown(socket.fd(), how) }; Ok(ret as isize) } @@ -792,13 +834,23 @@ fn do_bind( addr_len: libc::socklen_t, ) -> Result { info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len); - let ret = unsafe { libc::ocall::bind(fd, addr, addr_len) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::bind(socket.fd(), addr, addr_len) }; Ok(ret as isize) } fn do_listen(fd: c_int, backlog: c_int) -> Result { info!("listen: fd: {}, backlog: {}", fd, backlog); - let ret = unsafe { libc::ocall::listen(fd, backlog) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::listen(socket.fd(), backlog) }; Ok(ret as isize) } @@ -813,7 +865,12 @@ fn do_setsockopt( "setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", fd, level, optname, optval, optlen ); - let ret = unsafe { libc::ocall::setsockopt(fd, level, optname, optval, optlen) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::setsockopt(socket.fd(), level, optname, optval, optlen) }; Ok(ret as isize) } @@ -828,6 +885,65 @@ fn do_getsockopt( "getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", fd, level, optname, optval, optlen ); - let ret = unsafe { libc::ocall::getsockopt(fd, level, optname, optval, optlen) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::getsockopt(socket.fd(), level, optname, optval, optlen) }; Ok(ret as isize) } + +fn do_sendto( + fd: c_int, + base: *const c_void, + len: size_t, + flags: c_int, + addr: *const libc::sockaddr, + addr_len: libc::socklen_t, +) -> Result { + info!( + "sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}", + fd, base, len, addr, addr_len + ); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::sendto(socket.fd(), base, len, flags, addr, addr_len) }; + Ok(ret as isize) +} + +fn do_recvfrom( + fd: c_int, + base: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, +) -> Result { + info!( + "recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}", + fd, base, len, flags, addr, addr_len + ); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::recvfrom(socket.fd(), base, len, flags, addr, addr_len) }; + Ok(ret as isize) +} + +trait AsSocket { + fn as_socket(&self) -> Result<&SocketFile, Error>; +} + +impl AsSocket for FileRef { + fn as_socket(&self) -> Result<&SocketFile, Error> { + self.as_any() + .downcast_ref::() + .ok_or(Error::new(Errno::EBADF, "not a socket")) + } +} diff --git a/src/libos/src/util/log.rs b/src/libos/src/util/log.rs index ee21aff1..302dd3db 100644 --- a/src/libos/src/util/log.rs +++ b/src/libos/src/util/log.rs @@ -23,9 +23,10 @@ impl Log for SimpleLogger { if self.enabled(record.metadata()) { let color = Color::from(record.level()); println!( - "\u{1B}[{}m[{:>5}] {}\u{1B}[0m", + "\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m", color as u8, record.level(), + crate::process::do_getpid(), record.args() ); } diff --git a/test/Makefile b/test/Makefile index 280ee50e..d53d3a5d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread clone server +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread client server # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/client/main.c b/test/client/main.c index 844a79df..558aa580 100644 --- a/test/client/main.c +++ b/test/client/main.c @@ -14,7 +14,7 @@ int main(int argc, const char *argv[]) { if (argc != 2) { printf("usage: ./client \n"); - return -1; + return 0; } int sockfd = socket(AF_INET, SOCK_STREAM, 0);