add tcp support and tcp_simplehttp app

This commit is contained in:
yufeng 2023-03-03 16:58:07 +08:00 committed by Yifan Wu
parent 3897e6e50f
commit 2a4c7c2cc3
19 changed files with 666 additions and 83 deletions

View File

@ -15,7 +15,7 @@ bitflags = "1.2.1"
xmas-elf = "0.7.0" xmas-elf = "0.7.0"
volatile = "0.3" volatile = "0.3"
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" } lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "db42380" }
easy-fs = { path = "../easy-fs" } easy-fs = { path = "../easy-fs" }
embedded-graphics = "0.7.1" embedded-graphics = "0.7.1"
tinybmp = "0.3.1" tinybmp = "0.3.1"

View File

@ -86,7 +86,7 @@ run-inner-none: build
-device virtio-keyboard-device \ -device virtio-keyboard-device \
-device virtio-mouse-device \ -device virtio-mouse-device \
-device virtio-net-device,netdev=net0 \ -device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \ -netdev user,id=net0,hostfwd=udp::6200-:2000,hostfwd=tcp::6201-:80 \
-serial stdio -serial stdio
run-inner: build run-inner: build
@ -102,7 +102,7 @@ run-inner: build
-device virtio-keyboard-device \ -device virtio-keyboard-device \
-device virtio-mouse-device \ -device virtio-mouse-device \
-device virtio-net-device,netdev=net0 \ -device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \ -netdev user,id=net0,hostfwd=udp::6200-:2000,hostfwd=tcp::6201-:80 \
-serial stdio -serial stdio
fdt: fdt:

View File

@ -1,6 +1,6 @@
use crate::mm::{ use crate::mm::{
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, frame_alloc_more, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
StepByOne, VirtAddr, frame_alloc_more, StepByOne, VirtAddr,
}; };
use crate::sync::UPIntrFreeCell; use crate::sync::UPIntrFreeCell;
use alloc::vec::Vec; use alloc::vec::Vec;
@ -18,7 +18,9 @@ impl Hal for VirtioHal {
fn dma_alloc(pages: usize) -> usize { fn dma_alloc(pages: usize) -> usize {
let trakcers = frame_alloc_more(pages); let trakcers = frame_alloc_more(pages);
let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn;
QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap()); QUEUE_FRAMES
.exclusive_access()
.append(&mut trakcers.unwrap());
let pa: PhysAddr = ppn_base.into(); let pa: PhysAddr = ppn_base.into();
pa.0 pa.0
} }

View File

