From 2a4c7c2cc3e99dc6c6366d8910ddbed422174443 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Fri, 3 Mar 2023 16:58:07 +0800 Subject: [PATCH] add tcp support and tcp_simplehttp app --- os/Cargo.toml | 2 +- os/Makefile | 4 +- os/src/drivers/bus/virtio.rs | 8 +- os/src/drivers/net/mod.rs | 21 ++-- os/src/main.rs | 2 +- os/src/net/mod.rs | 72 ++++++++++--- os/src/net/port_table.rs | 131 +++++++++++++++++++++++ os/src/net/socket.rs | 52 +++++++-- os/src/net/tcp.rs | 113 ++++++++++++++++++++ os/src/net/udp.rs | 45 ++++---- os/src/syscall/mod.rs | 8 +- os/src/syscall/net.rs | 49 ++++++++- user/src/bin/tcp_simplehttp.rs | 189 +++++++++++++++++++++++++++++++++ user/src/bin/udp.rs | 6 +- user/src/file.rs | 2 +- user/src/lib.rs | 14 +-- user/src/net.rs | 10 +- user/src/sync.rs | 2 +- user/src/syscall.rs | 19 +++- 19 files changed, 666 insertions(+), 83 deletions(-) create mode 100644 os/src/net/port_table.rs create mode 100644 os/src/net/tcp.rs create mode 100644 user/src/bin/tcp_simplehttp.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index 51fc1e88..89732b9b 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -15,7 +15,7 @@ bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" 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" } embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/Makefile b/os/Makefile index ac0fd273..a8bb617f 100644 --- a/os/Makefile +++ b/os/Makefile @@ -86,7 +86,7 @@ run-inner-none: build -device virtio-keyboard-device \ -device virtio-mouse-device \ -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 run-inner: build @@ -102,7 +102,7 @@ run-inner: build -device virtio-keyboard-device \ -device virtio-mouse-device \ -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 fdt: diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index d9a61219..069d4785 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,6 +1,6 @@ use crate::mm::{ - frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, frame_alloc_more, + frame_alloc_more, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, + StepByOne, VirtAddr, }; use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; @@ -18,7 +18,9 @@ impl Hal for VirtioHal { fn dma_alloc(pages: usize) -> usize { let trakcers = frame_alloc_more(pages); 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(); pa.0 } diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs index e1f76b00..7a705876 100644 --- a/os/src/drivers/net/mod.rs +++ b/os/src/drivers/net/mod.rs @@ -1,10 +1,10 @@ use core::any::Any; -use alloc::sync::Arc; -use lazy_static::*; -use virtio_drivers::{VirtIONet, VirtIOHeader}; use crate::drivers::virtio::VirtioHal; use crate::sync::UPIntrFreeCell; +use alloc::sync::Arc; +use lazy_static::*; +use virtio_drivers::{VirtIOHeader, VirtIONet}; const VIRTIO8: usize = 0x10004000; @@ -21,21 +21,26 @@ pub struct VirtIONetWrapper(UPIntrFreeCell>); impl NetDevice for VirtIONetWrapper { 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 { - self.0.exclusive_access().recv(data).expect("can't receive data") + self.0 + .exclusive_access() + .recv(data) + .expect("can't receive data") } } impl VirtIONetWrapper { pub fn new() -> Self { unsafe { - let virtio = - VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) + let virtio = VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) .expect("can't create net device by virtio"); VirtIONetWrapper(UPIntrFreeCell::new(virtio)) } } -} \ No newline at end of file +} diff --git a/os/src/main.rs b/os/src/main.rs index 83554ae7..cc194cfb 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -22,13 +22,13 @@ mod drivers; mod fs; mod lang_items; mod mm; +mod net; mod sbi; mod sync; mod syscall; mod task; mod timer; mod trap; -mod net; use riscv::register::*; // mod riscvreg; diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs index 57673d3e..f98f5662 100644 --- a/os/src/net/mod.rs +++ b/os/src/net/mod.rs @@ -1,12 +1,20 @@ -pub mod udp; pub mod socket; +pub mod tcp; +pub mod udp; +pub mod port_table; pub use lose_net_stack::IPv4; -use alloc::{vec, sync::Arc}; -use lose_net_stack::{LoseStack, MacAddress, results::Packet}; +use alloc::{sync::Arc, vec}; +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); @@ -15,7 +23,7 @@ impl NetStack { unsafe { NetStack(UPIntrFreeCell::new(LoseStack::new( 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 = Arc::new(NetStack::new()); } - pub fn net_interrupt_handler() { let mut recv_buf = vec![0u8; 1024]; 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"); // hexdump(&recv_buf[..len]); match packet { Packet::ARP(arp_packet) => { 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(); NET_DEVICE.transmit(&reply_data) - }, + } Packet::UDP(udp_packet) => { let target = udp_packet.source_ip; let lport = udp_packet.dest_port; let rport = udp_packet.source_port; - + if let Some(socket_index) = get_socket(target, lport, rport) { 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} ", ""); } } - + println!(""); } println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); -} \ No newline at end of file +} diff --git a/os/src/net/port_table.rs b/os/src/net/port_table.rs new file mode 100644 index 00000000..c7690758 --- /dev/null +++ b/os/src/net/port_table.rs @@ -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> +} + +lazy_static! { + static ref LISTEN_TABLE: UPIntrFreeCell>> = + unsafe { UPIntrFreeCell::new(Vec::new()) }; +} + +pub fn listen(port: u16) -> Option { + 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) { + 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> = 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) { + 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 + } +} + diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs index 4e92a00e..e1393c82 100644 --- a/os/src/net/socket.rs +++ b/os/src/net/socket.rs @@ -5,19 +5,47 @@ use lose_net_stack::IPv4; use crate::sync::UPIntrFreeCell; - // TODO: specify the protocol, TCP or UDP pub struct Socket { pub raddr: IPv4, // remote address pub lport: u16, // local port pub rport: u16, // rempote port - pub buffers: VecDeque> // datas + pub buffers: VecDeque>, // datas + pub seq: u32, + pub ack: u32 } lazy_static! { - static ref SOCKET_TABLE:UPIntrFreeCell>> = unsafe { - UPIntrFreeCell::new(Vec::new()) - }; + static ref SOCKET_TABLE: UPIntrFreeCell>> = + 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 { @@ -30,7 +58,7 @@ pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { let sock = sock.as_ref().unwrap(); if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { - return Some(i) + return Some(i); } } None @@ -54,7 +82,9 @@ pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { raddr, lport, rport, - buffers: VecDeque::new() + buffers: VecDeque::new(), + seq: 0, + ack: 0 }; if index == usize::MAX { @@ -80,7 +110,11 @@ pub fn push_data(index: usize, data: Vec) { assert!(socket_table.len() > index); 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> { @@ -90,4 +124,4 @@ pub fn pop_data(index: usize) -> Option> { assert!(socket_table[index].is_some()); socket_table[index].as_mut().unwrap().buffers.pop_front() -} \ No newline at end of file +} diff --git a/os/src/net/tcp.rs b/os/src/net/tcp.rs new file mode 100644 index 00000000..5cd7cb32 --- /dev/null +++ b/os/src/net/tcp.rs @@ -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) + } +} diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs index afa26d0e..f343ed47 100644 --- a/os/src/net/udp.rs +++ b/os/src/net/udp.rs @@ -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::socket::{add_socket, remove_socket, pop_data}; +use super::socket::{add_socket, pop_data, remove_socket}; use super::LOSE_NET_STACK; 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 sport: u16, pub dport: u16, - pub socket_index: usize + pub socket_index: usize, } impl UDP { @@ -23,7 +23,7 @@ impl UDP { target, sport, dport, - socket_index: index + socket_index: index, } } } @@ -44,9 +44,10 @@ impl File for UDP { 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)]); - + + buf.buffers[i][..buffer_i_len] + .copy_from_slice(&data[left..(left + buffer_i_len)]); + left += buffer_i_len; if left == data_len { break; @@ -63,7 +64,7 @@ impl File for UDP { 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]); @@ -73,14 +74,14 @@ impl File for UDP { let len = data.len(); let udp_packet = UDPPacket::new( - lose_net_stack.ip, - lose_net_stack.mac, - self.sport, - self.target, - MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), - self.dport, - len, - data.as_ref() + lose_net_stack.ip, + lose_net_stack.mac, + self.sport, + self.target, + MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + self.dport, + len, + data.as_ref(), ); NET_DEVICE.transmit(&udp_packet.build_data()); len @@ -91,4 +92,4 @@ impl Drop for UDP { fn drop(&mut self) { remove_socket(self.socket_index) } -} \ No newline at end of file +} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index a336a96f..cd12de02 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,5 +1,7 @@ const SYSCALL_DUP: usize = 24; const SYSCALL_CONNECT: usize = 29; +const SYSCALL_LISTEN: usize = 30; +const SYSCALL_ACCEPT: usize = 31; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -34,23 +36,25 @@ const SYSCALL_KEY_PRESSED: usize = 3001; mod fs; mod gui; mod input; +mod net; mod process; mod sync; mod thread; -mod net; use fs::*; use gui::*; use input::*; +use net::*; use process::*; use sync::*; use thread::*; -use net::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), 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_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs index 4ed4466d..57f8e07a 100644 --- a/os/src/syscall/net.rs +++ b/os/src/syscall/net.rs @@ -1,7 +1,8 @@ -use alloc::sync::Arc; -use crate::net::IPv4; +use crate::net::port_table::{listen, PortFd, accept, port_acceptable}; 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 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 udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); inner.fd_table[fd] = Some(Arc::new(udp_node)); - fd as isize -} \ No newline at end of file + 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 +} diff --git a/user/src/bin/tcp_simplehttp.rs b/user/src/bin/tcp_simplehttp.rs new file mode 100644 index 00000000..7ea71a9a --- /dev/null +++ b/user/src/bin/tcp_simplehttp.rs @@ -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#" + + + + + + + + + + +
+

