Add basic implementation for syscall: connect and write

toolchain_update
Jiajie Chen 6 years ago
parent 984df11971
commit 6124cd60fc

@ -51,7 +51,7 @@ volatile = "0.2"
linked_list_allocator = "0.6"
device_tree = { git = "https://github.com/jiegec/device_tree-rs" }
lazy_static = { version = "1.2", features = ["spin_no_std"] }
smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp"] }
smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
bit-allocator = { path = "../crate/bit-allocator" }
rcore-memory = { path = "../crate/memory" }
rcore-thread = { path = "../crate/thread" }

@ -4,6 +4,7 @@ use log::*;
use rcore_fs::vfs::INode;
use spin::Mutex;
use xmas_elf::{ElfFile, header, program::{Flags, Type}};
use smoltcp::socket::{SocketSet, SocketHandle};
use crate::arch::interrupt::{Context, TrapFrame};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
@ -18,10 +19,18 @@ pub struct Thread {
pub proc: Arc<Mutex<Process>>,
}
#[derive(Clone)]
pub enum FileLike {
File(FileHandle),
Socket(SocketHandle)
}
pub struct Process {
pub memory_set: MemorySet,
pub files: BTreeMap<usize, FileHandle>,
pub files: BTreeMap<usize, FileLike>,
pub cwd: String,
// TODO: discuss: move it to interface or leave it here
pub sockets: SocketSet<'static, 'static, 'static>,
}
/// Let `rcore_thread` can switch between our `Thread`
@ -43,6 +52,7 @@ impl Thread {
memory_set: MemorySet::new(),
files: BTreeMap::default(),
cwd: String::new(),
sockets: SocketSet::new(vec![])
})),
})
}
@ -58,6 +68,7 @@ impl Thread {
memory_set,
files: BTreeMap::default(),
cwd: String::new(),
sockets: SocketSet::new(vec![])
})),
})
}
@ -122,9 +133,9 @@ impl Thread {
let kstack = KernelStack::new();
let mut files = BTreeMap::new();
files.insert(0, FileHandle::new(crate::fs::STDIN.clone(), OpenOptions { read: true, write: false, append: false }));
files.insert(1, FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }));
files.insert(2, FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }));
files.insert(0, FileLike::File(FileHandle::new(crate::fs::STDIN.clone(), OpenOptions { read: true, write: false, append: false })));
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
Box::new(Thread {
context: unsafe {
@ -136,6 +147,7 @@ impl Thread {
memory_set,
files,
cwd: String::new(),
sockets: SocketSet::new(vec![])
})),
})
}
@ -167,6 +179,8 @@ impl Thread {
memory_set,
files: self.proc.lock().files.clone(),
cwd: String::new(),
// TODO: duplicate sockets for child process
sockets: SocketSet::new(vec![])
})),
})
}

