2023-05-31 02:47:52 +00:00
|
|
|
use core::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
|
|
|
|
|
|
use super::Ipv4Address;
|
|
|
|
|
use crate::prelude::*;
|
2023-09-04 03:04:42 +00:00
|
|
|
use alloc::collections::btree_map::Entry;
|
2023-05-31 02:47:52 +00:00
|
|
|
use keyable_arc::KeyableWeak;
|
|
|
|
|
use smoltcp::{
|
|
|
|
|
iface::{SocketHandle, SocketSet},
|
|
|
|
|
phy::Device,
|
|
|
|
|
wire::IpCidr,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
|
any_socket::{AnyBoundSocket, AnyRawSocket, AnyUnboundSocket},
|
|
|
|
|
time::get_network_timestamp,
|
|
|
|
|
util::BindPortConfig,
|
|
|
|
|
Iface,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct IfaceCommon {
|
2023-05-30 08:34:28 +00:00
|
|
|
interface: SpinLock<smoltcp::iface::Interface>,
|
|
|
|
|
sockets: SpinLock<SocketSet<'static>>,
|
2023-05-31 02:47:52 +00:00
|
|
|
used_ports: RwLock<BTreeMap<u16, usize>>,
|
|
|
|
|
/// The time should do next poll. We stores the total microseconds since system boots up.
|
|
|
|
|
next_poll_at_ms: AtomicU64,
|
|
|
|
|
bound_sockets: RwLock<BTreeSet<KeyableWeak<AnyBoundSocket>>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IfaceCommon {
|
|
|
|
|
pub(super) fn new(interface: smoltcp::iface::Interface) -> Self {
|
|
|
|
|
let socket_set = SocketSet::new(Vec::new());
|
|
|
|
|
let used_ports = BTreeMap::new();
|
|
|
|
|
Self {
|
2023-05-30 08:34:28 +00:00
|
|
|
interface: SpinLock::new(interface),
|
|
|
|
|
sockets: SpinLock::new(socket_set),
|
2023-05-31 02:47:52 +00:00
|
|
|
used_ports: RwLock::new(used_ports),
|
|
|
|
|
next_poll_at_ms: AtomicU64::new(0),
|
|
|
|
|
bound_sockets: RwLock::new(BTreeSet::new()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 02:18:20 +00:00
|
|
|
pub(super) fn interface(&self) -> SpinLockGuard<smoltcp::iface::Interface> {
|
2023-07-02 10:31:53 +00:00
|
|
|
self.interface.lock_irq_disabled()
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-25 02:18:20 +00:00
|
|
|
pub(super) fn sockets(&self) -> SpinLockGuard<smoltcp::iface::SocketSet<'static>> {
|
2023-07-02 10:31:53 +00:00
|
|
|
self.sockets.lock_irq_disabled()
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
2023-07-02 10:31:53 +00:00
|
|
|
self.interface.lock_irq_disabled().ipv4_addr()
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn netmask(&self) -> Option<Ipv4Address> {
|
2023-07-02 10:31:53 +00:00
|
|
|
let interface = self.interface.lock_irq_disabled();
|
2023-05-31 02:47:52 +00:00
|
|
|
let ip_addrs = interface.ip_addrs();
|
|
|
|
|
ip_addrs.first().map(|cidr| match cidr {
|
|
|
|
|
IpCidr::Ipv4(ipv4_cidr) => ipv4_cidr.netmask(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Alloc an unused port range from 49152 ~ 65535 (According to smoltcp docs)
|
|
|
|
|
fn alloc_ephemeral_port(&self) -> Result<u16> {
|
|
|
|
|
let mut used_ports = self.used_ports.write();
|
|
|
|
|
for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END {
|
2023-09-04 03:04:42 +00:00
|
|
|
if let Entry::Vacant(e) = used_ports.entry(port) {
|
|
|
|
|
e.insert(0);
|
2023-05-31 02:47:52 +00:00
|
|
|
return Ok(port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return_errno_with_message!(Errno::EAGAIN, "cannot find unused high port");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bind_port(&self, port: u16, can_reuse: bool) -> Result<()> {
|
|
|
|
|
let mut used_ports = self.used_ports.write();
|
|
|
|
|
if let Some(used_times) = used_ports.get_mut(&port) {
|
|
|
|
|
if *used_times == 0 || can_reuse {
|
2023-09-04 03:04:42 +00:00
|
|
|
*used_times += 1;
|
2023-05-31 02:47:52 +00:00
|
|
|
} else {
|
|
|
|
|
return_errno_with_message!(Errno::EADDRINUSE, "cannot bind port");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
used_ports.insert(port, 1);
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Release port number so the port can be used again. For reused port, the port may still be in use.
|
|
|
|
|
pub(super) fn release_port(&self, port: u16) {
|
|
|
|
|
let mut used_ports = self.used_ports.write();
|
|
|
|
|
if let Some(used_times) = used_ports.remove(&port) {
|
|
|
|
|
if used_times != 1 {
|
|
|
|
|
used_ports.insert(port, used_times - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn bind_socket(
|
|
|
|
|
&self,
|
|
|
|
|
iface: Arc<dyn Iface>,
|
2023-11-27 15:58:41 +00:00
|
|
|
socket: Box<AnyUnboundSocket>,
|
2023-05-31 02:47:52 +00:00
|
|
|
config: BindPortConfig,
|
2023-11-27 15:58:41 +00:00
|
|
|
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, Box<AnyUnboundSocket>)> {
|
2023-05-31 02:47:52 +00:00
|
|
|
let port = if let Some(port) = config.port() {
|
|
|
|
|
port
|
|
|
|
|
} else {
|
|
|
|
|
match self.alloc_ephemeral_port() {
|
|
|
|
|
Ok(port) => port,
|
|
|
|
|
Err(e) => return Err((e, socket)),
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if let Some(e) = self.bind_port(port, config.can_reuse()).err() {
|
|
|
|
|
return Err((e, socket));
|
|
|
|
|
}
|
|
|
|
|
let socket_family = socket.socket_family();
|
2023-07-02 10:31:53 +00:00
|
|
|
let mut sockets = self.sockets.lock_irq_disabled();
|
2023-05-31 02:47:52 +00:00
|
|
|
let handle = match socket.raw_socket_family() {
|
|
|
|
|
AnyRawSocket::Tcp(tcp_socket) => sockets.add(tcp_socket),
|
|
|
|
|
AnyRawSocket::Udp(udp_socket) => sockets.add(udp_socket),
|
|
|
|
|
};
|
Implement iface event observers and move `Pollee` to them
Finally, this commit implements an iface event observer trait for the
`ConnectingStream`, `ListenStream`, and `ConnectedStream` states in
`StreamSocket`, as well as the `BoundDatagram` state in
`DatagramSocket`. It also moves the `Pollee` from `AnyBoundSocket` to
these observer implementors.
What I have tried to do is minimize the semantic changes. Ideally, this
commit should be a pure refactor commit, meaning that even if the
sematics of the previous code is wrong, the sematics after this commit
should be wrong in the same way. Fixing the wrong sematics should be
done in a separate commit afterwards.
However, keeping exactly the same sematics for `ListenStream` is hard.
We used to maintain a `Pollee` for each `BacklogSocket`, but now we can
just maintain one `Pollee` for the whole `ListenStream`. However,
implementing the correct semantics looks much easier, so we just do it.
For `ConnectingStream`, it used to share the same `Pollee` logic with
`ConnectedStream` (because the `Pollee` was maintained by
`AnyBoundSocket`, which is used by both). Now we write the `Pollee`
logic separately for `ConnectingStream`, so we can just write a correct
one or try to reuse the logic in `ConnectingStream`. This commit does
the former.
There should be no semantic changes for `ConnectedStream` in
`StreamSocket` and `BoundDatagram` in `DatagramSocket`.
2023-11-19 15:54:58 +00:00
|
|
|
let bound_socket = AnyBoundSocket::new(iface, handle, port, socket_family);
|
2023-05-31 02:47:52 +00:00
|
|
|
self.insert_bound_socket(&bound_socket).unwrap();
|
|
|
|
|
Ok(bound_socket)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Remove a socket from the interface
|
|
|
|
|
pub(super) fn remove_socket(&self, handle: SocketHandle) {
|
2023-07-02 10:31:53 +00:00
|
|
|
self.sockets.lock_irq_disabled().remove(handle);
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn poll<D: Device + ?Sized>(&self, device: &mut D) {
|
2023-07-02 10:31:53 +00:00
|
|
|
let mut interface = self.interface.lock_irq_disabled();
|
2023-05-31 02:47:52 +00:00
|
|
|
let timestamp = get_network_timestamp();
|
|
|
|
|
let has_events = {
|
2023-07-02 10:31:53 +00:00
|
|
|
let mut sockets = self.sockets.lock_irq_disabled();
|
2023-05-31 02:47:52 +00:00
|
|
|
interface.poll(timestamp, device, &mut sockets)
|
|
|
|
|
// drop sockets here to avoid deadlock
|
|
|
|
|
};
|
|
|
|
|
if has_events {
|
|
|
|
|
self.bound_sockets.read().iter().for_each(|bound_socket| {
|
2023-08-28 09:37:59 +00:00
|
|
|
if let Some(bound_socket) = bound_socket.upgrade() {
|
Implement iface event observers and move `Pollee` to them
Finally, this commit implements an iface event observer trait for the
`ConnectingStream`, `ListenStream`, and `ConnectedStream` states in
`StreamSocket`, as well as the `BoundDatagram` state in
`DatagramSocket`. It also moves the `Pollee` from `AnyBoundSocket` to
these observer implementors.
What I have tried to do is minimize the semantic changes. Ideally, this
commit should be a pure refactor commit, meaning that even if the
sematics of the previous code is wrong, the sematics after this commit
should be wrong in the same way. Fixing the wrong sematics should be
done in a separate commit afterwards.
However, keeping exactly the same sematics for `ListenStream` is hard.
We used to maintain a `Pollee` for each `BacklogSocket`, but now we can
just maintain one `Pollee` for the whole `ListenStream`. However,
implementing the correct semantics looks much easier, so we just do it.
For `ConnectingStream`, it used to share the same `Pollee` logic with
`ConnectedStream` (because the `Pollee` was maintained by
`AnyBoundSocket`, which is used by both). Now we write the `Pollee`
logic separately for `ConnectingStream`, so we can just write a correct
one or try to reuse the logic in `ConnectingStream`. This commit does
the former.
There should be no semantic changes for `ConnectedStream` in
`StreamSocket` and `BoundDatagram` in `DatagramSocket`.
2023-11-19 15:54:58 +00:00
|
|
|
bound_socket.on_iface_events();
|
2023-08-28 09:37:59 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-02 10:31:53 +00:00
|
|
|
let sockets = self.sockets.lock_irq_disabled();
|
2023-05-31 02:47:52 +00:00
|
|
|
if let Some(instant) = interface.poll_at(timestamp, &sockets) {
|
|
|
|
|
self.next_poll_at_ms
|
|
|
|
|
.store(instant.total_millis() as u64, Ordering::SeqCst);
|
|
|
|
|
} else {
|
|
|
|
|
self.next_poll_at_ms.store(0, Ordering::SeqCst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn next_poll_at_ms(&self) -> Option<u64> {
|
|
|
|
|
let millis = self.next_poll_at_ms.load(Ordering::SeqCst);
|
|
|
|
|
if millis == 0 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(millis)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn insert_bound_socket(&self, socket: &Arc<AnyBoundSocket>) -> Result<()> {
|
2023-09-04 03:04:42 +00:00
|
|
|
let weak_ref = KeyableWeak::from(Arc::downgrade(socket));
|
2023-05-31 02:47:52 +00:00
|
|
|
let mut bound_sockets = self.bound_sockets.write();
|
|
|
|
|
if bound_sockets.contains(&weak_ref) {
|
|
|
|
|
return_errno_with_message!(Errno::EINVAL, "the socket is already bound");
|
|
|
|
|
}
|
|
|
|
|
bound_sockets.insert(weak_ref);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn remove_bound_socket(&self, socket: Weak<AnyBoundSocket>) {
|
|
|
|
|
let weak_ref = KeyableWeak::from(socket);
|
|
|
|
|
self.bound_sockets.write().remove(&weak_ref);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const IP_LOCAL_PORT_START: u16 = 49152;
|
|
|
|
|
const IP_LOCAL_PORT_END: u16 = 65535;
|