ready for merge in master (#964)

uevent should be format

Enum of smoltcp socket should be optimized.

need to add interface for routing subsys

actix is still not abled to run.

clean some casual added code to other places
This commit is contained in:
2024-10-10 17:53:39 +08:00
committed by GitHub
parent 79eda4bcf9
commit 40d9375b6b
102 changed files with 10497 additions and 3303 deletions

3
user/apps/ping/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
/install/

18
user/apps/ping/Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "ping"
version = "0.1.0"
edition = "2021"
description = "ping for dragonOS"
authors = [ "smallc <2628035541@qq.com>" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.86"
clap = { version = "4.5.11", features = ["derive"] }
crossbeam-channel = "0.5.13"
pnet = "0.35.0"
rand = "0.8.5"
signal-hook = "0.3.17"
socket2 = "0.5.7"
thiserror = "1.0.63"

56
user/apps/ping/Makefile Normal file
View File

@ -0,0 +1,56 @@
TOOLCHAIN=
RUSTFLAGS=
ifdef DADK_CURRENT_BUILD_DIR
# 如果是在dadk中编译那么安装到dadk的安装目录中
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
else
# 如果是在本地编译那么安装到当前目录下的install目录中
INSTALL_DIR = ./install
endif
ifeq ($(ARCH), x86_64)
export RUST_TARGET=x86_64-unknown-linux-musl
else ifeq ($(ARCH), riscv64)
export RUST_TARGET=riscv64gc-unknown-linux-gnu
else
# 默认为x86_86用于本地编译
export RUST_TARGET=x86_64-unknown-linux-musl
endif
run:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
build:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
clean:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
test:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
doc:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
fmt:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
fmt-check:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
run-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
build-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
clean-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
test-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
.PHONY: install
install:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

23
user/apps/ping/README.md Normal file
View File

@ -0,0 +1,23 @@
# PING
为DragonOS实现ping
## NAME
ping - 向网络主机发送ICMP ECHO_REQUEST
## SYNOPSIS
[-c count] 指定 ping 的次数。例如,`-c 4` 会向目标主机发送 4 个 ping 请求。
[-i interval]:指定两次 ping 请求之间的时间间隔,单位是秒。例如,`-i 2` 会每 2 秒发送一次 ping 请求。
[-w timeout] 指定等待 ping 响应的超时时间,单位是秒。例如,`-w 5` 会在 5 秒后超时。
[-s packetsize]:指定发送的 ICMP Packet 的大小,单位是字节。例如,`-s 64` 会发送大小为 64 字节的 ICMP Packet。
[-t ttl]:指定 ping 的 TTL (Time to Live)。例如,`-t 64` 会设置 TTL 为 64。
{destination}:指定要 ping 的目标主机。可以是 IP 地址或者主机名。例如,`192.168.1.1``www.example.com`
## DESCRIPTION
ping 使用 ICMP 协议的必需的 ECHO_REQUEST 数据报来引发主机或网关的 ICMP ECHO_RESPONSE。ECHO_REQUEST 数据报“ping”具有 IP 和 ICMP 头,后面跟着一个 struct timeval然后是用于填充数据包的任意数量的“填充”字节。
ping 支持 IPv4 和 IPv6。可以通过指定 -4 或 -6 来强制只使用其中一个。
ping 还可以发送 IPv6 节点信息查询RFC4620。可能不允许中间跳跃因为 IPv6 源路由已被弃用RFC5095

View File

@ -0,0 +1,50 @@
use clap::{arg, command, Parser};
use rand::random;
use crate::config::{Config, IpAddress};
/// # Args结构体
/// 使用clap库对命令行输入进行pasing产生参数配置
#[derive(Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)]
pub struct Args {
// Count of ping times
#[arg(short, default_value_t = 4)]
count: u16,
// Ping packet size
#[arg(short = 's', default_value_t = 64)]
packet_size: usize,
// Ping ttl
#[arg(short = 't', default_value_t = 64)]
ttl: u32,
// Ping timeout seconds
#[arg(short = 'w', default_value_t = 1)]
timeout: u64,
// Ping interval duration milliseconds
#[arg(short = 'i', default_value_t = 1000)]
interval: u64,
// Ping destination, ip or domain
#[arg(value_parser=IpAddress::parse)]
destination: IpAddress,
}
impl Args {
/// # 将Args结构体转换为config结构体
pub fn as_config(&self) -> Config {
Config {
count: self.count,
packet_size: self.packet_size,
ttl: self.ttl,
timeout: self.timeout,
interval: self.interval,
id: random::<u16>(),
sequence: 1,
address: self.destination.clone(),
}
}
}

View File

@ -0,0 +1,45 @@
use anyhow::bail;
use std::{
ffi::CString,
net::{self},
};
use crate::error;
///# Config结构体
/// 记录ping指令的一些参数值
#[derive(Debug, Clone)]
pub struct Config {
pub count: u16,
pub packet_size: usize,
pub ttl: u32,
pub timeout: u64,
pub interval: u64,
pub id: u16,
pub sequence: u16,
pub address: IpAddress,
}
///# 目标地址ip结构体
/// ip负责提供给socket使用
/// raw负责打印输出
#[derive(Debug, Clone)]
pub struct IpAddress {
pub ip: net::IpAddr,
pub raw: String,
}
impl IpAddress {
pub fn parse(host: &str) -> anyhow::Result<Self> {
let raw = String::from(host);
let opt = host.parse::<net::IpAddr>().ok();
match opt {
Some(ip) => Ok(Self { ip, raw }),
None => {
bail!(error::PingError::InvalidConfig(
"Invalid Address".to_string()
));
}
}
}
}

View File

@ -0,0 +1,10 @@
#![allow(dead_code)]
#[derive(Debug, Clone, thiserror::Error)]
pub enum PingError {
#[error("invaild config")]
InvalidConfig(String),
#[error("invaild packet")]
InvalidPacket,
}

View File

@ -0,0 +1,23 @@
use args::Args;
use clap::Parser;
use std::format;
mod args;
mod config;
mod error;
mod ping;
///# ping入口主函数
fn main() {
let args = Args::parse();
match ping::Ping::new(args.as_config()) {
Ok(pinger) => pinger.run().unwrap_or_else(|e| {
exit(format!("Error on run ping: {}", e));
}),
Err(e) => exit(format!("Error on init: {}", e)),
}
}
fn exit(msg: String) {
eprintln!("{}", msg);
std::process::exit(1);
}

151
user/apps/ping/src/ping.rs Normal file
View File

@ -0,0 +1,151 @@
use crossbeam_channel::{bounded, select, Receiver};
use pnet::packet::{
icmp::{
echo_reply::{EchoReplyPacket, IcmpCodes},
echo_request::MutableEchoRequestPacket,
IcmpTypes,
},
util, Packet,
};
use signal_hook::consts::{SIGINT, SIGTERM};
use socket2::{Domain, Protocol, Socket, Type};
use std::{
io,
net::{self, Ipv4Addr, SocketAddr},
sync::{
atomic::{AtomicU64, Ordering},
Arc,
},
thread::{self},
time::{Duration, Instant},
};
use crate::{config::Config, error::PingError};
#[derive(Clone)]
pub struct Ping {
config: Config,
socket: Arc<Socket>,
dest: SocketAddr,
}
impl Ping {
///# ping创建函数
/// 使用config进行ping的配置
pub fn new(config: Config) -> std::io::Result<Self> {
let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::ICMPV4))?;
let src = SocketAddr::new(net::IpAddr::V4(Ipv4Addr::UNSPECIFIED), 12549);
let dest = SocketAddr::new(config.address.ip, 12549);
socket.bind(&src.into())?;
// socket.set_ttl(64)?;
// socket.set_read_timeout(Some(Duration::from_secs(config.timeout)))?;
// socket.set_write_timeout(Some(Duration::from_secs(config.timeout)))?;
Ok(Self {
config,
dest,
socket: Arc::new(socket),
})
}
///# ping主要执行逻辑
/// 创建icmpPacket发送给socket
pub fn ping(&self, seq_offset: u16) -> anyhow::Result<()> {
//创建 icmp request packet
let mut buf = vec![0; self.config.packet_size];
let mut icmp = MutableEchoRequestPacket::new(&mut buf[..]).expect("InvalidBuffferSize");
icmp.set_icmp_type(IcmpTypes::EchoRequest);
icmp.set_icmp_code(IcmpCodes::NoCode);
icmp.set_identifier(self.config.id);
icmp.set_sequence_number(self.config.sequence + seq_offset);
icmp.set_checksum(util::checksum(icmp.packet(), 1));
let start = Instant::now();
//发送 request
self.socket.send_to(icmp.packet(), &self.dest.into())?;
//处理 recv
let mut mem_buf =
unsafe { &mut *(buf.as_mut_slice() as *mut [u8] as *mut [std::mem::MaybeUninit<u8>]) };
let (size, _) = self.socket.recv_from(&mut mem_buf)?;
let duration = start.elapsed().as_micros() as f64 / 1000.0;
let reply = EchoReplyPacket::new(&buf).ok_or(PingError::InvalidPacket)?;
println!(
"{} bytes from {}: icmp_seq={} ttl={} time={:.2}ms",
size,
self.config.address.ip,
reply.get_sequence_number(),
self.config.ttl,
duration
);
Ok(())
}
///# ping指令多线程运行
/// 创建多个线程负责不同的ping函数的执行
pub fn run(&self) -> io::Result<()> {
println!(
"PING {}({})",
self.config.address.raw, self.config.address.ip
);
let _now = Instant::now();
let send = Arc::new(AtomicU64::new(0));
let _send = send.clone();
let this = Arc::new(self.clone());
let success = Arc::new(AtomicU64::new(0));
let _success = success.clone();
let mut handles = vec![];
for i in 0..this.config.count {
let _this = this.clone();
let handle = thread::spawn(move||{
_this.ping(i).unwrap();
});
_send.fetch_add(1, Ordering::SeqCst);
handles.push(handle);
if i < this.config.count - 1 {
thread::sleep(Duration::from_millis(this.config.interval));
}
}
for handle in handles {
if handle.join().is_ok() {
_success.fetch_add(1, Ordering::SeqCst);
}
}
let total = _now.elapsed().as_micros() as f64 / 1000.0;
let send = send.load(Ordering::SeqCst);
let success = success.load(Ordering::SeqCst);
let loss_rate = if send > 0 {
(send - success) * 100 / send
} else {
0
};
println!("\n--- {} ping statistics ---", self.config.address.raw);
println!(
"{} packets transmitted, {} received, {}% packet loss, time {}ms",
send, success, loss_rate, total,
);
Ok(())
}
}
//TODO: 等待添加ctrl+c发送信号后添加该特性
// /// # 创建一个进程用于监听用户是否提前退出程序
// fn signal_notify() -> std::io::Result<Receiver<i32>> {
// let (s, r) = bounded(1);
// let mut signals = signal_hook::iterator::Signals::new(&[SIGINT, SIGTERM])?;
// thread::spawn(move || {
// for signal in signals.forever() {
// s.send(signal).unwrap();
// break;
// }
// });
// Ok(r)
// }

