first init

This commit is contained in:
Samuka007 2025-04-21 21:11:05 +08:00
commit a34468c6c1
39 changed files with 4453 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

496
Cargo.lock generated Normal file
View File

@ -0,0 +1,496 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "berkeley-socket"
version = "0.1.0"
dependencies = [
"bitflags 2.9.0",
"hashbrown",
"lazy_static",
"libc",
"linux-errnos",
"log",
"netsock",
"num-derive",
"num-traits",
"smoltcp",
"spin",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "defmt"
version = "0.3.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
dependencies = [
"defmt 1.0.1",
]
[[package]]
name = "defmt"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
dependencies = [
"bitflags 1.3.2",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
dependencies = [
"defmt-parser",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "defmt-parser"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "hash32"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"stable_deref_trait",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "linux-errnos"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de9df90411fa4fbcb0177a4d342f93fd59aa81382dc74bd568a820903bf28ef7"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "managed"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
[[package]]
name = "netlink-packet-core"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4"
dependencies = [
"anyhow",
"byteorder",
"netlink-packet-utils",
]
[[package]]
name = "netlink-packet-sock-diag"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a495cb1de50560a7cd12fdcf023db70eec00e340df81be31cedbbfd4aadd6b76"
dependencies = [
"anyhow",
"bitflags 1.3.2",
"byteorder",
"libc",
"netlink-packet-core",
"netlink-packet-utils",
"smallvec",
]
[[package]]
name = "netlink-packet-utils"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34"
dependencies = [
"anyhow",
"byteorder",
"paste",
"thiserror 1.0.69",
]
[[package]]
name = "netlink-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23"
dependencies = [
"bytes",
"libc",
"log",
]
[[package]]
name = "netsock"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0619d68669a4107fe8be0e76d4e7557304c83d7e6a23d50e3111b5dab888741"
dependencies = [
"bitflags 2.9.0",
"byteorder",
"netlink-packet-core",
"netlink-packet-sock-diag",
"netlink-packet-utils",
"netlink-sys",
"num-derive",
"num-traits",
"thiserror 2.0.12",
"windows-sys",
]
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
[[package]]
name = "smoltcp"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
dependencies = [
"bitflags 1.3.2",
"byteorder",
"cfg-if",
"defmt 0.3.100",
"heapless",
"log",
"managed",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl 2.0.12",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

28
Cargo.toml Normal file
View File

@ -0,0 +1,28 @@
[package]
name = "berkeley-socket"
version = "0.1.0"
edition = "2021"
[dependencies]
smoltcp = { version = "0.12.0", default-features = false, features = [
"std",
"alloc",
"log",
"medium-ethernet",
"medium-ip",
"proto-ipv4",
"socket-udp",
"socket-tcp",
]}
spin = "0.9.4"
linux-errnos = "*"
hashbrown = "0.15.2"
bitflags = "2.9.0"
num-derive = "0.4.2"
num-traits = "0.2.15"
log = "*"
netsock = "0.3.0"
libc = "0.2.172"
lazy_static = "1.5.0"

129
src/driver/irq.rs Normal file
View File

@ -0,0 +1,129 @@
use std::os::unix::io::RawFd;
use std::time::Duration;
use std::{io, thread};
use hashbrown::HashMap;
use crate::socket::inet::common::NET_DEVICES;
const EPOLL_TIMEOUT_MS: i32 = 100;
/// Start a thread that polls network devices when their tap interfaces are readable
pub fn start_network_polling_thread() -> io::Result<thread::JoinHandle<()>> {
// Create an epoll instance
let epoll_fd = unsafe { libc::epoll_create1(0) };
if epoll_fd < 0 {
return Err(io::Error::last_os_error());
}
let handle = thread::spawn(move || {
let mut events = Vec::with_capacity(32);
events.resize(32, libc::epoll_event { events: 0, u64: 0 });
let mut fd_to_device_id = HashMap::new();
loop {
// Update the list of devices to watch
update_watched_devices(epoll_fd, &mut fd_to_device_id);
// Wait for events
let num_events = unsafe {
libc::epoll_wait(
epoll_fd,
events.as_mut_ptr(),
events.len() as i32,
EPOLL_TIMEOUT_MS,
)
};
if num_events < 0 {
let err = io::Error::last_os_error();
// Ignore EINTR, which happens when the thread receives a signal
if err.kind() != io::ErrorKind::Interrupted {
log::error!("epoll_wait failed: {:?}", err);
}
continue;
}
// Process events
for event in events.iter().take(num_events as usize) {
let fd = event.u64 as RawFd;
if let Some(&device_id) = fd_to_device_id.get(&fd) {
if let Some(device) = NET_DEVICES.read().get(&device_id) {
// Poll the device that has data available
device.poll();
}
}
}
// Also poll all devices periodically regardless of events
// This ensures timers and other internal state are updated
for device in NET_DEVICES.read().values() {
device.poll();
}
// Small sleep to prevent CPU hogging
thread::sleep(Duration::from_millis(1));
}
});
Ok(handle)
}
/// Update the list of devices being watched by epoll
fn update_watched_devices(epoll_fd: RawFd, fd_to_device_id: &mut HashMap<RawFd, usize>) {
let devices = NET_DEVICES.read();
// Find new devices to add
for (&id, device) in devices.iter() {
// Try to downcast to get TAP device
if let Some(tap_fd) = device.raw_fd() {
if !fd_to_device_id.contains_key(&tap_fd) {
// Add new device to epoll
let mut event = libc::epoll_event {
events: (libc::EPOLLIN | libc::EPOLLET) as u32,
u64: tap_fd as u64,
};
let result =
unsafe { libc::epoll_ctl(epoll_fd, libc::EPOLL_CTL_ADD, tap_fd, &mut event) };
if result == 0 {
fd_to_device_id.insert(tap_fd, id);
} else {
log::error!(
"Failed to add device fd {} to epoll: {:?}",
tap_fd,
io::Error::last_os_error()
);
}
}
}
}
// Find devices to remove
let mut to_remove = Vec::new();
for &fd in fd_to_device_id.keys() {
let id = fd_to_device_id[&fd];
if !devices.contains_key(&id) {
to_remove.push(fd);
// Remove from epoll
let result =
unsafe { libc::epoll_ctl(epoll_fd, libc::EPOLL_CTL_DEL, fd, std::ptr::null_mut()) };
if result != 0 {
log::error!(
"Failed to remove device fd {} from epoll: {:?}",
fd,
io::Error::last_os_error()
);
}
}
}
// Actually remove the entries
for fd in to_remove {
fd_to_device_id.remove(&fd);
}
}

38
src/driver/mod.rs Normal file
View File

@ -0,0 +1,38 @@
use std::io;
pub mod tap;
pub use tap::TapDesc;
pub mod irq;
#[repr(C)]
#[derive(Debug)]
struct ifreq {
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
}
fn ifreq_for(name: &str) -> ifreq {
let mut ifreq = ifreq {
ifr_name: [0; libc::IF_NAMESIZE],
ifr_data: 0,
};
for (i, byte) in name.as_bytes().iter().enumerate() {
ifreq.ifr_name[i] = *byte as libc::c_char
}
ifreq
}
fn ifreq_ioctl(
lower: libc::c_int,
ifreq: &mut ifreq,
cmd: libc::c_ulong,
) -> io::Result<libc::c_int> {
unsafe {
let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
if res == -1 {
return Err(io::Error::last_os_error());
}
}
Ok(ifreq.ifr_data)
}

270
src/driver/tap.rs Normal file
View File

@ -0,0 +1,270 @@
use super::*;
use smoltcp::{phy::Medium, wire::EthernetFrame};
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
#[derive(Debug)]
pub struct TapDesc {
lower: libc::c_int,
mtu: usize,
}
impl AsRawFd for TapDesc {
fn as_raw_fd(&self) -> RawFd {
self.lower
}
}
impl TapDesc {
pub fn new(name: &str, medium: Medium) -> io::Result<TapDesc> {
let lower = unsafe {
let lower = libc::open(
c"/dev/net/tun".as_ptr() as *const libc::c_char,
libc::O_RDWR | libc::O_NONBLOCK,
);
if lower == -1 {
return Err(io::Error::last_os_error());
}
lower
};
let mut ifreq = ifreq_for(name);
Self::attach_interface_ifreq(lower, medium, &mut ifreq)?;
let mtu = Self::mtu_ifreq(medium, &mut ifreq)?;
Ok(TapDesc { lower, mtu })
}
pub fn from_fd(fd: RawFd, mtu: usize) -> io::Result<TapDesc> {
Ok(TapDesc { lower: fd, mtu })
}
fn attach_interface_ifreq(
lower: libc::c_int,
medium: Medium,
ifr: &mut ifreq,
) -> io::Result<()> {
let mode = match medium {
Medium::Ip => libc::IFF_TUN,
Medium::Ethernet => libc::IFF_TAP,
};
ifr.ifr_data = mode | libc::IFF_NO_PI;
ifreq_ioctl(lower, ifr, libc::TUNSETIFF).map(|_| ())
}
fn mtu_ifreq(medium: Medium, ifr: &mut ifreq) -> io::Result<usize> {
let lower = unsafe {
let lower = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
if lower == -1 {
return Err(io::Error::last_os_error());
}
lower
};
let ip_mtu = ifreq_ioctl(lower, ifr, libc::SIOCGIFMTU).map(|mtu| mtu as usize);
unsafe {
libc::close(lower);
}
// Propagate error after close, to ensure we always close.
let ip_mtu = ip_mtu?;
// SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
// smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
let mtu = match medium {
Medium::Ip => ip_mtu,
Medium::Ethernet => ip_mtu + EthernetFrame::<&[u8]>::header_len(),
// Medium::Ieee802154 => todo!(),
};
Ok(mtu)
}
pub fn interface_mtu(&self) -> io::Result<usize> {
Ok(self.mtu)
}
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
unsafe {
let len = libc::read(
self.lower,
buffer.as_mut_ptr() as *mut libc::c_void,
buffer.len(),
);
if len == -1 {
return Err(io::Error::last_os_error());
}
Ok(len as usize)
}
}
pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
unsafe {
let len = libc::write(
self.lower,
buffer.as_ptr() as *const libc::c_void,
buffer.len(),
);
if len == -1 {
return Err(io::Error::last_os_error());
}
Ok(len as usize)
}
}
}
impl Drop for TapDesc {
fn drop(&mut self) {
unsafe {
libc::close(self.lower);
}
}
}
use std::cell::RefCell;
use std::rc::Rc;
use std::vec::Vec;
use smoltcp::phy::{self, Device, DeviceCapabilities};
use smoltcp::time::Instant;
/// A virtual TUN (IP) or TAP (Ethernet) interface.
#[derive(Debug)]
pub struct TapDevice {
lower: Rc<RefCell<crate::driver::TapDesc>>,
mtu: usize,
medium: Medium,
mac: smoltcp::wire::EthernetAddress,
}
impl AsRawFd for TapDevice {
fn as_raw_fd(&self) -> RawFd {
self.lower.borrow().as_raw_fd()
}
}
impl TapDevice {
/// Attaches to a TUN/TAP interface called `name`, or creates it if it does not exist.
///
/// If `name` is a persistent interface configured with UID of the current user,
/// no special privileges are needed. Otherwise, this requires superuser privileges
/// or a corresponding capability set on the executable.
pub fn new(name: &str, medium: Medium) -> io::Result<TapDevice> {
let lower = crate::driver::TapDesc::new(name, medium)?;
let mtu = lower.interface_mtu()?;
let mac = smoltcp::wire::EthernetAddress::from_bytes(&[
0x02,
0x00,
0x00,
std::random::random::<u8>(),
std::random::random::<u8>(),
std::random::random::<u8>(),
]);
Ok(TapDevice {
lower: Rc::new(RefCell::new(lower)),
mtu,
medium,
mac,
})
}
/// Attaches to a TUN/TAP interface specified by file descriptor `fd`.
///
/// On platforms like Android, a file descriptor to a tun interface is exposed.
/// On these platforms, a TunTapInterface cannot be instantiated with a name.
pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result<TapDevice> {
let lower = crate::driver::TapDesc::from_fd(fd, mtu)?;
let mac = smoltcp::wire::EthernetAddress::from_bytes(&[
0x02,
0x00,
0x00,
std::random::random::<u8>(),
std::random::random::<u8>(),
std::random::random::<u8>(),
]);
Ok(TapDevice {
lower: Rc::new(RefCell::new(lower)),
mtu,
medium,
mac,
})
}
pub fn mac(&self) -> smoltcp::wire::EthernetAddress {
self.mac
}
}
impl Device for TapDevice {
type RxToken<'a> = RxToken;
type TxToken<'a> = TxToken;
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = self.mtu;
caps.medium = self.medium;
caps
}
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
let mut lower = self.lower.borrow_mut();
let mut buffer = vec![0; self.mtu];
match lower.recv(&mut buffer[..]) {
Ok(size) => {
buffer.resize(size, 0);
let rx = RxToken { buffer };
let tx = TxToken {
lower: self.lower.clone(),
};
Some((rx, tx))
}
Err(err) if err.kind() == io::ErrorKind::WouldBlock => None,
Err(err) => panic!("{}", err),
}
}
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
Some(TxToken {
lower: self.lower.clone(),
})
}
}
#[doc(hidden)]
pub struct RxToken {
buffer: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(&self.buffer[..])
}
}
#[doc(hidden)]
pub struct TxToken {
lower: Rc<RefCell<crate::driver::TapDesc>>,
}
impl phy::TxToken for TxToken {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut lower = self.lower.borrow_mut();
let mut buffer = vec![0; len];
let result = f(&mut buffer);
match lower.send(&buffer[..]) {
Ok(_) => {}
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
log::debug!("phy: tx failed due to WouldBlock")
}
Err(err) => panic!("{}", err),
}
result
}
}

65
src/event_poll.rs Normal file
View File

