implement SocketFile. pass socket test

This commit is contained in:
WangRunji 2019-04-03 01:06:46 +08:00
parent 0dda84d7f2
commit 5b90d90643
9 changed files with 258 additions and 17 deletions

@ -64,7 +64,7 @@ fn parse_arguments(
// TODO: make sure do_boot can only be called once // TODO: make sure do_boot can only be called once
fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> { fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
info!("boot: path: {:?}, argv: {:?}", path_str, argv); // info!("boot: path: {:?}, argv: {:?}", path_str, argv);
util::mpx_util::mpx_enable()?; util::mpx_util::mpx_enable()?;
let envp = std::vec::Vec::new(); let envp = std::vec::Vec::new();

@ -39,6 +39,7 @@ impl fmt::Display for Error {
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum Errno { pub enum Errno {
EUNDEF = 0, EUNDEF = 0,
EPERM = 1, EPERM = 1,
@ -86,6 +87,14 @@ impl Errno {
pub fn as_retval(&self) -> i32 { pub fn as_retval(&self) -> i32 {
-(*self as 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 { impl fmt::Display for Errno {

@ -3,8 +3,9 @@ use std;
use std::borrow::BorrowMut; use std::borrow::BorrowMut;
use std::fmt; use std::fmt;
use std::io::SeekFrom; 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<usize, Error>; fn read(&self, buf: &mut [u8]) -> Result<usize, Error>;
fn write(&self, buf: &[u8]) -> Result<usize, Error>; fn write(&self, buf: &[u8]) -> Result<usize, Error>;
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error>;
@ -17,6 +18,7 @@ pub trait File: Debug + Sync + Send {
fn sync_all(&self) -> Result<(), Error>; fn sync_all(&self) -> Result<(), Error>;
fn sync_data(&self) -> Result<(), Error>; fn sync_data(&self) -> Result<(), Error>;
fn read_entry(&self) -> Result<String, Error>; fn read_entry(&self) -> Result<String, Error>;
fn as_any(&self) -> &Any { unimplemented!() }
} }
pub type FileRef = Arc<Box<File>>; pub type FileRef = Arc<Box<File>>;

@ -9,12 +9,14 @@ use super::*;
pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile};
pub use self::file_table::{FileDesc, FileTable}; pub use self::file_table::{FileDesc, FileTable};
pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE};
pub use self::socket_file::SocketFile;
use self::inode_file::OpenOptions; use self::inode_file::OpenOptions;
pub use self::pipe::Pipe; pub use self::pipe::Pipe;
mod file; mod file;
mod file_table; mod file_table;
mod inode_file; mod inode_file;
mod socket_file;
mod pipe; mod pipe;
mod sgx_impl; mod sgx_impl;
@ -206,6 +208,7 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
} }
pub fn do_close(fd: FileDesc) -> Result<(), Error> { pub fn do_close(fd: FileDesc) -> Result<(), Error> {
info!("close: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
let file_table_ref = current_process.get_files(); let file_table_ref = current_process.get_files();

@ -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<Self, Error> {
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<Self, Error> {
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<usize, Error> {
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<usize, Error> {
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<usize, Error> {
unimplemented!()
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> {
unimplemented!()
}
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
unimplemented!()
}
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> {
unimplemented!()
}
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Socket does not support seek"))
}
fn metadata(&self) -> Result<Metadata, Error> {
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<String, Error> {
unimplemented!()
}
fn as_any(&self) -> &Any {
self
}
}

@ -7,8 +7,7 @@
//! 3. Dispatch the syscall to `do_*` (at this file) //! 3. Dispatch the syscall to `do_*` (at this file)
//! 4. Do some memory checks then call `mod::do_*` (at each module) //! 4. Do some memory checks then call `mod::do_*` (at each module)
use fs::File; use fs::{File, SocketFile, off_t, FileDesc, FileRef};
use fs::{off_t, FileDesc};
use prelude::*; use prelude::*;
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
@ -21,6 +20,7 @@ use {fs, process, std, vm};
use super::*; use super::*;
use self::consts::*; use self::consts::*;
use std::any::Any;
// Use the internal syscall wrappers from sgx_tstd // Use the internal syscall wrappers from sgx_tstd
//use std::libc_fs as fs; //use std::libc_fs as fs;
@ -177,6 +177,22 @@ pub extern "C" fn dispatch_syscall(
arg3 as *mut c_void, arg3 as *mut c_void,
arg4 as *mut libc::socklen_t, 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), _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5),
}; };
@ -654,6 +670,7 @@ fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize, Error> {
const MAP_FAILED: *const c_void = ((-1) as i64) as *const c_void; const MAP_FAILED: *const c_void = ((-1) as i64) as *const c_void;
fn do_exit(status: i32) -> ! { fn do_exit(status: i32) -> ! {
info!("exit: {}", status);
extern "C" { extern "C" {
fn do_exit_task() -> !; fn do_exit_task() -> !;
} }
@ -749,8 +766,15 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize
"socket: domain: {}, socket_type: {}, protocol: {}", "socket: domain: {}, socket_type: {}, protocol: {}",
domain, socket_type, protocol domain, socket_type, protocol
); );
let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) };
Ok(ret as isize) let socket = SocketFile::new(domain, socket_type, protocol)?;
let file_ref: Arc<Box<File>> = 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( fn do_connect(
@ -762,7 +786,12 @@ fn do_connect(
"connect: fd: {}, addr: {:?}, addr_len: {}", "connect: fd: {}, addr: {:?}, addr_len: {}",
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) Ok(ret as isize)
} }
@ -776,13 +805,26 @@ fn do_accept(
"accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
fd, addr, addr_len, flags fd, addr, addr_len, flags
); );
let ret = unsafe { libc::ocall::accept4(fd, addr, addr_len, flags) }; let current_ref = process::get_current();
Ok(ret as isize) 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<Box<File>> = 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<isize, Error> { fn do_shutdown(fd: c_int, how: c_int) -> Result<isize, Error> {
info!("shutdown: fd: {}, how: {}", fd, how); 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) Ok(ret as isize)
} }
@ -792,13 +834,23 @@ fn do_bind(
addr_len: libc::socklen_t, addr_len: libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize, Error> {
info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len); 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) Ok(ret as isize)
} }
fn do_listen(fd: c_int, backlog: c_int) -> Result<isize, Error> { fn do_listen(fd: c_int, backlog: c_int) -> Result<isize, Error> {
info!("listen: fd: {}, backlog: {}", fd, backlog); 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) Ok(ret as isize)
} }
@ -813,7 +865,12 @@ fn do_setsockopt(
"setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", "setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
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) Ok(ret as isize)
} }
@ -828,6 +885,65 @@ fn do_getsockopt(
"getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", "getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
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) 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<isize, Error> {
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<isize, Error> {
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::<SocketFile>()
.ok_or(Error::new(Errno::EBADF, "not a socket"))
}
}

@ -23,9 +23,10 @@ impl Log for SimpleLogger {
if self.enabled(record.metadata()) { if self.enabled(record.metadata()) {
let color = Color::from(record.level()); let color = Color::from(record.level());
println!( println!(
"\u{1B}[{}m[{:>5}] {}\u{1B}[0m", "\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m",
color as u8, color as u8,
record.level(), record.level(),
crate::process::do_getpid(),
record.args() record.args()
); );
} }

@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
# Dependencies: need to be compiled but not to run by any Makefile target # Dependencies: need to be compiled but not to run by any Makefile target
TEST_DEPS := dev_null TEST_DEPS := dev_null
# Tests: need to be compiled and run by test-% target # 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 # Benchmarks: need to be compiled and run by bench-% target
BENCHES := spawn_and_exit_latency pipe_throughput BENCHES := spawn_and_exit_latency pipe_throughput

@ -14,7 +14,7 @@ int main(int argc, const char *argv[]) {
if (argc != 2) { if (argc != 2) {
printf("usage: ./client <ipaddress>\n"); printf("usage: ./client <ipaddress>\n");
return -1; return 0;
} }
int sockfd = socket(AF_INET, SOCK_STREAM, 0); int sockfd = socket(AF_INET, SOCK_STREAM, 0);