@ -6,6 +6,7 @@ use crate::fs::*;
use crate::memory::MemorySet;
use super::*;
use super::net::*;
pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
@ -24,8 +25,16 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
if !proc.memory_set.check_array(base, len) {
return Err(SysError::EINVAL);
}
match proc.files.get(&fd) {
Some(FileLike::File(_)) => sys_write_file(&mut proc, fd, base, len),
Some(FileLike::Socket(_)) => sys_write_socket(&mut proc, fd, base, len),
None => Err(SysError::EINVAL)
}
}
pub fn sys_write_file(proc: &mut MutexGuard<'static, Process>, fd: usize, base: *const u8, len: usize) -> SysResult {
let slice = unsafe { slice::from_raw_parts(base, len) };
let len = get_file(&mut proc, fd)?.write(slice)?;
let len = get_file(proc, fd)?.write(slice)?;
Ok(len as isize)
}
@ -92,7 +101,7 @@ pub fn sys_open(path: *const u8, flags: usize, mode: usize) -> SysResult {
let fd = proc.get_free_inode();
let file = FileHandle::new(inode, flags.to_options());
proc.files.insert(fd, file);
proc.files.insert(fd, FileLike::File(file));
Ok(fd as isize)
}
@ -176,12 +185,17 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
return Err(SysError::EINVAL);
}
let file = get_file(&mut proc, fd1)?.clone();
proc.files.insert(fd2, file);
proc.files.insert(fd2, FileLike::File(file));
Ok(0)
}
fn get_file<'a>(proc: &'a mut MutexGuard<'static, Process>, fd: usize) -> Result<&'a mut FileHandle, SysError> {
proc.files.get_mut(&fd).ok_or(SysError::EINVAL)
proc.files.get_mut(&fd).ok_or(SysError::EINVAL).and_then(|f| {
match f {
FileLike::File(file) => Ok(file),
_ => Err(SysError::EINVAL)
}
})
}
impl From<FsError> for SysError {

@ -51,16 +51,16 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
039 => sys_getpid(),
// 040 => sys_getppid(),
041 => sys_socket(args[0], args[1], args[2]),
// 042 => sys_connect(),
042 => sys_connect(args[0], args[1] as *const u8, args[2]),
// 043 => sys_accept(),
// 044 => sys_sendto(),
// 045 => sys_recvfrom(),
044 => sys_sendto(args[0], args[1] as *const u8, args[2], args[3], args[4] as *const u8, args[5]),
045 => sys_recvfrom(args[0], args[1] as *mut u8, args[2], args[3], args[4] as *const u8, args[5]),
// 046 => sys_sendmsg(),
// 047 => sys_recvmsg(),
// 048 => sys_shutdown(),
// 049 => sys_bind(),
// 050 => sys_listen(),
// 054 => sys_setsockopt(),
054 => sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]),
// 055 => sys_getsockopt(),
// 056 => sys_clone(),
057 => sys_fork(tf),
@ -106,10 +106,22 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
warn!("sys_ioctl is unimplemented");
Ok(0)
}
037 => {
warn!("sys_alarm is unimplemented");
Ok(0)
}
072 => {
warn!("sys_fcntl is unimplemented");
Ok(0)
}
102 => {
warn!("sys_getuid is unimplemented");
Ok(0)
}
105 => {
warn!("sys_setuid is unimplemented");
Ok(0)
}
107 => {
warn!("sys_geteuid is unimplemented");
Ok(0)
@ -136,6 +148,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
crate::trap::error(tf);
}
};
debug!("syscall id {} ret with {:?}", id, ret);
match ret {
Ok(code) => code,
Err(err) => -(err as isize),
@ -188,6 +201,13 @@ pub enum SysError {
ENOLCK = 37,
ENOSYS = 38,
ENOTEMPTY = 39,
ENOTSOCK = 80,
EPFNOSUPPORT = 96,
EAFNOSUPPORT = 97,
ENOBUFS = 105,
EISCONN = 106,
ENOTCONN = 107,
ECONNREFUSED = 111,
}
#[allow(non_snake_case)]

@ -1,29 +1,206 @@
//! Syscalls for networking
use super::*;
use crate::drivers::NET_DRIVERS;
use core::mem::size_of;
use smoltcp::socket::*;
use smoltcp::wire::*;
const AF_INET: usize = 2;
const SOCK_STREAM: usize = 1;
const SOCK_DGRAM: usize = 2;
const SOCK_RAW: usize = 3;
const IPPROTO_IP: usize = 0;
const IPPROTO_ICMP: usize = 1;
pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult {
info!("socket: domain: {}, socket_type: {:?}, protocol: {:#x}", domain, socket_type, protocol);
info!(
"socket: domain: {}, socket_type: {}, protocol: {}",
domain, socket_type, protocol
);
let mut proc = process();
match domain {
AF_INET => {
return match socket_type {
SOCK_STREAM => {
let fd = proc.get_free_inode();
AF_INET => match socket_type {
SOCK_STREAM => {
let fd = proc.get_free_inode();
Ok(fd as isize)
}
_ => {
Err(SysError::EINVAL)
}
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 2048]);
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 2048]);
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
let tcp_handle = proc.sockets.add(tcp_socket);
proc.files.insert(fd, FileLike::Socket(tcp_handle));
Ok(fd as isize)
}
SOCK_RAW => {
let fd = proc.get_free_inode();
let raw_rx_buffer =
RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; 2], vec![0; 2048]);
let raw_tx_buffer =
RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; 2], vec![0; 2048]);
let raw_socket = RawSocket::new(
IpVersion::Ipv4,
IpProtocol::from(protocol as u8),
raw_rx_buffer,
raw_tx_buffer,
);
let raw_handle = proc.sockets.add(raw_socket);
proc.files.insert(fd, FileLike::Socket(raw_handle));
Ok(fd as isize)
}
_ => Err(SysError::EINVAL),
},
_ => Err(SysError::EAFNOSUPPORT),
}
}
pub fn sys_setsockopt(
fd: usize,
level: usize,
optname: usize,
optval: *const u8,
optlen: usize,
) -> SysResult {
info!(
"setsockopt: fd: {}, level: {}, optname: {}",
fd, level, optname
);
warn!("sys_setsockopt is unimplemented");
Ok(0)
}
#[repr(C)]
struct SockaddrIn {
sin_family: u16,
sin_port: u16,
sin_addr: u32,
sin_zero: [u8; 8],
}
pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult {
info!(
"sys_connect: fd: {}, addr: {:?}, addrlen: {}",
fd, addr, addrlen
);
let mut dest = None;
let mut port = 0;
if addrlen == size_of::<SockaddrIn>() {
let sockaddr_in = unsafe { &*(addr as *const SockaddrIn) };
port = ((sockaddr_in.sin_port & 0xFF) << 8) | (sockaddr_in.sin_port >> 8);
dest = Some(IpAddress::v4(
(sockaddr_in.sin_addr & 0xFF) as u8,
((sockaddr_in.sin_addr >> 8) & 0xFF) as u8,
((sockaddr_in.sin_addr >> 16) & 0xFF) as u8,
(sockaddr_in.sin_addr >> 24) as u8,
));
}
if dest == None {
return Err(SysError::EINVAL);
}
let mut proc = process();
// little hack: kick it forward
let iface = &mut *NET_DRIVERS.lock()[0];
iface.poll(&mut proc.sockets);
if let Some(FileLike::Socket(handle)) = proc.files.get(&fd) {
// TODO: check its type
let tcp_handle = (*handle).clone();
let mut socket = proc.sockets.get::<TcpSocket>(tcp_handle);
// TODO selects non-conflict high port
static mut ephermeral_port: u16 = 49152;
let temp_port = unsafe {
if ephermeral_port == 65535 {
ephermeral_port = 49152;
} else {
ephermeral_port = ephermeral_port + 1;
}
ephermeral_port
};
match socket.connect((dest.unwrap(), port), temp_port) {
Ok(()) => Ok(0),
Err(_) => Err(SysError::EISCONN),
}
_ => {
return Err(SysError::EINVAL);
} else {
Err(SysError::ENOTSOCK)
}
}
pub fn sys_write_socket(
proc: &mut MutexGuard<'static, Process>,
fd: usize,
base: *const u8,
len: usize,
) -> SysResult {
// little hack: kick it forward
let iface = &mut *NET_DRIVERS.lock()[0];
iface.poll(&mut proc.sockets);
if let Some(FileLike::Socket(handle)) = proc.files.get(&fd) {
// TODO: check its type
let tcp_handle = (*handle).clone();
let mut socket = proc.sockets.get::<TcpSocket>(tcp_handle);
let slice = unsafe { slice::from_raw_parts(base, len) };
if socket.is_open() {
if socket.can_send() {
match socket.send_slice(&slice) {
Ok(size) => Ok(size as isize),
Err(err) => Err(SysError::ENOBUFS)
}
} else {
Err(SysError::ENOBUFS)
}
} else {
Err(SysError::ECONNREFUSED)
}
} else {
Err(SysError::ENOTSOCK)
}
}
}
pub fn sys_select(
fd: usize,
inp: *const u8,
outp: *const u8,
exp: *const u8,
tvp: *const u8,
) -> SysResult {
info!("sys_select: fd: {}", fd);
warn!("sys_select is unimplemented");
Err(SysError::EINVAL)
}
pub fn sys_sendto(
fd: usize,
buffer: *const u8,
len: usize,
flags: usize,
addr: *const u8,
addr_len: usize,
) -> SysResult {
info!("sys_sendto: fd: {} buffer: {:?} len: {}", fd, buffer, len);
warn!("sys_sendto is unimplemented");
Err(SysError::EINVAL)
}
pub fn sys_recvfrom(
fd: usize,
buffer: *mut u8,
len: usize,
flags: usize,
addr: *const u8,
addr_len: usize,
) -> SysResult {
info!("sys_recvfrom: fd: {} buffer: {:?} len: {}", fd, buffer, len);
warn!("sys_recvfrom is unimplemented");
Err(SysError::EINVAL)
}

Loading…
Cancel
Save