2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-07-26 07:43:13 +00:00
|
|
|
use super::Iface;
|
|
|
|
|
use crate::{
|
|
|
|
|
events::Observer,
|
|
|
|
|
net::socket::ip::{IpAddress, IpEndpoint},
|
|
|
|
|
prelude::*,
|
|
|
|
|
};
|
2023-05-31 02:47:52 +00:00
|
|
|
|
|
|
|
|
pub type RawTcpSocket = smoltcp::socket::tcp::Socket<'static>;
|
|
|
|
|
pub type RawUdpSocket = smoltcp::socket::udp::Socket<'static>;
|
|
|
|
|
|
|
|
|
|
pub struct AnyUnboundSocket {
|
|
|
|
|
socket_family: AnyRawSocket,
|
2024-01-07 15:55:23 +00:00
|
|
|
observer: Weak<dyn Observer<()>>,
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-04 03:04:42 +00:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
2023-05-31 02:47:52 +00:00
|
|
|
pub(super) enum AnyRawSocket {
|
|
|
|
|
Tcp(RawTcpSocket),
|
|
|
|
|
Udp(RawUdpSocket),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) enum SocketFamily {
|
|
|
|
|
Tcp,
|
|
|
|
|
Udp,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AnyUnboundSocket {
|
2024-01-07 15:55:23 +00:00
|
|
|
pub fn new_tcp(observer: Weak<dyn Observer<()>>) -> Self {
|
2023-05-31 02:47:52 +00:00
|
|
|
let raw_tcp_socket = {
|
2024-08-24 04:00:42 +00:00
|
|
|
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_RECV_BUF_LEN]);
|
|
|
|
|
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_SEND_BUF_LEN]);
|
2023-05-31 02:47:52 +00:00
|
|
|
RawTcpSocket::new(rx_buffer, tx_buffer)
|
|
|
|
|
};
|
|
|
|
|
AnyUnboundSocket {
|
|
|
|
|
socket_family: AnyRawSocket::Tcp(raw_tcp_socket),
|
2024-01-07 15:55:23 +00:00
|
|
|
observer,
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
pub fn new_udp(observer: Weak<dyn Observer<()>>) -> Self {
|
2023-05-31 02:47:52 +00:00
|
|
|
let raw_udp_socket = {
|
|
|
|
|
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
|
|
|
|
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
|
|
|
|
vec![metadata; UDP_METADATA_LEN],
|
2024-08-24 04:00:42 +00:00
|
|
|
vec![0u8; UDP_RECV_PAYLOAD_LEN],
|
2023-05-31 02:47:52 +00:00
|
|
|
);
|
|
|
|
|
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
|
|
|
|
vec![metadata; UDP_METADATA_LEN],
|
2024-06-18 08:19:26 +00:00
|
|
|
vec![0u8; UDP_SEND_PAYLOAD_LEN],
|
2023-05-31 02:47:52 +00:00
|
|
|
);
|
|
|
|
|
RawUdpSocket::new(rx_buffer, tx_buffer)
|
|
|
|
|
};
|
|
|
|
|
AnyUnboundSocket {
|
|
|
|
|
socket_family: AnyRawSocket::Udp(raw_udp_socket),
|
2024-01-07 15:55:23 +00:00
|
|
|
observer,
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
pub(super) fn into_raw(self) -> (AnyRawSocket, Weak<dyn Observer<()>>) {
|
|
|
|
|
(self.socket_family, self.observer)
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
pub struct AnyBoundSocket(Arc<AnyBoundSocketInner>);
|
2023-05-31 02:47:52 +00:00
|
|
|
|
|
|
|
|
impl AnyBoundSocket {
|
|
|
|
|
pub(super) fn new(
|
|
|
|
|
iface: Arc<dyn Iface>,
|
|
|
|
|
handle: smoltcp::iface::SocketHandle,
|
|
|
|
|
port: u16,
|
|
|
|
|
socket_family: SocketFamily,
|
2024-01-07 15:55:23 +00:00
|
|
|
observer: Weak<dyn Observer<()>>,
|
2024-07-23 15:03:10 +00:00
|
|
|
) -> Self {
|
|
|
|
|
Self(Arc::new(AnyBoundSocketInner {
|
2023-05-31 02:47:52 +00:00
|
|
|
iface,
|
|
|
|
|
handle,
|
|
|
|
|
port,
|
|
|
|
|
socket_family,
|
2024-01-07 15:55:23 +00:00
|
|
|
observer: RwLock::new(observer),
|
2024-07-23 15:03:10 +00:00
|
|
|
}))
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
pub(super) fn inner(&self) -> &Arc<AnyBoundSocketInner> {
|
|
|
|
|
&self.0
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set the observer whose `on_events` will be called when certain iface events happen. After
|
|
|
|
|
/// setting, the new observer will fire once immediately to avoid missing any events.
|
|
|
|
|
///
|
2024-08-26 07:31:58 +00:00
|
|
|
/// If there is an existing observer, due to race conditions, this function does not guarantee
|
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
|
|
|
/// that the old observer will never be called after the setting. Users should be aware of this
|
|
|
|
|
/// and proactively handle the race conditions if necessary.
|
|
|
|
|
pub fn set_observer(&self, handler: Weak<dyn Observer<()>>) {
|
2024-07-23 15:03:10 +00:00
|
|
|
*self.0.observer.write() = handler;
|
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
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
self.0.on_iface_events();
|
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
|
|
|
}
|
|
|
|
|
|
2023-05-31 02:47:52 +00:00
|
|
|
pub fn local_endpoint(&self) -> Option<IpEndpoint> {
|
|
|
|
|
let ip_addr = {
|
2024-07-23 15:03:10 +00:00
|
|
|
let ipv4_addr = self.0.iface.ipv4_addr()?;
|
2023-05-31 02:47:52 +00:00
|
|
|
IpAddress::Ipv4(ipv4_addr)
|
|
|
|
|
};
|
2024-07-23 15:03:10 +00:00
|
|
|
Some(IpEndpoint::new(ip_addr, self.0.port))
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn raw_with<T: smoltcp::socket::AnySocket<'static>, R, F: FnMut(&mut T) -> R>(
|
|
|
|
|
&self,
|
2024-07-23 15:03:10 +00:00
|
|
|
f: F,
|
2023-05-31 02:47:52 +00:00
|
|
|
) -> R {
|
2024-07-23 15:03:10 +00:00
|
|
|
self.0.raw_with(f)
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try to connect to a remote endpoint. Tcp socket only.
|
|
|
|
|
pub fn do_connect(&self, remote_endpoint: IpEndpoint) -> Result<()> {
|
2024-07-23 15:03:10 +00:00
|
|
|
let mut sockets = self.0.iface.sockets();
|
|
|
|
|
let socket = sockets.get_mut::<RawTcpSocket>(self.0.handle);
|
|
|
|
|
let port = self.0.port;
|
|
|
|
|
let mut iface_inner = self.0.iface.iface_inner();
|
2023-05-31 02:47:52 +00:00
|
|
|
let cx = iface_inner.context();
|
|
|
|
|
socket
|
|
|
|
|
.connect(cx, remote_endpoint, port)
|
|
|
|
|
.map_err(|_| Error::with_message(Errno::ENOBUFS, "send connection request failed"))?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn iface(&self) -> &Arc<dyn Iface> {
|
2024-07-23 15:03:10 +00:00
|
|
|
&self.0.iface
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
2024-07-23 15:03:10 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
impl Drop for AnyBoundSocket {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
if self.0.start_closing() {
|
|
|
|
|
self.0.iface.common().remove_bound_socket_now(&self.0);
|
|
|
|
|
} else {
|
|
|
|
|
self.0
|
|
|
|
|
.iface
|
|
|
|
|
.common()
|
|
|
|
|
.remove_bound_socket_when_closed(&self.0);
|
|
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
2024-07-23 15:03:10 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
pub(super) struct AnyBoundSocketInner {
|
|
|
|
|
iface: Arc<dyn Iface>,
|
|
|
|
|
handle: smoltcp::iface::SocketHandle,
|
|
|
|
|
port: u16,
|
|
|
|
|
socket_family: SocketFamily,
|
|
|
|
|
observer: RwLock<Weak<dyn Observer<()>>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AnyBoundSocketInner {
|
|
|
|
|
pub(super) fn on_iface_events(&self) {
|
|
|
|
|
if let Some(observer) = Weak::upgrade(&*self.observer.read()) {
|
|
|
|
|
observer.on_events(&())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn is_closed(&self) -> bool {
|
|
|
|
|
match self.socket_family {
|
|
|
|
|
SocketFamily::Tcp => self.raw_with(|socket: &mut RawTcpSocket| {
|
|
|
|
|
socket.state() == smoltcp::socket::tcp::State::Closed
|
|
|
|
|
}),
|
|
|
|
|
SocketFamily::Udp => true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Starts closing the socket and returns whether the socket is closed.
|
|
|
|
|
///
|
|
|
|
|
/// For sockets that can be closed immediately, such as UDP sockets and TCP listening sockets,
|
|
|
|
|
/// this method will always return `true`.
|
|
|
|
|
///
|
|
|
|
|
/// For other sockets, such as TCP connected sockets, they cannot be closed immediately because
|
|
|
|
|
/// we at least need to send the FIN packet and wait for the remote end to send an ACK packet.
|
|
|
|
|
/// In this case, this method will return `false` and [`Self::is_closed`] can be used to
|
|
|
|
|
/// determine if the closing process is complete.
|
|
|
|
|
fn start_closing(&self) -> bool {
|
2023-05-31 02:47:52 +00:00
|
|
|
match self.socket_family {
|
2024-07-23 15:03:10 +00:00
|
|
|
SocketFamily::Tcp => self.raw_with(|socket: &mut RawTcpSocket| {
|
|
|
|
|
socket.close();
|
|
|
|
|
socket.state() == smoltcp::socket::tcp::State::Closed
|
|
|
|
|
}),
|
|
|
|
|
SocketFamily::Udp => {
|
|
|
|
|
self.raw_with(|socket: &mut RawUdpSocket| socket.close());
|
|
|
|
|
true
|
|
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-07-23 15:03:10 +00:00
|
|
|
|
|
|
|
|
pub fn raw_with<T: smoltcp::socket::AnySocket<'static>, R, F: FnMut(&mut T) -> R>(
|
|
|
|
|
&self,
|
|
|
|
|
mut f: F,
|
|
|
|
|
) -> R {
|
|
|
|
|
let mut sockets = self.iface.sockets();
|
|
|
|
|
let socket = sockets.get_mut::<T>(self.handle);
|
|
|
|
|
f(socket)
|
|
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
impl Drop for AnyBoundSocketInner {
|
2023-05-31 02:47:52 +00:00
|
|
|
fn drop(&mut self) {
|
2024-07-23 15:03:10 +00:00
|
|
|
let iface_common = self.iface.common();
|
|
|
|
|
iface_common.remove_socket(self.handle);
|
|
|
|
|
iface_common.release_port(self.port);
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For TCP
|
2024-08-24 04:00:42 +00:00
|
|
|
pub const TCP_RECV_BUF_LEN: usize = 65536;
|
|
|
|
|
pub const TCP_SEND_BUF_LEN: usize = 65536;
|
2023-05-31 02:47:52 +00:00
|
|
|
|
|
|
|
|
// For UDP
|
2024-08-24 04:00:42 +00:00
|
|
|
pub const UDP_SEND_PAYLOAD_LEN: usize = 65536;
|
|
|
|
|
pub const UDP_RECV_PAYLOAD_LEN: usize = 65536;
|
2023-05-31 02:47:52 +00:00
|
|
|
const UDP_METADATA_LEN: usize = 256;
|