View File

@ -0,0 +1,2 @@
[build]
target = "x86_64-unknown-linux-musl"

3
user/apps/test-uevent/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
/install/

View File

@ -0,0 +1,12 @@
[package]
name = "test-uevent"
version = "0.1.0"
edition = "2021"
description = "test for uevent"
authors = [ "val213 <val213666@gmail.com>" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
netlink-sys = "0.5"
nix = "0.24"

View File

@ -0,0 +1,56 @@
TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu"
RUSTFLAGS+=""
ifdef DADK_CURRENT_BUILD_DIR
# 如果是在dadk中编译那么安装到dadk的安装目录中
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
else
# 如果是在本地编译那么安装到当前目录下的install目录中
INSTALL_DIR = ./install
endif
ifeq ($(ARCH), x86_64)
export RUST_TARGET=x86_64-unknown-linux-musl
else ifeq ($(ARCH), riscv64)
export RUST_TARGET=riscv64gc-unknown-linux-gnu
else
# 默认为x86_86用于本地编译
export RUST_TARGET=x86_64-unknown-linux-musl
endif
run:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
build:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
clean:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
test:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
doc:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
fmt:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
fmt-check:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
run-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
build-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
clean-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
test-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
.PHONY: install
install:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

View File

@ -0,0 +1,14 @@
# DragonOS Rust-Application Template
您可以使用此模板来创建DragonOS应用程序。
## 使用方法
1. 使用DragonOS的tools目录下的`bootstrap.sh`脚本初始化环境
2. 在终端输入`cargo install cargo-generate`
3. 在终端输入`cargo generate --git https://github.com/DragonOS-Community/Rust-App-Template`即可创建项目
如果您的网络较慢,请使用镜像站`cargo generate --git https://git.mirrors.dragonos.org/DragonOS-Community/Rust-App-Template`
4. 使用`cargo run`来运行项目
5. 在DragonOS的`user/dadk/config`目录下,使用`dadk new`命令,创建编译配置,安装到DragonOS的`/`目录下。
(在dadk的编译命令选项处请使用Makefile里面的`make install`配置进行编译、安装)
6. 编译DragonOS即可安装

View File

@ -0,0 +1,150 @@
use libc::{sockaddr, sockaddr_storage, recvfrom, bind, sendto, socket, AF_NETLINK, SOCK_DGRAM, SOCK_CLOEXEC, getpid, c_void};
use nix::libc;
use std::os::unix::io::RawFd;
use std::{ mem, io};
#[repr(C)]
struct Nlmsghdr {
nlmsg_len: u32,
nlmsg_type: u16,
nlmsg_flags: u16,
nlmsg_seq: u32,
nlmsg_pid: u32,
}
fn create_netlink_socket() -> io::Result<RawFd> {
let sockfd = unsafe {
socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, libc::NETLINK_KOBJECT_UEVENT)
};
if sockfd < 0 {
println!("Error: {}", io::Error::last_os_error());
return Err(io::Error::last_os_error());
}
Ok(sockfd)
}
fn bind_netlink_socket(sock: RawFd) -> io::Result<()> {
let pid = unsafe { getpid() };
let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
addr.nl_family = AF_NETLINK as u16;
addr.nl_pid = pid as u32;
addr.nl_groups = 0;
let ret = unsafe {
bind(sock, &addr as *const _ as *const sockaddr, mem::size_of::<libc::sockaddr_nl>() as u32)
};
if ret < 0 {
println!("Error: {}", io::Error::last_os_error());
return Err(io::Error::last_os_error());
}
Ok(())
}
fn send_uevent(sock: RawFd, message: &str) -> io::Result<()> {
let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
addr.nl_family = AF_NETLINK as u16;
addr.nl_pid = 0;
addr.nl_groups = 0;
let nlmsghdr = Nlmsghdr {
nlmsg_len: (mem::size_of::<Nlmsghdr>() + message.len()) as u32,
nlmsg_type: 0,
nlmsg_flags: 0,
nlmsg_seq: 0,
nlmsg_pid: 0,
};
let mut buffer = Vec::with_capacity(nlmsghdr.nlmsg_len as usize);
buffer.extend_from_slice(unsafe {
std::slice::from_raw_parts(
&nlmsghdr as *const Nlmsghdr as *const u8,
mem::size_of::<Nlmsghdr>(),
)
});
buffer.extend_from_slice(message.as_bytes());
let ret = unsafe {
sendto(
sock,
buffer.as_ptr() as *const c_void,
buffer.len(),
0,
&addr as *const _ as *const sockaddr,
mem::size_of::<libc::sockaddr_nl>() as u32,
)
};
if ret < 0 {
println!("Error: {}", io::Error::last_os_error());
return Err(io::Error::last_os_error());
}
Ok(())
}
fn receive_uevent(sock: RawFd) -> io::Result<String> {
// 检查套接字文件描述符是否有效
if sock < 0 {
println!("Invalid socket file descriptor: {}", sock);
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid socket file descriptor"));
}
let mut buf = [0u8; 1024];
// let mut addr: sockaddr_storage = unsafe { mem::zeroed() };
// let mut addr_len = mem::size_of::<sockaddr_storage>() as u32;
// 检查缓冲区指针和长度是否有效
if buf.is_empty() {
println!("Buffer is empty");
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Buffer is empty"));
}
let len = unsafe {
recvfrom(
sock,
buf.as_mut_ptr() as *mut c_void,
buf.len(),
0,
core::ptr::null_mut(), // 不接收发送方地址
core::ptr::null_mut(), // 不接收发送方地址长度
)
};
println!("Received {} bytes", len);
println!("Received message: {:?}", &buf[..len as usize]);
if len < 0 {
println!("Error: {}", io::Error::last_os_error());
return Err(io::Error::last_os_error());
}
let nlmsghdr_size = mem::size_of::<Nlmsghdr>();
if (len as usize) < nlmsghdr_size {
println!("Received message is too short");
return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is too short"));
}
let nlmsghdr = unsafe { &*(buf.as_ptr() as *const Nlmsghdr) };
if nlmsghdr.nlmsg_len as isize > len {
println!("Received message is incomplete");
return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is incomplete"));
}
let message_data = &buf[nlmsghdr_size..nlmsghdr.nlmsg_len as usize];
Ok(String::from_utf8_lossy(message_data).to_string())
}
fn main() {
let socket = create_netlink_socket().expect("Failed to create Netlink socket");
println!("Netlink socket created successfully");
bind_netlink_socket(socket).expect("Failed to bind Netlink socket");
println!("Netlink socket created and bound successfully");
send_uevent(socket, "add@/devices/virtual/block/loop0").expect("Failed to send uevent message");
println!("Custom uevent message sent successfully");
let message = receive_uevent(socket).expect("Failed to receive uevent message");
println!("Received uevent message: {}", message);
}