@ -0,0 +1,65 @@
bitflags::bitflags! {
pub struct EPollEventType: u32 {
/// 对应的描述符有新的数据可读时会触发
const EPOLLIN = 0x00000001;
/// 对应的描述符有紧急数据可读时会触发
const EPOLLPRI = 0x00000002;
/// 对应的描述符可以写入数据时会触发
const EPOLLOUT = 0x00000004;
/// 对应的描述符发生错误时会触发
const EPOLLERR = 0x00000008;
/// 对应的描述符被挂断(连接关闭)时会触发
const EPOLLHUP = 0x00000010;
/// 对应的描述符不是一个有效的文件描述符时会触发
const EPOLLNVAL = 0x00000020;
/// 普通数据可读,类似于`EPOLLIN`
const EPOLLRDNORM = 0x00000040;
/// 优先级带外数据可读
const EPOLLRDBAND = 0x00000080;
/// 普通数据可写,类似于'EPOLLOUT'
const EPOLLWRNORM = 0x00000100;
/// 优先级带外数据可写
const EPOLLWRBAND = 0x00000200;
/// 通过消息队列收到消息时会触
const EPOLLMSG = 0x00000400;
/// 对应的描述符被挂断(连接关闭)的一端发送了 FIN 时会触发(读关闭)
const EPOLLRDHUP = 0x00002000;
/// 以下为额外选项
///
/// 特定选项,用于异步 I/O目前未实现
const EPOLL_URING_WAKE = 1u32 << 27;
/// 设置epoll为独占模式
const EPOLLEXCLUSIVE = 1u32 << 28;
/// 允许在系统挂起时唤醒 epoll通常用于通过 eventfd 或 timerfd 唤醒 epoll,(通常与电源管理相关,未实现)
const EPOLLWAKEUP = 1u32 << 29;
/// 表示只监听一次事件,之后需要重新添加
const EPOLLONESHOT = 1u32 << 30;
/// 启用边缘触发模式(即只有下次触发事件时才会通过epoll_wait返回)
/// 对应为水平触发(默认)水平触发模式下若这次未处理完数据那epoll还会将其加入自己的就绪队列
const EPOLLET = 1u32 << 31;
/// 以下为组合码
const EPOLLINOUT_BITS = Self::EPOLLIN.bits() | Self::EPOLLOUT.bits();
const EPOLLEXCLUSIVE_OK_BITS =
Self::EPOLLINOUT_BITS.bits()
| Self::EPOLLERR.bits()
| Self::EPOLLHUP.bits()
| Self::EPOLLWAKEUP.bits()
| Self::EPOLLET.bits()
| Self::EPOLLEXCLUSIVE.bits();
const EP_PRIVATE_BITS =
Self::EPOLLWAKEUP.bits()
| Self::EPOLLONESHOT.bits()
| Self::EPOLLET.bits()
| Self::EPOLLEXCLUSIVE.bits();
/// 表示epoll已经被释放但是在目前的设计中未用到
const POLLFREE = 0x4000;
/// listen状态的socket可以接受连接
const EPOLL_LISTEN_CAN_ACCEPT = Self::EPOLLIN.bits() | Self::EPOLLRDNORM.bits();
}
}

262
src/interface/mod.rs Normal file
View File

@ -0,0 +1,262 @@
use linux_errnos::Errno;
use spin::Mutex;
use spin::RwLock;
use std::any::Any;
use std::fmt;
use std::fmt::Debug;
use std::sync::Arc;
use crate::socket::inet::common::PortManager;
use crate::socket::inet::InetSocket;
pub mod tap;
pub trait Iface: Sync + Send + Debug + Any {
/// # `common`
/// 获取网卡的公共信息
fn common(&self) -> &IfaceCommon;
/// # `mac`
/// 获取网卡的MAC地址
fn mac(&self) -> smoltcp::wire::EthernetAddress;
// /// # `name`
// /// 获取网卡名
// fn iface_name(&self) -> String;
// /// # `nic_id`
// /// 获取网卡id
// fn nic_id(&self) -> usize {
// self.common().iface_id
// }
/// # `poll`
/// 用于轮询接口的状态。
/// ## 参数
/// - `sockets` :一个可变引用到 `smoltcp::iface::SocketSet`,表示要轮询的套接字集
/// ## 返回值
/// - 成功返回 `Ok(())`
/// - 如果轮询失败,返回 `Err(Errno::EAGAIN_OR_EWOULDBLOCK)`,表示需要再次尝试或者操作会阻塞
fn poll(&self);
/// # `update_ip_addrs`
/// 用于更新接口的 IP 地址
/// ## 参数
/// - `ip_addrs` :一个包含 `smoltcp::wire::IpCidr` 的切片,表示要设置的 IP 地址和子网掩码
/// ## 返回值
/// - 如果 `ip_addrs` 的长度不为 1返回 `Err(Errno::EINVAL)`,表示输入参数无效
fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), Errno> {
self.common().update_ip_addrs(ip_addrs)
}
/// @brief 获取smoltcp的网卡接口类型
#[inline(always)]
fn smol_iface(&self) -> &Mutex<smoltcp::iface::Interface> {
&self.common().smol_iface
}
// fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
/// # `sockets`
/// 获取网卡的套接字集
fn sockets(&self) -> &Mutex<smoltcp::iface::SocketSet<'static>> {
&self.common().sockets
}
/// # `port_manager`
/// 用于管理网卡的端口
fn port_manager(&self) -> &PortManager {
&self.common().port_manager
}
/// Get the raw file descriptor if this interface has one
/// Returns None if this interface doesn't have a file descriptor
fn raw_fd(&self) -> Option<std::os::unix::io::RawFd> {
None
}
// fn addr_assign_type(&self) -> u8;
// fn net_device_type(&self) -> u16;
// fn net_state(&self) -> NetDeivceState;
// fn set_net_state(&self, state: NetDeivceState);
// fn operstate(&self) -> Operstate;
// fn set_operstate(&self, state: Operstate);
}
/// 网络设备的公共数据
#[derive(Debug)]
pub struct NetDeviceCommonData {
/// 表示网络接口的地址分配类型
pub addr_assign_type: u8,
/// 表示网络接口的类型
pub net_device_type: u16,
// /// 表示网络接口的状态
// pub state: NetDeivceState,
// /// 表示网络接口的操作状态
// pub operstate: Operstate,
}
impl Default for NetDeviceCommonData {
fn default() -> Self {
Self {
addr_assign_type: 0,
net_device_type: 1,
// state: NetDeivceState::empty(),
// operstate: Operstate::IF_OPER_UNKNOWN,
}
}
}
// /// 将网络设备注册到sysfs中
// /// 参考https://code.dragonos.org.cn/xref/linux-2.6.39/net/core/dev.c?fi=register_netdev#5373
// fn register_netdevice(dev: Arc<dyn Iface>) -> Result<(), Errno> {
// // 在sysfs中注册设备
// netdev_register_kobject(dev.clone())?;
// // 标识网络设备在系统中存在
// dev.set_net_state(NetDeivceState::__LINK_STATE_PRESENT);
// return Ok(());
// }
pub struct IfaceCommon {
iface_id: usize,
smol_iface: Mutex<smoltcp::iface::Interface>,
/// 存smoltcp网卡的套接字集
sockets: Mutex<smoltcp::iface::SocketSet<'static>>,
/// 存 kernel wrap smoltcp socket 的集合
bounds: RwLock<Vec<Arc<dyn InetSocket>>>,
/// 端口管理器
port_manager: PortManager,
/// 下次轮询的时间
poll_at_ms: core::sync::atomic::AtomicU64,
/// 默认网卡标识
/// TODO: 此字段设置目的是解决对bind unspecified地址的分包问题需要在inet实现多网卡监听或路由子系统实现后移除
default_iface: bool,
}
impl fmt::Debug for IfaceCommon {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IfaceCommon")
.field("iface_id", &self.iface_id)
.field("sockets", &self.sockets)
// .field("bounds", &self.bounds)
.field("port_manager", &self.port_manager)
.field("poll_at_ms", &self.poll_at_ms)
.finish()
}
}
impl IfaceCommon {
pub fn new(iface_id: usize, default_iface: bool, iface: smoltcp::iface::Interface) -> Self {
IfaceCommon {
iface_id,
smol_iface: Mutex::new(iface),
sockets: Mutex::new(smoltcp::iface::SocketSet::new(Vec::new())),
bounds: RwLock::new(Vec::new()),
port_manager: PortManager::new(),
poll_at_ms: core::sync::atomic::AtomicU64::new(0),
default_iface,
}
}
pub fn poll<D>(&self, device: &mut D)
where
D: smoltcp::phy::Device + ?Sized,
{
let timestamp = std::time::Instant::now().into();
let mut sockets = self.sockets.lock();
let mut interface = self.smol_iface.lock();
let (has_events, poll_at) = {
(
matches!(
interface.poll(timestamp, device, &mut sockets),
smoltcp::iface::PollResult::SocketStateChanged
),
loop {
let poll_at = interface.poll_at(timestamp, &sockets);
let Some(instant) = poll_at else {
break poll_at;
};
if instant > timestamp {
break poll_at;
}
},
)
};
// drop sockets here to avoid deadlock
drop(interface);
drop(sockets);
use core::sync::atomic::Ordering;
if let Some(instant) = poll_at {
let _old_instant = self.poll_at_ms.load(Ordering::Relaxed);
let new_instant = instant.total_millis() as u64;
self.poll_at_ms.store(new_instant, Ordering::Relaxed);
// TODO: poll at
// if old_instant == 0 || new_instant < old_instant {
// self.polling_wait_queue.wake_all();
// }
} else {
self.poll_at_ms.store(0, Ordering::Relaxed);
}
self.bounds.read().iter().for_each(|bound_socket| {
// incase our inet socket missed the event, we manually notify it each time we poll
if has_events {
bound_socket.on_iface_events();
bound_socket.wait_queue().wakeup();
}
});
// TODO: remove closed sockets
// let closed_sockets = self
// .closing_sockets
// .lock_irq_disabled()
// .extract_if(|closing_socket| closing_socket.is_closed())
// .collect::<Vec<_>>();
// drop(closed_sockets);
}
pub fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), Errno> {
if ip_addrs.len() != 1 {
return Err(Errno::EINVAL);
}
self.smol_iface.lock().update_ip_addrs(|addrs| {
let dest = addrs.iter_mut().next();
if let Some(dest) = dest {
*dest = ip_addrs[0];
} else {
addrs.push(ip_addrs[0]).expect("Push ipCidr failed: full");
}
});
Ok(())
}
// 需要bounds储存具体的Inet Socket信息以提供不同种类inet socket的事件分发
pub fn bind_socket(&self, socket: Arc<dyn InetSocket>) {
self.bounds.write().push(socket);
}
pub fn unbind_socket(&self, socket: Arc<dyn InetSocket>) {
let mut bounds = self.bounds.write();
if let Some(index) = bounds.iter().position(|s| Arc::ptr_eq(s, &socket)) {
bounds.remove(index);
log::debug!("unbind socket success");
}
}
// TODO: 需要在inet实现多网卡监听或路由子系统实现后移除
pub fn is_default_iface(&self) -> bool {
self.default_iface
}
}

62
src/interface/tap.rs Normal file
View File

@ -0,0 +1,62 @@
use std::{ops::DerefMut, sync::Arc, time::Instant};
use smoltcp::{
iface::{Config, Interface},
wire::HardwareAddress,
};
use spin::Mutex;
use crate::driver::tap::TapDevice;
use super::{Iface, IfaceCommon};
#[derive(Debug)]
pub struct TapIface {
pub inner: Arc<Mutex<TapDevice>>,
pub common: IfaceCommon,
}
// #[derive(Debug)]
// pub struct TapIface (Arc<Mutex<TapIfaceInner>>);
impl TapIface {
pub fn new(inner: Arc<Mutex<TapDevice>>) -> Self {
let mut iface_config = Config::new(HardwareAddress::Ethernet(inner.lock().mac()));
iface_config.random_seed = std::random::random();
let iface = Interface::new(
iface_config,
inner.lock().deref_mut(),
Instant::now().into(),
);
let common = IfaceCommon::new(1, true, iface);
TapIface { inner, common }
}
}
unsafe impl Send for TapIface {}
unsafe impl Sync for TapIface {}
impl Iface for TapIface {
fn common(&self) -> &IfaceCommon {
&self.common
}
fn mac(&self) -> smoltcp::wire::EthernetAddress {
self.inner.lock().mac()
}
// fn iface_name(&self) -> String {
// "tap0".to_string()
// }
// fn nic_id(&self) -> usize {
// self.inner.nic_id()
// }
fn poll(&self) {
let mut guard = self.inner.lock();
let reference = guard.deref_mut();
self.common.poll(reference);
}
}

15
src/lib.rs Normal file
View File

@ -0,0 +1,15 @@
#![feature(thread_id_value)]
#![feature(random)]
pub mod driver;
pub mod event_poll;
pub mod interface;
pub mod libs;
pub mod posix;
pub mod process;
pub mod socket;
extern crate alloc;
extern crate bitflags;
extern crate num_derive;
extern crate num_traits;
extern crate smoltcp;

3
src/libs/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod rwlock;
pub mod spinlock;
pub mod wait_queue;

1
src/libs/rwlock.rs Normal file
View File

@ -0,0 +1 @@
pub use spin::RwLock;

24
src/libs/spinlock.rs Normal file
View File

@ -0,0 +1,24 @@
pub use spin::{Mutex as SpinLock, MutexGuard};
// pub struct SpinLock<T: ?Sized> {
// inner: Mutex<T>,
// }
// impl<T> SpinLock<T> {
// pub fn new(data: T) -> Self {
// Self {
// inner: Mutex::new(data),
// }
// }
// pub fn lock(&self) -> MutexGuard<'_, T> {
// self.inner.lock()
// }
// pub fn lock_irq_disabled(&self) -> MutexGuard<'_, T> {
// self.inner.lock()
// }
// pub fn lock_irqsave(&self) -> MutexGuard<'_, T> {
// self.inner.lock()
// }
// }

58
src/libs/wait_queue.rs Normal file
View File

@ -0,0 +1,58 @@
use std::{
sync::atomic::AtomicBool,
thread::sleep,
time::Duration,
};
use linux_errnos::Errno;
#[derive(Debug)]
pub struct WaitQueue {
// events: AtomicUsize,
is_scheduled: AtomicBool,
}
pub fn wq_wait_event_interruptible<T: Fn() -> bool>(
wait_queue: &WaitQueue,
should_wake: T,
_: Option<usize>,
) -> Result<(), Errno> {
// Simulate waiting for an event
if should_wake() {
wait_queue
.is_scheduled
.store(false, std::sync::atomic::Ordering::SeqCst);
return Ok(());
}
wait_queue
.is_scheduled
.store(false, std::sync::atomic::Ordering::SeqCst);
loop {
if wait_queue
.is_scheduled
.load(std::sync::atomic::Ordering::SeqCst)
&& should_wake()
{
return Ok(());
} else {
// simulate never schedule to this process
sleep(Duration::from_millis(10));
}
}
}
impl WaitQueue {
pub fn wakeup(&self) {
self.is_scheduled
.store(true, std::sync::atomic::Ordering::SeqCst);
}
}
impl Default for WaitQueue {
fn default() -> Self {
Self {
// events: AtomicUsize::new(0),
is_scheduled: AtomicBool::new(false),
}
}
}

16
src/main.rs Normal file
View File

@ -0,0 +1,16 @@
use std::sync::Arc;
use berkeley_socket::{
driver::{irq::start_network_polling_thread, tap::TapDevice},
interface::tap::TapIface,
socket::inet::common::NET_DEVICES,
};
use spin::Mutex;
fn main() {
let device = TapDevice::new("tap0", smoltcp::phy::Medium::Ethernet).unwrap();
let iface = Arc::new(TapIface::new(Arc::new(Mutex::new(device))));
NET_DEVICES.write().insert(0, iface);
let _ = start_network_polling_thread();
// TODO: add socket tests
}

113
src/posix/family.rs Normal file
View File