@ -1,10 +1,10 @@
use core::any::Any; use core::any::Any;
use alloc::sync::Arc;
use lazy_static::*;
use virtio_drivers::{VirtIONet, VirtIOHeader};
use crate::drivers::virtio::VirtioHal; use crate::drivers::virtio::VirtioHal;
use crate::sync::UPIntrFreeCell; use crate::sync::UPIntrFreeCell;
use alloc::sync::Arc;
use lazy_static::*;
use virtio_drivers::{VirtIOHeader, VirtIONet};
const VIRTIO8: usize = 0x10004000; const VIRTIO8: usize = 0x10004000;
@ -21,21 +21,26 @@ pub struct VirtIONetWrapper(UPIntrFreeCell<VirtIONet<'static, VirtioHal>>);
impl NetDevice for VirtIONetWrapper { impl NetDevice for VirtIONetWrapper {
fn transmit(&self, data: &[u8]) { fn transmit(&self, data: &[u8]) {
self.0.exclusive_access().send(data).expect("can't send data") self.0
.exclusive_access()
.send(data)
.expect("can't send data")
} }
fn receive(&self, data: &mut [u8]) -> usize { fn receive(&self, data: &mut [u8]) -> usize {
self.0.exclusive_access().recv(data).expect("can't receive data") self.0
.exclusive_access()
.recv(data)
.expect("can't receive data")
} }
} }
impl VirtIONetWrapper { impl VirtIONetWrapper {
pub fn new() -> Self { pub fn new() -> Self {
unsafe { unsafe {
let virtio = let virtio = VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
.expect("can't create net device by virtio"); .expect("can't create net device by virtio");
VirtIONetWrapper(UPIntrFreeCell::new(virtio)) VirtIONetWrapper(UPIntrFreeCell::new(virtio))
} }
} }
} }

View File

@ -22,13 +22,13 @@ mod drivers;
mod fs; mod fs;
mod lang_items; mod lang_items;
mod mm; mod mm;
mod net;
mod sbi; mod sbi;
mod sync; mod sync;
mod syscall; mod syscall;
mod task; mod task;
mod timer; mod timer;
mod trap; mod trap;
mod net;
use riscv::register::*; use riscv::register::*;
// mod riscvreg; // mod riscvreg;

View File

@ -1,12 +1,20 @@
pub mod udp;
pub mod socket; pub mod socket;
pub mod tcp;
pub mod udp;
pub mod port_table;
pub use lose_net_stack::IPv4; pub use lose_net_stack::IPv4;
use alloc::{vec, sync::Arc}; use alloc::{sync::Arc, vec};
use lose_net_stack::{LoseStack, MacAddress, results::Packet}; use lose_net_stack::{results::Packet, LoseStack, MacAddress, TcpFlags};
use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}}; use crate::{
drivers::NET_DEVICE,
net::socket::{get_socket, push_data},
sync::UPIntrFreeCell,
};
use self::{port_table::check_accept, socket::set_s_a_by_index};
pub struct NetStack(UPIntrFreeCell<LoseStack>); pub struct NetStack(UPIntrFreeCell<LoseStack>);
@ -15,7 +23,7 @@ impl NetStack {
unsafe { unsafe {
NetStack(UPIntrFreeCell::new(LoseStack::new( NetStack(UPIntrFreeCell::new(LoseStack::new(
IPv4::new(10, 0, 2, 15), IPv4::new(10, 0, 2, 15),
MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]) MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]),
))) )))
} }
} }
@ -25,34 +33,70 @@ lazy_static::lazy_static! {
static ref LOSE_NET_STACK: Arc<NetStack> = Arc::new(NetStack::new()); static ref LOSE_NET_STACK: Arc<NetStack> = Arc::new(NetStack::new());
} }
pub fn net_interrupt_handler() { pub fn net_interrupt_handler() {
let mut recv_buf = vec![0u8; 1024]; let mut recv_buf = vec![0u8; 1024];
let len = NET_DEVICE.receive(&mut recv_buf); let len = NET_DEVICE.receive(&mut recv_buf);
let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]); let packet = LOSE_NET_STACK
.0
.exclusive_access()
.analysis(&recv_buf[..len]);
// println!("[kernel] receive a packet"); // println!("[kernel] receive a packet");
// hexdump(&recv_buf[..len]); // hexdump(&recv_buf[..len]);
match packet { match packet {
Packet::ARP(arp_packet) => { Packet::ARP(arp_packet) => {
let lose_stack = LOSE_NET_STACK.0.exclusive_access(); let lose_stack = LOSE_NET_STACK.0.exclusive_access();
let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply"); let reply_packet = arp_packet
.reply_packet(lose_stack.ip, lose_stack.mac)
.expect("can't build reply");
let reply_data = reply_packet.build_data(); let reply_data = reply_packet.build_data();
NET_DEVICE.transmit(&reply_data) NET_DEVICE.transmit(&reply_data)
}, }
Packet::UDP(udp_packet) => { Packet::UDP(udp_packet) => {
let target = udp_packet.source_ip; let target = udp_packet.source_ip;
let lport = udp_packet.dest_port; let lport = udp_packet.dest_port;
let rport = udp_packet.source_port; let rport = udp_packet.source_port;
if let Some(socket_index) = get_socket(target, lport, rport) { if let Some(socket_index) = get_socket(target, lport, rport) {
push_data(socket_index, udp_packet.data.to_vec()); push_data(socket_index, udp_packet.data.to_vec());
} }
} }
Packet::TCP(tcp_packet) => {
let target = tcp_packet.source_ip;
let lport = tcp_packet.dest_port;
let rport = tcp_packet.source_port;
let flags = tcp_packet.flags;
if flags.contains(TcpFlags::S) {
// if it has a port to accept, then response the request
if check_accept(lport, &tcp_packet).is_some() {
let mut reply_packet = tcp_packet.ack();
reply_packet.flags = TcpFlags::S | TcpFlags::A;
NET_DEVICE.transmit(&reply_packet.build_data());
}
return;
} else if tcp_packet.flags.contains(TcpFlags::F) {
// tcp disconnected
let reply_packet = tcp_packet.ack();
NET_DEVICE.transmit(&reply_packet.build_data());
let mut end_packet = reply_packet.ack();
end_packet.flags |= TcpFlags::F;
NET_DEVICE.transmit(&end_packet.build_data());
} else if tcp_packet.flags.contains(TcpFlags::A) && tcp_packet.data_len == 0 {
return;
}
if let Some(socket_index) = get_socket(target, lport, rport) {
push_data(socket_index, tcp_packet.data.to_vec());
set_s_a_by_index(socket_index, tcp_packet.seq, tcp_packet.ack);
}
}
_ => {} _ => {}
} }
} }
@ -85,8 +129,8 @@ pub fn hexdump(data: &[u8]) {
print!("{:02} ", ""); print!("{:02} ", "");
} }
} }
println!(""); println!("");
} }
println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH);
} }

