From c01e185651c7d2a60fbbcb72e005733417a6bb78 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 7 Jul 2023 23:12:36 +0200 Subject: [PATCH 01/37] Add connect syscall --- doc/syscalls.md | 6 +++++ src/api/syscall.rs | 11 +++++++++ src/sys/syscall/mod.rs | 14 ++++++++++- src/sys/syscall/number.rs | 1 + src/sys/syscall/service.rs | 49 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/doc/syscalls.md b/doc/syscalls.md index 34497c16..2c289334 100644 --- a/doc/syscalls.md +++ b/doc/syscalls.md @@ -69,3 +69,9 @@ The system will reboot with `0xcafe` and halt with `0xdead`. ```rust pub fn sleep(seconds: f64) ``` + +## CONNECT (0xC) + +```rust +pub fn connect(handle, usize, addr: &str, port: u16) -> isize +``` diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 6d2faa4c..76a2627d 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -106,6 +106,17 @@ pub fn halt() { stop(0xdead); } +pub fn connect(handle: usize, addr: &str, port: u16) -> Result<(), ()> { + let ptr = addr.as_ptr() as usize; + let len = addr.len(); + let res = unsafe { syscall!(CONNECT, handle, ptr, len, port) } as isize; + if res >= 0 { + Ok(()) + } else { + Err(()) + } +} + #[test_case] fn test_file() { use crate::sys::fs::{mount_mem, format_mem, dismount, OpenFlag}; diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index b7f24b2a..ce78f4fc 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -6,6 +6,8 @@ use crate::sys; use crate::sys::fs::FileInfo; use core::arch::asm; +use smoltcp::wire::IpAddress; +use core::str::FromStr; /* * Dispatching system calls @@ -75,7 +77,17 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) service::spawn(path, args_ptr, args_len) as usize } number::STOP => { - service::stop(arg1) + let code = arg1; + service::stop(code) + } + number::CONNECT => { + let handle = arg1; + let addr_ptr = sys::process::ptr_from_addr(arg2 as u64); + let addr_len = arg3; + let addr_str = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(addr_ptr, addr_len)) }; + let addr = IpAddress::from_str(&addr_str).expect("invalid address format"); + let port = arg4 as u16; + service::connect(handle, addr, port) as usize } _ => { unimplemented!(); diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index b7b5c532..6a3883ab 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -9,3 +9,4 @@ pub const DUP: usize = 0x8; pub const DELETE: usize = 0x9; pub const STOP: usize = 0xA; pub const SLEEP: usize = 0xB; +pub const CONNECT: usize = 0xC; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 54e08d78..e80cccd0 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -6,6 +6,11 @@ use crate::sys::process::Process; use alloc::vec; use core::arch::asm; +use smoltcp::time::Instant; +use smoltcp::wire::IpAddress; +use crate::sys::net::SOCKETS; +use crate::sys::fs::Device; +use smoltcp::socket::tcp; pub fn exit(code: ExitCode) -> ExitCode { sys::process::exit(); @@ -124,3 +129,47 @@ pub fn stop(code: usize) -> usize { } 0 } + +pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { + let timeout = 5.0; + let started = sys::clock::realtime(); + if let Some(file) = sys::process::file_handle(handle) { + if let sys::fs::Resource::Device(Device::TcpSocket(dev)) = *file { + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + loop { + if sys::clock::realtime() - started > timeout { + return -1; + } + let mut sockets = SOCKETS.lock(); + let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); + iface.poll(time, device, &mut sockets); + let socket = sockets.get_mut::(dev.handle); + let cx = iface.context(); + + match socket.state() { + tcp::State::Closed => { + let local_port = 49152 + sys::random::get_u16() % 16384; + if socket.connect(cx, (addr, port), local_port).is_err() { + return -1; + } + } + tcp::State::SynSent => { + } + tcp::State::Established => { + break; + } + _ => { + return -1; + } + } + + if let Some(wait_duration) = iface.poll_delay(time, &sockets) { + sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + } + sys::time::halt(); + } + } + } + } + 0 +} From 96f9676d5c75bc75e73fb4bfa7c643e11dcaa394 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 7 Jul 2023 23:14:46 +0200 Subject: [PATCH 02/37] Add tcp socket device --- src/sys/fs/device.rs | 59 +++++++++++++++------------ src/sys/net/mod.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++ src/usr/install.rs | 4 +- 3 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index b5d81bcc..c7d15cfd 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -7,6 +7,7 @@ use crate::sys::cmos::RTC; use crate::sys::console::Console; use crate::sys::random::Random; use crate::sys::clock::{Uptime, Realtime}; +use crate::sys::net::TcpSocket; use alloc::vec; use alloc::vec::Vec; @@ -14,24 +15,26 @@ use alloc::vec::Vec; #[derive(PartialEq, Eq, Clone, Copy)] #[repr(u8)] pub enum DeviceType { - Null = 0, - File = 1, - Console = 2, - Random = 3, - Uptime = 4, - Realtime = 5, - RTC = 6, + Null = 0, + File = 1, + Console = 2, + Random = 3, + Uptime = 4, + Realtime = 5, + RTC = 6, + TcpSocket = 7, } // Used when creating a device impl DeviceType { pub fn buf(self) -> Vec { let len = match self { - DeviceType::RTC => RTC::size(), - DeviceType::Uptime => Uptime::size(), - DeviceType::Realtime => Realtime::size(), - DeviceType::Console => Console::size(), - _ => 1, + DeviceType::RTC => RTC::size(), + DeviceType::Uptime => Uptime::size(), + DeviceType::Realtime => Realtime::size(), + DeviceType::Console => Console::size(), + DeviceType::TcpSocket => RTC::size(), + _ => 1, }; let mut res = vec![0; len]; res[0] = self as u8; @@ -48,6 +51,7 @@ pub enum Device { Uptime(Uptime), Realtime(Realtime), RTC(RTC), + TcpSocket(TcpSocket), } impl From for Device { @@ -60,6 +64,7 @@ impl From for Device { i if i == DeviceType::Uptime as u8 => Device::Uptime(Uptime::new()), i if i == DeviceType::Realtime as u8 => Device::Realtime(Realtime::new()), i if i == DeviceType::RTC as u8 => Device::RTC(RTC::new()), + i if i == DeviceType::TcpSocket as u8 => Device::TcpSocket(TcpSocket::new()), _ => unimplemented!(), } } @@ -100,25 +105,27 @@ impl Device { impl FileIO for Device { fn read(&mut self, buf: &mut [u8]) -> Result { match self { - Device::Null => Err(()), - Device::File(io) => io.read(buf), - Device::Console(io) => io.read(buf), - Device::Random(io) => io.read(buf), - Device::Uptime(io) => io.read(buf), - Device::Realtime(io) => io.read(buf), - Device::RTC(io) => io.read(buf), + Device::Null => Err(()), + Device::File(io) => io.read(buf), + Device::Console(io) => io.read(buf), + Device::Random(io) => io.read(buf), + Device::Uptime(io) => io.read(buf), + Device::Realtime(io) => io.read(buf), + Device::RTC(io) => io.read(buf), + Device::TcpSocket(io) => io.read(buf), } } fn write(&mut self, buf: &[u8]) -> Result { match self { - Device::Null => Ok(0), - Device::File(io) => io.write(buf), - Device::Console(io) => io.write(buf), - Device::Random(io) => io.write(buf), - Device::Uptime(io) => io.write(buf), - Device::Realtime(io) => io.write(buf), - Device::RTC(io) => io.write(buf), + Device::Null => Ok(0), + Device::File(io) => io.write(buf), + Device::Console(io) => io.write(buf), + Device::Random(io) => io.write(buf), + Device::Uptime(io) => io.write(buf), + Device::Realtime(io) => io.write(buf), + Device::RTC(io) => io.write(buf), + Device::TcpSocket(io) => io.write(buf), } } } diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 8c395aa4..9e19452b 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -1,10 +1,16 @@ use crate::{sys, usr}; +use crate::sys::fs::FileIO; use alloc::sync::Arc; use alloc::vec::Vec; +use alloc::vec; use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use lazy_static::lazy_static; use smoltcp::iface::Interface; +use smoltcp::iface::SocketHandle; +use smoltcp::iface::SocketSet; use smoltcp::phy::DeviceCapabilities; +use smoltcp::socket::tcp; use smoltcp::time::Instant; use smoltcp::wire::EthernetAddress; use spin::Mutex; @@ -12,6 +18,10 @@ use spin::Mutex; mod rtl8139; mod pcnet; +lazy_static! { + pub static ref SOCKETS: Mutex> = Mutex::new(SocketSet::new(vec![])); +} + pub static NET: Mutex> = Mutex::new(None); #[derive(Clone)] @@ -207,6 +217,90 @@ impl Stats { } } +#[derive(Debug, Clone)] +pub struct TcpSocket { + pub handle: SocketHandle, +} + +impl TcpSocket { + pub fn new() -> Self { + let mut sockets = SOCKETS.lock(); + let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); + let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); + let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); + let handle = sockets.add(tcp_socket); + + Self { handle } + } +} + +impl FileIO for TcpSocket { + fn read(&mut self, buf: &mut [u8]) -> Result { + let timeout = 5.0; + let started = sys::clock::realtime(); + let mut bytes = 0; + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + let mut sockets = SOCKETS.lock(); + loop { + if sys::clock::realtime() - started > timeout { + return Err(()); + } + let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); + iface.poll(time, device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + if socket.can_recv() { + socket.recv(|data| { + bytes = data.len(); + buf[0..bytes].clone_from_slice(&data); + (bytes, ()) + }).map_err(|_| ())?; + break; + } + if !socket.may_recv() { + break; + } + if let Some(wait_duration) = iface.poll_delay(time, &sockets) { + sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + } + sys::time::halt(); + } + Ok(bytes) + } else { + Err(()) + } + } + + fn write(&mut self, buf: &[u8]) -> Result { + let timeout = 5.0; + let started = sys::clock::realtime(); + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + let mut sockets = SOCKETS.lock(); + loop { + if sys::clock::realtime() - started > timeout { + return Err(()); + } + let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); + iface.poll(time, device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + if socket.can_send() { + socket.send_slice(buf.as_ref()).expect("cannot send"); + break; + } + + if let Some(wait_duration) = iface.poll_delay(time, &sockets) { + sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + } + sys::time::halt(); + } + Ok(buf.len()) + } else { + Ok(0) + } + } +} + fn find_pci_io_base(vendor_id: u16, device_id: u16) -> Option { if let Some(mut pci_device) = sys::pci::find_device(vendor_id, device_id) { pci_device.enable_bus_mastering(); diff --git a/src/usr/install.rs b/src/usr/install.rs index 8c691c93..a79c952c 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -27,13 +27,15 @@ pub fn copy_files(verbose: bool) { copy_file("/bin/reboot", include_bytes!("../../dsk/bin/reboot"), verbose); copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"), verbose); - create_dir("/dev/clk", verbose); // Clocks + create_dir("/dev/clk", verbose); // Clock create_dev("/dev/clk/uptime", DeviceType::Uptime, verbose); create_dev("/dev/clk/realtime", DeviceType::Realtime, verbose); create_dev("/dev/rtc", DeviceType::RTC, verbose); create_dev("/dev/null", DeviceType::Null, verbose); create_dev("/dev/random", DeviceType::Random, verbose); create_dev("/dev/console", DeviceType::Console, verbose); + create_dir("/dev/net", verbose); // Network + create_dev("/dev/net/tcp", DeviceType::TcpSocket, verbose); copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt"), verbose); copy_file("/ini/boot.sh", include_bytes!("../../dsk/ini/boot.sh"), verbose); From 794441c938d28e6d68741c07f6cc35f5eab6e991 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 7 Jul 2023 23:16:03 +0200 Subject: [PATCH 03/37] Add socket.connect to lisp --- src/usr/lisp/env.rs | 1 + src/usr/lisp/primitive.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/usr/lisp/env.rs b/src/usr/lisp/env.rs index 3611eebe..0d8f5e9e 100644 --- a/src/usr/lisp/env.rs +++ b/src/usr/lisp/env.rs @@ -74,6 +74,7 @@ pub fn default_env() -> Rc> { data.insert("file.read".to_string(), Exp::Primitive(primitive::lisp_file_read)); data.insert("file.write".to_string(), Exp::Primitive(primitive::lisp_file_write)); data.insert("file.close".to_string(), Exp::Primitive(primitive::lisp_file_close)); + data.insert("socket.connect".to_string(), Exp::Primitive(primitive::lisp_socket_connect)); // Setup autocompletion *FUNCTIONS.lock() = data.keys().cloned().chain(BUILT_INS.map(String::from)).collect(); diff --git a/src/usr/lisp/primitive.rs b/src/usr/lisp/primitive.rs index 071b1b84..79d54920 100644 --- a/src/usr/lisp/primitive.rs +++ b/src/usr/lisp/primitive.rs @@ -477,3 +477,17 @@ pub fn lisp_file_write(args: &[Exp]) -> Result { _ => expected!("second argument to be a list") } } + +pub fn lisp_socket_connect(args: &[Exp]) -> Result { + ensure_length_eq!(args, 3); + let kind = string(&args[0])?; + let addr = string(&args[1])?; + let port: usize = number(&args[2])?.try_into()?; + let flags = OpenFlag::Device as usize; + if let Some(handle) = syscall::open(&format!("/dev/net/{}", kind), flags) { + if syscall::connect(handle, &addr, port as u16).is_ok() { + return Ok(Exp::Num(Number::from(handle))); + } + } + could_not!("connect to {}:{}", addr, port) +} From 00c87ed91c7cabf7906d4d2b14a98505af0292e0 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 7 Jul 2023 23:16:47 +0200 Subject: [PATCH 04/37] Rewrite tcp command to use the syscalls --- src/usr/tcp.rs | 91 +++++++++++++------------------------------------- 1 file changed, 24 insertions(+), 67 deletions(-) diff --git a/src/usr/tcp.rs b/src/usr/tcp.rs index 563683b6..7091980c 100644 --- a/src/usr/tcp.rs +++ b/src/usr/tcp.rs @@ -1,17 +1,11 @@ -use crate::{sys, usr, debug}; +use crate::{sys, usr}; use crate::api::console::Style; -use crate::api::clock; use crate::api::process::ExitCode; -use crate::api::random; use crate::api::syscall; -use alloc::string::String; use alloc::vec; use alloc::vec::Vec; use core::str::{self, FromStr}; -use smoltcp::iface::SocketSet; -use smoltcp::socket::tcp; -use smoltcp::time::Instant; use smoltcp::wire::IpAddress; pub fn main(args: &[&str]) -> Result<(), ExitCode> { @@ -44,9 +38,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let host = &args[1]; let port: u16 = args[2].parse().expect("Could not parse port"); - let request = ""; - - let address = if host.ends_with(char::is_numeric) { + let addr = if host.ends_with(char::is_numeric) { IpAddress::from_str(host).expect("invalid address format") } else { match usr::host::resolve(host) { @@ -54,77 +46,42 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { ip_addr } Err(e) => { - error!("Could not resolve host: {:?}", e); + error!("Could not resolve host {:?}", e); return Err(ExitCode::Failure); } } }; - enum State { Connect, Request, Response } - let mut state = State::Connect; - - if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { - let mut sockets = SocketSet::new(vec![]); - let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); - let tcp_handle = sockets.add(tcp_socket); - - let timeout = 5.0; - let started = clock::realtime(); + use alloc::format; + use crate::sys::fs::OpenFlag; + let addr = format!("{}", addr); + let flags = OpenFlag::Device as usize; + if let Some(handle) = syscall::open("/dev/net/tcp", flags) { + if syscall::connect(handle, &addr, port).is_err() { + error!("Could not connect to {}:{}", addr, port); + syscall::close(handle); + return Err(ExitCode::Failure); + } loop { - if clock::realtime() - started > timeout { - error!("Timeout reached"); - return Err(ExitCode::Failure); - } if sys::console::end_of_text() || sys::console::end_of_transmission() { eprintln!(); + syscall::close(handle); return Err(ExitCode::Failure); } - - let time = Instant::from_micros((clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); - let socket = sockets.get_mut::(tcp_handle); - let cx = iface.context(); - - state = match state { - State::Connect if !socket.is_active() => { - let local_port = 49152 + random::get_u16() % 16384; - if verbose { - debug!("Connecting to {}:{}", address, port); - } - if socket.connect(cx, (address, port), local_port).is_err() { - error!("Could not connect to {}:{}", address, port); - return Err(ExitCode::Failure); - } - State::Request - } - State::Request if socket.may_send() => { - if !request.is_empty() { - socket.send_slice(request.as_ref()).expect("cannot send"); - } - State::Response - } - State::Response if socket.can_recv() => { - socket.recv(|data| { - let contents = String::from_utf8_lossy(data); - for line in contents.lines() { - println!("{}", line); - } - (data.len(), ()) - }).unwrap(); - State::Response - } - State::Response if !socket.may_recv() => { + let mut data = vec![0; 2048]; + if let Some(bytes) = syscall::read(handle, &mut data) { + if bytes == 0 { break; } - _ => state - }; - - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - syscall::sleep((wait_duration.total_micros() as f64) / 1000000.0); + data.resize(bytes, 0); + syscall::write(1, &data); + } else { + error!("Could not read from {}:{}", addr, port); + syscall::close(handle); + return Err(ExitCode::Failure); } } + syscall::close(handle); Ok(()) } else { Err(ExitCode::Failure) From 249908bddcb5e3b6683f9885eb68767b109ad657 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 7 Jul 2023 23:17:04 +0200 Subject: [PATCH 05/37] Rewrite http command to use the syscalls --- src/usr/http.rs | 182 ++++++++++++++++++++---------------------------- 1 file changed, 77 insertions(+), 105 deletions(-) diff --git a/src/usr/http.rs b/src/usr/http.rs index dde51b16..8ee6058b 100644 --- a/src/usr/http.rs +++ b/src/usr/http.rs @@ -1,15 +1,10 @@ use crate::{sys, usr}; use crate::api::console::Style; -use crate::api::clock; use crate::api::process::ExitCode; -use crate::api::random; use crate::api::syscall; use alloc::string::{String, ToString}; use alloc::vec; use core::str::{self, FromStr}; -use smoltcp::iface::SocketSet; -use smoltcp::socket::tcp; -use smoltcp::time::Instant; use smoltcp::wire::IpAddress; #[derive(Debug)] @@ -19,7 +14,6 @@ struct URL { pub path: String, } -enum SessionState { Connect, Request, Response } enum ResponseState { Headers, Body } impl URL { @@ -103,9 +97,17 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let url = "http://".to_string() + host + path; let url = URL::parse(&url).expect("invalid URL format"); - - let address = if url.host.ends_with(char::is_numeric) { - IpAddress::from_str(&url.host).expect("invalid address format") + let port = url.port; + let addr = if url.host.ends_with(char::is_numeric) { + match IpAddress::from_str(&url.host) { + Ok(ip_addr) => { + ip_addr + } + Err(_) => { + error!("Invalid address format"); + return Err(ExitCode::UsageError); + } + } } else { match usr::host::resolve(&url.host) { Ok(ip_addr) => { @@ -118,117 +120,87 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } }; - let mut session_state = SessionState::Connect; - - if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { - let mut sockets = SocketSet::new(vec![]); - let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); - let tcp_handle = sockets.add(tcp_socket); + use alloc::format; + use crate::sys::fs::OpenFlag; + let addr = format!("{}", addr); + let flags = OpenFlag::Device as usize; + if let Some(handle) = syscall::open("/dev/net/tcp", flags) { + if syscall::connect(handle, &addr, port).is_err() { + error!("Could not connect to {}:{}", addr, port); + syscall::close(handle); + return Err(ExitCode::Failure); + } + let req = vec![ + format!("GET {} HTTP/1.1\r\n", url.path), + format!("Host: {}\r\n", url.host), + format!("User-Agent: MOROS/{}\r\n", env!("CARGO_PKG_VERSION")), + format!("Connection: close\r\n"), + format!("\r\n"), + ]; + if is_verbose { + print!("{}", csi_verbose); + for line in &req { + print!("> {}", line); + } + print!("{}", csi_reset); + } + let req = req.join(""); + syscall::write(handle, &req.as_bytes()); - let mut last_received_at = clock::realtime(); let mut response_state = ResponseState::Headers; loop { - if clock::realtime() - last_received_at > timeout { - error!("Timeout reached"); - return Err(ExitCode::Failure); - } if sys::console::end_of_text() || sys::console::end_of_transmission() { eprintln!(); + syscall::close(handle); return Err(ExitCode::Failure); } - - let time = Instant::from_micros((clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); - let socket = sockets.get_mut::(tcp_handle); - let cx = iface.context(); - - session_state = match session_state { - SessionState::Connect if !socket.is_active() => { - let local_port = 49152 + random::get_u16() % 16384; - if is_verbose { - print!("{}", csi_verbose); - println!("* Connecting to {}:{}", address, url.port); - print!("{}", csi_reset); - } - if socket.connect(cx, (address, url.port), local_port).is_err() { - error!("Could not connect to {}:{}", address, url.port); - return Err(ExitCode::Failure); - } - SessionState::Request - } - SessionState::Request if socket.may_send() => { - let http_get = "GET ".to_string() + &url.path + " HTTP/1.1\r\n"; - let http_host = "Host: ".to_string() + &url.host + "\r\n"; - let http_ua = "User-Agent: MOROS/".to_string() + env!("CARGO_PKG_VERSION") + "\r\n"; - let http_connection = "Connection: close\r\n".to_string(); - if is_verbose { - print!("{}", csi_verbose); - print!("> {}", http_get); - print!("> {}", http_host); - print!("> {}", http_ua); - print!("> {}", http_connection); - println!(">"); - print!("{}", csi_reset); - } - socket.send_slice(http_get.as_ref()).expect("cannot send"); - socket.send_slice(http_host.as_ref()).expect("cannot send"); - socket.send_slice(http_ua.as_ref()).expect("cannot send"); - socket.send_slice(http_connection.as_ref()).expect("cannot send"); - socket.send_slice(b"\r\n").expect("cannot send"); - SessionState::Response + let mut data = vec![0; 2048]; + if let Some(n) = syscall::read(handle, &mut data) { + if n == 0 { + break; } - SessionState::Response if socket.can_recv() => { - socket.recv(|data| { - last_received_at = clock::realtime(); - let n = data.len(); - let mut i = 0; - while i < n { - match response_state { - ResponseState::Headers => { - let mut j = i; - while j < n { - if data[j] == b'\n' { - break; - } - j += 1; - } - let line = String::from_utf8_lossy(&data[i..j]); // TODO: check i == j - if is_verbose { - if i == 0 { - print!("{}", csi_verbose); - } - println!("< {}", line); - } - if line.trim().is_empty() { - if is_verbose { - print!("{}", csi_reset); - } - response_state = ResponseState::Body; - } - i = j + 1; - } - ResponseState::Body => { - syscall::write(1, &data[i..n]); + data.resize(n, 0); + let mut i = 0; + while i < n { + match response_state { + ResponseState::Headers => { + let mut j = i; + while j < n { + if data[j] == b'\n' { break; } + j += 1; + } + let line = String::from_utf8_lossy(&data[i..j]); // TODO: check i == j + if is_verbose { + if i == 0 { + print!("{}", csi_verbose); + } + println!("< {}", line); } + if line.trim().is_empty() { + if is_verbose { + print!("{}", csi_reset); + } + response_state = ResponseState::Body; + } + i = j + 1; } - (data.len(), ()) - }).unwrap(); - SessionState::Response - } - SessionState::Response if !socket.may_recv() => { - break; + ResponseState::Body => { + // NOTE: The buffer may not be convertible to a UTF-8 string + // so we write it to STDOUT directly instead of using print. + syscall::write(1, &data[i..n]); + break; + } + } } - _ => session_state - }; - - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - syscall::sleep((wait_duration.total_micros() as f64) / 1000000.0); + } else { + error!("Could not read from {}:{}", addr, port); + syscall::close(handle); + return Err(ExitCode::Failure); } } + syscall::close(handle); Ok(()) } else { Err(ExitCode::Failure) From 52ee4592831a1716e04672c22f4a6478a4fa7df5 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 8 Jul 2023 09:13:05 +0200 Subject: [PATCH 06/37] Use socket#recv_slice instead of socket#recv --- src/sys/net/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 9e19452b..c967298e 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -250,11 +250,7 @@ impl FileIO for TcpSocket { let socket = sockets.get_mut::(self.handle); if socket.can_recv() { - socket.recv(|data| { - bytes = data.len(); - buf[0..bytes].clone_from_slice(&data); - (bytes, ()) - }).map_err(|_| ())?; + bytes = socket.recv_slice(buf).map_err(|_| ())?; break; } if !socket.may_recv() { From eb2fed2cafe82dfcc5d76c9bab96aadbcc0d67fe Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 8 Jul 2023 09:37:14 +0200 Subject: [PATCH 07/37] Move connect to net module --- src/sys/net/mod.rs | 41 ++++++++++++++++++++++++++++++++++++ src/sys/syscall/service.rs | 43 ++++---------------------------------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index c967298e..ebeb0222 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -13,6 +13,7 @@ use smoltcp::phy::DeviceCapabilities; use smoltcp::socket::tcp; use smoltcp::time::Instant; use smoltcp::wire::EthernetAddress; +use smoltcp::wire::IpAddress; use spin::Mutex; mod rtl8139; @@ -232,6 +233,46 @@ impl TcpSocket { Self { handle } } + + pub fn connect(&mut self, addr: IpAddress, port: u16) -> Result<(), ()> { + let timeout = 5.0; + let started = sys::clock::realtime(); + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + loop { + if sys::clock::realtime() - started > timeout { + return Err(()); + } + let mut sockets = SOCKETS.lock(); + let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); + iface.poll(time, device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + let cx = iface.context(); + + match socket.state() { + tcp::State::Closed => { + let local_port = 49152 + sys::random::get_u16() % 16384; + if socket.connect(cx, (addr, port), local_port).is_err() { + return Err(()); + } + } + tcp::State::SynSent => { + } + tcp::State::Established => { + break; + } + _ => { + return Err(()); + } + } + + if let Some(wait_duration) = iface.poll_delay(time, &sockets) { + sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + } + sys::time::halt(); + } + } + Ok(()) + } } impl FileIO for TcpSocket { diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index e80cccd0..4b38f48e 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -6,11 +6,8 @@ use crate::sys::process::Process; use alloc::vec; use core::arch::asm; -use smoltcp::time::Instant; use smoltcp::wire::IpAddress; -use crate::sys::net::SOCKETS; use crate::sys::fs::Device; -use smoltcp::socket::tcp; pub fn exit(code: ExitCode) -> ExitCode { sys::process::exit(); @@ -131,43 +128,11 @@ pub fn stop(code: usize) -> usize { } pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { - let timeout = 5.0; - let started = sys::clock::realtime(); + //debug!("connect"); if let Some(file) = sys::process::file_handle(handle) { - if let sys::fs::Resource::Device(Device::TcpSocket(dev)) = *file { - if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { - loop { - if sys::clock::realtime() - started > timeout { - return -1; - } - let mut sockets = SOCKETS.lock(); - let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); - let socket = sockets.get_mut::(dev.handle); - let cx = iface.context(); - - match socket.state() { - tcp::State::Closed => { - let local_port = 49152 + sys::random::get_u16() % 16384; - if socket.connect(cx, (addr, port), local_port).is_err() { - return -1; - } - } - tcp::State::SynSent => { - } - tcp::State::Established => { - break; - } - _ => { - return -1; - } - } - - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); - } - sys::time::halt(); - } + if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { + if dev.connect(addr, port).is_err() { + return -1; } } } From 2afa56f711c28b8f13f2a6b08212247ae6bae878 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 8 Jul 2023 10:19:51 +0200 Subject: [PATCH 08/37] Refactor connect --- src/sys/syscall/service.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 4b38f48e..54189132 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -131,10 +131,10 @@ pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { //debug!("connect"); if let Some(file) = sys::process::file_handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { - if dev.connect(addr, port).is_err() { - return -1; + if dev.connect(addr, port).is_ok() { + return 0; } } } - 0 + -1 } From bf8db97e5600fd924cf034fc4ac78278340dd89d Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 8 Jul 2023 22:17:38 +0200 Subject: [PATCH 09/37] Refactor code --- src/sys/net/mod.rs | 53 +++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index ebeb0222..bb2a5c80 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -11,6 +11,7 @@ use smoltcp::iface::SocketHandle; use smoltcp::iface::SocketSet; use smoltcp::phy::DeviceCapabilities; use smoltcp::socket::tcp; +use smoltcp::time::Duration; use smoltcp::time::Instant; use smoltcp::wire::EthernetAddress; use smoltcp::wire::IpAddress; @@ -218,6 +219,28 @@ impl Stats { } } +fn debug_tcp_socket(socket: &tcp::Socket) { + debug!("socket.state: {:?}", socket.state()); + debug!("socket.is_active: {:?}", socket.is_active()); + debug!("socket.is_open: {:?}", socket.is_open()); + debug!("socket.can_recv: {:?}", socket.can_recv()); + debug!("socket.may_recv: {:?}", socket.may_recv()); + debug!("socket.can_send: {:?}", socket.can_send()); + debug!("socket.may_send: {:?}", socket.may_send()); +} + +fn random_port() -> u16 { + 49152 + sys::random::get_u16() % 16384 +} + +fn time() -> Instant { + Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64) +} + +fn wait(duration: Duration) { + sys::time::sleep((duration.total_micros() as f64) / 1000000.0); +} + #[derive(Debug, Clone)] pub struct TcpSocket { pub handle: SocketHandle, @@ -243,15 +266,14 @@ impl TcpSocket { return Err(()); } let mut sockets = SOCKETS.lock(); - let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); + iface.poll(time(), device, &mut sockets); let socket = sockets.get_mut::(self.handle); - let cx = iface.context(); match socket.state() { tcp::State::Closed => { - let local_port = 49152 + sys::random::get_u16() % 16384; - if socket.connect(cx, (addr, port), local_port).is_err() { + let cx = iface.context(); + let dest = (addr, port); + if socket.connect(cx, dest, random_port()).is_err() { return Err(()); } } @@ -265,8 +287,8 @@ impl TcpSocket { } } - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); } sys::time::halt(); } @@ -286,8 +308,7 @@ impl FileIO for TcpSocket { if sys::clock::realtime() - started > timeout { return Err(()); } - let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); + iface.poll(time(), device, &mut sockets); let socket = sockets.get_mut::(self.handle); if socket.can_recv() { @@ -297,8 +318,8 @@ impl FileIO for TcpSocket { if !socket.may_recv() { break; } - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); } sys::time::halt(); } @@ -317,8 +338,7 @@ impl FileIO for TcpSocket { if sys::clock::realtime() - started > timeout { return Err(()); } - let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); + iface.poll(time(), device, &mut sockets); let socket = sockets.get_mut::(self.handle); if socket.can_send() { @@ -326,8 +346,8 @@ impl FileIO for TcpSocket { break; } - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - sys::time::sleep((wait_duration.total_micros() as f64) / 1000000.0); + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); } sys::time::halt(); } @@ -354,8 +374,7 @@ pub fn init() { log!("NET {} MAC {}\n", name, mac); let config = smoltcp::iface::Config::new(mac.into()); - let time = Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64); - let iface = Interface::new(config, &mut device, time); + let iface = Interface::new(config, &mut device, time()); *NET.lock() = Some((iface, device)); } From c6196e69281cfba2dda1d294707c081de293596b Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 9 Jul 2023 11:20:13 +0200 Subject: [PATCH 10/37] Add listen syscall --- doc/syscalls.md | 6 ++++++ src/sys/net/mod.rs | 26 ++++++++++++++++++++++++-- src/sys/syscall/mod.rs | 5 +++++ src/sys/syscall/number.rs | 1 + src/sys/syscall/service.rs | 12 +++++++++++- 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/doc/syscalls.md b/doc/syscalls.md index 2c289334..9af083dc 100644 --- a/doc/syscalls.md +++ b/doc/syscalls.md @@ -75,3 +75,9 @@ pub fn sleep(seconds: f64) ```rust pub fn connect(handle, usize, addr: &str, port: u16) -> isize ``` + +## LISTEN (0xD) + +```rust +pub fn listen(handle, usize, port: u16) -> isize +``` diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index bb2a5c80..726448d1 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -295,6 +295,26 @@ impl TcpSocket { } Ok(()) } + + pub fn listen(&mut self, port: u16) -> Result<(), ()> { + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + let mut sockets = SOCKETS.lock(); + iface.poll(time(), device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + if socket.listen(port).is_err() { + return Err(()); + } + + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); + } + sys::time::halt(); + Ok(()) + } else { + Err(()) + } + } } impl FileIO for TcpSocket { @@ -342,7 +362,9 @@ impl FileIO for TcpSocket { let socket = sockets.get_mut::(self.handle); if socket.can_send() { - socket.send_slice(buf.as_ref()).expect("cannot send"); + if socket.send_slice(buf.as_ref()).is_err() { + return Err(()); + } break; } @@ -353,7 +375,7 @@ impl FileIO for TcpSocket { } Ok(buf.len()) } else { - Ok(0) + Err(()) } } } diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index ce78f4fc..2b5e911a 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -89,6 +89,11 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) let port = arg4 as u16; service::connect(handle, addr, port) as usize } + number::LISTEN => { + let handle = arg1; + let port = arg2 as u16; + service::listen(handle, port) as usize + } _ => { unimplemented!(); } diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 6a3883ab..499b1b87 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -10,3 +10,4 @@ pub const DELETE: usize = 0x9; pub const STOP: usize = 0xA; pub const SLEEP: usize = 0xB; pub const CONNECT: usize = 0xC; +pub const LISTEN: usize = 0xD; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 54189132..a0f4df90 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -128,7 +128,6 @@ pub fn stop(code: usize) -> usize { } pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { - //debug!("connect"); if let Some(file) = sys::process::file_handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { if dev.connect(addr, port).is_ok() { @@ -138,3 +137,14 @@ pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { } -1 } + +pub fn listen(handle: usize, port: u16) -> isize { + if let Some(file) = sys::process::file_handle(handle) { + if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { + if dev.listen(port).is_ok() { + return 0; + } + } + } + -1 +} From 553124edd950376eb79da53415e8503fc01632dd Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 10 Jul 2023 00:20:19 +0200 Subject: [PATCH 11/37] Add accept --- doc/syscalls.md | 6 ++++++ src/api/syscall.rs | 32 +++++++++++++++++++++++++++++--- src/sys/net/mod.rs | 28 ++++++++++++++++++++++++++++ src/sys/syscall/mod.rs | 24 +++++++++++++++++------- src/sys/syscall/number.rs | 1 + src/sys/syscall/service.rs | 9 +++++++++ src/usr/http.rs | 3 +-- src/usr/lisp/env.rs | 2 ++ src/usr/lisp/primitive.rs | 33 +++++++++++++++++++++++++++++++-- src/usr/tcp.rs | 3 +-- 10 files changed, 125 insertions(+), 16 deletions(-) diff --git a/doc/syscalls.md b/doc/syscalls.md index 9af083dc..deed4d03 100644 --- a/doc/syscalls.md +++ b/doc/syscalls.md @@ -81,3 +81,9 @@ pub fn connect(handle, usize, addr: &str, port: u16) -> isize ```rust pub fn listen(handle, usize, port: u16) -> isize ``` + +## ACCEPT (0xE) + +```rust +pub fn accept(handle, usize, addr: &str) -> isize +``` diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 76a2627d..84114a9d 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -3,6 +3,9 @@ use crate::syscall; use crate::sys::syscall::number::*; use crate::sys::fs::FileInfo; +use smoltcp::wire::IpAddress; +use smoltcp::wire::Ipv4Address; + pub fn exit(code: ExitCode) { unsafe { syscall!(EXIT, code as usize) }; } @@ -106,9 +109,10 @@ pub fn halt() { stop(0xdead); } -pub fn connect(handle: usize, addr: &str, port: u16) -> Result<(), ()> { - let ptr = addr.as_ptr() as usize; - let len = addr.len(); +pub fn connect(handle: usize, addr: IpAddress, port: u16) -> Result<(), ()> { + let buf = addr.as_bytes(); + let ptr = buf.as_ptr() as usize; + let len = buf.len(); let res = unsafe { syscall!(CONNECT, handle, ptr, len, port) } as isize; if res >= 0 { Ok(()) @@ -117,6 +121,28 @@ pub fn connect(handle: usize, addr: &str, port: u16) -> Result<(), ()> { } } +pub fn listen(handle: usize, port: u16) -> Result<(), ()> { + let res = unsafe { syscall!(LISTEN, handle, port) } as isize; + if res >= 0 { + Ok(()) + } else { + Err(()) + } +} + +pub fn accept(handle: usize) -> Result { + let addr = IpAddress::v4(0, 0, 0, 0); + let buf = addr.as_bytes(); + let ptr = buf.as_ptr() as usize; + let len = buf.len(); + let res = unsafe { syscall!(ACCEPT, handle, ptr, len) } as isize; + if res >= 0 { + Ok(IpAddress::from(Ipv4Address::from_bytes(buf))) + } else { + Err(()) + } +} + #[test_case] fn test_file() { use crate::sys::fs::{mount_mem, format_mem, dismount, OpenFlag}; diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 726448d1..8c8aa18d 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -315,6 +315,34 @@ impl TcpSocket { Err(()) } } + + pub fn accept(&mut self) -> Result { + //let timeout = 5.0; + //let started = sys::clock::realtime(); + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + loop { + /* + if sys::clock::realtime() - started > timeout { + return Err(()); + } + */ + let mut sockets = SOCKETS.lock(); + iface.poll(time(), device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + if let Some(endpoint) = socket.remote_endpoint() { + return Ok(endpoint.addr); + } + + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); + } + sys::time::halt(); + } + } else { + Err(()) + } + } } impl FileIO for TcpSocket { diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index 2b5e911a..c909c33d 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -7,7 +7,7 @@ use crate::sys::fs::FileInfo; use core::arch::asm; use smoltcp::wire::IpAddress; -use core::str::FromStr; +use smoltcp::wire::Ipv4Address; /* * Dispatching system calls @@ -70,10 +70,8 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) let path_ptr = sys::process::ptr_from_addr(arg1 as u64); let path_len = arg2; let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(path_ptr, path_len)) }; - let args_ptr = arg3; let args_len = arg4; - service::spawn(path, args_ptr, args_len) as usize } number::STOP => { @@ -82,10 +80,10 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) } number::CONNECT => { let handle = arg1; - let addr_ptr = sys::process::ptr_from_addr(arg2 as u64); - let addr_len = arg3; - let addr_str = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(addr_ptr, addr_len)) }; - let addr = IpAddress::from_str(&addr_str).expect("invalid address format"); + let buf_ptr = sys::process::ptr_from_addr(arg2 as u64); + let buf_len = arg3; + let buf = unsafe { core::slice::from_raw_parts(buf_ptr, buf_len) }; + let addr = IpAddress::from(Ipv4Address::from_bytes(buf)); let port = arg4 as u16; service::connect(handle, addr, port) as usize } @@ -94,6 +92,18 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) let port = arg2 as u16; service::listen(handle, port) as usize } + number::ACCEPT => { + let handle = arg1; + let buf_ptr = sys::process::ptr_from_addr(arg2 as u64); + let buf_len = arg3; + let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr, buf_len) }; + if let Ok(addr) = service::accept(handle) { + buf[0..buf_len].clone_from_slice(&addr.as_bytes()); + 0 + } else { + -1 as isize as usize + } + } _ => { unimplemented!(); } diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 499b1b87..488e925e 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -11,3 +11,4 @@ pub const STOP: usize = 0xA; pub const SLEEP: usize = 0xB; pub const CONNECT: usize = 0xC; pub const LISTEN: usize = 0xD; +pub const ACCEPT: usize = 0xE; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index a0f4df90..2a5432a1 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -148,3 +148,12 @@ pub fn listen(handle: usize, port: u16) -> isize { } -1 } + +pub fn accept(handle: usize) -> Result { + if let Some(file) = sys::process::file_handle(handle) { + if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { + return dev.accept(); + } + } + Err(()) +} diff --git a/src/usr/http.rs b/src/usr/http.rs index 8ee6058b..f9119abe 100644 --- a/src/usr/http.rs +++ b/src/usr/http.rs @@ -122,10 +122,9 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { use alloc::format; use crate::sys::fs::OpenFlag; - let addr = format!("{}", addr); let flags = OpenFlag::Device as usize; if let Some(handle) = syscall::open("/dev/net/tcp", flags) { - if syscall::connect(handle, &addr, port).is_err() { + if syscall::connect(handle, addr, port).is_err() { error!("Could not connect to {}:{}", addr, port); syscall::close(handle); return Err(ExitCode::Failure); diff --git a/src/usr/lisp/env.rs b/src/usr/lisp/env.rs index 0d8f5e9e..798d9790 100644 --- a/src/usr/lisp/env.rs +++ b/src/usr/lisp/env.rs @@ -75,6 +75,8 @@ pub fn default_env() -> Rc> { data.insert("file.write".to_string(), Exp::Primitive(primitive::lisp_file_write)); data.insert("file.close".to_string(), Exp::Primitive(primitive::lisp_file_close)); data.insert("socket.connect".to_string(), Exp::Primitive(primitive::lisp_socket_connect)); + data.insert("socket.listen".to_string(), Exp::Primitive(primitive::lisp_socket_listen)); + data.insert("socket.accept".to_string(), Exp::Primitive(primitive::lisp_socket_accept)); // Setup autocompletion *FUNCTIONS.lock() = data.keys().cloned().chain(BUILT_INS.map(String::from)).collect(); diff --git a/src/usr/lisp/primitive.rs b/src/usr/lisp/primitive.rs index 79d54920..2fb535e9 100644 --- a/src/usr/lisp/primitive.rs +++ b/src/usr/lisp/primitive.rs @@ -17,6 +17,8 @@ use alloc::vec; use core::cmp::Ordering::Equal; use core::convert::TryFrom; use core::convert::TryInto; +use core::str::FromStr; +use smoltcp::wire::IpAddress; pub fn lisp_eq(args: &[Exp]) -> Result { Ok(Exp::Bool(numbers(args)?.windows(2).all(|nums| nums[0] == nums[1]))) @@ -481,13 +483,40 @@ pub fn lisp_file_write(args: &[Exp]) -> Result { pub fn lisp_socket_connect(args: &[Exp]) -> Result { ensure_length_eq!(args, 3); let kind = string(&args[0])?; - let addr = string(&args[1])?; + let addr_str = string(&args[1])?; + let addr = match IpAddress::from_str(&addr_str) { + Ok(addr) => addr, + Err(()) => return expected!("valid IP address"), + }; let port: usize = number(&args[2])?.try_into()?; let flags = OpenFlag::Device as usize; if let Some(handle) = syscall::open(&format!("/dev/net/{}", kind), flags) { - if syscall::connect(handle, &addr, port as u16).is_ok() { + if syscall::connect(handle, addr, port as u16).is_ok() { return Ok(Exp::Num(Number::from(handle))); } } could_not!("connect to {}:{}", addr, port) } + +pub fn lisp_socket_listen(args: &[Exp]) -> Result { + ensure_length_eq!(args, 2); + let kind = string(&args[0])?; + let port: usize = number(&args[1])?.try_into()?; + let flags = OpenFlag::Device as usize; + if let Some(handle) = syscall::open(&format!("/dev/net/{}", kind), flags) { + if syscall::listen(handle, port as u16).is_ok() { + return Ok(Exp::Num(Number::from(handle))); + } + } + could_not!("listen to {}", port) +} + +pub fn lisp_socket_accept(args: &[Exp]) -> Result { + ensure_length_eq!(args, 1); + let handle: usize = number(&args[0])?.try_into()?; + if let Ok(addr) = syscall::accept(handle) { + Ok(Exp::Str(format!("{}", addr))) + } else { + could_not!("accept connections") + } +} diff --git a/src/usr/tcp.rs b/src/usr/tcp.rs index 7091980c..a67a7846 100644 --- a/src/usr/tcp.rs +++ b/src/usr/tcp.rs @@ -54,10 +54,9 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { use alloc::format; use crate::sys::fs::OpenFlag; - let addr = format!("{}", addr); let flags = OpenFlag::Device as usize; if let Some(handle) = syscall::open("/dev/net/tcp", flags) { - if syscall::connect(handle, &addr, port).is_err() { + if syscall::connect(handle, addr, port).is_err() { error!("Could not connect to {}:{}", addr, port); syscall::close(handle); return Err(ExitCode::Failure); From 99c640c904bda40875c16f28c3ba53234697f94b Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 10 Jul 2023 01:18:31 +0200 Subject: [PATCH 12/37] Add close to FileIO --- src/api/fs.rs | 1 + src/sys/clock.rs | 8 ++++++++ src/sys/cmos.rs | 3 +++ src/sys/console.rs | 3 +++ src/sys/fs/device.rs | 13 +++++++++++++ src/sys/fs/dir.rs | 4 ++++ src/sys/fs/file.rs | 3 +++ src/sys/fs/mod.rs | 8 ++++++++ src/sys/net/mod.rs | 22 ++++++++++++++++++++++ src/sys/random.rs | 4 ++++ src/sys/syscall/service.rs | 5 ++++- 11 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 538303ea..19a116fe 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -12,6 +12,7 @@ pub use crate::sys::fs::{FileInfo, DeviceType}; pub trait FileIO { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result; + fn close(&mut self); } pub fn dirname(pathname: &str) -> &str { diff --git a/src/sys/clock.rs b/src/sys/clock.rs index 3edad8b0..fd8c349b 100644 --- a/src/sys/clock.rs +++ b/src/sys/clock.rs @@ -31,9 +31,13 @@ impl FileIO for Uptime { Err(()) } } + fn write(&mut self, _buf: &[u8]) -> Result { unimplemented!(); } + + fn close(&mut self) { + } } // NOTE: This clock is monotonic @@ -65,9 +69,13 @@ impl FileIO for Realtime { Err(()) } } + fn write(&mut self, _buf: &[u8]) -> Result { unimplemented!(); } + + fn close(&mut self) { + } } // NOTE: This clock is not monotonic diff --git a/src/sys/cmos.rs b/src/sys/cmos.rs index 6c48b792..ef27b598 100644 --- a/src/sys/cmos.rs +++ b/src/sys/cmos.rs @@ -83,6 +83,9 @@ impl FileIO for RTC { CMOS::new().update_rtc(self); Ok(buf.len()) } + + fn close(&mut self) { + } } pub struct CMOS { diff --git a/src/sys/console.rs b/src/sys/console.rs index bff59614..fd50b391 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -43,6 +43,9 @@ impl FileIO for Console { print_fmt(format_args!("{}", s)); Ok(n) } + + fn close(&mut self) { + } } pub fn cols() -> usize { diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index c7d15cfd..dd732187 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -128,4 +128,17 @@ impl FileIO for Device { Device::TcpSocket(io) => io.write(buf), } } + + fn close(&mut self) { + match self { + Device::Null => {}, + Device::File(io) => io.close(), + Device::Console(io) => io.close(), + Device::Random(io) => io.close(), + Device::Uptime(io) => io.close(), + Device::Realtime(io) => io.close(), + Device::RTC(io) => io.close(), + Device::TcpSocket(io) => io.close(), + } + } } diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index 6d7f4f97..2f90329f 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -239,9 +239,13 @@ impl FileIO for Dir { } Ok(i) } + fn write(&mut self, _buf: &[u8]) -> Result { Err(()) } + + fn close(&mut self) { + } } // Truncate to the given number of bytes at most while respecting char boundaries diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index 5a6564c7..b46ea43a 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -199,6 +199,9 @@ impl FileIO for File { } Ok(bytes) } + + fn close(&mut self) { + } } #[test_case] diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 99e5459c..8425edfd 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -122,6 +122,14 @@ impl FileIO for Resource { Resource::Device(io) => io.write(buf), } } + + fn close(&mut self) { + match self { + Resource::Dir(io) => io.close(), + Resource::File(io) => io.close(), + Resource::Device(io) => io.close(), + } + } } pub fn canonicalize(path: &str) -> Result { diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 8c8aa18d..19d363ee 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -406,6 +406,28 @@ impl FileIO for TcpSocket { Err(()) } } + + fn close(&mut self) { + let mut closed = false; + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + let mut sockets = SOCKETS.lock(); + loop { + iface.poll(time(), device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + if closed { + break; + } + socket.close(); + closed = true; + + if let Some(duration) = iface.poll_delay(time(), &sockets) { + wait(duration); + } + sys::time::halt(); + } + } + } } fn find_pci_io_base(vendor_id: u16, device_id: u16) -> Option { diff --git a/src/sys/random.rs b/src/sys/random.rs index db9562b7..376a5c00 100644 --- a/src/sys/random.rs +++ b/src/sys/random.rs @@ -22,9 +22,13 @@ impl FileIO for Random { } Ok(n) } + fn write(&mut self, _buf: &[u8]) -> Result { unimplemented!(); } + + fn close(&mut self) { + } } pub fn get_u64() -> u64 { diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 2a5432a1..8b7567f3 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -81,7 +81,10 @@ pub fn write(handle: usize, buf: &mut [u8]) -> isize { } pub fn close(handle: usize) { - sys::process::delete_file_handle(handle); + if let Some(mut file) = sys::process::file_handle(handle) { + file.close(); + sys::process::delete_file_handle(handle); + } } pub fn spawn(path: &str, args_ptr: usize, args_len: usize) -> ExitCode { From 9e5b08059078fc17ca6f8379ec1aefd71751680c Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 10 Jul 2023 01:18:56 +0200 Subject: [PATCH 13/37] Fix write loop --- src/sys/net/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 19d363ee..0fec6988 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -380,6 +380,7 @@ impl FileIO for TcpSocket { fn write(&mut self, buf: &[u8]) -> Result { let timeout = 5.0; let started = sys::clock::realtime(); + let mut sent = false; if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { let mut sockets = SOCKETS.lock(); loop { @@ -389,11 +390,14 @@ impl FileIO for TcpSocket { iface.poll(time(), device, &mut sockets); let socket = sockets.get_mut::(self.handle); + if sent { + break; + } if socket.can_send() { if socket.send_slice(buf.as_ref()).is_err() { return Err(()); } - break; + sent = true; // Break after next poll } if let Some(duration) = iface.poll_delay(time(), &sockets) { From 2459b271e70a1a98e22a867e839d7d5b8f3008cf Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 10 Jul 2023 12:40:22 +0200 Subject: [PATCH 14/37] Add poll syscall --- src/api/fs.rs | 4 ++++ src/sys/clock.rs | 16 +++++++++++++++- src/sys/cmos.rs | 9 ++++++++- src/sys/console.rs | 9 ++++++++- src/sys/fs/device.rs | 15 ++++++++++++++- src/sys/fs/dir.rs | 9 ++++++++- src/sys/fs/file.rs | 9 ++++++++- src/sys/fs/mod.rs | 11 ++++++++++- src/sys/net/mod.rs | 17 ++++++++++++++++- src/sys/random.rs | 9 ++++++++- src/sys/syscall/mod.rs | 8 +++++++- src/sys/syscall/number.rs | 7 ++++--- src/sys/syscall/service.rs | 13 ++++++++++++- src/usr/lisp/primitive.rs | 2 +- src/usr/tcp.rs | 7 ++++--- 15 files changed, 127 insertions(+), 18 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 19a116fe..aaf15f45 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -9,10 +9,14 @@ use alloc::vec; pub use crate::sys::fs::{FileInfo, DeviceType}; +#[derive(Clone, Copy)] +pub enum IO { Read, Write } + pub trait FileIO { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result; fn close(&mut self); + fn poll(&mut self, event: IO) -> bool; } pub fn dirname(pathname: &str) -> &str { diff --git a/src/sys/clock.rs b/src/sys/clock.rs index fd8c349b..ba9b834c 100644 --- a/src/sys/clock.rs +++ b/src/sys/clock.rs @@ -1,7 +1,7 @@ use crate::api::clock::DATE_TIME_ZONE; +use crate::api::fs::{FileIO, IO}; use crate::sys; use crate::sys::cmos::CMOS; -use crate::sys::fs::FileIO; use time::{OffsetDateTime, Duration}; @@ -38,6 +38,13 @@ impl FileIO for Uptime { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } } // NOTE: This clock is monotonic @@ -76,6 +83,13 @@ impl FileIO for Realtime { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } } // NOTE: This clock is not monotonic diff --git a/src/sys/cmos.rs b/src/sys/cmos.rs index ef27b598..07263671 100644 --- a/src/sys/cmos.rs +++ b/src/sys/cmos.rs @@ -1,5 +1,5 @@ use crate::api::clock::{DATE_TIME, DATE_TIME_LEN}; -use crate::sys::fs::FileIO; +use crate::api::fs::{FileIO, IO}; use alloc::string::String; use bit_field::BitField; @@ -86,6 +86,13 @@ impl FileIO for RTC { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => true, + } + } } pub struct CMOS { diff --git a/src/sys/console.rs b/src/sys/console.rs index fd50b391..d473a3a0 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -1,5 +1,5 @@ +use crate::api::fs::{FileIO, IO}; use crate::sys; -use crate::sys::fs::FileIO; use alloc::string::String; use alloc::string::ToString; use core::fmt; @@ -46,6 +46,13 @@ impl FileIO for Console { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => !STDIN.lock().is_empty(), + IO::Write => true, + } + } } pub fn cols() -> usize { diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index dd732187..c5962eb1 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -1,4 +1,4 @@ -use super::{dirname, filename, realpath, FileIO}; +use super::{dirname, filename, realpath, FileIO, IO}; use super::dir::Dir; use super::file::File; use super::block::LinkedBlock; @@ -141,4 +141,17 @@ impl FileIO for Device { Device::TcpSocket(io) => io.close(), } } + + fn poll(&mut self, event: IO) -> bool { + match self { + Device::Null => false, + Device::File(io) => io.poll(event), + Device::Console(io) => io.poll(event), + Device::Random(io) => io.poll(event), + Device::Uptime(io) => io.poll(event), + Device::Realtime(io) => io.poll(event), + Device::RTC(io) => io.poll(event), + Device::TcpSocket(io) => io.poll(event), + } + } } diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index 2f90329f..0dc59fda 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -1,4 +1,4 @@ -use super::{dirname, filename, realpath, FileIO}; +use super::{dirname, filename, realpath, FileIO, IO}; use super::super_block::SuperBlock; use super::dir_entry::DirEntry; use super::read_dir::ReadDir; @@ -246,6 +246,13 @@ impl FileIO for Dir { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => self.entry_index < self.entries().count() as u32, + IO::Write => true, + } + } } // Truncate to the given number of bytes at most while respecting char boundaries diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index b46ea43a..c825d121 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -1,4 +1,4 @@ -use super::{dirname, filename, realpath, FileIO}; +use super::{dirname, filename, realpath, FileIO, IO}; use super::dir::Dir; use super::block::LinkedBlock; use super::dir_entry::DirEntry; @@ -202,6 +202,13 @@ impl FileIO for File { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => self.offset < self.size, + IO::Write => true, + } + } } #[test_case] diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 8425edfd..80b0fd06 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -16,7 +16,7 @@ pub use dir::Dir; pub use dir_entry::FileInfo; pub use file::{File, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; -pub use crate::api::fs::{dirname, filename, realpath, FileIO}; +pub use crate::api::fs::{dirname, filename, realpath, FileIO, IO}; pub use crate::sys::ata::BLOCK_SIZE; use dir_entry::DirEntry; @@ -26,6 +26,7 @@ use alloc::string::{String, ToString}; pub const VERSION: u8 = 1; +// TODO: Move that to API #[derive(Clone, Copy)] #[repr(u8)] pub enum OpenFlag { @@ -130,6 +131,14 @@ impl FileIO for Resource { Resource::Device(io) => io.close(), } } + + fn poll(&mut self, event: IO) -> bool { + match self { + Resource::Dir(io) => io.poll(event), + Resource::File(io) => io.poll(event), + Resource::Device(io) => io.poll(event), + } + } } pub fn canonicalize(path: &str) -> Result { diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 0fec6988..a1380dd3 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -1,5 +1,5 @@ use crate::{sys, usr}; -use crate::sys::fs::FileIO; +use crate::api::fs::{FileIO, IO}; use alloc::sync::Arc; use alloc::vec::Vec; @@ -432,6 +432,21 @@ impl FileIO for TcpSocket { } } } + + fn poll(&mut self, event: IO) -> bool { + if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { + let mut sockets = SOCKETS.lock(); + iface.poll(time(), device, &mut sockets); + let socket = sockets.get_mut::(self.handle); + + match event { + IO::Read => socket.can_recv(), + IO::Write => socket.can_send(), + } + } else { + false + } + } } fn find_pci_io_base(vendor_id: u16, device_id: u16) -> Option { diff --git a/src/sys/random.rs b/src/sys/random.rs index 376a5c00..0e8e4175 100644 --- a/src/sys/random.rs +++ b/src/sys/random.rs @@ -1,5 +1,5 @@ use crate::sys; -use crate::sys::fs::FileIO; +use crate::api::fs::{FileIO, IO}; use rand::{RngCore, SeedableRng}; use rand_hc::Hc128Rng; @@ -29,6 +29,13 @@ impl FileIO for Random { fn close(&mut self) { } + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } } pub fn get_u64() -> u64 { diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index c909c33d..ec265aae 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -3,7 +3,7 @@ pub mod service; use crate::api::process::ExitCode; use crate::sys; -use crate::sys::fs::FileInfo; +use crate::sys::fs::{FileInfo, IO}; use core::arch::asm; use smoltcp::wire::IpAddress; @@ -78,6 +78,12 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) let code = arg1; service::stop(code) } + number::POLL => { + let ptr = sys::process::ptr_from_addr(arg1 as u64) as *const (usize, IO); + let len = arg2; + let list = unsafe { core::slice::from_raw_parts(ptr, len) }; + service::poll(list) as usize + } number::CONNECT => { let handle = arg1; let buf_ptr = sys::process::ptr_from_addr(arg2 as u64); diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 488e925e..96f34d0b 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -9,6 +9,7 @@ pub const DUP: usize = 0x8; pub const DELETE: usize = 0x9; pub const STOP: usize = 0xA; pub const SLEEP: usize = 0xB; -pub const CONNECT: usize = 0xC; -pub const LISTEN: usize = 0xD; -pub const ACCEPT: usize = 0xE; +pub const POLL: usize = 0xC; +pub const CONNECT: usize = 0xD; +pub const LISTEN: usize = 0xE; +pub const ACCEPT: usize = 0xF; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 8b7567f3..0f4d02de 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -1,7 +1,7 @@ use crate::sys; use crate::api::process::ExitCode; +use crate::api::fs::{FileIO, IO}; use crate::sys::fs::FileInfo; -use crate::sys::fs::FileIO; use crate::sys::process::Process; use alloc::vec; @@ -130,6 +130,17 @@ pub fn stop(code: usize) -> usize { 0 } +pub fn poll(list: &[(usize, IO)]) -> isize { + for (i, (handle, event)) in list.iter().enumerate() { + if let Some(mut file) = sys::process::file_handle(*handle) { + if file.poll(*event) { + return i as isize; + } + } + } + -1 +} + pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { if let Some(file) = sys::process::file_handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { diff --git a/src/usr/lisp/primitive.rs b/src/usr/lisp/primitive.rs index 2fb535e9..f907ea14 100644 --- a/src/usr/lisp/primitive.rs +++ b/src/usr/lisp/primitive.rs @@ -508,7 +508,7 @@ pub fn lisp_socket_listen(args: &[Exp]) -> Result { return Ok(Exp::Num(Number::from(handle))); } } - could_not!("listen to {}", port) + could_not!("listen to 0.0.0.0:{}", port) } pub fn lisp_socket_accept(args: &[Exp]) -> Result { diff --git a/src/usr/tcp.rs b/src/usr/tcp.rs index a67a7846..82ea426b 100644 --- a/src/usr/tcp.rs +++ b/src/usr/tcp.rs @@ -2,10 +2,13 @@ use crate::{sys, usr}; use crate::api::console::Style; use crate::api::process::ExitCode; use crate::api::syscall; +use crate::sys::fs::OpenFlag; +use alloc::format; use alloc::vec; use alloc::vec::Vec; -use core::str::{self, FromStr}; +use core::str; +use core::str::FromStr; use smoltcp::wire::IpAddress; pub fn main(args: &[&str]) -> Result<(), ExitCode> { @@ -52,8 +55,6 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } }; - use alloc::format; - use crate::sys::fs::OpenFlag; let flags = OpenFlag::Device as usize; if let Some(handle) = syscall::open("/dev/net/tcp", flags) { if syscall::connect(handle, addr, port).is_err() { From 36a72e6a41f690e7fe883ecd747326f4cf44e9f1 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 10 Jul 2023 14:22:03 +0200 Subject: [PATCH 15/37] Rewrite socket command to use poll --- doc/network.md | 4 +- src/api/syscall.rs | 12 +++ src/usr/socket.rs | 177 +++++++++++++-------------------------------- 3 files changed, 63 insertions(+), 130 deletions(-) diff --git a/doc/network.md b/doc/network.md index a523a55b..dc1f0672 100644 --- a/doc/network.md +++ b/doc/network.md @@ -145,16 +145,16 @@ Here's a connexion to a SMTP server to send a mail: 250-NO-SOLICITING 250 SIZE 20000000 > MAIL FROM: - > RCPT TO: 250 Ok + > RCPT TO: 250 Ok > DATA 354 Send it > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec > diam vitae ex blandit malesuada nec a turpis. > . - > QUIT 250 Message accepted + > QUIT 221 Ok Sending a file to a server: diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 84114a9d..20d98fd6 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -1,3 +1,4 @@ +use crate::api::fs::IO; use crate::api::process::ExitCode; use crate::syscall; use crate::sys::syscall::number::*; @@ -109,6 +110,17 @@ pub fn halt() { stop(0xdead); } +pub fn poll(list: &[(usize, IO)]) -> Option<(usize, IO)> { + let ptr = list.as_ptr() as usize; + let len = list.len(); + let idx = unsafe { syscall!(POLL, ptr, len) } as isize; + if 0 <= idx && idx < len as isize { + Some(list[idx as usize]) + } else { + None + } +} + pub fn connect(handle: usize, addr: IpAddress, port: u16) -> Result<(), ()> { let buf = addr.as_bytes(); let ptr = buf.as_ptr() as usize; diff --git a/src/usr/socket.rs b/src/usr/socket.rs index 2b627142..12203e73 100644 --- a/src/usr/socket.rs +++ b/src/usr/socket.rs @@ -1,28 +1,27 @@ use crate::{sys, usr, debug}; use crate::api::console::Style; -use crate::api::clock; use crate::api::io; +use crate::api::fs::IO; use crate::api::process::ExitCode; -use crate::api::random; use crate::api::syscall; +use crate::sys::fs::OpenFlag; use alloc::format; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; use core::str::{self, FromStr}; -use smoltcp::iface::SocketSet; -use smoltcp::socket::tcp; -use smoltcp::time::Instant; use smoltcp::wire::IpAddress; +fn print_prompt() { + print!("{}>{} ", Style::color("Cyan"), Style::reset()); +} + pub fn main(args: &[&str]) -> Result<(), ExitCode> { let mut listen = false; let mut prompt = false; let mut verbose = false; let mut read_only = false; - let mut interval = 0.0; - let mut next_arg_is_interval = false; let mut args: Vec<&str> = args.iter().filter_map(|arg| { match *arg { "-l" | "--listen" => { @@ -41,24 +40,13 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { verbose = true; None } - "-i" | "--interval" => { - next_arg_is_interval = true; - None - } - _ if next_arg_is_interval => { - next_arg_is_interval = false; - if let Ok(i) = arg.parse() { - interval = i; - } - None - } _ => { Some(*arg) } } }).collect(); if prompt { - println!("MOROS Socket v0.1.0\n"); + println!("MOROS Socket v0.2.0\n"); } let required_args_count = if listen { 2 } else { 3 }; @@ -79,7 +67,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let host = if listen { "0.0.0.0" } else { args[1] }; let port: u16 = args[required_args_count - 1].parse().expect("Could not parse port"); - let address = if host.ends_with(char::is_numeric) { + let addr = if host.ends_with(char::is_numeric) { IpAddress::from_str(host).expect("invalid address format") } else { match usr::host::resolve(host) { @@ -93,129 +81,62 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } }; - #[derive(Debug)] - enum State { Connecting, Sending, Receiving } - let mut state = State::Connecting; - - if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { - let mut sockets = SocketSet::new(vec![]); - let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1024]); - let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); - let tcp_handle = sockets.add(tcp_socket); + let mut line = String::new(); + if prompt { + print_prompt(); + } - loop { - if sys::console::end_of_text() || sys::console::end_of_transmission() { - eprintln!(); + let stdin = 0; + let stdout = 1; + let flags = OpenFlag::Device as usize; + if let Some(handle) = syscall::open("/dev/net/tcp", flags) { + if listen { + if syscall::listen(handle, port).is_err() { + error!("Could not listen to {}:{}", addr, port); + syscall::close(handle); return Err(ExitCode::Failure); } - let time = Instant::from_micros((clock::realtime() * 1000000.0) as i64); - iface.poll(time, device, &mut sockets); - let socket = sockets.get_mut::(tcp_handle); - let cx = iface.context(); + } else { + if syscall::connect(handle, addr, port).is_err() { + error!("Could not connect to {}:{}", addr, port); + syscall::close(handle); + return Err(ExitCode::Failure); + } + } - if verbose { - debug!("*********************************"); - debug!("APP State: {:?}", state); - debug!("TCP State: {:?}", socket.state()); - debug!("is active: {}", socket.is_active()); - debug!("is open: {}", socket.is_open()); - debug!("can recv: {}", socket.can_recv()); - debug!("can send: {}", socket.can_send()); - debug!("may recv: {}", socket.may_recv()); - debug!("may send: {}", socket.may_send()); + loop { + if sys::console::end_of_text() || sys::console::end_of_transmission() { + syscall::close(handle); + return Ok(()); } - state = match state { - State::Connecting if !socket.is_active() => { - if listen { // Listen to a local port - if !socket.is_open() { - if verbose { - debug!("Listening to {}", port); + let list = vec![(stdin, IO::Read), (handle, IO::Read)]; + if let Some((h, _)) = syscall::poll(&list) { + if h == stdin { + match io::stdin().read_char() { + Some('\n') => { + line.push_str("\r\n"); + syscall::write(handle, &line.as_bytes()); + line.clear(); + if prompt { + print_prompt(); } - socket.listen(port).unwrap(); - } - } else { // Connect to a remote port - let local_port = 49152 + random::get_u16() % 16384; - if verbose { - debug!("Connecting to {}:{}", address, port); } - if socket.connect(cx, (address, port), local_port).is_err() { - error!("Could not connect to {}:{}", address, port); - return Err(ExitCode::Failure); + Some(c) => { + line.push(c); } + None => {} } - State::Receiving - } - State::Sending if socket.can_recv() => { - if verbose { - debug!("Sending -> Receiving"); + } else { + let mut data = vec![0; 2048]; + if let Some(bytes) = syscall::read(handle, &mut data) { + data.resize(bytes, 0); + syscall::write(stdout, &data); } - State::Receiving - } - State::Sending if socket.can_send() && socket.may_recv() => { - if !read_only { - if verbose { - debug!("Sending ..."); - } - if prompt { - // Print prompt - print!("{}>{} ", Style::color("Cyan"), Style::reset()); - } - let line = io::stdin().read_line(); - if line.is_empty() { - socket.close(); - } else { - let line = line.replace("\n", "\r\n"); - socket.send_slice(line.as_ref()).expect("cannot send"); - } - } - State::Receiving - } - State::Receiving if socket.can_recv() => { - if verbose { - debug!("Receiving ..."); - } - socket.recv(|data| { - let contents = String::from_utf8_lossy(data); - print!("{}", contents.replace("\r\n", "\n")); - (data.len(), ()) - }).unwrap(); - State::Receiving - } - _ if socket.state() == tcp::State::SynSent || socket.state() == tcp::State::SynReceived => { - state } - State::Receiving if !socket.may_recv() && !listen => { - if verbose { - debug!("Break from response"); - } - break; - } - State::Receiving if socket.can_send() => { - if verbose { - debug!("Receiving -> Sending"); - } - State::Sending - } - _ if !socket.is_active() && !listen => { - if verbose { - debug!("Break from inactive"); - } - break; - } - _ => state - }; - - if interval > 0.0 { - syscall::sleep(interval); - } - if let Some(wait_duration) = iface.poll_delay(time, &sockets) { - syscall::sleep((wait_duration.total_micros() as f64) / 1000000.0); } } - Ok(()) } else { Err(ExitCode::Failure) } From 6ff4ef18a862cb3da87d2dbee0e9ae77d536e43f Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 11 Jul 2023 08:28:28 +0200 Subject: [PATCH 16/37] Update console polling --- src/sys/console.rs | 2 +- src/usr/socket.rs | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/sys/console.rs b/src/sys/console.rs index d473a3a0..6966480e 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -49,7 +49,7 @@ impl FileIO for Console { fn poll(&mut self, event: IO) -> bool { match event { - IO::Read => !STDIN.lock().is_empty(), + IO::Read => STDIN.lock().contains('\n'), IO::Write => true, } } diff --git a/src/usr/socket.rs b/src/usr/socket.rs index 12203e73..630bc91d 100644 --- a/src/usr/socket.rs +++ b/src/usr/socket.rs @@ -81,7 +81,6 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } }; - let mut line = String::new(); if prompt { print_prompt(); } @@ -107,6 +106,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { loop { if sys::console::end_of_text() || sys::console::end_of_transmission() { + println!(); syscall::close(handle); return Ok(()); } @@ -114,19 +114,10 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let list = vec![(stdin, IO::Read), (handle, IO::Read)]; if let Some((h, _)) = syscall::poll(&list) { if h == stdin { - match io::stdin().read_char() { - Some('\n') => { - line.push_str("\r\n"); - syscall::write(handle, &line.as_bytes()); - line.clear(); - if prompt { - print_prompt(); - } - } - Some(c) => { - line.push(c); - } - None => {} + let line = io::stdin().read_line().replace("\n", "\r\n"); + syscall::write(handle, &line.as_bytes()); + if prompt { + print_prompt(); } } else { let mut data = vec![0; 2048]; From 4b241ed32ba90c86228fddeb626c75c179fe3896 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 12 Jul 2023 14:07:14 +0200 Subject: [PATCH 17/37] Rename file handle to handle --- doc/shell.md | 8 +++---- src/sys/process.rs | 44 +++++++++++++++++++------------------- src/sys/syscall/service.rs | 26 +++++++++++----------- src/usr/shell.rs | 12 +++++------ src/usr/socket.rs | 1 - www/shell.html | 8 +++---- 6 files changed, 49 insertions(+), 50 deletions(-) diff --git a/doc/shell.md b/doc/shell.md index a31f1a9d..29ec303f 100644 --- a/doc/shell.md +++ b/doc/shell.md @@ -100,15 +100,15 @@ file while the standard error is kept: > time read foo.txt => /dev/null The standard output is implied as the source of a redirection, but it is -possible to explicitly redirect a file handle to another (TODO): +possible to explicitly redirect a handle to another (TODO): > time read foo.txt [1]=>[3] -Or to redirect a file handle to a file: +Or to redirect a handle to a file: > time read foo.txt [1]=> bar.txt -Or to pipe a file handle to another command: +Or to pipe a handle to another command: > time read foo.txt [1]-> write bar.txt @@ -125,7 +125,7 @@ Redirections should be declared before piping (TODO): > write <= req.txt => /net/http/moros.cc -> find --line href -> sort -NOTE: The following file handles are available when a process is created: +NOTE: The following handles are available when a process is created: - `stdin(0)` - `stdout(1)` diff --git a/src/sys/process.rs b/src/sys/process.rs index 365d62ad..a52f1a06 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -13,7 +13,7 @@ use object::{Object, ObjectSegment}; use spin::RwLock; use x86_64::structures::idt::InterruptStackFrameValue; -const MAX_FILE_HANDLES: usize = 64; +const MAX_HANDLES: usize = 64; const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once const MAX_PROC_SIZE: usize = 10 << 20; // 10 MB @@ -29,7 +29,7 @@ pub struct ProcessData { env: BTreeMap, dir: String, user: Option, - file_handles: [Option>; MAX_FILE_HANDLES], + handles: [Option>; MAX_HANDLES], } impl ProcessData { @@ -37,12 +37,12 @@ impl ProcessData { let env = BTreeMap::new(); let dir = dir.to_string(); let user = user.map(String::from); - let mut file_handles = [(); MAX_FILE_HANDLES].map(|_| None); - file_handles[0] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stdin - file_handles[1] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stdout - file_handles[2] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stderr - file_handles[3] = Some(Box::new(Resource::Device(Device::Null))); // stdnull - Self { env, dir, user, file_handles } + let mut handles = [(); MAX_HANDLES].map(|_| None); + handles[0] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stdin + handles[1] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stdout + handles[2] = Some(Box::new(Resource::Device(Device::Console(Console::new())))); // stderr + handles[3] = Some(Box::new(Resource::Device(Device::Null))); // stdnull + Self { env, dir, user, handles } } } @@ -96,43 +96,43 @@ pub fn set_user(user: &str) { proc.data.user = Some(user.into()) } -pub fn create_file_handle(file: Resource) -> Result { +pub fn create_handle(file: Resource) -> Result { let mut table = PROCESS_TABLE.write(); let proc = &mut table[id()]; - let min = 4; // The first 4 file handles are reserved - let max = MAX_FILE_HANDLES; + let min = 4; // The first 4 handles are reserved + let max = MAX_HANDLES; for handle in min..max { - if proc.data.file_handles[handle].is_none() { - proc.data.file_handles[handle] = Some(Box::new(file)); + if proc.data.handles[handle].is_none() { + proc.data.handles[handle] = Some(Box::new(file)); return Ok(handle); } } - debug!("Could not create file handle"); + debug!("Could not create handle"); Err(()) } -pub fn update_file_handle(handle: usize, file: Resource) { +pub fn update_handle(handle: usize, file: Resource) { let mut table = PROCESS_TABLE.write(); let proc = &mut table[id()]; - proc.data.file_handles[handle] = Some(Box::new(file)); + proc.data.handles[handle] = Some(Box::new(file)); } -pub fn delete_file_handle(handle: usize) { +pub fn delete_handle(handle: usize) { let mut table = PROCESS_TABLE.write(); let proc = &mut table[id()]; - proc.data.file_handles[handle] = None; + proc.data.handles[handle] = None; } -pub fn file_handle(handle: usize) -> Option> { +pub fn handle(handle: usize) -> Option> { let table = PROCESS_TABLE.read(); let proc = &table[id()]; - proc.data.file_handles[handle].clone() + proc.data.handles[handle].clone() } -pub fn file_handles() -> Vec>> { +pub fn handles() -> Vec>> { let table = PROCESS_TABLE.read(); let proc = &table[id()]; - proc.data.file_handles.to_vec() + proc.data.handles.to_vec() } pub fn code_addr() -> u64 { diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 0f4d02de..3ca0e313 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -45,7 +45,7 @@ pub fn open(path: &str, flags: usize) -> isize { Err(_) => return -1, }; if let Some(resource) = sys::fs::open(&path, flags) { - if let Ok(handle) = sys::process::create_file_handle(resource) { + if let Ok(handle) = sys::process::create_handle(resource) { return handle as isize; } } @@ -53,17 +53,17 @@ pub fn open(path: &str, flags: usize) -> isize { } pub fn dup(old_handle: usize, new_handle: usize) -> isize { - if let Some(file) = sys::process::file_handle(old_handle) { - sys::process::update_file_handle(new_handle, *file); + if let Some(file) = sys::process::handle(old_handle) { + sys::process::update_handle(new_handle, *file); return new_handle as isize; } -1 } pub fn read(handle: usize, buf: &mut [u8]) -> isize { - if let Some(mut file) = sys::process::file_handle(handle) { + if let Some(mut file) = sys::process::handle(handle) { if let Ok(bytes) = file.read(buf) { - sys::process::update_file_handle(handle, *file); + sys::process::update_handle(handle, *file); return bytes as isize; } } @@ -71,9 +71,9 @@ pub fn read(handle: usize, buf: &mut [u8]) -> isize { } pub fn write(handle: usize, buf: &mut [u8]) -> isize { - if let Some(mut file) = sys::process::file_handle(handle) { + if let Some(mut file) = sys::process::handle(handle) { if let Ok(bytes) = file.write(buf) { - sys::process::update_file_handle(handle, *file); + sys::process::update_handle(handle, *file); return bytes as isize; } } @@ -81,9 +81,9 @@ pub fn write(handle: usize, buf: &mut [u8]) -> isize { } pub fn close(handle: usize) { - if let Some(mut file) = sys::process::file_handle(handle) { + if let Some(mut file) = sys::process::handle(handle) { file.close(); - sys::process::delete_file_handle(handle); + sys::process::delete_handle(handle); } } @@ -132,7 +132,7 @@ pub fn stop(code: usize) -> usize { pub fn poll(list: &[(usize, IO)]) -> isize { for (i, (handle, event)) in list.iter().enumerate() { - if let Some(mut file) = sys::process::file_handle(*handle) { + if let Some(mut file) = sys::process::handle(*handle) { if file.poll(*event) { return i as isize; } @@ -142,7 +142,7 @@ pub fn poll(list: &[(usize, IO)]) -> isize { } pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { - if let Some(file) = sys::process::file_handle(handle) { + if let Some(file) = sys::process::handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { if dev.connect(addr, port).is_ok() { return 0; @@ -153,7 +153,7 @@ pub fn connect(handle: usize, addr: IpAddress, port: u16) -> isize { } pub fn listen(handle: usize, port: u16) -> isize { - if let Some(file) = sys::process::file_handle(handle) { + if let Some(file) = sys::process::handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { if dev.listen(port).is_ok() { return 0; @@ -164,7 +164,7 @@ pub fn listen(handle: usize, port: u16) -> isize { } pub fn accept(handle: usize) -> Result { - if let Some(file) = sys::process::file_handle(handle) { + if let Some(file) = sys::process::handle(handle) { if let sys::fs::Resource::Device(Device::TcpSocket(mut dev)) = *file { return dev.accept(); } diff --git a/src/usr/shell.rs b/src/usr/shell.rs index c27e6703..bfbef59d 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -252,7 +252,7 @@ fn cmd_proc(args: &[&str]) -> Result<(), ExitCode> { Ok(()) } "files" => { - for (i, handle) in sys::process::file_handles().iter().enumerate() { + for (i, handle) in sys::process::handles().iter().enumerate() { if let Some(resource) = handle { println!("{}: {:?}", i, resource); } @@ -380,7 +380,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> { let mut args: Vec<&str> = args.iter().map(String::as_str).collect(); // Redirections - let mut restore_file_handles = false; + let mut restore_handles = false; let mut n = args.len(); let mut i = 0; loop { @@ -417,7 +417,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> { continue; } - // Parse file handles + // Parse handles let mut num = String::new(); for c in args[i].chars() { match c { @@ -438,10 +438,10 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> { } if is_fat_arrow { // Redirections - restore_file_handles = true; + restore_handles = true; if !num.is_empty() { // if let Ok(right_handle) = num.parse() {} - println!("Redirecting to a file handle has not been implemented yet"); + println!("Redirecting to a handle has not been implemented yet"); return Err(ExitCode::Failure); } else { if i == n - 1 { @@ -538,7 +538,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> { // TODO: Remove this when redirections are done in spawned process - if restore_file_handles { + if restore_handles { for i in 0..3 { api::fs::reopen("/dev/console", i, false).ok(); } diff --git a/src/usr/socket.rs b/src/usr/socket.rs index 630bc91d..7df1bea2 100644 --- a/src/usr/socket.rs +++ b/src/usr/socket.rs @@ -7,7 +7,6 @@ use crate::api::syscall; use crate::sys::fs::OpenFlag; use alloc::format; -use alloc::string::String; use alloc::vec; use alloc::vec::Vec; use core::str::{self, FromStr}; diff --git a/www/shell.html b/www/shell.html index 28b7d4c3..df8720f1 100644 --- a/www/shell.html +++ b/www/shell.html @@ -119,17 +119,17 @@