@ -0,0 +1,113 @@
use num_derive::{FromPrimitive, ToPrimitive};
/// # AddressFamily
/// Socket address families.
/// ## Reference
/// https://code.dragonos.org.cn/xref/linux-5.19.10/include/linux/socket.h#180
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum AddressFamily {
/// AF_UNSPEC 表示地址族未指定
Unspecified = 0,
/// AF_UNIX 表示Unix域的socket (与AF_LOCAL相同)
Unix = 1,
/// AF_INET 表示IPv4的socket
INet = 2,
/// AF_AX25 表示AMPR AX.25的socket
AX25 = 3,
/// AF_IPX 表示IPX的socket
IPX = 4,
/// AF_APPLETALK 表示Appletalk的socket
Appletalk = 5,
/// AF_NETROM 表示AMPR NET/ROM的socket
Netrom = 6,
/// AF_BRIDGE 表示多协议桥接的socket
Bridge = 7,
/// AF_ATMPVC 表示ATM PVCs的socket
Atmpvc = 8,
/// AF_X25 表示X.25的socket
X25 = 9,
/// AF_INET6 表示IPv6的socket
INet6 = 10,
/// AF_ROSE 表示AMPR ROSE的socket
Rose = 11,
/// AF_DECnet Reserved for DECnet project
Decnet = 12,
/// AF_NETBEUI Reserved for 802.2LLC project
Netbeui = 13,
/// AF_SECURITY 表示Security callback的伪AF
Security = 14,
/// AF_KEY 表示Key management API
Key = 15,
/// AF_NETLINK 表示Netlink的socket
Netlink = 16,
/// AF_PACKET 表示Low level packet interface
Packet = 17,
/// AF_ASH 表示Ash
Ash = 18,
/// AF_ECONET 表示Acorn Econet
Econet = 19,
/// AF_ATMSVC 表示ATM SVCs
Atmsvc = 20,
/// AF_RDS 表示Reliable Datagram Sockets
Rds = 21,
/// AF_SNA 表示Linux SNA Project
Sna = 22,
/// AF_IRDA 表示IRDA sockets
Irda = 23,
/// AF_PPPOX 表示PPPoX sockets
Pppox = 24,
/// AF_WANPIPE 表示WANPIPE API sockets
WanPipe = 25,
/// AF_LLC 表示Linux LLC
Llc = 26,
/// AF_IB 表示Native InfiniBand address
/// 介绍https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/configuring_infiniband_and_rdma_networks/index#understanding-infiniband-and-rdma_configuring-infiniband-and-rdma-networks
Ib = 27,
/// AF_MPLS 表示MPLS
Mpls = 28,
/// AF_CAN 表示Controller Area Network
Can = 29,
/// AF_TIPC 表示TIPC sockets
Tipc = 30,
/// AF_BLUETOOTH 表示Bluetooth sockets
Bluetooth = 31,
/// AF_IUCV 表示IUCV sockets
Iucv = 32,
/// AF_RXRPC 表示RxRPC sockets
Rxrpc = 33,
/// AF_ISDN 表示mISDN sockets
Isdn = 34,
/// AF_PHONET 表示Phonet sockets
Phonet = 35,
/// AF_IEEE802154 表示IEEE 802.15.4 sockets
Ieee802154 = 36,
/// AF_CAIF 表示CAIF sockets
Caif = 37,
/// AF_ALG 表示Algorithm sockets
Alg = 38,
/// AF_NFC 表示NFC sockets
Nfc = 39,
/// AF_VSOCK 表示vSockets
Vsock = 40,
/// AF_KCM 表示Kernel Connection Multiplexor
Kcm = 41,
/// AF_QIPCRTR 表示Qualcomm IPC Router
Qipcrtr = 42,
/// AF_SMC 表示SMC-R sockets.
/// reserve number for PF_SMC protocol family that reuses AF_INET address family
Smc = 43,
/// AF_XDP 表示XDP sockets
Xdp = 44,
/// AF_MCTP 表示Management Component Transport Protocol
Mctp = 45,
/// AF_MAX 表示最大的地址族
Max = 46,
}
impl core::convert::TryFrom<u16> for AddressFamily {
type Error = linux_errnos::Errno;
fn try_from(x: u16) -> Result<Self, Self::Error> {
use num_traits::FromPrimitive;
// this will return EINVAL but still works, idk why
<Self as FromPrimitive>::from_u16(x).ok_or(Self::Error::EINVAL)
}
}

14
src/posix/mod.rs Normal file
View File

@ -0,0 +1,14 @@
// posix socket and arguments definitions
// now all posix definitions are with P front like MSG -> PMSG,
// for better understanding and avoiding conflicts with other definitions
pub mod family;
mod msg_flag;
mod option;
mod option_level;
pub mod posix;
mod types;
pub use msg_flag::MessageFlag as PMSG; // Socket message flags MSG_*
pub use option::Options as PSO; // Socket options SO_*
pub use option_level::OptionLevel as PSOL; // Socket options level SOL_*
pub use types::SOCK; // Socket types SOCK_*

110
src/posix/msg_flag.rs Normal file
View File

@ -0,0 +1,110 @@
bitflags::bitflags! {
/// # Message Flags
/// Flags we can use with send/ and recv. \
/// Added those for 1003.1g not all are supported yet
/// ## Reference
/// - [Linux Socket Flags](https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/socket.h#299)
pub struct MessageFlag: u32 {
/// `MSG_OOB`
/// `0b0000_0001`\
/// Process out-of-band data.
const OOB = 1;
/// `MSG_PEEK`
/// `0b0000_0010`\
/// Peek at an incoming message.
const PEEK = 2;
/// `MSG_DONTROUTE`
/// `0b0000_0100`\
/// Don't use routing tables.
const DONTROUTE = 4;
/// `MSG_TRYHARD`
/// `0b0000_0100`\
/// `MSG_TRYHARD` is not defined in the standard, but it is used in Linux.
const TRYHARD = 4;
/// `MSG_CTRUNC`
/// `0b0000_1000`\
/// Control data lost before delivery.
const CTRUNC = 8;
/// `MSG_PROBE`
/// `0b0001_0000`\
const PROBE = 0x10;
/// `MSG_TRUNC`
/// `0b0010_0000`\
/// Data truncated before delivery.
const TRUNC = 0x20;
/// `MSG_DONTWAIT`
/// `0b0100_0000`\
/// This flag is used to make the socket non-blocking.
const DONTWAIT = 0x40;
/// `MSG_EOR`
/// `0b1000_0000`\
/// End of record.
const EOR = 0x80;
/// `MSG_WAITALL`
/// `0b0001_0000_0000`\
/// Wait for full request or error.
const WAITALL = 0x100;
/// `MSG_FIN`
/// `0b0010_0000_0000`\
/// Terminate the connection.
const FIN = 0x200;
/// `MSG_SYN`
/// `0b0100_0000_0000`\
/// Synchronize sequence numbers.
const SYN = 0x400;
/// `MSG_CONFIRM`
/// `0b1000_0000_0000`\
/// Confirm path validity.
const CONFIRM = 0x800;
/// `MSG_RST`
/// `0b0001_0000_0000_0000`\
/// Reset the connection.
const RST = 0x1000;
/// `MSG_ERRQUEUE`
/// `0b0010_0000_0000_0000`\
/// Fetch message from error queue.
const ERRQUEUE = 0x2000;
/// `MSG_NOSIGNAL`
/// `0b0100_0000_0000_0000`\
/// Do not generate a signal.
const NOSIGNAL = 0x4000;
/// `MSG_MORE`
/// `0b1000_0000_0000_0000`\
/// Sender will send more.
const MORE = 0x8000;
/// `MSG_WAITFORONE`
/// `0b0001_0000_0000_0000_0000`\
/// For nonblocking operation.
const WAITFORONE = 0x10000;
/// `MSG_SENDPAGE_NOPOLICY`
/// `0b0010_0000_0000_0000_0000`\
/// Sendpage: do not apply policy.
const SENDPAGE_NOPOLICY = 0x10000;
/// `MSG_BATCH`
/// `0b0100_0000_0000_0000_0000`\
/// Sendpage: next message is batch.
const BATCH = 0x40000;
/// `MSG_EOF`
const EOF = Self::FIN.bits();
/// `MSG_NO_SHARED_FRAGS`
const NO_SHARED_FRAGS = 0x80000;
/// `MSG_SENDPAGE_DECRYPTED`
const SENDPAGE_DECRYPTED = 0x10_0000;
/// `MSG_ZEROCOPY`
const ZEROCOPY = 0x400_0000;
/// `MSG_SPLICE_PAGES`
const SPLICE_PAGES = 0x800_0000;
/// `MSG_FASTOPEN`
const FASTOPEN = 0x2000_0000;
/// `MSG_CMSG_CLOEXEC`
const CMSG_CLOEXEC = 0x4000_0000;
/// `MSG_CMSG_COMPAT`
// if define CONFIG_COMPAT
// const CMSG_COMPAT = 0x8000_0000;
const CMSG_COMPAT = 0;
/// `MSG_INTERNAL_SENDMSG_FLAGS`
const INTERNAL_SENDMSG_FLAGS
= Self::SPLICE_PAGES.bits() | Self::SENDPAGE_NOPOLICY.bits() | Self::SENDPAGE_DECRYPTED.bits();
}
}

94
src/posix/option.rs Normal file
View File

@ -0,0 +1,94 @@
use num_derive::{FromPrimitive, ToPrimitive};
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[allow(non_camel_case_types)]
pub enum Options {
DEBUG = 1,
REUSEADDR = 2,
TYPE = 3,
ERROR = 4,
DONTROUTE = 5,
BROADCAST = 6,
SNDBUF = 7,
RCVBUF = 8,
SNDBUFFORCE = 32,
RCVBUFFORCE = 33,
KEEPALIVE = 9,
OOBINLINE = 10,
NO_CHECK = 11,
PRIORITY = 12,
LINGER = 13,
BSDCOMPAT = 14,
REUSEPORT = 15,
PASSCRED = 16,
PEERCRED = 17,
RCVLOWAT = 18,
SNDLOWAT = 19,
RCVTIMEO_OLD = 20,
SNDTIMEO_OLD = 21,
SECURITY_AUTHENTICATION = 22,
SECURITY_ENCRYPTION_TRANSPORT = 23,
SECURITY_ENCRYPTION_NETWORK = 24,
BINDTODEVICE = 25,
/// 与GET_FILTER相同
ATTACH_FILTER = 26,
DETACH_FILTER = 27,
PEERNAME = 28,
ACCEPTCONN = 30,
PEERSEC = 31,
PASSSEC = 34,
MARK = 36,
PROTOCOL = 38,
DOMAIN = 39,
RXQ_OVFL = 40,
/// 与SCM_WIFI_STATUS相同
WIFI_STATUS = 41,
PEEK_OFF = 42,
/* Instruct lower device to use last 4-bytes of skb data as FCS */
NOFCS = 43,
LOCK_FILTER = 44,
SELECT_ERR_QUEUE = 45,
BUSY_POLL = 46,
MAX_PACING_RATE = 47,
BPF_EXTENSIONS = 48,
INCOMING_CPU = 49,
ATTACH_BPF = 50,
// DETACH_BPF = DETACH_FILTER,
ATTACH_REUSEPORT_CBPF = 51,
ATTACH_REUSEPORT_EBPF = 52,
CNX_ADVICE = 53,
SCM_TIMESTAMPING_OPT_STATS = 54,
MEMINFO = 55,
INCOMING_NAPI_ID = 56,
COOKIE = 57,
SCM_TIMESTAMPING_PKTINFO = 58,
PEERGROUPS = 59,
ZEROCOPY = 60,
/// 与SCM_TXTIME相同
TXTIME = 61,
BINDTOIFINDEX = 62,
TIMESTAMP_OLD = 29,
TIMESTAMPNS_OLD = 35,
TIMESTAMPING_OLD = 37,
TIMESTAMP_NEW = 63,
TIMESTAMPNS_NEW = 64,
TIMESTAMPING_NEW = 65,
RCVTIMEO_NEW = 66,
SNDTIMEO_NEW = 67,
DETACH_REUSEPORT_BPF = 68,
PREFER_BUSY_POLL = 69,
BUSY_POLL_BUDGET = 70,
NETNS_COOKIE = 71,
BUF_LOCK = 72,
RESERVE_MEM = 73,
TXREHASH = 74,
RCVMARK = 75,
}
impl TryFrom<u32> for Options {
type Error = linux_errnos::Errno;
fn try_from(x: u32) -> Result<Self, Self::Error> {
use num_traits::FromPrimitive;
<Self as FromPrimitive>::from_u32(x).ok_or(Self::Error::EINVAL)
}
}

69
src/posix/option_level.rs Normal file
View File

@ -0,0 +1,69 @@
use num_derive::{FromPrimitive, ToPrimitive};
/// # SOL (Socket Option Level)
/// Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx
/// ## Reference
/// - [Setsockoptions(2) level](https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/socket.h#345)
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[allow(non_camel_case_types)]
pub enum OptionLevel {
IP = 0,
SOCKET = 1,
// ICMP = 1, No-no-no! Due to Linux :-) we cannot
TCP = 6,
UDP = 17,
IPV6 = 41,
ICMPV6 = 58,
SCTP = 132,
UDPLITE = 136, // UDP-Lite (RFC 3828)
RAW = 255,
IPX = 256,
AX25 = 257,
ATALK = 258,
NETROM = 259,
ROSE = 260,
DECNET = 261,
X25 = 262,
PACKET = 263,
ATM = 264, // ATM layer (cell level)
AAL = 265, // ATM Adaption Layer (packet level)
IRDA = 266,
NETBEUI = 267,
LLC = 268,
DCCP = 269,
NETLINK = 270,
TIPC = 271,
RXRPC = 272,
PPPOL2TP = 273,
BLUETOOTH = 274,
PNPIPE = 275,
RDS = 276,
IUCV = 277,
CAIF = 278,
ALG = 279,
NFC = 280,
KCM = 281,
TLS = 282,
XDP = 283,
MPTCP = 284,
MCTP = 285,
SMC = 286,
VSOCK = 287,
}
impl TryFrom<u32> for OptionLevel {
type Error = linux_errnos::Errno;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match <Self as num_traits::FromPrimitive>::from_u32(value) {
Some(p) => Ok(p),
None => Err(linux_errnos::Errno::EPROTONOSUPPORT),
}
}
}
impl From<OptionLevel> for u32 {
fn from(value: OptionLevel) -> Self {
<OptionLevel as num_traits::ToPrimitive>::to_u32(&value).unwrap()
}
}

84
src/posix/posix.rs Normal file
View File