131
os/src/net/port_table.rs Normal file
View File

@ -0,0 +1,131 @@
use alloc::{vec::Vec, sync::Arc};
use lazy_static::lazy_static;
use lose_net_stack::packets::tcp::TCPPacket;
use crate::{sync::UPIntrFreeCell, fs::File, task::{TaskControlBlock, wakeup_task}};
use super::tcp::TCP;
pub struct Port {
pub port: u16,
pub receivable: bool,
pub schedule: Option<Arc<TaskControlBlock>>
}
lazy_static! {
static ref LISTEN_TABLE: UPIntrFreeCell<Vec<Option<Port>>> =
unsafe { UPIntrFreeCell::new(Vec::new()) };
}
pub fn listen(port: u16) -> Option<usize> {
let mut listen_table = LISTEN_TABLE.exclusive_access();
let mut index = usize::MAX;
for i in 0..listen_table.len() {
if listen_table[i].is_none() {
index = i;
break;
}
}
let listen_port = Port {
port,
receivable: false,
schedule: None
};
if index == usize::MAX {
listen_table.push(Some(listen_port));
Some(listen_table.len() - 1)
} else {
listen_table[index] = Some(listen_port);
Some(index)
}
}
// can accept request
pub fn accept(listen_index: usize, task: Arc<TaskControlBlock>) {
let mut listen_table = LISTEN_TABLE.exclusive_access();
assert!(listen_index < listen_table.len());
let listen_port = listen_table[listen_index].as_mut();
assert!(listen_port.is_some());
let listen_port = listen_port.unwrap();
listen_port.receivable = true;
listen_port.schedule = Some(task);
}
pub fn port_acceptable(listen_index: usize) -> bool {
let mut listen_table = LISTEN_TABLE.exclusive_access();
assert!(listen_index < listen_table.len());
let listen_port = listen_table[listen_index].as_mut();
listen_port.map_or(false, |x| x.receivable)
}
// check whether it can accept request
pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> {
LISTEN_TABLE.exclusive_session(|listen_table| {
let mut listen_ports: Vec<&mut Option<Port>> = listen_table.iter_mut().filter(|x| match x {
Some(t) => t.port == port && t.receivable == true,
None => false,
}).collect();
if listen_ports.len() == 0 {
None
} else {
let listen_port = listen_ports[0].as_mut().unwrap();
let task = listen_port.schedule.clone().unwrap();
// wakeup_task(Arc::clone(&listen_port.schedule.clone().unwrap()));
listen_port.schedule = None;
listen_port.receivable = false;
accept_connection(port, tcp_packet, task);
Some(())
}
})
}
pub fn accept_connection(port: u16, tcp_packet: &TCPPacket, task: Arc<TaskControlBlock>) {
let process = task.process.upgrade().unwrap();
let mut inner = process.inner_exclusive_access();
let fd = inner.alloc_fd();
let tcp_socket = TCP::new(tcp_packet.source_ip, tcp_packet.dest_port, tcp_packet.source_port, tcp_packet.seq, tcp_packet.ack);
inner.fd_table[fd] = Some(Arc::new(tcp_socket));
let cx = task.inner_exclusive_access().get_trap_cx();
cx.x[10] = fd;
}
// store in the fd_table, delete the listen table when close the application.
pub struct PortFd(usize);
impl PortFd {
pub fn new(port_index: usize) -> Self {
PortFd(port_index)
}
}
impl Drop for PortFd {
fn drop(&mut self) {
LISTEN_TABLE.exclusive_access()[self.0] = None
}
}
impl File for PortFd {
fn readable(&self) -> bool {
false
}
fn writable(&self) -> bool {
false
}
fn read(&self, _buf: crate::mm::UserBuffer) -> usize {
0
}
fn write(&self, _buf: crate::mm::UserBuffer) -> usize {
0
}
}

