From 6124cd60fc4dea112649b934457ce01b1fe137f5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 28 Feb 2019 14:46:46 +0800 Subject: [PATCH] Add basic implementation for syscall: connect and write --- kernel/Cargo.toml | 2 +- kernel/src/process/structs.rs | 22 +++- kernel/src/syscall/fs.rs | 22 +++- kernel/src/syscall/mod.rs | 28 ++++- kernel/src/syscall/net.rs | 203 +++++++++++++++++++++++++++++++--- 5 files changed, 251 insertions(+), 26 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index ac4be57..b8b5d68 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -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" } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index ff43a47..ae64823 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -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>, } +#[derive(Clone)] +pub enum FileLike { + File(FileHandle), + Socket(SocketHandle) +} + pub struct Process { pub memory_set: MemorySet, - pub files: BTreeMap, + pub files: BTreeMap, 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![]) })), }) } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 215a4ad..9139dac 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -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 for SysError { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 8c07a03..a62d576 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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)] diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index fa80a54..6bbe6d6 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -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::() { + 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::(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::(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) } -} \ No newline at end of file +} + +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) +}