@ -0,0 +1,84 @@
//
// posix.rs 记录了系统调用时用到的结构
//
bitflags::bitflags! {
// #[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub struct PosixArgsSocketType: u32 {
const DGRAM = 1; // 0b0000_0001
const STREAM = 2; // 0b0000_0010
const RAW = 3; // 0b0000_0011
const RDM = 4; // 0b0000_0100
const SEQPACKET = 5; // 0b0000_0101
const DCCP = 6; // 0b0000_0110
const PACKET = 10; // 0b0000_1010
const NONBLOCK = 0b0000_1000; // 0x8000_0000
const CLOEXEC = 0b0000_0100; // 0x4000_0000
}
}
impl PosixArgsSocketType {
#[inline(always)]
pub(super) fn types(&self) -> PosixArgsSocketType {
PosixArgsSocketType::from_bits(self.bits() & 0b_1111).unwrap()
}
#[inline(always)]
pub fn is_nonblock(&self) -> bool {
self.contains(PosixArgsSocketType::NONBLOCK)
}
#[inline(always)]
pub fn is_cloexec(&self) -> bool {
self.contains(PosixArgsSocketType::CLOEXEC)
}
}
use super::family::AddressFamily;
// use super::socket::{endpoint::Endpoint, AddressFamily};
// 参考资料: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html#tag_13_32
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SockAddrIn {
pub sin_family: u16,
pub sin_port: u16,
pub sin_addr: u32,
pub sin_zero: [u8; 8],
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SockAddrUn {
pub sun_family: u16,
pub sun_path: [u8; 108],
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SockAddrLl {
pub sll_family: u16,
pub sll_protocol: u16,
pub sll_ifindex: u32,
pub sll_hatype: u16,
pub sll_pkttype: u8,
pub sll_halen: u8,
pub sll_addr: [u8; 8],
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SockAddrNl {
pub nl_family: AddressFamily,
pub nl_pad: u16,
pub nl_pid: u32,
pub nl_groups: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SockAddrPlaceholder {
pub family: u16,
pub data: [u8; 14],
}

21
src/posix/types.rs Normal file
View File

@ -0,0 +1,21 @@
use linux_errnos::Errno;
use num_derive::{FromPrimitive, ToPrimitive};
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum SOCK {
Stream = 1,
Datagram = 2,
Raw = 3,
RDM = 4,
SeqPacket = 5,
DCCP = 6,
Packet = 10,
}
use super::posix::PosixArgsSocketType;
impl TryFrom<PosixArgsSocketType> for SOCK {
type Error = Errno;
fn try_from(x: PosixArgsSocketType) -> Result<Self, Self::Error> {
use num_traits::FromPrimitive;
<Self as FromPrimitive>::from_u32(x.types().bits()).ok_or(Self::Error::EINVAL)
}
}

11
src/process/mod.rs Normal file
View File

@ -0,0 +1,11 @@
// To make compatible
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Pid(usize);
pub struct ProcessManager {}
impl ProcessManager {
pub fn current_pid() -> Pid {
Pid(std::thread::current().id().as_u64().get() as usize)
}
}

18
src/socket/common/mod.rs Normal file
View File

@ -0,0 +1,18 @@
// pub mod poll_unit;
// mod epoll_items;
pub mod shutdown;
// pub use epoll_items::EPollItems;
// /// @brief 在trait Socket的metadata函数中返回该结构体供外部使用
// #[derive(Debug, Clone)]
// pub struct Metadata {
// /// 接收缓冲区的大小
// pub rx_buf_size: usize,
// /// 发送缓冲区的大小
// pub tx_buf_size: usize,
// /// 元数据的缓冲区的大小
// pub metadata_buf_size: usize,
// /// socket的选项
// pub options: SocketOptions,
// }

View File

@ -0,0 +1,136 @@
// TODO: 其他模块需要实现shutdown的具体逻辑
#![allow(dead_code)]
use core::sync::atomic::AtomicU8;
use linux_errnos::Errno;
bitflags::bitflags! {
/// @brief 用于指定socket的关闭类型
/// 参考https://code.dragonos.org.cn/xref/linux-6.1.9/include/net/sock.h?fi=SHUTDOWN_MASK#1573
#[derive(Debug, PartialEq, Eq)]
pub struct ShutdownBit: u8 {
const SHUT_RD = 0;
const SHUT_WR = 1;
const SHUT_RDWR = 2;
}
}
const RCV_SHUTDOWN: u8 = 0x01;
const SEND_SHUTDOWN: u8 = 0x02;
const SHUTDOWN_MASK: u8 = 0x03;
#[derive(Debug, Default)]
pub struct Shutdown {
bit: AtomicU8,
}
impl From<ShutdownBit> for Shutdown {
fn from(shutdown_bit: ShutdownBit) -> Self {
match shutdown_bit {
ShutdownBit::SHUT_RD => Shutdown {
bit: AtomicU8::new(RCV_SHUTDOWN),
},
ShutdownBit::SHUT_WR => Shutdown {
bit: AtomicU8::new(SEND_SHUTDOWN),
},
ShutdownBit::SHUT_RDWR => Shutdown {
bit: AtomicU8::new(SHUTDOWN_MASK),
},
_ => Shutdown::default(),
}
}
}
impl Shutdown {
pub fn new() -> Self {
Self {
bit: AtomicU8::new(0),
}
}
pub fn recv_shutdown(&self) {
self.bit
.fetch_or(RCV_SHUTDOWN, core::sync::atomic::Ordering::SeqCst);
}
pub fn send_shutdown(&self) {
self.bit
.fetch_or(SEND_SHUTDOWN, core::sync::atomic::Ordering::SeqCst);
}
pub fn is_recv_shutdown(&self) -> bool {
self.bit.load(core::sync::atomic::Ordering::SeqCst) & RCV_SHUTDOWN != 0
}
pub fn is_send_shutdown(&self) -> bool {
self.bit.load(core::sync::atomic::Ordering::SeqCst) & SEND_SHUTDOWN != 0
}
pub fn is_both_shutdown(&self) -> bool {
self.bit.load(core::sync::atomic::Ordering::SeqCst) & SHUTDOWN_MASK == SHUTDOWN_MASK
}
pub fn is_empty(&self) -> bool {
self.bit.load(core::sync::atomic::Ordering::SeqCst) == 0
}
pub fn from_how(how: usize) -> Self {
Self::from(ShutdownBit::from_bits_truncate(how as u8))
}
pub fn get(&self) -> ShutdownTemp {
ShutdownTemp {
bit: self.bit.load(core::sync::atomic::Ordering::SeqCst),
}
}
}
pub struct ShutdownTemp {
bit: u8,
}
impl ShutdownTemp {
pub fn is_recv_shutdown(&self) -> bool {
self.bit & RCV_SHUTDOWN != 0
}
pub fn is_send_shutdown(&self) -> bool {
self.bit & SEND_SHUTDOWN != 0
}
pub fn is_both_shutdown(&self) -> bool {
self.bit & SHUTDOWN_MASK == SHUTDOWN_MASK
}
pub fn is_empty(&self) -> bool {
self.bit == 0
}
pub fn bits(&self) -> ShutdownBit {
ShutdownBit::from_bits_truncate(self.bit)
}
}
impl From<ShutdownBit> for ShutdownTemp {
fn from(shutdown_bit: ShutdownBit) -> Self {
match shutdown_bit {
ShutdownBit::SHUT_RD => Self { bit: RCV_SHUTDOWN },
ShutdownBit::SHUT_WR => Self { bit: SEND_SHUTDOWN },
ShutdownBit::SHUT_RDWR => Self { bit: SHUTDOWN_MASK },
_ => Self { bit: 0 },
}
}
}
impl TryFrom<usize> for ShutdownTemp {
type Error = Errno;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
0..2 => Ok(ShutdownTemp {
bit: value as u8 + 1,
}),
_ => Err(Errno::EINVAL),
}
}
}

44
src/socket/endpoint.rs Normal file
View File

@ -0,0 +1,44 @@
// use crate::{filesystem::vfs::InodeId, net::socket};
// use alloc::{string::String, sync::Arc};
pub use smoltcp::wire::IpEndpoint;
// use super::unix::ns::abs::AbsHandle;
#[derive(Debug, Clone)]
pub enum Endpoint {
// /// 链路层端点
// LinkLayer(LinkLayerEndpoint),
/// 网络层端点
Ip(IpEndpoint),
// /// inode端点,Unix实际保存的端点
// Inode((Arc<socket::SocketInode>, String)),
// /// Unix传递id索引和path所用的端点
// Unixpath((InodeId, String)),
// /// Unix抽象端点
// Abspath((AbsHandle, String)),
}
// /// @brief 链路层端点
// #[derive(Debug, Clone)]
// pub struct LinkLayerEndpoint {
// /// 网卡的接口号
// pub interface: usize,
// }
// impl LinkLayerEndpoint {
// /// @brief 创建一个链路层端点
// ///
// /// @param interface 网卡的接口号
// ///
// /// @return 返回创建的链路层端点
// pub fn new(interface: usize) -> Self {
// Self { interface }
// }
// }
impl From<IpEndpoint> for Endpoint {
fn from(endpoint: IpEndpoint) -> Self {
Self::Ip(endpoint)
}
}

View File

@ -0,0 +1,157 @@
use std::collections::BTreeMap;
// use crate::net::{Iface, NET_DEVICES};
use crate::interface::Iface;
use alloc::sync::Arc;
pub mod port;
use linux_errnos::Errno as SystemError;
pub use port::PortManager;
use spin::RwLock;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Types {
Raw,
Icmp,
Udp,
Tcp,
Dhcpv4,
Dns,
}
lazy_static::lazy_static! {
/// # 所有网络接口的列表
/// 这个列表在中断上下文会使用到因此需要irqsave
pub static ref NET_DEVICES: RwLock<BTreeMap<usize, Arc<dyn Iface>>> = RwLock::new(BTreeMap::new());
}
/**
* listen问题socket在绑定单网卡下的问题
*/
#[derive(Debug)]
pub struct BoundInner {
handle: smoltcp::iface::SocketHandle,
iface: Arc<dyn Iface>,
// inner: Vec<(smoltcp::iface::SocketHandle, Arc<dyn Iface>)>
// address: smoltcp::wire::IpAddress,
}
impl BoundInner {
/// # `bind`
/// 将socket绑定到指定的地址上置入指定的网络接口中
pub fn bind<T>(
socket: T,
// socket_type: Types,
address: &smoltcp::wire::IpAddress,
) -> Result<Self, SystemError>
where
T: smoltcp::socket::AnySocket<'static>,
{
if address.is_unspecified() {
// 强绑VirtualIO
let iface = NET_DEVICES
.read()
.iter()
.find_map(|(_, v)| {
if v.common().is_default_iface() {
Some(v.clone())
} else {
None
}
})
.expect("No default interface");
let handle = iface.sockets().lock().add(socket);
Ok(Self { handle, iface })
} else {
let iface = get_iface_to_bind(address).ok_or(SystemError::ENODEV)?;
let handle = iface.sockets().lock().add(socket);
Ok(Self { handle, iface })
}
}
pub fn bind_ephemeral<T>(
socket: T,
// socket_type: Types,
remote: smoltcp::wire::IpAddress,
) -> Result<(Self, smoltcp::wire::IpAddress), SystemError>
where
T: smoltcp::socket::AnySocket<'static>,
{
let (iface, address) = get_ephemeral_iface(&remote);
// let bound_port = iface.port_manager().bind_ephemeral_port(socket_type)?;
let handle = iface.sockets().lock().add(socket);
// let endpoint = smoltcp::wire::IpEndpoint::new(local_addr, bound_port);
Ok((Self { handle, iface }, address))
}
pub fn port_manager(&self) -> &PortManager {
self.iface.port_manager()
}
pub fn with_mut<T: smoltcp::socket::AnySocket<'static>, R, F: FnMut(&mut T) -> R>(
&self,
mut f: F,
) -> R {
f(self.iface.sockets().lock().get_mut::<T>(self.handle))
}
pub fn with<T: smoltcp::socket::AnySocket<'static>, R, F: Fn(&T) -> R>(&self, f: F) -> R {
f(self.iface.sockets().lock().get::<T>(self.handle))
}
pub fn iface(&self) -> &Arc<dyn Iface> {
&self.iface
}
pub fn release(&self) {
self.iface.sockets().lock().remove(self.handle);
}
}
#[inline]
pub fn get_iface_to_bind(ip_addr: &smoltcp::wire::IpAddress) -> Option<Arc<dyn Iface>> {
// log::debug!("get_iface_to_bind: {:?}", ip_addr);
// if ip_addr.is_unspecified()
NET_DEVICES
.read()
.iter()
.find(|(_, iface)| {
let guard = iface.smol_iface().lock();
// log::debug!("iface name: {}, ip: {:?}", iface.iface_name(), guard.ip_addrs());
guard.has_ip_addr(*ip_addr)
})
.map(|(_, iface)| iface.clone())
}
/// Get a suitable iface to deal with sendto/connect request if the socket is not bound to an iface.
/// If the remote address is the same as that of some iface, we will use the iface.
/// Otherwise, we will use a default interface.
fn get_ephemeral_iface(
remote_ip_addr: &smoltcp::wire::IpAddress,
) -> (Arc<dyn Iface>, smoltcp::wire::IpAddress) {
get_iface_to_bind(remote_ip_addr)
.map(|iface| (iface, *remote_ip_addr))
.or({
let ifaces = NET_DEVICES.read();
ifaces.iter().find_map(|(_, iface)| {
iface
.smol_iface()
.lock()
.ip_addrs()
.iter()
.find(|cidr| cidr.contains_addr(remote_ip_addr))
.map(|cidr| (iface.clone(), cidr.address()))
})
})
.or({
NET_DEVICES.read().values().next().map(|iface| {
(
iface.clone(),
iface.smol_iface().lock().ip_addrs()[0].address(),
)
})
})
.expect("No network interface")
}

View File

@ -0,0 +1,121 @@
use hashbrown::HashMap;
use libc::rand;
use linux_errnos::Errno as SystemError;
use crate::{
// arch::rand::rand,
libs::spinlock::SpinLock,
process::{Pid, ProcessManager},
};
use super::Types::{self, *};
/// # TCP 和 UDP 的端口管理器。
/// 如果 TCP/UDP 的 socket 绑定了某个端口,它会在对应的表中记录,以检测端口冲突。
#[derive(Debug)]
pub struct PortManager {
// TCP 端口记录表
tcp_port_table: SpinLock<HashMap<u16, Pid>>,
// UDP 端口记录表
udp_port_table: SpinLock<HashMap<u16, Pid>>,
}
impl Default for PortManager {
fn default() -> Self {
Self::new()
}
}
impl PortManager {
pub fn new() -> Self {
Self {
tcp_port_table: SpinLock::new(HashMap::new()),
udp_port_table: SpinLock::new(HashMap::new()),
}
}
/// @brief 自动分配一个相对应协议中未被使用的PORT如果动态端口均已被占用返回错误码 EADDRINUSE
pub fn get_ephemeral_port(&self, socket_type: Types) -> Result<u16, SystemError> {
// TODO: selects non-conflict high port
static mut EPHEMERAL_PORT: u16 = 0;
unsafe {
if EPHEMERAL_PORT == 0 {
EPHEMERAL_PORT = (49152 + rand() % (65536 - 49152)) as u16;
}
}
let mut remaining = 65536 - 49152; // 剩余尝试分配端口次数
let mut port: u16;
while remaining > 0 {
unsafe {
if EPHEMERAL_PORT == 65535 {
EPHEMERAL_PORT = 49152;
} else {
EPHEMERAL_PORT += 1;
}
port = EPHEMERAL_PORT;
}
// 使用 ListenTable 检查端口是否被占用
let listen_table_guard = match socket_type {
Udp => self.udp_port_table.lock(),
Tcp => self.tcp_port_table.lock(),
_ => panic!("{:?} cann't get a port", socket_type),
};
if listen_table_guard.get(&port).is_none() {
drop(listen_table_guard);
return Ok(port);
}
remaining -= 1;
}
Err(SystemError::EADDRINUSE)
}
#[inline]
pub fn bind_ephemeral_port(&self, socket_type: Types) -> Result<u16, SystemError> {
let port = self.get_ephemeral_port(socket_type)?;
self.bind_port(socket_type, port)?;
Ok(port)
}
/// @brief 检测给定端口是否已被占用,如果未被占用则在 TCP/UDP 对应的表中记录
///
/// TODO: 增加支持端口复用的逻辑
pub fn bind_port(&self, socket_type: Types, port: u16) -> Result<(), SystemError> {
if port > 0 {
match socket_type {
Udp => {
let mut guard = self.udp_port_table.lock();
if guard.get(&port).is_some() {
return Err(SystemError::EADDRINUSE);
}
guard.insert(port, ProcessManager::current_pid());
}
Tcp => {
let mut guard = self.tcp_port_table.lock();
if guard.get(&port).is_some() {
return Err(SystemError::EADDRINUSE);
}
guard.insert(port, ProcessManager::current_pid());
}
_ => {}
};
}
Ok(())
}
/// @brief 在对应的端口记录表中将端口和 socket 解绑
/// should call this function when socket is closed or aborted
pub fn unbind_port(&self, socket_type: Types, port: u16) {
match socket_type {
Udp => {
self.udp_port_table.lock().remove(&port);
}
Tcp => {
self.tcp_port_table.lock().remove(&port);
}
_ => {}
};
}
}