View File

@ -5,19 +5,47 @@ use lose_net_stack::IPv4;
use crate::sync::UPIntrFreeCell; use crate::sync::UPIntrFreeCell;
// TODO: specify the protocol, TCP or UDP // TODO: specify the protocol, TCP or UDP
pub struct Socket { pub struct Socket {
pub raddr: IPv4, // remote address pub raddr: IPv4, // remote address
pub lport: u16, // local port pub lport: u16, // local port
pub rport: u16, // rempote port pub rport: u16, // rempote port
pub buffers: VecDeque<Vec<u8>> // datas pub buffers: VecDeque<Vec<u8>>, // datas
pub seq: u32,
pub ack: u32
} }
lazy_static! { lazy_static! {
static ref SOCKET_TABLE:UPIntrFreeCell<Vec<Option<Socket>>> = unsafe { static ref SOCKET_TABLE: UPIntrFreeCell<Vec<Option<Socket>>> =
UPIntrFreeCell::new(Vec::new()) unsafe { UPIntrFreeCell::new(Vec::new()) };
}; }
/// get the seq and ack by socket index
pub fn get_s_a_by_index(index: usize) -> Option<(u32, u32)> {
let socket_table = SOCKET_TABLE.exclusive_access();
assert!(index < socket_table.len());
socket_table.get(index).map_or(None, |x| {
match x {
Some(x) => Some((x.seq, x.ack)),
None => None,
}
})
}
pub fn set_s_a_by_index(index: usize, seq: u32, ack: u32) {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
let sock = socket_table[index]
.as_mut()
.unwrap();
sock.ack = ack;
sock.seq = seq;
} }
pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> { pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
@ -30,7 +58,7 @@ pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
let sock = sock.as_ref().unwrap(); let sock = sock.as_ref().unwrap();
if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { if sock.raddr == raddr && sock.lport == lport && sock.rport == rport {
return Some(i) return Some(i);
} }
} }
None None
@ -54,7 +82,9 @@ pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
raddr, raddr,
lport, lport,
rport, rport,
buffers: VecDeque::new() buffers: VecDeque::new(),
seq: 0,
ack: 0
}; };
if index == usize::MAX { if index == usize::MAX {
@ -80,7 +110,11 @@ pub fn push_data(index: usize, data: Vec<u8>) {
assert!(socket_table.len() > index); assert!(socket_table.len() > index);
assert!(socket_table[index].is_some()); assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.push_back(data); socket_table[index]
.as_mut()
.unwrap()
.buffers
.push_back(data);
} }
pub fn pop_data(index: usize) -> Option<Vec<u8>> { pub fn pop_data(index: usize) -> Option<Vec<u8>> {
@ -90,4 +124,4 @@ pub fn pop_data(index: usize) -> Option<Vec<u8>> {
assert!(socket_table[index].is_some()); assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.pop_front() socket_table[index].as_mut().unwrap().buffers.pop_front()
} }

113
os/src/net/tcp.rs Normal file
View File

@ -0,0 +1,113 @@
use alloc::vec;
use lose_net_stack::MacAddress;
use lose_net_stack::IPv4;
use lose_net_stack::TcpFlags;
use lose_net_stack::packets::tcp::TCPPacket;
use crate::{drivers::NET_DEVICE, fs::File};
use super::socket::get_s_a_by_index;
use super::{
net_interrupt_handler,
socket::{add_socket, pop_data, remove_socket},
LOSE_NET_STACK,
};
// add tcp packet info to this structure
pub struct TCP {
pub target: IPv4,
pub sport: u16,
pub dport: u16,
pub seq: u32,
pub ack: u32,
pub socket_index: usize,
}
impl TCP {
pub fn new(target: IPv4, sport: u16, dport: u16, seq: u32, ack: u32) -> Self {
let index = add_socket(target, sport, dport).expect("can't add socket");
Self {
target,
sport,
dport,
seq,
ack,
socket_index: index,
}
}
}
impl File for TCP {
fn readable(&self) -> bool {
true
}
fn writable(&self) -> bool {
true
}
fn read(&self, mut buf: crate::mm::UserBuffer) -> usize {
loop {
if let Some(data) = pop_data(self.socket_index) {
let data_len = data.len();
let mut left = 0;
for i in 0..buf.buffers.len() {
let buffer_i_len = buf.buffers[i].len().min(data_len - left);
buf.buffers[i][..buffer_i_len]
.copy_from_slice(&data[left..(left + buffer_i_len)]);
left += buffer_i_len;
if left == data_len {
break;
}
}
return left;
} else {
net_interrupt_handler();
}
}
}
fn write(&self, buf: crate::mm::UserBuffer) -> usize {
let lose_net_stack = LOSE_NET_STACK.0.exclusive_access();
let mut data = vec![0u8; buf.len()];
let mut left = 0;
for i in 0..buf.buffers.len() {
data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]);
left += buf.buffers[i].len();
}
let len = data.len();
// get sock and sequence
let (ack, seq) = get_s_a_by_index(self.socket_index).map_or((0, 0), |x| x);
let tcp_packet = TCPPacket {
source_ip: lose_net_stack.ip,
source_mac: lose_net_stack.mac,
source_port: self.sport,
dest_ip: self.target,
dest_mac: MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
dest_port: self.dport,
data_len: len,
seq,
ack,
flags: TcpFlags::A,
win: 65535,
urg: 0,
data: data.as_ref(),
};
NET_DEVICE.transmit(&tcp_packet.build_data());
len
}
}
impl Drop for TCP {
fn drop(&mut self) {
remove_socket(self.socket_index)
}
}

