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
> 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