View File

@ -0,0 +1,167 @@
use linux_errnos::Errno as SystemError;
use smoltcp;
use crate::{
libs::spinlock::SpinLock,
socket::inet::common::{BoundInner, Types as InetTypes},
};
pub type SmolUdpSocket = smoltcp::socket::udp::Socket<'static>;
pub const DEFAULT_METADATA_BUF_SIZE: usize = 1024;
pub const DEFAULT_RX_BUF_SIZE: usize = 64 * 1024;
pub const DEFAULT_TX_BUF_SIZE: usize = 64 * 1024;
#[derive(Debug)]
pub struct UnboundUdp {
socket: SmolUdpSocket,
}
impl Default for UnboundUdp {
fn default() -> Self {
Self::new()
}
}
impl UnboundUdp {
pub fn new() -> Self {
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
vec![smoltcp::socket::udp::PacketMetadata::EMPTY; DEFAULT_METADATA_BUF_SIZE],
vec![0; DEFAULT_RX_BUF_SIZE],
);
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
vec![smoltcp::socket::udp::PacketMetadata::EMPTY; DEFAULT_METADATA_BUF_SIZE],
vec![0; DEFAULT_TX_BUF_SIZE],
);
let socket = SmolUdpSocket::new(rx_buffer, tx_buffer);
Self { socket }
}
pub fn bind(self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<BoundUdp, SystemError> {
let inner = BoundInner::bind(self.socket, &local_endpoint.addr)?;
let bind_addr = local_endpoint.addr;
let bind_port = if local_endpoint.port == 0 {
inner.port_manager().bind_ephemeral_port(InetTypes::Udp)?
} else {
inner
.port_manager()
.bind_port(InetTypes::Udp, local_endpoint.port)?;
local_endpoint.port
};
if bind_addr.is_unspecified() {
if inner
.with_mut::<smoltcp::socket::udp::Socket, _, _>(|socket| socket.bind(bind_port))
.is_err()
{
return Err(SystemError::EINVAL);
}
} else if inner
.with_mut::<smoltcp::socket::udp::Socket, _, _>(|socket| {
socket.bind(smoltcp::wire::IpEndpoint::new(bind_addr, bind_port))
})
.is_err()
{
return Err(SystemError::EINVAL);
}
Ok(BoundUdp {
inner,
remote: SpinLock::new(None),
})
}
pub fn bind_ephemeral(self, remote: smoltcp::wire::IpAddress) -> Result<BoundUdp, SystemError> {
// let (addr, port) = (remote.addr, remote.port);
let (inner, address) = BoundInner::bind_ephemeral(self.socket, remote)?;
let bound_port = inner.port_manager().bind_ephemeral_port(InetTypes::Udp)?;
let endpoint = smoltcp::wire::IpEndpoint::new(address, bound_port);
Ok(BoundUdp {
inner,
remote: SpinLock::new(Some(endpoint)),
})
}
}
#[derive(Debug)]
pub struct BoundUdp {
inner: BoundInner,
remote: SpinLock<Option<smoltcp::wire::IpEndpoint>>,
}
impl BoundUdp {
pub fn with_mut_socket<F, T>(&self, f: F) -> T
where
F: FnMut(&mut SmolUdpSocket) -> T,
{
self.inner.with_mut(f)
}
pub fn with_socket<F, T>(&self, f: F) -> T
where
F: Fn(&SmolUdpSocket) -> T,
{
self.inner.with(f)
}
pub fn endpoint(&self) -> smoltcp::wire::IpListenEndpoint {
self.inner
.with::<SmolUdpSocket, _, _>(|socket| socket.endpoint())
}
pub fn connect(&self, remote: smoltcp::wire::IpEndpoint) {
self.remote.lock().replace(remote);
}
#[inline]
pub fn try_recv(
&self,
buf: &mut [u8],
) -> Result<(usize, smoltcp::wire::IpEndpoint), SystemError> {
self.with_mut_socket(|socket| {
if socket.can_recv() {
if let Ok((size, metadata)) = socket.recv_slice(buf) {
return Ok((size, metadata.endpoint));
}
}
Err(SystemError::EAGAIN)
})
}
pub fn try_send(
&self,
buf: &[u8],
to: Option<smoltcp::wire::IpEndpoint>,
) -> Result<usize, SystemError> {
let remote = to.or(*self.remote.lock()).ok_or(SystemError::ENOTCONN)?;
self.with_mut_socket(|socket| {
if socket.can_send() && socket.send_slice(buf, remote).is_ok() {
log::debug!("send {} bytes", buf.len());
return Ok(buf.len());
}
Err(SystemError::ENOBUFS)
})
}
pub fn inner(&self) -> &BoundInner {
&self.inner
}
pub fn close(&self) {
self.inner
.iface()
.port_manager()
.unbind_port(InetTypes::Udp, self.endpoint().port);
self.with_mut_socket(|socket| {
socket.close();
});
}
}
// Udp Inner 负责其内部资源管理
#[derive(Debug)]
pub enum UdpInner {
Unbound(UnboundUdp),
Bound(BoundUdp),
}

View File

@ -0,0 +1,306 @@
use inner::{UdpInner, UnboundUdp};
use linux_errnos::Errno as SystemError;
use smoltcp;
use crate::event_poll::EPollEventType;
use crate::libs::wait_queue::{wq_wait_event_interruptible, WaitQueue};
use crate::socket::{Socket, PMSG};
use crate::{libs::rwlock::RwLock, socket::endpoint::Endpoint};
use alloc::sync::{Arc, Weak};
use core::sync::atomic::AtomicBool;
use super::InetSocket;
pub mod inner;
type EP = EPollEventType;
// Udp Socket 负责提供状态切换接口、执行状态切换
#[derive(Debug)]
pub struct UdpSocket {
inner: RwLock<Option<UdpInner>>,
nonblock: AtomicBool,
wait_queue: WaitQueue,
self_ref: Weak<UdpSocket>,
}
impl UdpSocket {
pub fn new(nonblock: bool) -> Arc<Self> {
Arc::new_cyclic(|me| Self {
inner: RwLock::new(Some(UdpInner::Unbound(UnboundUdp::new()))),
nonblock: AtomicBool::new(nonblock),
wait_queue: WaitQueue::default(),
self_ref: me.clone(),
})
}
pub fn is_nonblock(&self) -> bool {
self.nonblock.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn do_bind(&self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<(), SystemError> {
let mut inner = self.inner.write();
if let Some(UdpInner::Unbound(unbound)) = inner.take() {
let bound = unbound.bind(local_endpoint)?;
bound
.inner()
.iface()
.common()
.bind_socket(self.self_ref.upgrade().unwrap());
*inner = Some(UdpInner::Bound(bound));
return Ok(());
}
Err(SystemError::EINVAL)
}
pub fn bind_emphemeral(&self, remote: smoltcp::wire::IpAddress) -> Result<(), SystemError> {
let mut inner_guard = self.inner.write();
let bound = match inner_guard.take().expect("Udp inner is None") {
UdpInner::Bound(inner) => inner,
UdpInner::Unbound(inner) => inner.bind_ephemeral(remote)?,
};
inner_guard.replace(UdpInner::Bound(bound));
Ok(())
}
pub fn is_bound(&self) -> bool {
let inner = self.inner.read();
if let Some(UdpInner::Bound(_)) = &*inner {
return true;
}
false
}
pub fn close(&self) {
let mut inner = self.inner.write();
if let Some(UdpInner::Bound(bound)) = &mut *inner {
bound.close();
inner.take();
}
// unbound socket just drop (only need to free memory)
}
pub fn try_recv(
&self,
buf: &mut [u8],
) -> Result<(usize, smoltcp::wire::IpEndpoint), SystemError> {
match self.inner.read().as_ref().expect("Udp Inner is None") {
UdpInner::Bound(bound) => {
let ret = bound.try_recv(buf);
bound.inner().iface().poll();
ret
}
_ => Err(SystemError::ENOTCONN),
}
}
#[inline]
pub fn can_recv(&self) -> bool {
self.event().contains(EP::EPOLLIN)
}
#[inline]
#[allow(dead_code)]
pub fn can_send(&self) -> bool {
self.event().contains(EP::EPOLLOUT)
}
pub fn try_send(
&self,
buf: &[u8],
to: Option<smoltcp::wire::IpEndpoint>,
) -> Result<usize, SystemError> {
{
let mut inner_guard = self.inner.write();
let inner = match inner_guard.take().expect("Udp Inner is None") {
UdpInner::Bound(bound) => bound,
UdpInner::Unbound(unbound) => {
unbound.bind_ephemeral(to.ok_or(SystemError::EADDRNOTAVAIL)?.addr)?
}
};
// size = inner.try_send(buf, to)?;
inner_guard.replace(UdpInner::Bound(inner));
};
// Optimize: 拿两次锁的平均效率是否比一次长时间的读锁效率要高?
let result = match self.inner.read().as_ref().expect("Udp Inner is None") {
UdpInner::Bound(bound) => {
let ret = bound.try_send(buf, to);
bound.inner().iface().poll();
ret
}
_ => Err(SystemError::ENOTCONN),
};
result
}
pub fn event(&self) -> EPollEventType {
let mut event = EPollEventType::empty();
match self.inner.read().as_ref().unwrap() {
UdpInner::Unbound(_) => {
event.insert(EP::EPOLLOUT | EP::EPOLLWRNORM | EP::EPOLLWRBAND);
}
UdpInner::Bound(bound) => {
let (can_recv, can_send) =
bound.with_socket(|socket| (socket.can_recv(), socket.can_send()));
if can_recv {
event.insert(EP::EPOLLIN | EP::EPOLLRDNORM);
}
if can_send {
event.insert(EP::EPOLLOUT | EP::EPOLLWRNORM | EP::EPOLLWRBAND);
}
}
}
event
}
}
impl Socket for UdpSocket {
fn wait_queue(&self) -> &WaitQueue {
&self.wait_queue
}
fn poll(&self) -> usize {
self.event().bits() as usize
}
fn bind(&self, local_endpoint: Endpoint) -> Result<(), SystemError> {
if let Endpoint::Ip(local_endpoint) = local_endpoint {
return self.do_bind(local_endpoint);
}
Err(SystemError::EAFNOSUPPORT)
}
fn send_buffer_size(&self) -> usize {
match self.inner.read().as_ref().unwrap() {
UdpInner::Bound(bound) => bound.with_socket(|socket| socket.payload_send_capacity()),
_ => inner::DEFAULT_TX_BUF_SIZE,
}
}
fn recv_buffer_size(&self) -> usize {
match self.inner.read().as_ref().unwrap() {
UdpInner::Bound(bound) => bound.with_socket(|socket| socket.payload_recv_capacity()),
_ => inner::DEFAULT_RX_BUF_SIZE,
}
}
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
if let Endpoint::Ip(remote) = endpoint {
if !self.is_bound() {
self.bind_emphemeral(remote.addr)?;
}
if let UdpInner::Bound(inner) = self.inner.read().as_ref().expect("UDP Inner disappear")
{
inner.connect(remote);
return Ok(());
} else {
panic!("");
}
}
Err(SystemError::EAFNOSUPPORT)
}
fn send(&self, buffer: &[u8], flags: PMSG) -> Result<usize, SystemError> {
if flags.contains(PMSG::DONTWAIT) {
log::warn!("Nonblock send is not implemented yet");
}
self.try_send(buffer, None)
}
fn send_to(&self, buffer: &[u8], flags: PMSG, address: Endpoint) -> Result<usize, SystemError> {
if flags.contains(PMSG::DONTWAIT) {
log::warn!("Nonblock send is not implemented yet");
}
if let Endpoint::Ip(remote) = address {
return self.try_send(buffer, Some(remote));
}
Err(SystemError::EINVAL)
}
fn recv(&self, buffer: &mut [u8], flags: PMSG) -> Result<usize, SystemError> {
if self.is_nonblock() || flags.contains(PMSG::DONTWAIT) {
self.try_recv(buffer)
} else {
loop {
match self.try_recv(buffer) {
Err(SystemError::EAGAIN) => {
wq_wait_event_interruptible(&self.wait_queue, || self.can_recv(), None)?;
}
result => break result,
}
}
}
.map(|(len, _)| len)
}
fn recv_from(
&self,
buffer: &mut [u8],
flags: PMSG,
address: Option<Endpoint>,
) -> Result<(usize, Endpoint), SystemError> {
// could block io
if let Some(endpoint) = address {
self.connect(endpoint)?;
}
if self.is_nonblock() || flags.contains(PMSG::DONTWAIT) {
self.try_recv(buffer)
} else {
loop {
match self.try_recv(buffer) {
Err(SystemError::EAGAIN) => {
wq_wait_event_interruptible(&self.wait_queue, || self.can_recv(), None)?;
log::debug!("UdpSocket::recv_from: wake up");
}
result => break result,
}
}
}
.map(|(len, remote)| (len, Endpoint::Ip(remote)))
}
fn close(&self) -> Result<(), SystemError> {
self.close();
Ok(())
}
}
impl InetSocket for UdpSocket {
fn on_iface_events(&self) {
}
}
bitflags::bitflags! {
pub struct UdpSocketOptions: u32 {
const ZERO = 0; /* No UDP options */
const UDP_CORK = 1; /* Never send partially complete segments */
const UDP_ENCAP = 100; /* Set the socket to accept encapsulated packets */
const UDP_NO_CHECK6_TX = 101; /* Disable sending checksum for UDP6X */
const UDP_NO_CHECK6_RX = 102; /* Disable accepting checksum for UDP6 */
const UDP_SEGMENT = 103; /* Set GSO segmentation size */
const UDP_GRO = 104; /* This socket can receive UDP GRO packets */
const UDPLITE_SEND_CSCOV = 10; /* sender partial coverage (as sent) */
const UDPLITE_RECV_CSCOV = 11; /* receiver partial coverage (threshold ) */
}
}
bitflags::bitflags! {
pub struct UdpEncapTypes: u8 {
const ZERO = 0;
const ESPINUDP_NON_IKE = 1; // draft-ietf-ipsec-nat-t-ike-00/01
const ESPINUDP = 2; // draft-ietf-ipsec-udp-encaps-06
const L2TPINUDP = 3; // rfc2661
const GTP0 = 4; // GSM TS 09.60
const GTP1U = 5; // 3GPP TS 29.060
const RXRPC = 6;
const ESPINTCP = 7; // Yikes, this is really xfrm encap types.
}
}

40
src/socket/inet/mod.rs Normal file
View File

@ -0,0 +1,40 @@
use smoltcp;
// pub mod raw;
// pub mod icmp;
pub mod common;
pub mod datagram;
// pub mod stream;
pub mod posix;
pub mod syscall;
pub use common::BoundInner;
pub use common::Types;
// pub use raw::RawSocket;
pub use datagram::UdpSocket;
use smoltcp::wire::IpAddress;
use smoltcp::wire::IpEndpoint;
use smoltcp::wire::Ipv4Address;
// use smoltcp::wire::Ipv6Address;
// pub use stream::TcpSocket;
// pub use syscall::Inet;
use super::Socket;
/// A local endpoint, which indicates that the local endpoint is unspecified.
///
/// According to the Linux man pages and the Linux implementation, `getsockname()` will _not_ fail
/// even if the socket is unbound. Instead, it will return an unspecified socket address. This
/// unspecified endpoint helps with that.
const UNSPECIFIED_LOCAL_ENDPOINT_V4: IpEndpoint =
IpEndpoint::new(IpAddress::Ipv4(Ipv4Address::UNSPECIFIED), 0);
// const UNSPECIFIED_LOCAL_ENDPOINT_V6: IpEndpoint =
// IpEndpoint::new(IpAddress::Ipv6(Ipv6Address::UNSPECIFIED), 0);
pub trait InetSocket: Socket {
/// `on_iface_events`
/// 通知socket发生的事件
fn on_iface_events(&self);
}

View File

@ -0,0 +1,2 @@
pub mod option;
pub mod proto;

View File

@ -0,0 +1,67 @@
bitflags::bitflags! {
pub struct IpOptions: u32 {
const IP_TOS = 1; // Type of service
const IP_TTL = 2; // Time to live
const IP_HDRINCL = 3; // Header compression
const IP_OPTIONS = 4; // IP options
const IP_ROUTER_ALERT = 5; // Router alert
const IP_RECVOPTS = 6; // Receive options
const IP_RETOPTS = 7; // Return options
const IP_PKTINFO = 8; // Packet information
const IP_PKTOPTIONS = 9; // Packet options
const IP_MTU_DISCOVER = 10; // MTU discovery
const IP_RECVERR = 11; // Receive errors
const IP_RECVTTL = 12; // Receive time to live
const IP_RECVTOS = 13; // Receive type of service
const IP_MTU = 14; // MTU
const IP_FREEBIND = 15; // Freebind
const IP_IPSEC_POLICY = 16; // IPsec policy
const IP_XFRM_POLICY = 17; // IPipsec transform policy
const IP_PASSSEC = 18; // Pass security
const IP_TRANSPARENT = 19; // Transparent
const IP_RECVRETOPTS = 20; // Receive return options (deprecated)
const IP_ORIGDSTADDR = 21; // Originate destination address (used by TProxy)
const IP_RECVORIGDSTADDR = 21; // Receive originate destination address
const IP_MINTTL = 22; // Minimum time to live
const IP_NODEFRAG = 23; // Don't fragment (used by TProxy)
const IP_CHECKSUM = 24; // Checksum offload (used by TProxy)
const IP_BIND_ADDRESS_NO_PORT = 25; // Bind to address without port (used by TProxy)
const IP_RECVFRAGSIZE = 26; // Receive fragment size
const IP_RECVERR_RFC4884 = 27; // Receive ICMPv6 error notifications
const IP_PMTUDISC_DONT = 28; // Don't send DF frames
const IP_PMTUDISC_DO = 29; // Always DF
const IP_PMTUDISC_PROBE = 30; // Ignore dst pmtu
const IP_PMTUDISC_INTERFACE = 31; // Always use interface mtu (ignores dst pmtu)
const IP_PMTUDISC_OMIT = 32; // Weaker version of IP_PMTUDISC_INTERFACE
const IP_MULTICAST_IF = 33; // Multicast interface
const IP_MULTICAST_TTL = 34; // Multicast time to live
const IP_MULTICAST_LOOP = 35; // Multicast loopback
const IP_ADD_MEMBERSHIP = 36; // Add multicast group membership
const IP_DROP_MEMBERSHIP = 37; // Drop multicast group membership
const IP_UNBLOCK_SOURCE = 38; // Unblock source
const IP_BLOCK_SOURCE = 39; // Block source
const IP_ADD_SOURCE_MEMBERSHIP = 40; // Add source multicast group membership
const IP_DROP_SOURCE_MEMBERSHIP = 41; // Drop source multicast group membership
const IP_MSFILTER = 42; // Multicast source filter
const MCAST_JOIN_GROUP = 43; // Join a multicast group
const MCAST_BLOCK_SOURCE = 44; // Block a multicast source
const MCAST_UNBLOCK_SOURCE = 45; // Unblock a multicast source
const MCAST_LEAVE_GROUP = 46; // Leave a multicast group
const MCAST_JOIN_SOURCE_GROUP = 47; // Join a multicast source group
const MCAST_LEAVE_SOURCE_GROUP = 48; // Leave a multicast source group
const MCAST_MSFILTER = 49; // Multicast source filter
const IP_MULTICAST_ALL = 50; // Multicast all
const IP_UNICAST_IF = 51; // Unicast interface
const IP_LOCAL_PORT_RANGE = 52; // Local port range
const IP_PROTOCOL = 53; // Protocol
// ... other flags ...
}
}

View File

@ -0,0 +1,78 @@
use num_derive::{FromPrimitive, ToPrimitive};
pub const SOL_SOCKET: u16 = 1;
#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum IPProtocol {
/// Dummy protocol for TCP.
IP = 0,
/// Internet Control Message Protocol.
ICMP = 1,
/// Internet Group Management Protocol.
IGMP = 2,
/// IPIP tunnels (older KA9Q tunnels use 94).
IPIP = 4,
/// Transmission Control Protocol.
TCP = 6,
/// Exterior Gateway Protocol.
EGP = 8,
/// PUP protocol.
PUP = 12,
/// User Datagram Protocol.
UDP = 17,
/// XNS IDP protocol.
IDP = 22,
/// SO Transport Protocol Class 4.
TP = 29,
/// Datagram Congestion Control Protocol.
DCCP = 33,
/// IPv6-in-IPv4 tunnelling.
IPv6 = 41,
/// RSVP Protocol.
RSVP = 46,
/// Generic Routing Encapsulation. (Cisco GRE) (rfc 1701, 1702)
GRE = 47,
/// Encapsulation Security Payload protocol
ESP = 50,
/// Authentication Header protocol
AH = 51,
/// Multicast Transport Protocol.
MTP = 92,
/// IP option pseudo header for BEET
BEETPH = 94,
/// Encapsulation Header.
ENCAP = 98,
/// Protocol Independent Multicast.
PIM = 103,
/// Compression Header Protocol.
COMP = 108,
/// Stream Control Transport Protocol
SCTP = 132,
/// UDP-Lite protocol (RFC 3828)
UDPLITE = 136,
/// MPLS in IP (RFC 4023)
MPLSINIP = 137,
/// Ethernet-within-IPv6 Encapsulation
ETHERNET = 143,
/// Raw IP packets
RAW = 255,
/// Multipath TCP connection
MPTCP = 262,
}
impl TryFrom<u16> for IPProtocol {
type Error = linux_errnos::Errno;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match <Self as num_traits::FromPrimitive>::from_u16(value) {
Some(p) => Ok(p),
None => Err(Self::Error::EPROTONOSUPPORT),
}
}
}
impl From<IPProtocol> for u16 {
fn from(value: IPProtocol) -> Self {
<IPProtocol as num_traits::ToPrimitive>::to_u16(&value).unwrap()
}
}