3
user/apps/test_seqpacket/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
/install/

View File

@ -0,0 +1,12 @@
[package]
name = "test_seqpacket"
version = "0.1.0"
edition = "2021"
description = "测试seqpacket的socket"
authors = [ "Saga <1750226968@qq.com>" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nix = "0.26"
libc = "0.2"

View File

@ -0,0 +1,56 @@
TOOLCHAIN=
RUSTFLAGS=
ifdef DADK_CURRENT_BUILD_DIR
# 如果是在dadk中编译那么安装到dadk的安装目录中
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
else
# 如果是在本地编译那么安装到当前目录下的install目录中
INSTALL_DIR = ./install
endif
ifeq ($(ARCH), x86_64)
export RUST_TARGET=x86_64-unknown-linux-musl
else ifeq ($(ARCH), riscv64)
export RUST_TARGET=riscv64gc-unknown-linux-gnu
else
# 默认为x86_86用于本地编译
export RUST_TARGET=x86_64-unknown-linux-musl
endif
run:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
build:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
clean:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
test:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
doc:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
fmt:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
fmt-check:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
run-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
build-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
clean-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
test-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
.PHONY: install
install:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

View File

@ -0,0 +1,14 @@
# DragonOS Rust-Application Template
您可以使用此模板来创建DragonOS应用程序。
## 使用方法
1. 使用DragonOS的tools目录下的`bootstrap.sh`脚本初始化环境
2. 在终端输入`cargo install cargo-generate`
3. 在终端输入`cargo generate --git https://github.com/DragonOS-Community/Rust-App-Template`即可创建项目
如果您的网络较慢,请使用镜像站`cargo generate --git https://git.mirrors.dragonos.org/DragonOS-Community/Rust-App-Template`
4. 使用`cargo run`来运行项目
5. 在DragonOS的`user/dadk/config`目录下,使用`dadk new`命令,创建编译配置,安装到DragonOS的`/`目录下。
(在dadk的编译命令选项处请使用Makefile里面的`make install`配置进行编译、安装)
6. 编译DragonOS即可安装

View File

@ -0,0 +1,190 @@
mod seq_socket;
mod seq_pair;
use seq_socket::test_seq_socket;
use seq_pair::test_seq_pair;
fn main() -> Result<(), std::io::Error> {
if let Err(e) = test_seq_socket() {
println!("[ fault ] test_seq_socket, err: {}", e);
} else {
println!("[success] test_seq_socket");
}
if let Err(e) = test_seq_pair() {
println!("[ fault ] test_seq_pair, err: {}", e);
} else {
println!("[success] test_seq_pair");
}
Ok(())
}
// use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
// use std::fs::File;
// use std::io::{Read, Write};
// use std::os::fd::FromRawFd;
// use std::{fs, str};
// use libc::*;
// use std::ffi::CString;
// use std::io::Error;
// use std::mem;
// use std::os::unix::io::RawFd;
// use std::ptr;
// const SOCKET_PATH: &str = "/test.seqpacket";
// const MSG: &str = "Hello, Unix SEQPACKET socket!";
// fn create_seqpacket_socket() -> Result<RawFd, Error> {
// unsafe {
// let fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
// if fd == -1 {
// return Err(Error::last_os_error());
// }
// Ok(fd)
// }
// }
// fn bind_socket(fd: RawFd) -> Result<(), Error> {
// unsafe {
// let mut addr = sockaddr_un {
// sun_family: AF_UNIX as u16,
// sun_path: [0; 108],
// };
// let path_cstr = CString::new(SOCKET_PATH).unwrap();
// let path_bytes = path_cstr.as_bytes();
// for (i, &byte) in path_bytes.iter().enumerate() {
// addr.sun_path[i] = byte as i8;
// }
// if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
// return Err(Error::last_os_error());
// }
// }
// Ok(())
// }
// fn listen_socket(fd: RawFd) -> Result<(), Error> {
// unsafe {
// if listen(fd, 5) == -1 {
// return Err(Error::last_os_error());
// }
// }
// Ok(())
// }
// fn accept_connection(fd: RawFd) -> Result<RawFd, Error> {
// unsafe {
// // let mut addr = sockaddr_un {
// // sun_family: AF_UNIX as u16,
// // sun_path: [0; 108],
// // };
// // let mut len = mem::size_of_val(&addr) as socklen_t;
// let client_fd = accept(fd, std::ptr::null_mut(), std::ptr::null_mut());
// if client_fd == -1 {
// return Err(Error::last_os_error());
// }
// Ok(client_fd)
// }
// }
// fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
// unsafe {
// let msg_bytes = msg.as_bytes();
// if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0) == -1 {
// return Err(Error::last_os_error());
// }
// }
// Ok(())
// }
// fn receive_message(fd: RawFd) -> Result<String, Error> {
// let mut buffer = [0; 1024];
// unsafe {
// let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), 0);
// if len == -1 {
// return Err(Error::last_os_error());
// }
// Ok(String::from_utf8_lossy(&buffer[..len as usize]).into_owned())
// }
// }
// fn main() -> Result<(), Error> {
// // Create and bind the server socket
// fs::remove_file(&SOCKET_PATH).ok();
// let server_fd = create_seqpacket_socket()?;
// bind_socket(server_fd)?;
// listen_socket(server_fd)?;
// // Accept connection in a separate thread
// let server_thread = std::thread::spawn(move || {
// let client_fd = accept_connection(server_fd).expect("Failed to accept connection");
// // Receive and print message
// let received_msg = receive_message(client_fd).expect("Failed to receive message");
// println!("Server: Received message: {}", received_msg);
// // Close client connection
// unsafe { close(client_fd) };
// });
// // Create and connect the client socket
// let client_fd = create_seqpacket_socket()?;
// unsafe {
// let mut addr = sockaddr_un {
// sun_family: AF_UNIX as u16,
// sun_path: [0; 108],
// };
// let path_cstr = CString::new(SOCKET_PATH).unwrap();
// let path_bytes = path_cstr.as_bytes();
// // Convert u8 to i8
// for (i, &byte) in path_bytes.iter().enumerate() {
// addr.sun_path[i] = byte as i8;
// }
// if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
// return Err(Error::last_os_error());
// }
// }
// send_message(client_fd, MSG)?;
// // Close client connection
// unsafe { close(client_fd) };
// // Wait for server thread to complete
// server_thread.join().expect("Server thread panicked");
// fs::remove_file(&SOCKET_PATH).ok();
// // 创建 socket pair
// let (sock1, sock2) = socketpair(
// AddressFamily::Unix,
// SockType::SeqPacket, // 使用 SeqPacket 类型
// None, // 协议默认
// SockFlag::empty(),
// ).expect("Failed to create socket pair");
// let mut socket1 = unsafe { File::from_raw_fd(sock1) };
// let mut socket2 = unsafe { File::from_raw_fd(sock2) };
// // sock1 写入数据
// let msg = b"hello from sock1";
// socket1.write_all(msg)?;
// println!("sock1 send: {:?}", String::from_utf8_lossy(&msg[..]));
// // 因os read和write时会调整file的offset,write会对offset和meta size(目前返回的都是0)进行比较,
// // 而read不会故双socket都先send,后recv
// // sock2 回复数据
// let reply = b"hello from sock2";
// socket2.write_all(reply)?;
// println!("sock2 send: {:?}", String::from_utf8_lossy(reply));
// // sock2 读取数据
// let mut buf = [0u8; 128];
// let len = socket2.read(&mut buf)?;
// println!("sock2 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
// // sock1 读取回复
// let len = socket1.read(&mut buf)?;
// println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
// Ok(())
// }

View File

@ -0,0 +1,39 @@
use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
use std::fs::File;
use std::io::{Read, Write,Error};
use std::os::fd::FromRawFd;
pub fn test_seq_pair()->Result<(),Error>{
// 创建 socket pair
let (sock1, sock2) = socketpair(
AddressFamily::Unix,
SockType::SeqPacket, // 使用 SeqPacket 类型
None, // 协议默认
SockFlag::empty(),
).expect("Failed to create socket pair");
let mut socket1 = unsafe { File::from_raw_fd(sock1) };
let mut socket2 = unsafe { File::from_raw_fd(sock2) };
// sock1 写入数据
let msg = b"hello from sock1";
socket1.write_all(msg)?;
println!("sock1 send: {:?}", String::from_utf8_lossy(&msg[..]));
// 因os read和write时会调整file的offset,write会对offset和meta size(目前返回的都是0)进行比较,
// 而read不会故双socket都先send,后recv
// sock2 回复数据
let reply = b"hello from sock2";
socket2.write_all(reply)?;
println!("sock2 send: {:?}", String::from_utf8_lossy(reply));
// sock2 读取数据
let mut buf = [0u8; 128];
let len = socket2.read(&mut buf)?;
println!("sock2 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
// sock1 读取回复
let len = socket1.read(&mut buf)?;
println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len]));
Ok(())
}