View File

@ -1,18 +1,18 @@
use alloc::vec;
use lose_net_stack::MacAddress;
use lose_net_stack::packets::udp::UDPPacket;
use lose_net_stack::IPv4;
use crate::fs::File;
use super::net_interrupt_handler; use super::net_interrupt_handler;
use super::socket::{add_socket, remove_socket, pop_data}; use super::socket::{add_socket, pop_data, remove_socket};
use super::LOSE_NET_STACK; use super::LOSE_NET_STACK;
use super::NET_DEVICE; use super::NET_DEVICE;
use crate::fs::File;
use alloc::vec;
use lose_net_stack::packets::udp::UDPPacket;
use lose_net_stack::IPv4;
use lose_net_stack::MacAddress;
pub struct UDP{ pub struct UDP {
pub target: IPv4, pub target: IPv4,
pub sport: u16, pub sport: u16,
pub dport: u16, pub dport: u16,
pub socket_index: usize pub socket_index: usize,
} }
impl UDP { impl UDP {
@ -23,7 +23,7 @@ impl UDP {
target, target,
sport, sport,
dport, dport,
socket_index: index socket_index: index,
} }
} }
} }
@ -44,9 +44,10 @@ impl File for UDP {
let mut left = 0; let mut left = 0;
for i in 0..buf.buffers.len() { for i in 0..buf.buffers.len() {
let buffer_i_len = buf.buffers[i].len().min(data_len - left); let buffer_i_len = buf.buffers[i].len().min(data_len - left);
buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]); buf.buffers[i][..buffer_i_len]
.copy_from_slice(&data[left..(left + buffer_i_len)]);
left += buffer_i_len; left += buffer_i_len;
if left == data_len { if left == data_len {
break; break;
@ -63,7 +64,7 @@ impl File for UDP {
let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); let lose_net_stack = LOSE_NET_STACK.0.exclusive_access();
let mut data = vec![0u8; buf.len()]; let mut data = vec![0u8; buf.len()];
let mut left = 0; let mut left = 0;
for i in 0..buf.buffers.len() { for i in 0..buf.buffers.len() {
data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]);
@ -73,14 +74,14 @@ impl File for UDP {
let len = data.len(); let len = data.len();
let udp_packet = UDPPacket::new( let udp_packet = UDPPacket::new(
lose_net_stack.ip, lose_net_stack.ip,
lose_net_stack.mac, lose_net_stack.mac,
self.sport, self.sport,
self.target, self.target,
MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
self.dport, self.dport,
len, len,
data.as_ref() data.as_ref(),
); );
NET_DEVICE.transmit(&udp_packet.build_data()); NET_DEVICE.transmit(&udp_packet.build_data());
len len
@ -91,4 +92,4 @@ impl Drop for UDP {
fn drop(&mut self) { fn drop(&mut self) {
remove_socket(self.socket_index) remove_socket(self.socket_index)
} }
} }

View File

@ -1,5 +1,7 @@
const SYSCALL_DUP: usize = 24; const SYSCALL_DUP: usize = 24;
const SYSCALL_CONNECT: usize = 29; const SYSCALL_CONNECT: usize = 29;
const SYSCALL_LISTEN: usize = 30;
const SYSCALL_ACCEPT: usize = 31;
const SYSCALL_OPEN: usize = 56; const SYSCALL_OPEN: usize = 56;
const SYSCALL_CLOSE: usize = 57; const SYSCALL_CLOSE: usize = 57;
const SYSCALL_PIPE: usize = 59; const SYSCALL_PIPE: usize = 59;
@ -34,23 +36,25 @@ const SYSCALL_KEY_PRESSED: usize = 3001;
mod fs; mod fs;
mod gui; mod gui;
mod input; mod input;
mod net;
mod process; mod process;
mod sync; mod sync;
mod thread; mod thread;
mod net;
use fs::*; use fs::*;
use gui::*; use gui::*;
use input::*; use input::*;
use net::*;
use process::*; use process::*;
use sync::*; use sync::*;
use thread::*; use thread::*;
use net::*;
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
match syscall_id { match syscall_id {
SYSCALL_DUP => sys_dup(args[0]), SYSCALL_DUP => sys_dup(args[0]),
SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _), SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _),
SYSCALL_LISTEN => sys_listen(args[0] as _),
SYSCALL_ACCEPT => sys_accept(args[0] as _),
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_CLOSE => sys_close(args[0]),
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),

View File

@ -1,7 +1,8 @@
use alloc::sync::Arc; use crate::net::port_table::{listen, PortFd, accept, port_acceptable};
use crate::net::IPv4;
use crate::net::udp::UDP; use crate::net::udp::UDP;
use crate::task::current_process; use crate::net::{IPv4, net_interrupt_handler};
use crate::task::{current_process, block_current_and_run_next, current_task, current_trap_cx};
use alloc::sync::Arc;
// just support udp // just support udp
pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize { pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize {
@ -10,5 +11,43 @@ pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize {
let fd = inner.alloc_fd(); let fd = inner.alloc_fd();
let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport);
inner.fd_table[fd] = Some(Arc::new(udp_node)); inner.fd_table[fd] = Some(Arc::new(udp_node));
fd as isize fd as isize
} }
// listen a port
pub fn sys_listen(port: u16) -> isize {
match listen(port) {
Some(port_index) => {
let process = current_process();
let mut inner = process.inner_exclusive_access();
let fd = inner.alloc_fd();
let port_fd = PortFd::new(port_index);
inner.fd_table[fd] = Some(Arc::new(port_fd));
// NOTICE: this return the port index, not the fd
port_index as isize
}
None => -1,
}
}
// accept a tcp connection
pub fn sys_accept(port_index: usize) -> isize {
println!("accepting port {}", port_index);
let task = current_task().unwrap();
accept(port_index, task);
// block_current_and_run_next();
// NOTICE: There does not have interrupt handler, just call it munually.
loop {
net_interrupt_handler();
if !port_acceptable(port_index) {
break;
}
}
let cx = current_trap_cx();
cx.x[10] as isize
}

View File

@ -0,0 +1,189 @@
#![no_std]
#![no_main]
use alloc::string::{String, ToString};
#[macro_use]
extern crate user_lib;
#[macro_use]
extern crate alloc;
// use http://localhost:6201/ to access the http server
use user_lib::{read, write, listen, accept};
// get url from the tcp request list.
fn get_url_from_tcp_request(req: &[u8]) -> String {
let mut index = 0;
for i in 4..req.len() {
if req[i] == 0x20 {
index = i;
break;
}
}
String::from_utf8_lossy(&req[4..index]).to_string()
}
// just receive GET requests
fn handle_tcp_client(client_fd: usize) -> bool {
// a buf to receive the data from the server
let mut buf = vec![0u8; 1024];
let len = read(client_fd as usize, &mut buf);
println!("receive {} bytes", len);
hexdump(&buf[..len as usize]);
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
if len < 4 || buf[..4] != [0x47,0x45,0x54, 0x20] {
println!("it's not a valid http request");
return false;
}
let url = get_url_from_tcp_request(&buf);
if url == "/close" {
let content = r#"<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container-fluid p-5 bg-danger text-white text-center">
<h1>server closed</h1>
</div>
</body>
</html>"#;
let response = format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnecion: Close\r\n\r\n{}", content.len(),content);
write(client_fd, response.as_bytes());
// terminate the connection immediately.
return true;
}
let content = r#"<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container-fluid p-5 bg-primary text-white text-center">
<h1>lose-net-stack</h1>
<p>rcore-tutorial RISC-V Unix .</p>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-4">
<h3>Rust</h3>
<p>Rust</p>
<p>Rust是一门系统编程语言</p>
</div>
<div class="col-sm-4">
<h3></h3>
<p>repo url</p>
<p>https://github.com/yfblock/lose-net-stack</p>
</div>
<div class="col-sm-4">
<h3>QQ </h3>
<p>Official QQ group number</p>
<p>735045051</p>
</div>
</div>
</div>
<div class="container p-5 text-black text-center d-grid col-sm-4">
<p></p>
<button type="button" class="btn btn-warning btn-block p-3" onclick="close_server()"> server</button>
</div>
<script>
function close_server() {
location.href = "/close";
}
</script>
</body>
</html>"#;
let response = format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnecion: Close\r\n\r\n{}", content.len(),content);
// write a response
write(client_fd, response.as_bytes());
false
}
#[no_mangle]
pub fn main() -> i32 {
println!("This is a very simple http server");
let tcp_fd = listen(80);
if tcp_fd < 0 {
println!("Failed to listen on port 80");
return -1;
}
loop {
let client = accept(tcp_fd as usize);
println!("client connected: {}", client);
if client < 1 {
println!("Failed to accept a client on port 80");
return -1;
}
if handle_tcp_client(client as usize) {
break;
}
}
println!("finish tcp test");
// String::from_utf8_lossy(&buf[..len as usize])
0
}
#[allow(unused)]
pub fn hexdump(data: &[u8]) {
const PRELAND_WIDTH: usize = 70;
println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH);
for offset in (0..data.len()).step_by(16) {
print!("[kernel] ");
for i in 0..16 {
if offset + i < data.len() {
print!("{:02x} ", data[offset + i]);
} else {
print!("{:02} ", "");
}
}
print!("{:>6}", ' ');
for i in 0..16 {
if offset + i < data.len() {
let c = data[offset + i];
if c >= 0x20 && c <= 0x7e {
print!("{}", c as char);
} else {
print!(".");
}
} else {
print!("{:02} ", "");
}
}
println!("");
}
println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH);
}