Pipes and redirections (WIP)

The standard output is implied as the source of a redirection, but it is -possible to explicitly redirect a file handle to another (TODO):

+possible to explicitly redirect a handle to another (TODO):

> time read foo.txt [1]=>[3]
 
-

Or to redirect a file handle to a file:

+

Or to redirect a handle to a file:

> time read foo.txt [1]=> bar.txt
 
-

Or to pipe a file handle to another command:

+

Or to pipe a handle to another command:

> time read foo.txt [1]-> write bar.txt
 
@@ -150,7 +150,7 @@

Pipes and redirections (WIP)

> write <= req.txt => /net/http/moros.cc -> find --line href -> sort
 
-

NOTE: The following file handles are available when a process is created:

+

NOTE: The following handles are available when a process is created:

  • stdin(0)
  • From 705b554386038524e0593734363b607a0ba6263d Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Thu, 13 Jul 2023 15:21:31 +0200 Subject: [PATCH 18/37] Remove prompt option from socket --- doc/network.md | 31 +++++++++++++------------------ src/usr/socket.rs | 20 +------------------- 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/doc/network.md b/doc/network.md index dc1f0672..1cf6c7b3 100644 --- a/doc/network.md +++ b/doc/network.md @@ -107,12 +107,10 @@ For example the request made with `tcp` above is equivalent to this: And the request made with `http` is equivalent to that: - > socket moros.cc 80 --prompt - MOROS Socket v0.1.0 + > socket moros.cc 80 + GET /test.html HTTP/1.0 + Host: moros.cc - > GET /test.html HTTP/1.0 - > Host: moros.cc - > HTTP/1.1 200 OK Server: nginx Date: Wed, 11 May 2022 21:46:34 GMT @@ -136,25 +134,22 @@ And the request made with `http` is equivalent to that: Here's a connexion to a SMTP server to send a mail: - > socket 10.0.2.2 2500 --prompt - MOROS Socket v0.1.0 - + > socket 10.0.2.2 2500 220 EventMachine SMTP Server - > EHLO moros.cc + HELO moros.cc 250-Ok EventMachine SMTP Server - 250-NO-SOLICITING - 250 SIZE 20000000 - > MAIL FROM: + MAIL FROM: 250 Ok - > RCPT TO: + RCPT TO: 250 Ok - > DATA + DATA 354 Send it - > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec - > diam vitae ex blandit malesuada nec a turpis. - > . + Subject: Test + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec + diam vitae ex blandit malesuada nec a turpis. + . 250 Message accepted - > QUIT + QUIT 221 Ok Sending a file to a server: diff --git a/src/usr/socket.rs b/src/usr/socket.rs index 7df1bea2..5314d66d 100644 --- a/src/usr/socket.rs +++ b/src/usr/socket.rs @@ -12,13 +12,8 @@ use alloc::vec::Vec; use core::str::{self, FromStr}; use smoltcp::wire::IpAddress; -fn print_prompt() { - print!("{}>{} ", Style::color("Cyan"), Style::reset()); -} - pub fn main(args: &[&str]) -> Result<(), ExitCode> { let mut listen = false; - let mut prompt = false; let mut verbose = false; let mut read_only = false; let mut args: Vec<&str> = args.iter().filter_map(|arg| { @@ -27,10 +22,6 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { listen = true; None } - "-p" | "--prompt" => { - prompt = true; - None - } "-r" | "--read-only" => { read_only = true; None @@ -44,7 +35,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } } }).collect(); - if prompt { + if verbose { println!("MOROS Socket v0.2.0\n"); } @@ -80,10 +71,6 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { } }; - if prompt { - print_prompt(); - } - let stdin = 0; let stdout = 1; let flags = OpenFlag::Device as usize; @@ -115,9 +102,6 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { if h == stdin { let line = io::stdin().read_line().replace("\n", "\r\n"); syscall::write(handle, &line.as_bytes()); - if prompt { - print_prompt(); - } } else { let mut data = vec![0; 2048]; if let Some(bytes) = syscall::read(handle, &mut data) { @@ -141,7 +125,5 @@ fn help() { println!("{}Options:{}", csi_title, csi_reset); println!(" {0}-l{1}, {0}--listen{1} Listen to a local port", csi_option, csi_reset); println!(" {0}-v{1}, {0}--verbose{1} Increase verbosity", csi_option, csi_reset); - println!(" {0}-p{1}, {0}--prompt{1} Display prompt", csi_option, csi_reset); println!(" {0}-r{1}, {0}--read-only{1} Read only connexion", csi_option, csi_reset); - println!(" {0}-i{1}, {0}--interval

File Library

@@ -239,6 +240,7 @@

Unreleased

  • Add file, number, string, and regex namespaces
  • +
  • Add socket functions