View File

@ -0,0 +1,155 @@
use libc::*;
use std::{fs, str};
use std::ffi::CString;
use std::io::Error;
use std::mem;
use std::os::unix::io::RawFd;
const SOCKET_PATH: &str = "/test.seqpacket";
const MSG1: &str = "Hello, Unix SEQPACKET socket from Client!";
const MSG2: &str = "Hello, Unix SEQPACKET socket from Server!";
fn create_seqpacket_socket() -> Result<RawFd, Error> {
unsafe {
let fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if fd == -1 {
return Err(Error::last_os_error());
}
Ok(fd)
}
}
fn bind_socket(fd: RawFd) -> Result<(), Error> {
unsafe {
let mut addr = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let path_cstr = CString::new(SOCKET_PATH).unwrap();
let path_bytes = path_cstr.as_bytes();
for (i, &byte) in path_bytes.iter().enumerate() {
addr.sun_path[i] = byte as i8;
}
if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn listen_socket(fd: RawFd) -> Result<(), Error> {
unsafe {
if listen(fd, 5) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn accept_connection(fd: RawFd) -> Result<RawFd, Error> {
unsafe {
// let mut addr = sockaddr_un {
// sun_family: AF_UNIX as u16,
// sun_path: [0; 108],
// };
// let mut len = mem::size_of_val(&addr) as socklen_t;
// let client_fd = accept(fd, &mut addr as *mut _ as *mut sockaddr, &mut len);
let client_fd = accept(fd, std::ptr::null_mut(), std::ptr::null_mut());
if client_fd == -1 {
return Err(Error::last_os_error());
}
Ok(client_fd)
}
}
fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
unsafe {
let msg_bytes = msg.as_bytes();
if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn receive_message(fd: RawFd) -> Result<String, Error> {
let mut buffer = [0; 1024];
unsafe {
let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), 0);
if len == -1 {
return Err(Error::last_os_error());
}
Ok(String::from_utf8_lossy(&buffer[..len as usize]).into_owned())
}
}
pub fn test_seq_socket() ->Result<(), Error>{
// Create and bind the server socket
fs::remove_file(&SOCKET_PATH).ok();
let server_fd = create_seqpacket_socket()?;
bind_socket(server_fd)?;
listen_socket(server_fd)?;
// Accept connection in a separate thread
let server_thread = std::thread::spawn(move || {
let client_fd = accept_connection(server_fd).expect("Failed to accept connection");
// Receive and print message
let received_msg = receive_message(client_fd).expect("Failed to receive message");
println!("Server: Received message: {}", received_msg);
send_message(client_fd, MSG2).expect("Failed to send message");
// Close client connection
unsafe { close(client_fd) };
});
// Create and connect the client socket
let client_fd = create_seqpacket_socket()?;
unsafe {
let mut addr = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let path_cstr = CString::new(SOCKET_PATH).unwrap();
let path_bytes = path_cstr.as_bytes();
// Convert u8 to i8
for (i, &byte) in path_bytes.iter().enumerate() {
addr.sun_path[i] = byte as i8;
}
if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
return Err(Error::last_os_error());
}
}
send_message(client_fd, MSG1)?;
let received_msg = receive_message(client_fd).expect("Failed to receive message");
println!("Client: Received message: {}", received_msg);
// get peer_name
unsafe {
let mut addrss = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let mut len = mem::size_of_val(&addrss) as socklen_t;
let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len);
if res == -1 {
return Err(Error::last_os_error());
}
let sun_path = addrss.sun_path.clone();
let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::<Vec<u8>>().try_into().unwrap();
println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path));
}
server_thread.join().expect("Server thread panicked");
let received_msg = receive_message(client_fd).expect("Failed to receive message");
println!("Client: Received message: {}", received_msg);
// Close client connection
unsafe { close(client_fd) };
fs::remove_file(&SOCKET_PATH).ok();
Ok(())
}