View File

@ -8,12 +8,12 @@ extern crate user_lib;
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;
use user_lib::{connect, write, read}; use user_lib::{connect, read, write};
#[no_mangle] #[no_mangle]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("udp test open!"); println!("udp test open!");
let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099);
if udp_fd < 0 { if udp_fd < 0 {
@ -43,4 +43,4 @@ pub fn main() -> i32 {
println!("receive reply <{}>", recv_str); println!("receive reply <{}>", recv_str);
0 0
} }

View File

@ -27,4 +27,4 @@ pub fn read(fd: usize, buf: &mut [u8]) -> isize {
} }
pub fn write(fd: usize, buf: &[u8]) -> isize { pub fn write(fd: usize, buf: &[u8]) -> isize {
sys_write(fd, buf) sys_write(fd, buf)
} }

View File

@ -6,13 +6,13 @@
#[macro_use] #[macro_use]
pub mod console; pub mod console;
mod lang_items;
mod syscall;
mod file; mod file;
mod task;
mod sync;
mod io; mod io;
mod lang_items;
mod net; mod net;
mod sync;
mod syscall;
mod task;
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]
@ -20,12 +20,12 @@ extern crate bitflags;
use alloc::vec::Vec; use alloc::vec::Vec;
use buddy_system_allocator::LockedHeap; use buddy_system_allocator::LockedHeap;
use syscall::*;
pub use file::*; pub use file::*;
pub use task::*;
pub use sync::*;
pub use io::*; pub use io::*;
pub use net::*; pub use net::*;
pub use sync::*;
use syscall::*;
pub use task::*;
const USER_HEAP_SIZE: usize = 32768; const USER_HEAP_SIZE: usize = 32768;

