2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
use alloc::sync::Weak;
|
2023-06-13 09:49:44 +00:00
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
use aster_bigtcp::{
|
|
|
|
|
errors::tcp::{RecvError, SendError},
|
|
|
|
|
socket::{RawTcpSocket, SocketEventObserver},
|
|
|
|
|
wire::IpEndpoint,
|
|
|
|
|
};
|
2024-01-08 15:32:04 +00:00
|
|
|
|
2023-05-31 02:48:16 +00:00
|
|
|
use crate::{
|
2024-09-06 10:49:37 +00:00
|
|
|
events::IoEvents,
|
2023-05-31 02:48:16 +00:00
|
|
|
net::{
|
2024-09-06 10:49:37 +00:00
|
|
|
iface::AnyBoundSocket,
|
2023-05-31 02:48:16 +00:00
|
|
|
socket::util::{send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd},
|
|
|
|
|
},
|
|
|
|
|
prelude::*,
|
2024-01-07 15:55:23 +00:00
|
|
|
process::signal::Pollee,
|
2023-05-31 02:48:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct ConnectedStream {
|
2024-07-23 15:03:10 +00:00
|
|
|
bound_socket: AnyBoundSocket,
|
2023-05-31 02:48:16 +00:00
|
|
|
remote_endpoint: IpEndpoint,
|
2024-01-09 15:42:26 +00:00
|
|
|
/// Indicates whether this connection is "new" in a `connect()` system call.
|
|
|
|
|
///
|
|
|
|
|
/// If the connection is not new, `connect()` will fail with the error code `EISCONN`,
|
|
|
|
|
/// otherwise it will succeed. This means that `connect()` will succeed _exactly_ once,
|
|
|
|
|
/// regardless of whether the connection is established synchronously or asynchronously.
|
|
|
|
|
///
|
|
|
|
|
/// If the connection is established synchronously, the synchronous `connect()` will succeed
|
|
|
|
|
/// and any subsequent `connect()` will fail; otherwise, the first `connect()` after the
|
|
|
|
|
/// connection is established asynchronously will succeed and any subsequent `connect()` will
|
|
|
|
|
/// fail.
|
|
|
|
|
is_new_connection: bool,
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ConnectedStream {
|
2024-01-09 15:42:26 +00:00
|
|
|
pub fn new(
|
2024-07-23 15:03:10 +00:00
|
|
|
bound_socket: AnyBoundSocket,
|
2024-01-09 15:42:26 +00:00
|
|
|
remote_endpoint: IpEndpoint,
|
|
|
|
|
is_new_connection: bool,
|
|
|
|
|
) -> Self {
|
2024-01-07 15:55:23 +00:00
|
|
|
Self {
|
2023-05-31 02:48:16 +00:00
|
|
|
bound_socket,
|
|
|
|
|
remote_endpoint,
|
2024-01-09 15:42:26 +00:00
|
|
|
is_new_connection,
|
2024-01-07 15:55:23 +00:00
|
|
|
}
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-18 08:05:20 +00:00
|
|
|
pub fn shutdown(&self, _cmd: SockShutdownCmd) -> Result<()> {
|
2023-05-31 02:48:16 +00:00
|
|
|
// TODO: deal with cmd
|
|
|
|
|
self.bound_socket.raw_with(|socket: &mut RawTcpSocket| {
|
|
|
|
|
socket.close();
|
|
|
|
|
});
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-18 08:05:20 +00:00
|
|
|
pub fn try_recv(&self, buf: &mut [u8], _flags: SendRecvFlags) -> Result<usize> {
|
2024-01-08 15:32:04 +00:00
|
|
|
let result = self
|
2024-01-07 15:55:23 +00:00
|
|
|
.bound_socket
|
2024-01-08 15:32:04 +00:00
|
|
|
.raw_with(|socket: &mut RawTcpSocket| socket.recv_slice(buf));
|
2024-03-20 03:25:18 +00:00
|
|
|
|
2024-01-08 15:32:04 +00:00
|
|
|
match result {
|
|
|
|
|
Ok(0) => return_errno_with_message!(Errno::EAGAIN, "the receive buffer is empty"),
|
|
|
|
|
Ok(recv_bytes) => Ok(recv_bytes),
|
|
|
|
|
Err(RecvError::Finished) => Ok(0),
|
|
|
|
|
Err(RecvError::InvalidState) => {
|
|
|
|
|
return_errno_with_message!(Errno::ECONNRESET, "the connection is reset")
|
|
|
|
|
}
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-18 08:05:20 +00:00
|
|
|
pub fn try_send(&self, buf: &[u8], _flags: SendRecvFlags) -> Result<usize> {
|
2024-01-08 15:32:04 +00:00
|
|
|
let result = self
|
2023-11-02 06:00:50 +00:00
|
|
|
.bound_socket
|
2024-01-08 15:32:04 +00:00
|
|
|
.raw_with(|socket: &mut RawTcpSocket| socket.send_slice(buf));
|
2024-03-20 03:25:18 +00:00
|
|
|
|
2024-01-08 15:32:04 +00:00
|
|
|
match result {
|
|
|
|
|
Ok(0) => return_errno_with_message!(Errno::EAGAIN, "the send buffer is full"),
|
|
|
|
|
Ok(sent_bytes) => Ok(sent_bytes),
|
|
|
|
|
Err(SendError::InvalidState) => {
|
|
|
|
|
// FIXME: `EPIPE` is another possibility, which means that the socket is shut down
|
|
|
|
|
// for writing. In that case, we should also trigger a `SIGPIPE` if `MSG_NOSIGNAL`
|
|
|
|
|
// is not specified.
|
|
|
|
|
return_errno_with_message!(Errno::ECONNRESET, "the connection is reset");
|
|
|
|
|
}
|
2024-01-07 15:55:23 +00:00
|
|
|
}
|
2023-11-02 06:00:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
pub fn local_endpoint(&self) -> IpEndpoint {
|
|
|
|
|
self.bound_socket.local_endpoint().unwrap()
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
pub fn remote_endpoint(&self) -> IpEndpoint {
|
|
|
|
|
self.remote_endpoint
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-09 15:42:26 +00:00
|
|
|
pub fn check_new(&mut self) -> Result<()> {
|
|
|
|
|
if !self.is_new_connection {
|
|
|
|
|
return_errno_with_message!(Errno::EISCONN, "the socket is already connected");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.is_new_connection = false;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-07 15:55:23 +00:00
|
|
|
pub(super) fn init_pollee(&self, pollee: &Pollee) {
|
|
|
|
|
pollee.reset_events();
|
|
|
|
|
self.update_io_events(pollee);
|
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-01-07 15:55:23 +00:00
|
|
|
pub(super) fn update_io_events(&self, pollee: &Pollee) {
|
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
|
|
|
self.bound_socket.raw_with(|socket: &mut RawTcpSocket| {
|
|
|
|
|
if socket.can_recv() {
|
|
|
|
|
pollee.add_events(IoEvents::IN);
|
|
|
|
|
} else {
|
|
|
|
|
pollee.del_events(IoEvents::IN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if socket.can_send() {
|
|
|
|
|
pollee.add_events(IoEvents::OUT);
|
|
|
|
|
} else {
|
|
|
|
|
pollee.del_events(IoEvents::OUT);
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-05-31 02:48:16 +00:00
|
|
|
}
|
2023-06-13 09:49:44 +00:00
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(super) fn set_observer(&self, observer: Weak<dyn SocketEventObserver>) {
|
2024-01-07 15:55:23 +00:00
|
|
|
self.bound_socket.set_observer(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
|
|
|
}
|
|
|
|
|
}
|