mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
add tcp support and tcp_simplehttp app
This commit is contained in:
parent
3897e6e50f
commit
2a4c7c2cc3
@ -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"
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<VirtIONet<'static, VirtioHal>>);
|
||||
|
||||
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::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
|
||||
let virtio = VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
|
||||
.expect("can't create net device by virtio");
|
||||
VirtIONetWrapper(UPIntrFreeCell::new(virtio))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<LoseStack>);
|
||||
|
||||
@ -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<NetStack> = 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);
|
||||
}
|
||||
}
|
||||
|
131
os/src/net/port_table.rs
Normal file
131
os/src/net/port_table.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
@ -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<Vec<u8>> // datas
|
||||
pub buffers: VecDeque<Vec<u8>>, // datas
|
||||
pub seq: u32,
|
||||
pub ack: u32
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SOCKET_TABLE:UPIntrFreeCell<Vec<Option<Socket>>> = unsafe {
|
||||
UPIntrFreeCell::new(Vec::new())
|
||||
};
|
||||
static ref SOCKET_TABLE: UPIntrFreeCell<Vec<Option<Socket>>> =
|
||||
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> {
|
||||
@ -30,7 +58,7 @@ pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
|
||||
|
||||
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<usize> {
|
||||
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<u8>) {
|
||||
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<Vec<u8>> {
|
||||
@ -90,4 +124,4 @@ pub fn pop_data(index: usize) -> Option<Vec<u8>> {
|
||||
assert!(socket_table[index].is_some());
|
||||
|
||||
socket_table[index].as_mut().unwrap().buffers.pop_front()
|
||||
}
|
||||
}
|
||||
|
113
os/src/net/tcp.rs
Normal file
113
os/src/net/tcp.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
189
user/src/bin/tcp_simplehttp.rs
Normal file
189
user/src/bin/tcp_simplehttp.rs
Normal 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);
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -2,4 +2,12 @@ use super::*;
|
||||
|
||||
pub fn connect(ip: u32, sport: u16, dport: u16) -> isize {
|
||||
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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user