server closed

+
+ + "#; + 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#" + + + + + + + + + + +
+

lose-net-stack

+

rcore-tutorial 是一个 基于 RISC-V 架构的 类 Unix 内核.

+
+ +
+
+
+

Rust

+

Rust

+

Rust是一门系统编程语言,专注于安全,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言

+
+
+

仓库地址

+

repo url

+

https://github.com/yfblock/lose-net-stack

+
+
+

QQ 群号

+

Official QQ group number

+

735045051

+
+
+
+ +
+

点击下列按钮即可关闭服务器。

+ +
+ + + "#; + + 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); +} diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs index f2f00936..68a1a109 100644 --- a/user/src/bin/udp.rs +++ b/user/src/bin/udp.rs @@ -8,12 +8,12 @@ extern crate user_lib; #[macro_use] extern crate alloc; -use user_lib::{connect, write, read}; +use user_lib::{connect, read, write}; #[no_mangle] pub fn main() -> i32 { println!("udp test open!"); - + let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); if udp_fd < 0 { @@ -43,4 +43,4 @@ pub fn main() -> i32 { println!("receive reply <{}>", recv_str); 0 -} \ No newline at end of file +} diff --git a/user/src/file.rs b/user/src/file.rs index bf77667a..19e25641 100644 --- a/user/src/file.rs +++ b/user/src/file.rs @@ -27,4 +27,4 @@ pub fn read(fd: usize, buf: &mut [u8]) -> isize { } pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) -} \ No newline at end of file +} diff --git a/user/src/lib.rs b/user/src/lib.rs index 1b5b2f38..bda0e8b6 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -6,13 +6,13 @@ #[macro_use] pub mod console; -mod lang_items; -mod syscall; mod file; -mod task; -mod sync; mod io; +mod lang_items; mod net; +mod sync; +mod syscall; +mod task; extern crate alloc; #[macro_use] @@ -20,12 +20,12 @@ extern crate bitflags; use alloc::vec::Vec; use buddy_system_allocator::LockedHeap; -use syscall::*; pub use file::*; -pub use task::*; -pub use sync::*; pub use io::*; pub use net::*; +pub use sync::*; +use syscall::*; +pub use task::*; const USER_HEAP_SIZE: usize = 32768; diff --git a/user/src/net.rs b/user/src/net.rs index 40ebca45..78529d00 100644 --- a/user/src/net.rs +++ b/user/src/net.rs @@ -2,4 +2,12 @@ use super::*; pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { sys_connect(ip, sport, dport) -} \ No newline at end of file +} + +pub fn listen(sport: u16) -> isize { + sys_listen(sport) +} + +pub fn accept(socket_fd: usize) -> isize { + sys_accept(socket_fd) +} diff --git a/user/src/sync.rs b/user/src/sync.rs index c41e4d6b..82cd2a0a 100644 --- a/user/src/sync.rs +++ b/user/src/sync.rs @@ -29,4 +29,4 @@ pub fn condvar_signal(condvar_id: usize) { } pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { sys_condvar_wait(condvar_id, mutex_id); -} \ No newline at end of file +} diff --git a/user/src/syscall.rs b/user/src/syscall.rs index c5fb48dc..48b3e99c 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,5 +1,7 @@ const SYSCALL_DUP: usize = 24; const SYSCALL_CONNECT: usize = 29; +const SYSCALL_LISTEN: usize = 30; +const SYSCALL_ACCEPT: usize = 31; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; 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 { - 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 { @@ -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]) } - pub fn sys_framebuffer() -> isize { syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0]) } @@ -179,4 +192,4 @@ pub fn sys_event_get() -> isize { pub fn sys_key_pressed() -> isize { syscall(SYSCALL_KEY_PRESSED, [0, 0, 0]) -} \ No newline at end of file +}