View File

@ -0,0 +1,517 @@
use core::sync::atomic::AtomicUsize;
use crate::libs::rwlock::RwLock;
// use crate::net::socket::EPollEventType;
use crate::socket::{self, inet::Types};
use alloc::boxed::Box;
use alloc::vec::Vec;
use smoltcp;
use smoltcp::socket::tcp;
use linux_errnos::Errno as SystemError;
// pub const DEFAULT_METADATA_BUF_SIZE: usize = 1024;
pub const DEFAULT_RX_BUF_SIZE: usize = 512 * 1024;
pub const DEFAULT_TX_BUF_SIZE: usize = 512 * 1024;
fn new_smoltcp_socket() -> smoltcp::socket::tcp::Socket<'static> {
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0; DEFAULT_RX_BUF_SIZE]);
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0; DEFAULT_TX_BUF_SIZE]);
smoltcp::socket::tcp::Socket::new(rx_buffer, tx_buffer)
}
fn new_listen_smoltcp_socket<T>(local_endpoint: T) -> smoltcp::socket::tcp::Socket<'static>
where
T: Into<smoltcp::wire::IpListenEndpoint>,
{
let mut socket = new_smoltcp_socket();
socket.listen(local_endpoint).unwrap();
socket
}
#[derive(Debug)]
pub enum Init {
Unbound(
(
Box<smoltcp::socket::tcp::Socket<'static>>,
smoltcp::wire::IpVersion,
),
),
Bound((socket::inet::BoundInner, smoltcp::wire::IpEndpoint)),
}
impl Init {
pub(super) fn new(ver: smoltcp::wire::IpVersion) -> Self {
Init::Unbound((Box::new(new_smoltcp_socket()), ver))
}
/// 传入一个已经绑定的socket
pub(super) fn new_bound(inner: socket::inet::BoundInner) -> Self {
let endpoint = inner.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.local_endpoint()
.expect("A Bound Socket Must Have A Local Endpoint")
});
Init::Bound((inner, endpoint))
}
pub(super) fn bind(
self,
local_endpoint: smoltcp::wire::IpEndpoint,
) -> Result<Self, SystemError> {
match self {
Init::Unbound((socket, _)) => {
let bound = socket::inet::BoundInner::bind(*socket, &local_endpoint.addr)?;
bound
.port_manager()
.bind_port(Types::Tcp, local_endpoint.port)?;
// bound.iface().common().bind_socket()
Ok(Init::Bound((bound, local_endpoint)))
}
Init::Bound(_) => {
log::debug!("Already Bound");
Err(SystemError::EINVAL)
}
}
}
pub(super) fn bind_to_ephemeral(
self,
remote_endpoint: smoltcp::wire::IpEndpoint,
) -> Result<(socket::inet::BoundInner, smoltcp::wire::IpEndpoint), (Self, SystemError)> {
match self {
Init::Unbound((socket, ver)) => {
let (bound, address) =
socket::inet::BoundInner::bind_ephemeral(*socket, remote_endpoint.addr)
.map_err(|err| (Self::new(ver), err))?;
let bound_port = bound
.port_manager()
.bind_ephemeral_port(Types::Tcp)
.map_err(|err| (Self::new(ver), err))?;
let endpoint = smoltcp::wire::IpEndpoint::new(address, bound_port);
Ok((bound, endpoint))
}
Init::Bound(_) => Err((self, SystemError::EINVAL)),
}
}
pub(super) fn connect(
self,
remote_endpoint: smoltcp::wire::IpEndpoint,
) -> Result<Connecting, (Self, SystemError)> {
let (inner, local) = match self {
Init::Unbound(_) => self.bind_to_ephemeral(remote_endpoint)?,
Init::Bound(inner) => inner,
};
if local.addr.is_unspecified() {
return Err((Init::Bound((inner, local)), SystemError::EINVAL));
}
let result = inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.connect(
inner.iface().smol_iface().lock().context(),
remote_endpoint,
local,
)
.map_err(|_| SystemError::ECONNREFUSED)
});
match result {
Ok(_) => Ok(Connecting::new(inner)),
Err(err) => Err((Init::Bound((inner, local)), err)),
}
}
/// # `listen`
pub(super) fn listen(self, backlog: usize) -> Result<Listening, (Self, SystemError)> {
let (inner, local) = match self {
Init::Unbound(_) => {
return Err((self, SystemError::EINVAL));
}
Init::Bound(inner) => inner,
};
let listen_addr = if local.addr.is_unspecified() {
smoltcp::wire::IpListenEndpoint::from(local.port)
} else {
smoltcp::wire::IpListenEndpoint::from(local)
};
log::debug!("listen at {:?}", listen_addr);
let mut inners = Vec::new();
if let Err(err) = || -> Result<(), SystemError> {
for _ in 0..(backlog - 1) {
// -1 because the first one is already bound
let new_listen = socket::inet::BoundInner::bind(
new_listen_smoltcp_socket(listen_addr),
listen_addr
.addr
.as_ref()
.unwrap_or(&smoltcp::wire::IpAddress::from(
smoltcp::wire::Ipv4Address::UNSPECIFIED,
)),
)?;
inners.push(new_listen);
}
Ok(())
}() {
return Err((Init::Bound((inner, local)), err));
}
if let Err(err) = inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.listen(listen_addr)
.map_err(|_| SystemError::ECONNREFUSED)
}) {
return Err((Init::Bound((inner, local)), err));
}
inners.push(inner);
return Ok(Listening {
inners,
connect: AtomicUsize::new(0),
listen_addr,
});
}
pub(super) fn close(&self) {
match self {
Init::Unbound(_) => {}
Init::Bound((inner, endpoint)) => {
inner.port_manager().unbind_port(Types::Tcp, endpoint.port);
inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
}
}
}
}
#[derive(Debug, Default, Clone, Copy)]
enum ConnectResult {
Connected,
#[default]
Connecting,
Refused,
}
#[derive(Debug)]
pub struct Connecting {
inner: socket::inet::BoundInner,
result: RwLock<ConnectResult>,
}
impl Connecting {
fn new(inner: socket::inet::BoundInner) -> Self {
Connecting {
inner,
result: RwLock::new(ConnectResult::Connecting),
}
}
pub fn with_mut<R, F: FnMut(&mut smoltcp::socket::tcp::Socket<'static>) -> R>(
&self,
f: F,
) -> R {
self.inner.with_mut(f)
}
pub fn into_result(self) -> (Inner, Result<(), SystemError>) {
let result = *self.result.read();
match result {
ConnectResult::Connecting => (
Inner::Connecting(self),
Err(SystemError::EAGAIN_OR_EWOULDBLOCK),
),
ConnectResult::Connected => (
Inner::Established(Established { inner: self.inner }),
Ok(()),
),
ConnectResult::Refused => (
Inner::Init(Init::new_bound(self.inner)),
Err(SystemError::ECONNREFUSED),
),
}
}
pub unsafe fn into_established(self) -> Established {
Established { inner: self.inner }
}
/// Returns `true` when `conn_result` becomes ready, which indicates that the caller should
/// invoke the `into_result()` method as soon as possible.
///
/// Since `into_result()` needs to be called only once, this method will return `true`
/// _exactly_ once. The caller is responsible for not missing this event.
#[must_use]
pub(super) fn update_io_events(&self) -> bool {
// if matches!(*self.result.read_irqsave(), ConnectResult::Connecting) {
// return false;
// }
self.inner
.with_mut(|socket: &mut smoltcp::socket::tcp::Socket| {
let mut result = self.result.write();
if matches!(*result, ConnectResult::Refused | ConnectResult::Connected) {
return false; // Already connected or refused
}
// Connected
if socket.can_send() {
log::debug!("can send");
*result = ConnectResult::Connected;
return true;
}
// Connecting
if socket.is_open() {
log::debug!("connecting");
*result = ConnectResult::Connecting;
return false;
}
// Refused
*result = ConnectResult::Refused;
return true;
})
}
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
self.inner
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.local_endpoint()
.expect("A Connecting Tcp With No Local Endpoint")
})
}
pub fn get_peer_name(&self) -> smoltcp::wire::IpEndpoint {
self.inner
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.remote_endpoint()
.expect("A Connecting Tcp With No Remote Endpoint")
})
}
}
#[derive(Debug)]
pub struct Listening {
inners: Vec<socket::inet::BoundInner>,
connect: AtomicUsize,
listen_addr: smoltcp::wire::IpListenEndpoint,
}
impl Listening {
pub fn accept(&mut self) -> Result<(Established, smoltcp::wire::IpEndpoint), SystemError> {
let connected: &mut socket::inet::BoundInner = self
.inners
.get_mut(self.connect.load(core::sync::atomic::Ordering::Relaxed))
.unwrap();
if connected.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| !socket.is_active()) {
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
let remote_endpoint = connected.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
socket
.remote_endpoint()
.expect("A Connected Tcp With No Remote Endpoint")
});
// log::debug!("local at {:?}", local_endpoint);
let mut new_listen = socket::inet::BoundInner::bind(
new_listen_smoltcp_socket(self.listen_addr),
self.listen_addr
.addr
.as_ref()
.unwrap_or(&smoltcp::wire::IpAddress::from(
smoltcp::wire::Ipv4Address::UNSPECIFIED,
)),
)?;
// swap the connected socket with the new_listen socket
// TODO is smoltcp socket swappable?
core::mem::swap(&mut new_listen, connected);
return Ok((Established { inner: new_listen }, remote_endpoint));
}
pub fn update_io_events(&self, pollee: &AtomicUsize) {
let position = self.inners.iter().position(|inner| {
inner.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.is_active())
});
if let Some(position) = position {
self.connect
.store(position, core::sync::atomic::Ordering::Relaxed);
pollee.fetch_or(
EPollEventType::EPOLLIN.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
} else {
pollee.fetch_and(
!EPollEventType::EPOLLIN.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
}
}
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
smoltcp::wire::IpEndpoint::new(
self.listen_addr
.addr
.unwrap_or(smoltcp::wire::IpAddress::from(
smoltcp::wire::Ipv4Address::UNSPECIFIED,
)),
self.listen_addr.port,
)
}
pub fn close(&self) {
// log::debug!("Close Listening Socket");
let port = self.get_name().port;
for inner in self.inners.iter() {
inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
}
self.inners[0]
.iface()
.port_manager()
.unbind_port(Types::Tcp, port);
}
pub fn release(&self) {
// log::debug!("Release Listening Socket");
for inner in self.inners.iter() {
inner.release();
}
}
}
#[derive(Debug)]
pub struct Established {
inner: socket::inet::BoundInner,
}
impl Established {
pub fn with_mut<R, F: FnMut(&mut smoltcp::socket::tcp::Socket<'static>) -> R>(
&self,
f: F,
) -> R {
self.inner.with_mut(f)
}
pub fn close(&self) {
self.inner
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
self.inner.iface().poll();
}
pub fn release(&self) {
self.inner.release();
}
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
self.inner
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.local_endpoint())
.unwrap()
}
pub fn get_peer_name(&self) -> smoltcp::wire::IpEndpoint {
self.inner
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.remote_endpoint().unwrap())
}
pub fn recv_slice(&self, buf: &mut [u8]) -> Result<usize, SystemError> {
self.inner
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
if socket.can_send() {
match socket.recv_slice(buf) {
Ok(size) => Ok(size),
Err(tcp::RecvError::InvalidState) => {
log::error!("TcpSocket::try_recv: InvalidState");
Err(SystemError::ENOTCONN)
}
Err(tcp::RecvError::Finished) => Ok(0),
}
} else {
Err(SystemError::ENOBUFS)
}
})
}
pub fn send_slice(&self, buf: &[u8]) -> Result<usize, SystemError> {
self.inner
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
if socket.can_send() {
socket
.send_slice(buf)
.map_err(|_| SystemError::ECONNABORTED)
} else {
Err(SystemError::ENOBUFS)
}
})
}
pub fn update_io_events(&self, pollee: &AtomicUsize) {
self.inner
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
if socket.can_send() {
pollee.fetch_or(
EPollEventType::EPOLLOUT.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
} else {
pollee.fetch_and(
!EPollEventType::EPOLLOUT.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
}
if socket.can_recv() {
pollee.fetch_or(
EPollEventType::EPOLLIN.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
} else {
pollee.fetch_and(
!EPollEventType::EPOLLIN.bits() as usize,
core::sync::atomic::Ordering::Relaxed,
);
}
})
}
}
#[derive(Debug)]
pub enum Inner {
Init(Init),
Connecting(Connecting),
Listening(Listening),
Established(Established),
}
impl Inner {
pub fn send_buffer_size(&self) -> usize {
match self {
Inner::Init(_) => DEFAULT_TX_BUF_SIZE,
Inner::Connecting(conn) => conn.with_mut(|socket| socket.send_capacity()),
// only the first socket in the list is used for sending
Inner::Listening(listen) => listen.inners[0]
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.send_capacity()),
Inner::Established(est) => est.with_mut(|socket| socket.send_capacity()),
}
}
pub fn recv_buffer_size(&self) -> usize {
match self {
Inner::Init(_) => DEFAULT_RX_BUF_SIZE,
Inner::Connecting(conn) => conn.with_mut(|socket| socket.recv_capacity()),
// only the first socket in the list is used for receiving
Inner::Listening(listen) => listen.inners[0]
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.recv_capacity()),
Inner::Established(est) => est.with_mut(|socket| socket.recv_capacity()),
}
}
pub fn iface(&self) -> Option<&alloc::sync::Arc<dyn crate::interface::Iface>> {
match self {
Inner::Init(_) => None,
Inner::Connecting(conn) => Some(conn.inner.iface()),
Inner::Listening(listen) => Some(listen.inners[0].iface()),
Inner::Established(est) => Some(est.inner.iface()),
}
}
}

