Files
asterinas/kernel/src/net/socket/ip/stream/connecting.rs
2024-12-15 16:50:43 +08:00

97 lines
2.7 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
use aster_bigtcp::{
socket::{ConnectState, RawTcpSetOption},
wire::IpEndpoint,
};
use super::{connected::ConnectedStream, init::InitStream};
use crate::{
events::IoEvents,
net::iface::{BoundTcpSocket, Iface},
prelude::*,
};
pub struct ConnectingStream {
bound_socket: BoundTcpSocket,
remote_endpoint: IpEndpoint,
}
pub enum ConnResult {
Connecting(ConnectingStream),
Connected(ConnectedStream),
Refused(InitStream),
}
impl ConnectingStream {
pub fn new(
bound_socket: BoundTcpSocket,
remote_endpoint: IpEndpoint,
) -> core::result::Result<Self, (Error, BoundTcpSocket)> {
// The only reason this method might fail is because we're trying to connect to an
// unspecified address (i.e. 0.0.0.0). We currently have no support for binding to,
// listening on, or connecting to the unspecified address.
//
// We assume the remote will just refuse to connect, so we return `ECONNREFUSED`.
if bound_socket.connect(remote_endpoint).is_err() {
return Err((
Error::with_message(
Errno::ECONNREFUSED,
"connecting to an unspecified address is not supported",
),
bound_socket,
));
}
Ok(Self {
bound_socket,
remote_endpoint,
})
}
pub fn has_result(&self) -> bool {
match self.bound_socket.connect_state() {
ConnectState::Connecting => false,
ConnectState::Connected => true,
ConnectState::Refused => true,
}
}
pub fn into_result(self) -> ConnResult {
let next_state = self.bound_socket.connect_state();
match next_state {
ConnectState::Connecting => ConnResult::Connecting(self),
ConnectState::Connected => ConnResult::Connected(ConnectedStream::new(
self.bound_socket,
self.remote_endpoint,
true,
)),
ConnectState::Refused => ConnResult::Refused(InitStream::new_bound(self.bound_socket)),
}
}
pub fn local_endpoint(&self) -> IpEndpoint {
self.bound_socket.local_endpoint().unwrap()
}
pub fn remote_endpoint(&self) -> IpEndpoint {
self.remote_endpoint
}
pub fn iface(&self) -> &Arc<Iface> {
self.bound_socket.iface()
}
pub(super) fn check_io_events(&self) -> IoEvents {
IoEvents::empty()
}
pub(super) fn set_raw_option<R>(
&mut self,
set_option: impl Fn(&mut dyn RawTcpSetOption) -> R,
) -> R {
set_option(&mut self.bound_socket)
}
}