2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
use alloc::sync::{Arc, Weak};
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
use ostd::sync::RwLock;
|
|
|
|
|
use smoltcp::{
|
|
|
|
|
socket::tcp::ConnectError,
|
|
|
|
|
wire::{IpAddress, IpEndpoint},
|
|
|
|
|
};
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
use super::{event::SocketEventObserver, RawTcpSocket, RawUdpSocket};
|
|
|
|
|
use crate::iface::Iface;
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(crate) enum SocketFamily {
|
2023-05-31 02:47:52 +00:00
|
|
|
Tcp,
|
|
|
|
|
Udp,
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
pub struct AnyBoundSocket<E>(Arc<AnyBoundSocketInner<E>>);
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-09-05 15:49:14 +00:00
|
|
|
impl<E> AnyBoundSocket<E> {
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(crate) fn new(
|
2024-09-05 15:49:14 +00:00
|
|
|
iface: Arc<dyn Iface<E>>,
|
2023-05-31 02:47:52 +00:00
|
|
|
handle: smoltcp::iface::SocketHandle,
|
|
|
|
|
port: u16,
|
|
|
|
|
socket_family: SocketFamily,
|
2024-09-06 10:49:37 +00:00
|
|
|
observer: Weak<dyn SocketEventObserver>,
|
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-09-06 10:49:37 +00:00
|
|
|
pub(crate) fn inner(&self) -> &Arc<AnyBoundSocketInner<E>> {
|
2024-07-23 15:03:10 +00:00
|
|
|
&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
|
|
|
}
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
/// Sets the observer whose `on_events` will be called when certain iface events happen. After
|
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
|
|
|
/// 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.
|
2024-09-06 10:49:37 +00:00
|
|
|
pub fn set_observer(&self, new_observer: Weak<dyn SocketEventObserver>) {
|
2024-09-19 11:13:56 +00:00
|
|
|
*self.0.observer.write_irq_disabled() = new_observer;
|
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
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:01:55 +00:00
|
|
|
/// Connects to a remote endpoint.
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// This method will panic if the socket is not a TCP socket.
|
2024-09-06 10:49:37 +00:00
|
|
|
pub fn do_connect(&self, remote_endpoint: IpEndpoint) -> Result<(), ConnectError> {
|
2024-09-05 15:01:55 +00:00
|
|
|
let common = self.iface().common();
|
|
|
|
|
|
|
|
|
|
let mut sockets = common.sockets();
|
2024-07-23 15:03:10 +00:00
|
|
|
let socket = sockets.get_mut::<RawTcpSocket>(self.0.handle);
|
2024-09-05 15:01:55 +00:00
|
|
|
|
|
|
|
|
let mut iface = common.interface();
|
|
|
|
|
let cx = iface.context();
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
socket.connect(cx, remote_endpoint, self.0.port)
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:49:14 +00:00
|
|
|
pub fn iface(&self) -> &Arc<dyn Iface<E>> {
|
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-09-05 15:49:14 +00:00
|
|
|
impl<E> Drop for AnyBoundSocket<E> {
|
2024-07-23 15:03:10 +00:00
|
|
|
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-09-06 10:49:37 +00:00
|
|
|
pub(crate) struct AnyBoundSocketInner<E> {
|
2024-09-05 15:49:14 +00:00
|
|
|
iface: Arc<dyn Iface<E>>,
|
2024-07-23 15:03:10 +00:00
|
|
|
handle: smoltcp::iface::SocketHandle,
|
|
|
|
|
port: u16,
|
|
|
|
|
socket_family: SocketFamily,
|
2024-09-06 10:49:37 +00:00
|
|
|
observer: RwLock<Weak<dyn SocketEventObserver>>,
|
2024-07-23 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:49:14 +00:00
|
|
|
impl<E> AnyBoundSocketInner<E> {
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(crate) fn on_iface_events(&self) {
|
2024-09-19 11:13:56 +00:00
|
|
|
// We never hold the write lock in IRQ handlers, so we don't need to disable IRQs when we
|
|
|
|
|
// get the read lock.
|
|
|
|
|
let observer = Weak::upgrade(&*self.observer.read());
|
|
|
|
|
|
|
|
|
|
if let Some(inner) = observer {
|
|
|
|
|
inner.on_events();
|
2024-07-23 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(crate) fn is_closed(&self) -> bool {
|
2024-07-23 15:03:10 +00:00
|
|
|
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 {
|
2024-09-05 15:01:55 +00:00
|
|
|
let mut sockets = self.iface.common().sockets();
|
2024-07-23 15:03:10 +00:00
|
|
|
let socket = sockets.get_mut::<T>(self.handle);
|
|
|
|
|
f(socket)
|
|
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:49:14 +00:00
|
|
|
impl<E> Drop for AnyBoundSocketInner<E> {
|
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
|
|
|
}
|
|
|
|
|
}
|