View File

@ -0,0 +1,507 @@
use alloc::sync::{Arc, Weak};
use core::sync::atomic::{AtomicBool, AtomicUsize};
use system_error::SystemError;
use crate::libs::wait_queue::WaitQueue;
// use crate::event_poll::EPollEventType;
use crate::socket::common::shutdown::{ShutdownBit, ShutdownTemp};
use crate::socket::endpoint::Endpoint;
use crate::socket::{Socket, PMSG, PSOL};
// use crate::sched::SchedMode;
use crate::{libs::rwlock::RwLock, net::socket::common::shutdown::Shutdown};
use smoltcp;
mod inner;
mod option;
pub use option::Options as TcpOption;
use super::{InetSocket, UNSPECIFIED_LOCAL_ENDPOINT_V4};
type EP = EPollEventType;
#[derive(Debug)]
pub struct TcpSocket {
inner: RwLock<Option<inner::Inner>>,
#[allow(dead_code)]
shutdown: Shutdown, // TODO set shutdown status
nonblock: AtomicBool,
wait_queue: WaitQueue,
self_ref: Weak<Self>,
pollee: AtomicUsize,
}
impl TcpSocket {
pub fn new(_nonblock: bool, ver: smoltcp::wire::IpVersion) -> Arc<Self> {
Arc::new_cyclic(|me| Self {
inner: RwLock::new(Some(inner::Inner::Init(inner::Init::new(ver)))),
shutdown: Shutdown::new(),
nonblock: AtomicBool::new(false),
wait_queue: WaitQueue::default(),
self_ref: me.clone(),
pollee: AtomicUsize::new(0_usize),
})
}
pub fn new_established(inner: inner::Established, nonblock: bool) -> Arc<Self> {
Arc::new_cyclic(|me| Self {
inner: RwLock::new(Some(inner::Inner::Established(inner))),
shutdown: Shutdown::new(),
nonblock: AtomicBool::new(nonblock),
wait_queue: WaitQueue::default(),
self_ref: me.clone(),
pollee: AtomicUsize::new((EP::EPOLLIN.bits() | EP::EPOLLOUT.bits()) as usize),
})
}
pub fn is_nonblock(&self) -> bool {
self.nonblock.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn do_bind(&self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<(), SystemError> {
let mut writer = self.inner.write();
match writer.take().expect("Tcp inner::Inner is None") {
inner::Inner::Init(inner) => {
let bound = inner.bind(local_endpoint)?;
if let inner::Init::Bound((ref bound, _)) = bound {
bound
.iface()
.common()
.bind_socket(self.self_ref.upgrade().unwrap());
}
writer.replace(inner::Inner::Init(bound));
Ok(())
}
any => {
writer.replace(any);
log::error!("TcpSocket::do_bind: not Init");
Err(SystemError::EINVAL)
}
}
}
pub fn do_listen(&self, backlog: usize) -> Result<(), SystemError> {
let mut writer = self.inner.write();
let inner = writer.take().expect("Tcp inner::Inner is None");
let (listening, err) = match inner {
inner::Inner::Init(init) => {
let listen_result = init.listen(backlog);
match listen_result {
Ok(listening) => (inner::Inner::Listening(listening), None),
Err((init, err)) => (inner::Inner::Init(init), Some(err)),
}
}
_ => (inner, Some(SystemError::EINVAL)),
};
writer.replace(listening);
drop(writer);
if let Some(err) = err {
return Err(err);
}
return Ok(());
}
pub fn try_accept(&self) -> Result<(Arc<TcpSocket>, smoltcp::wire::IpEndpoint), SystemError> {
match self
.inner
.write()
.as_mut()
.expect("Tcp inner::Inner is None")
{
inner::Inner::Listening(listening) => listening.accept().map(|(stream, remote)| {
(
TcpSocket::new_established(stream, self.is_nonblock()),
remote,
)
}),
_ => Err(SystemError::EINVAL),
}
}
// SHOULD refactor
pub fn start_connect(
&self,
remote_endpoint: smoltcp::wire::IpEndpoint,
) -> Result<(), SystemError> {
let mut writer = self.inner.write();
let inner = writer.take().expect("Tcp inner::Inner is None");
let (init, result) = match inner {
inner::Inner::Init(init) => {
let conn_result = init.connect(remote_endpoint);
match conn_result {
Ok(connecting) => (
inner::Inner::Connecting(connecting),
if !self.is_nonblock() {
Ok(())
} else {
Err(SystemError::EINPROGRESS)
},
),
Err((init, err)) => (inner::Inner::Init(init), Err(err)),
}
}
inner::Inner::Connecting(connecting) if self.is_nonblock() => (
inner::Inner::Connecting(connecting),
Err(SystemError::EALREADY),
),
inner::Inner::Connecting(connecting) => (inner::Inner::Connecting(connecting), Ok(())),
inner::Inner::Listening(inner) => {
(inner::Inner::Listening(inner), Err(SystemError::EISCONN))
}
inner::Inner::Established(inner) => {
(inner::Inner::Established(inner), Err(SystemError::EISCONN))
}
};
match result {
Ok(()) | Err(SystemError::EINPROGRESS) => {
init.iface().unwrap().poll();
}
_ => {}
}
writer.replace(init);
return result;
}
// for irq use
pub fn finish_connect(&self) -> Result<(), SystemError> {
let mut writer = self.inner.write();
let inner::Inner::Connecting(conn) = writer.take().expect("Tcp inner::Inner is None")
else {
log::error!("TcpSocket::finish_connect: not Connecting");
return Err(SystemError::EINVAL);
};
let (inner, result) = conn.into_result();
writer.replace(inner);
drop(writer);
result
}
pub fn check_connect(&self) -> Result<(), SystemError> {
self.update_events();
let mut write_state = self.inner.write();
let inner = write_state.take().expect("Tcp inner::Inner is None");
let (replace, result) = match inner {
inner::Inner::Connecting(conn) => conn.into_result(),
inner::Inner::Established(es) => {
log::warn!("TODO: check new established");
(inner::Inner::Established(es), Ok(()))
} // TODO check established
_ => {
log::warn!("TODO: connecting socket error options");
(inner, Err(SystemError::EINVAL))
} // TODO socket error options
};
write_state.replace(replace);
result
}
pub fn try_recv(&self, buf: &mut [u8]) -> Result<usize, SystemError> {
self.inner
.read()
.as_ref()
.map(|inner| {
inner.iface().unwrap().poll();
let result = match inner {
inner::Inner::Established(inner) => inner.recv_slice(buf),
_ => Err(SystemError::EINVAL),
};
inner.iface().unwrap().poll();
result
})
.unwrap()
}
pub fn try_send(&self, buf: &[u8]) -> Result<usize, SystemError> {
// TODO: add nonblock check of connecting socket
let sent = match self
.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
{
inner::Inner::Established(inner) => inner.send_slice(buf),
_ => Err(SystemError::EINVAL),
};
self.inner.read().as_ref().unwrap().iface().unwrap().poll();
sent
}
fn update_events(&self) -> bool {
match self
.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
{
inner::Inner::Init(_) => false,
inner::Inner::Connecting(connecting) => connecting.update_io_events(),
inner::Inner::Established(established) => {
established.update_io_events(&self.pollee);
false
}
inner::Inner::Listening(listening) => {
listening.update_io_events(&self.pollee);
false
}
}
}
fn incoming(&self) -> bool {
EP::from_bits_truncate(self.poll() as u32).contains(EP::EPOLLIN)
}
}
impl Socket for TcpSocket {
fn wait_queue(&self) -> &WaitQueue {
&self.wait_queue
}
fn get_name(&self) -> Result<Endpoint, SystemError> {
match self
.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
{
inner::Inner::Init(inner::Init::Unbound((_, ver))) => Ok(Endpoint::Ip(match ver {
smoltcp::wire::IpVersion::Ipv4 => UNSPECIFIED_LOCAL_ENDPOINT_V4,
// smoltcp::wire::IpVersion::Ipv6 => UNSPECIFIED_LOCAL_ENDPOINT_V6,
})),
inner::Inner::Init(inner::Init::Bound((_, local))) => Ok(Endpoint::Ip(*local)),
inner::Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_name())),
inner::Inner::Established(established) => Ok(Endpoint::Ip(established.get_name())),
inner::Inner::Listening(listening) => Ok(Endpoint::Ip(listening.get_name())),
}
}
fn get_peer_name(&self) -> Result<Endpoint, SystemError> {
match self
.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
{
inner::Inner::Init(_) => Err(SystemError::ENOTCONN),
inner::Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_peer_name())),
inner::Inner::Established(established) => Ok(Endpoint::Ip(established.get_peer_name())),
inner::Inner::Listening(_) => Err(SystemError::ENOTCONN),
}
}
fn bind(&self, endpoint: Endpoint) -> Result<(), SystemError> {
if let Endpoint::Ip(addr) = endpoint {
return self.do_bind(addr);
}
log::debug!("TcpSocket::bind: invalid endpoint");
return Err(SystemError::EINVAL);
}
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
let Endpoint::Ip(endpoint) = endpoint else {
log::debug!("TcpSocket::connect: invalid endpoint");
return Err(SystemError::EINVAL);
};
self.start_connect(endpoint)?; // Only Nonblock or error will return error.
return loop {
match self.check_connect() {
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {}
result => break result,
}
};
}
fn poll(&self) -> usize {
self.pollee.load(core::sync::atomic::Ordering::SeqCst)
}
fn listen(&self, backlog: usize) -> Result<(), SystemError> {
self.do_listen(backlog)
}
fn accept(&self) -> Result<(Arc<SocketInode>, Endpoint), SystemError> {
if self.is_nonblock() {
self.try_accept()
} else {
loop {
match self.try_accept() {
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {
wq_wait_event_interruptible!(self.wait_queue, self.incoming(), {})?;
}
result => break result,
}
}
}
.map(|(inner, endpoint)| (SocketInode::new(inner), Endpoint::Ip(endpoint)))
}
fn recv(&self, buffer: &mut [u8], _flags: PMSG) -> Result<usize, SystemError> {
self.try_recv(buffer)
}
fn send(&self, buffer: &[u8], _flags: PMSG) -> Result<usize, SystemError> {
self.try_send(buffer)
}
fn send_buffer_size(&self) -> usize {
self.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
.send_buffer_size()
}
fn recv_buffer_size(&self) -> usize {
self.inner
.read()
.as_ref()
.expect("Tcp inner::Inner is None")
.recv_buffer_size()
}
fn shutdown(&self, how: ShutdownTemp) -> Result<(), SystemError> {
let self_shutdown = self.shutdown.get().bits();
let diff = how.bits().difference(self_shutdown);
match diff.is_empty() {
true => return Ok(()),
false => {
if diff.contains(ShutdownBit::SHUT_RD) {
self.shutdown.recv_shutdown();
// TODO 协议栈处理
}
if diff.contains(ShutdownBit::SHUT_WR) {
self.shutdown.send_shutdown();
// TODO 协议栈处理
}
}
}
Ok(())
}
fn close(&self) -> Result<(), SystemError> {
let Some(inner) = self.inner.write().take() else {
log::warn!("TcpSocket::close: already closed, unexpected");
return Ok(());
};
if let Some(iface) = inner.iface() {
iface
.common()
.unbind_socket(self.self_ref.upgrade().unwrap());
}
match inner {
// complete connecting socket close logic
inner::Inner::Connecting(conn) => {
let conn = unsafe { conn.into_established() };
conn.close();
conn.release();
}
inner::Inner::Established(es) => {
es.close();
es.release();
}
inner::Inner::Listening(ls) => {
ls.close();
ls.release();
}
inner::Inner::Init(init) => {
init.close();
}
};
Ok(())
}
fn set_option(&self, level: PSOL, name: usize, val: &[u8]) -> Result<(), SystemError> {
if level != PSOL::TCP {
// return Err(SystemError::EINVAL);
log::debug!("TcpSocket::set_option: not TCP");
return Ok(());
}
use option::Options::{self, *};
let option_name = Options::try_from(name as i32)?;
log::debug!("TCP Option: {:?}, value = {:?}", option_name, val);
match option_name {
NoDelay => {
let nagle_enabled = val[0] != 0;
let mut writer = self.inner.write();
let inner = writer.take().expect("Tcp inner::Inner is None");
match inner {
inner::Inner::Established(established) => {
established.with_mut(|socket| {
socket.set_nagle_enabled(nagle_enabled);
});
writer.replace(inner::Inner::Established(established));
}
_ => {
writer.replace(inner);
return Err(SystemError::EINVAL);
}
}
}
KeepIntvl => {
if val.len() == 4 {
let mut writer = self.inner.write();
let inner = writer.take().expect("Tcp inner::Inner is None");
match inner {
inner::Inner::Established(established) => {
let interval = u32::from_ne_bytes([val[0], val[1], val[2], val[3]]);
established.with_mut(|socket| {
socket.set_keep_alive(Some(smoltcp::time::Duration::from_secs(
interval as u64,
)));
});
writer.replace(inner::Inner::Established(established));
}
_ => {
writer.replace(inner);
return Err(SystemError::EINVAL);
}
}
} else {
return Err(SystemError::EINVAL);
}
}
KeepCnt => {
// if val.len() == 4 {
// let mut writer = self.inner.write();
// let inner = writer.take().expect("Tcp inner::Inner is None");
// match inner {
// inner::Inner::Established(established) => {
// let count = u32::from_ne_bytes([val[0], val[1], val[2], val[3]]);
// established.with_mut(|socket| {
// socket.set_keep_alive_count(count);
// });
// writer.replace(inner::Inner::Established(established));
// }
// _ => {
// writer.replace(inner);
// return Err(SystemError::EINVAL);
// }
// }
// } else {
// return Err(SystemError::EINVAL);
// }
}
KeepIdle => {}
_ => {
log::debug!("TcpSocket::set_option: not supported");
// return Err(ENOPROTOOPT);
}
}
Ok(())
}
}
impl InetSocket for TcpSocket {
fn on_iface_events(&self) {
if self.update_events() {
let _result = self.finish_connect();
// set error
}
}
}