View File

@ -0,0 +1,3 @@
/target
Cargo.lock
/install/

View File

@ -0,0 +1,11 @@
[package]
name = "test_unix_stream_socket"
version = "0.1.0"
edition = "2021"
description = "test for unix stream socket"
authors = [ "smallcjy <2628035541@qq.com>" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2.158"

View File

@ -0,0 +1,56 @@
TOOLCHAIN=
RUSTFLAGS=
ifdef DADK_CURRENT_BUILD_DIR
# 如果是在dadk中编译那么安装到dadk的安装目录中
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
else
# 如果是在本地编译那么安装到当前目录下的install目录中
INSTALL_DIR = ./install
endif
ifeq ($(ARCH), x86_64)
export RUST_TARGET=x86_64-unknown-linux-musl
else ifeq ($(ARCH), riscv64)
export RUST_TARGET=riscv64gc-unknown-linux-gnu
else
# 默认为x86_86用于本地编译
export RUST_TARGET=x86_64-unknown-linux-musl
endif
run:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
build:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
clean:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
test:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
doc:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
fmt:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
fmt-check:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
run-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
build-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
clean-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
test-release:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
.PHONY: install
install:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

View File

@ -0,0 +1,5 @@
# unix stream socket 测试程序
## 测试思路
跨线程通信,一个线程作为服务端监听一个测试文件,另一个线程作为客户端连接监听的文件。若连接成功,测试能够正常通信。

View File

@ -0,0 +1,153 @@
use std::io::Error;
use std::os::fd::RawFd;
use std::fs;
use libc::*;
use std::ffi::CString;
use std::mem;
const SOCKET_PATH: &str = "/test.stream";
const MSG1: &str = "Hello, unix stream socket from Client!";
const MSG2: &str = "Hello, unix stream socket from Server!";
fn create_stream_socket() -> Result<RawFd, Error>{
unsafe {
let fd = socket(AF_UNIX, SOCK_STREAM, 0);
if fd == -1 {
return Err(Error::last_os_error())
}
Ok(fd)
}
}
fn bind_socket(fd: RawFd) -> Result<(), Error> {
unsafe {
let mut addr = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let path_cstr = CString::new(SOCKET_PATH).unwrap();
let path_bytes = path_cstr.as_bytes();
for (i, &byte) in path_bytes.iter().enumerate() {
addr.sun_path[i] = byte as i8;
}
if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn listen_socket(fd: RawFd) -> Result<(), Error> {
unsafe {
if listen(fd, 5) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn accept_conn(fd: RawFd) -> Result<RawFd, Error> {
unsafe {
let client_fd = accept(fd, std::ptr::null_mut(), std::ptr::null_mut());
if client_fd == -1 {
return Err(Error::last_os_error());
}
Ok(client_fd)
}
}
fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> {
unsafe {
let msg_bytes = msg.as_bytes();
if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0)== -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
fn recv_message(fd: RawFd) -> Result<String, Error> {
let mut buffer = [0; 1024];
unsafe {
let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(),0);
if len == -1 {
return Err(Error::last_os_error());
}
Ok(String::from_utf8_lossy(&buffer[..len as usize]).into_owned())
}
}
fn test_stream() -> Result<(), Error> {
fs::remove_file(&SOCKET_PATH).ok();
let server_fd = create_stream_socket()?;
bind_socket(server_fd)?;
listen_socket(server_fd)?;
let server_thread = std::thread::spawn(move || {
let client_fd = accept_conn(server_fd).expect("Failed to accept connection");
println!("accept success!");
let recv_msg = recv_message(client_fd).expect("Failed to receive message");
println!("Server: Received message: {}", recv_msg);
send_message(client_fd, MSG2).expect("Failed to send message");
println!("Server send finish");
unsafe {close(client_fd)};
});
let client_fd = create_stream_socket()?;
unsafe {
let mut addr = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let path_cstr = CString::new(SOCKET_PATH).unwrap();
let path_bytes = path_cstr.as_bytes();
for (i, &byte) in path_bytes.iter().enumerate() {
addr.sun_path[i] = byte as i8;
}
if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 {
return Err(Error::last_os_error());
}
}
send_message(client_fd, MSG1)?;
// get peer_name
unsafe {
let mut addrss = sockaddr_un {
sun_family: AF_UNIX as u16,
sun_path: [0; 108],
};
let mut len = mem::size_of_val(&addrss) as socklen_t;
let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len);
if res == -1 {
return Err(Error::last_os_error());
}
let sun_path = addrss.sun_path.clone();
let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::<Vec<u8>>().try_into().unwrap();
println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path));
}
server_thread.join().expect("Server thread panicked");
println!("Client try recv!");
let recv_msg = recv_message(client_fd).expect("Failed to receive message from server");
println!("Client Received message: {}", recv_msg);
unsafe {close(client_fd)};
fs::remove_file(&SOCKET_PATH).ok();
Ok(())
}
fn main() {
match test_stream() {
Ok(_) => println!("test for unix stream success"),
Err(_) => println!("test for unix stream failed")
}
}