From 878bd4c46b5873ca0456f8325216b097368a1474 Mon Sep 17 00:00:00 2001 From: rayylee Date: Tue, 16 Apr 2024 15:06:25 +0800 Subject: [PATCH] syscall: Support SO_REUSEADDR for udp Signed-off-by: rayylee --- Cargo.lock | 18 +++++++++++++++-- modules/axnet/Cargo.toml | 3 +-- modules/axnet/src/smoltcp_impl/mod.rs | 22 ++++++++++++++++++++- modules/axnet/src/smoltcp_impl/udp.rs | 26 ++++++++++++++++++++++++- ulib/axstarry/src/syscall_net/socket.rs | 22 ++++++++++----------- 5 files changed, 74 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 509f1e372..0428cce47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,7 +472,7 @@ dependencies = [ "lazy_init", "log", "num_enum", - "smoltcp", + "smoltcp 0.10.0 (git+https://github.com/YXalix/smoltcp.git)", "spin 0.9.8", ] @@ -1284,7 +1284,7 @@ dependencies = [ "bit_field", "core_detect", "log", - "smoltcp", + "smoltcp 0.10.0 (git+https://github.com/c0per/smoltcp?branch=starryos)", "volatile 0.3.0", ] @@ -1915,6 +1915,20 @@ dependencies = [ "managed", ] +[[package]] +name = "smoltcp" +version = "0.10.0" +source = "git+https://github.com/YXalix/smoltcp.git#8b004f1845607bea1b7650cffdd41ed8fe90a918" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt", + "heapless", + "log", + "managed", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/modules/axnet/Cargo.toml b/modules/axnet/Cargo.toml index f982a6f1e..9c3c976ef 100644 --- a/modules/axnet/Cargo.toml +++ b/modules/axnet/Cargo.toml @@ -36,8 +36,7 @@ version = "0.5.11" default-features = false [dependencies.smoltcp] -git = "https://github.com/rcore-os/smoltcp.git" -rev = "2ade274" +git = "https://github.com/YXalix/smoltcp.git" default-features = false features = [ "alloc", "log", # no std diff --git a/modules/axnet/src/smoltcp_impl/mod.rs b/modules/axnet/src/smoltcp_impl/mod.rs index ea2da327b..eb61ca203 100644 --- a/modules/axnet/src/smoltcp_impl/mod.rs +++ b/modules/axnet/src/smoltcp_impl/mod.rs @@ -9,6 +9,7 @@ use alloc::vec; use core::cell::RefCell; use core::ops::DerefMut; +use axerrno::{ax_err, ax_err_type, AxError, AxResult}; use axdriver::prelude::*; use axhal::time::{current_time_nanos, NANOS_PER_MICROS}; use axsync::Mutex; @@ -16,7 +17,7 @@ use driver_net::{DevError, NetBufPtr}; use lazy_init::LazyInit; use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet}; use smoltcp::phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}; -use smoltcp::socket::{self, AnySocket}; +use smoltcp::socket::{self, AnySocket, Socket}; use smoltcp::time::Instant; use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress, IpCidr}; @@ -130,6 +131,23 @@ impl<'a> SocketSetWrapper<'a> { f(socket) } + pub fn bind_check(&self, addr: IpAddress, port: u16) -> AxResult { + let mut sockets = self.0.lock(); + error!("checking addr: {:?}, port: {}", addr, port); + for item in sockets.iter_mut() { + match item.1 { + Socket::Udp(s) => { + error!("{}", s.endpoint().port); + if s.endpoint().port == port { + return Err(AxError::AddrInUse); + } + }, + _ => continue, + }; + } + Ok(()) + } + pub fn poll_interfaces(&self) { #[cfg(feature = "ip")] { @@ -350,6 +368,8 @@ pub(crate) fn init(_net_dev: AxNetDevice) { .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)) .unwrap(); }); + let multicast_addr = IpAddress::v4(239, 255, 0, 1); + let _= iface.join_multicast_group(&mut device, multicast_addr, Instant::from_micros_const((current_time_nanos() / NANOS_PER_MICROS) as i64)); LOOPBACK.init_by(Mutex::new(iface)); LOOPBACK_DEV.init_by(Mutex::new(device)); } diff --git a/modules/axnet/src/smoltcp_impl/udp.rs b/modules/axnet/src/smoltcp_impl/udp.rs index bc8ab1b45..ac2fddb49 100644 --- a/modules/axnet/src/smoltcp_impl/udp.rs +++ b/modules/axnet/src/smoltcp_impl/udp.rs @@ -26,6 +26,7 @@ pub struct UdpSocket { local_addr: RwLock>, peer_addr: RwLock>, nonblock: AtomicBool, + reuse_addr: AtomicBool, } impl UdpSocket { @@ -39,6 +40,7 @@ impl UdpSocket { local_addr: RwLock::new(None), peer_addr: RwLock::new(None), nonblock: AtomicBool::new(false), + reuse_addr: AtomicBool::new(false), } } @@ -63,6 +65,22 @@ impl UdpSocket { self.nonblock.load(Ordering::Acquire) } + /// Returns whether this socket is in reuse address mode. + #[inline] + pub fn is_reuse_addr(&self) -> bool { + self.reuse_addr.load(Ordering::Acquire) + } + + /// Moves this UDP socket into or out of reuse address mode. + /// + /// When a socket is bound, the `SO_REUSEADDR` option allows multiple sockets to be bound to the + /// same address if they are bound to different local addresses. This option must be set before + /// calling `bind`. + #[inline] + pub fn set_reuse_addr(&self, reuse_addr: bool) { + self.reuse_addr.store(reuse_addr, Ordering::Release); + } + /// Moves this UDP socket into or out of nonblocking mode. /// /// This will result in `recv`, `recv_from`, `send`, and `send_to` @@ -95,6 +113,12 @@ impl UdpSocket { addr: (!is_unspecified(local_endpoint.addr)).then_some(local_endpoint.addr), port: local_endpoint.port, }; + + if !self.is_reuse_addr() { + // Check if the address is already in use + SOCKET_SET.bind_check(local_endpoint.addr, local_endpoint.port)?; + } + SOCKET_SET.with_socket_mut::(self.handle, |socket| { socket.bind(endpoint).or_else(|e| match e { BindError::InvalidState => ax_err!(AlreadyExists, "socket bind() failed"), @@ -233,7 +257,7 @@ impl UdpSocket { multicast_addr, interface_addr ); let _ = LOOPBACK.lock().join_multicast_group(LOOPBACK_DEV.lock().deref_mut(), multicast_addr, timestamp); - } + } } /// Private methods diff --git a/ulib/axstarry/src/syscall_net/socket.rs b/ulib/axstarry/src/syscall_net/socket.rs index 03e18e4e8..869c0cdc8 100644 --- a/ulib/axstarry/src/syscall_net/socket.rs +++ b/ulib/axstarry/src/syscall_net/socket.rs @@ -153,23 +153,19 @@ impl SocketOption { pub fn set(&self, socket: &Socket, opt: &[u8]) -> SyscallResult { match self { SocketOption::SO_REUSEADDR => { + // unimplemented!("wait for implementation of SO_REUSEADDR"); if opt.len() < 4 { panic!("can't read a int from socket opt value"); } - let opt_value = i32::from_ne_bytes(<[u8; 4]>::try_from(&opt[0..4]).unwrap()); - socket.set_reuse_addr(opt_value != 0); - // socket.reuse_addr = opt_value != 0; Ok((0)) } SocketOption::SO_DONTROUTE => { if opt.len() < 4 { panic!("can't read a int from socket opt value"); } - let opt_value = i32::from_ne_bytes(<[u8; 4]>::try_from(&opt[0..4]).unwrap()); - socket.set_reuse_addr(opt_value != 0); // socket.reuse_addr = opt_value != 0; Ok((0)) @@ -450,7 +446,6 @@ pub struct Socket { recv_timeout: Mutex>, // fake options - reuse_addr: AtomicBool, dont_route: bool, send_buf_size: AtomicU64, recv_buf_size: AtomicU64, @@ -472,7 +467,11 @@ impl Socket { *self.recv_timeout.lock() } fn get_reuse_addr(&self) -> bool { - self.reuse_addr.load(core::sync::atomic::Ordering::Acquire) + let inner = self.inner.lock(); + match &*inner { + SocketInner::Udp(s) => s.is_reuse_addr(), + _ => unimplemented!("get_reuse_addr on other socket") + } } fn get_send_buf_size(&self) -> u64 { @@ -494,8 +493,11 @@ impl Socket { } fn set_reuse_addr(&self, flag: bool) { - self.reuse_addr - .store(flag, core::sync::atomic::Ordering::Release) + let inner = self.inner.lock(); + match &*inner { + SocketInner::Udp(s) => s.set_reuse_addr(flag), + _ => unimplemented!("set_reuse_addr on other socket") + } } fn set_send_buf_size(&self, size: u64) { @@ -536,7 +538,6 @@ impl Socket { inner: Mutex::new(inner), close_exec: false, recv_timeout: Mutex::new(None), - reuse_addr: AtomicBool::new(false), dont_route: false, send_buf_size: AtomicU64::new(64 * 1024), recv_buf_size: AtomicU64::new(64 * 1024), @@ -658,7 +659,6 @@ impl Socket { inner: Mutex::new(SocketInner::Tcp(new_socket)), close_exec: false, recv_timeout: Mutex::new(None), - reuse_addr: AtomicBool::new(false), dont_route: false, send_buf_size: AtomicU64::new(64 * 1024), recv_buf_size: AtomicU64::new(64 * 1024),