View File

@ -0,0 +1,94 @@
use linux_errnos::Errno;
use num_derive::{FromPrimitive, ToPrimitive};
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum Options {
/// Turn off Nagle's algorithm.
NoDelay = 1,
/// Limit MSS.
MaxSegment = 2,
/// Never send partially complete segments.
Cork = 3,
/// Start keeplives after this period.
KeepIdle = 4,
/// Interval between keepalives.
KeepIntvl = 5,
/// Number of keepalives before death.
KeepCnt = 6,
/// Number of SYN retransmits.
Syncnt = 7,
/// Lifetime for orphaned FIN-WAIT-2 state.
Linger2 = 8,
/// Wake up listener only when data arrive.
DeferAccept = 9,
/// Bound advertised window
WindowClamp = 10,
/// Information about this connection.
Info = 11,
/// Block/reenable quick acks.
QuickAck = 12,
/// Congestion control algorithm.
Congestion = 13,
/// TCP MD5 Signature (RFC2385).
Md5Sig = 14,
/// Use linear timeouts for thin streams
ThinLinearTimeouts = 16,
/// Fast retrans. after 1 dupack.
ThinDupack = 17,
/// How long for loss retry before timeout.
UserTimeout = 18,
/// TCP sock is under repair right now.
Repair = 19,
RepairQueue = 20,
QueueSeq = 21,
#[allow(clippy::enum_variant_names)]
RepairOptions = 22,
/// Enable FastOpen on listeners
FastOpen = 23,
Timestamp = 24,
/// Limit number of unsent bytes in write queue.
NotSentLowat = 25,
/// Get Congestion Control (optional) info.
CCInfo = 26,
/// Record SYN headers for new connections.
SaveSyn = 27,
/// Get SYN headers recorded for connection.
SavedSyn = 28,
/// Get/set window parameters.
RepairWindow = 29,
/// Attempt FastOpen with connect.
FastOpenConnect = 30,
/// Attach a ULP to a TCP connection.
ULP = 31,
/// TCP MD5 Signature with extensions.
Md5SigExt = 32,
/// Set the key for Fast Open(cookie).
FastOpenKey = 33,
/// Enable TFO without a TFO cookie.
FastOpenNoCookie = 34,
ZeroCopyReceive = 35,
/// Notify bytes available to read as a cmsg on read.
/// 与TCP_CM_INQ相同
INQ = 36,
/// delay outgoing packets by XX usec
TxDelay = 37,
}
impl TryFrom<i32> for Options {
type Error = Errno;
fn try_from(value: i32) -> Result<Self, Self::Error> {
use num_traits::FromPrimitive;
match <Self as FromPrimitive>::from_i32(value) {
Some(p) => Ok(p),
None => Err(Self::Error::EINVAL),
}
}
}
impl From<Options> for i32 {
fn from(val: Options) -> Self {
use num_traits::ToPrimitive;
<Options as ToPrimitive>::to_i32(&val).unwrap()
}
}

View File

@ -0,0 +1,67 @@
use alloc::sync::Arc;
use linux_errnos::Errno as SystemError;
use smoltcp::{self, wire::IpProtocol};
use crate::{
posix::SOCK,
socket::{
inet::UdpSocket,
Family,
Socket, // SocketInode,
},
};
fn create_inet_socket(
version: smoltcp::wire::IpVersion,
socket_type: SOCK,
protocol: smoltcp::wire::IpProtocol,
) -> Result<Arc<dyn Socket>, SystemError> {
// log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol);
match socket_type {
SOCK::Datagram => match protocol {
IpProtocol::HopByHop | IpProtocol::Udp => {
Ok(UdpSocket::new(false))
}
_ => {
Err(SystemError::EPROTONOSUPPORT)
}
},
// SOCK::Stream => match protocol {
// IpProtocol::HopByHop | IpProtocol::Tcp => {
// log::debug!("create tcp socket");
// return Ok(TcpSocket::new(false, version));
// }
// _ => {
// return Err(SystemError::EPROTONOSUPPORT);
// }
// },
SOCK::Raw => {
todo!("raw")
}
_ => {
Err(SystemError::EPROTONOSUPPORT)
}
}
}
pub struct Inet;
impl Family for Inet {
fn socket(stype: SOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError> {
create_inet_socket(
smoltcp::wire::IpVersion::Ipv4,
stype,
smoltcp::wire::IpProtocol::from(protocol as u8),
)
}
}
// pub struct Inet6;
// impl Family for Inet6 {
// fn socket(stype: PSOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError> {
// create_inet_socket(
// smoltcp::wire::IpVersion::Ipv6,
// stype,
// smoltcp::wire::IpProtocol::from(protocol as u8),
// )
// }
// }

148
src/socket/mod.rs Normal file
View File

@ -0,0 +1,148 @@
pub mod common;
pub mod endpoint;
pub mod inet;
use crate::{libs::wait_queue::WaitQueue, posix::SOCK};
use core::any::Any;
use core::fmt::Debug;
use linux_errnos::Errno as SystemError;
use std::sync::Arc;
use super::{
posix::{PMSG, PSOL},
// SocketInode,
};
use common::shutdown::ShutdownTemp;
use endpoint::Endpoint;
/// # `Socket` methods
/// ## Reference
/// - [Posix standard](https://pubs.opengroup.org/onlinepubs/9699919799/)
#[allow(unused_variables)]
pub trait Socket: Sync + Send + Debug + Any {
/// # `wait_queue`
/// 获取socket的wait queue
fn wait_queue(&self) -> &WaitQueue;
/// # `socket_poll`
/// 获取socket的事件。
fn poll(&self) -> usize;
fn send_buffer_size(&self) -> usize;
fn recv_buffer_size(&self) -> usize;
// /// # `accept`
// /// 接受连接仅用于listening stream socket
// /// ## Block
// /// 如果没有连接到来,会阻塞
// fn accept(&self) -> Result<(Arc<SocketInode>, Endpoint), SystemError> {
// Err(SystemError::ENOSYS)
// }
/// # `bind`
/// 对应于POSIX的bind函数用于绑定到本机指定的端点
fn bind(&self, endpoint: Endpoint) -> Result<(), SystemError> {
Err(SystemError::ENOSYS)
}
/// # `close`
/// 关闭socket
fn close(&self) -> Result<(), SystemError> {
Ok(())
}
/// # `connect`
/// 对应于POSIX的connect函数用于连接到指定的远程服务器端点
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
Err(SystemError::ENOSYS)
}
// fnctl
// freeaddrinfo
// getaddrinfo
// getnameinfo
/// # `get_peer_name`
/// 获取对端的地址
fn get_peer_name(&self) -> Result<Endpoint, SystemError> {
Err(SystemError::ENOSYS)
}
/// # `get_name`
/// 获取socket的地址
fn get_name(&self) -> Result<Endpoint, SystemError> {
Err(SystemError::ENOSYS)
}
/// # `get_option`
/// 对应于 Posix `getsockopt` 获取socket选项
fn get_option(&self, level: PSOL, name: usize, value: &mut [u8]) -> Result<usize, SystemError> {
log::warn!("getsockopt is not implemented");
Ok(0)
}
/// # `listen`
/// 监听socket仅用于stream socket
fn listen(&self, backlog: usize) -> Result<(), SystemError> {
Err(SystemError::ENOSYS)
}
// poll
// pselect
/// # `read`
fn read(&self, buffer: &mut [u8]) -> Result<usize, SystemError> {
self.recv(buffer, PMSG::empty())
}
/// # `recv`
/// 接收数据,`read` = `recv` with flags = 0
fn recv(&self, buffer: &mut [u8], flags: PMSG) -> Result<usize, SystemError> {
Err(SystemError::ENOSYS)
}
/// # `recv_from`
fn recv_from(
&self,
buffer: &mut [u8],
flags: PMSG,
address: Option<Endpoint>,
) -> Result<(usize, Endpoint), SystemError> {
Err(SystemError::ENOSYS)
}
// /// # `recv_msg`
// fn recv_msg(&self, msg: &mut MsgHdr, flags: PMSG) -> Result<usize, SystemError> {
// Err(SystemError::ENOSYS)
// }
// select
/// # `send`
fn send(&self, buffer: &[u8], flags: PMSG) -> Result<usize, SystemError> {
Err(SystemError::ENOSYS)
}
// /// # `send_msg`
// fn send_msg(&self, msg: &MsgHdr, flags: PMSG) -> Result<usize, SystemError> {
// Err(SystemError::ENOSYS)
// }
/// # `send_to`
fn send_to(&self, buffer: &[u8], flags: PMSG, address: Endpoint) -> Result<usize, SystemError> {
Err(SystemError::ENOSYS)
}
/// # `set_option`
/// Posix `setsockopt` 设置socket选项
/// ## Parameters
/// - level 选项的层次
/// - name 选项的名称
/// - value 选项的值
/// ## Reference
/// https://code.dragonos.org.cn/s?refs=sk_setsockopt&project=linux-6.6.21
fn set_option(&self, level: PSOL, name: usize, val: &[u8]) -> Result<(), SystemError> {
log::warn!("setsockopt is not implemented");
Ok(())
}
/// # `shutdown`
fn shutdown(&self, how: ShutdownTemp) -> Result<(), SystemError> {
// TODO 构建shutdown系统调用
// set shutdown bit
Err(SystemError::ENOSYS)
}
// sockatmark
// socket
// socketpair
/// # `write`
fn write(&self, buffer: &[u8]) -> Result<usize, SystemError> {
self.send(buffer, PMSG::empty())
}
// fn write_buffer(&self, _buf: &[u8]) -> Result<usize, SystemError> {
// todo!()
// }
}
pub trait Family {
fn socket(stype: SOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError>;
}