View File

@ -2,4 +2,12 @@ use super::*;
pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { pub fn connect(ip: u32, sport: u16, dport: u16) -> isize {
sys_connect(ip, sport, dport) sys_connect(ip, sport, dport)
} }
pub fn listen(sport: u16) -> isize {
sys_listen(sport)
}
pub fn accept(socket_fd: usize) -> isize {
sys_accept(socket_fd)
}

View File

@ -29,4 +29,4 @@ pub fn condvar_signal(condvar_id: usize) {
} }
pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { pub fn condvar_wait(condvar_id: usize, mutex_id: usize) {
sys_condvar_wait(condvar_id, mutex_id); sys_condvar_wait(condvar_id, mutex_id);
} }

View File

@ -1,5 +1,7 @@
const SYSCALL_DUP: usize = 24; const SYSCALL_DUP: usize = 24;
const SYSCALL_CONNECT: usize = 29; const SYSCALL_CONNECT: usize = 29;
const SYSCALL_LISTEN: usize = 30;
const SYSCALL_ACCEPT: usize = 31;
const SYSCALL_OPEN: usize = 56; const SYSCALL_OPEN: usize = 56;
const SYSCALL_CLOSE: usize = 57; const SYSCALL_CLOSE: usize = 57;
const SYSCALL_PIPE: usize = 59; const SYSCALL_PIPE: usize = 59;
@ -50,7 +52,19 @@ pub fn sys_dup(fd: usize) -> isize {
} }
pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize { pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize {
syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize]) syscall(
SYSCALL_CONNECT,
[dest as usize, sport as usize, dport as usize],
)
}
// just listen for tcp connections now
pub fn sys_listen(sport: u16) -> isize {
syscall(SYSCALL_LISTEN, [sport as usize, 0, 0])
}
pub fn sys_accept(socket_fd: usize) -> isize {
syscall(SYSCALL_ACCEPT, [socket_fd, 0, 0])
} }
pub fn sys_open(path: &str, flags: u32) -> isize { pub fn sys_open(path: &str, flags: u32) -> isize {
@ -164,7 +178,6 @@ pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize {
syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0])
} }
pub fn sys_framebuffer() -> isize { pub fn sys_framebuffer() -> isize {
syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0]) syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0])
} }
@ -179,4 +192,4 @@ pub fn sys_event_get() -> isize {
pub fn sys_key_pressed() -> isize { pub fn sys_key_pressed() -> isize {
syscall(SYSCALL_KEY_PRESSED, [0, 0, 0]) syscall(SYSCALL_KEY_PRESSED, [0, 0, 0])
} }