Skip to content

std: sys: net: uefi: tcp: Initial TcpListener support #145339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions library/std/src/sys/net/connection/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ pub struct TcpStream {
}

impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let inner = tcp::Tcp::connect(addr?, None)?;
Ok(Self {
fn new(inner: tcp::Tcp) -> Self {
Self {
inner,
read_timeout: Arc::new(Mutex::new(None)),
write_timeout: Arc::new(Mutex::new(None)),
})
}
}

pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let inner = tcp::Tcp::connect(addr?, None)?;
Ok(Self::new(inner))
}

pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
let inner = tcp::Tcp::connect(addr, Some(timeout))?;
Ok(Self {
inner,
read_timeout: Arc::new(Mutex::new(None)),
write_timeout: Arc::new(Mutex::new(None)),
})
Ok(Self::new(inner))
}

pub fn set_read_timeout(&self, t: Option<Duration>) -> io::Result<()> {
Expand Down Expand Up @@ -145,16 +145,19 @@ pub struct TcpListener {
}

impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
unsupported()
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let inner = tcp::Tcp::bind(addr?)?;
Ok(Self { inner })
}

pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unsupported()
self.inner.socket_addr()
}

pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
unsupported()
let tcp = self.inner.accept()?;
let addr = tcp.peer_addr()?;
Ok((TcpStream::new(tcp), addr))
}

pub fn duplicate(&self) -> io::Result<TcpListener> {
Expand Down
17 changes: 17 additions & 0 deletions library/std/src/sys/net/connection/uefi/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ impl Tcp {
}
}

pub(crate) fn bind(addr: &SocketAddr) -> io::Result<Self> {
match addr {
SocketAddr::V4(x) => {
let temp = tcp4::Tcp4::new()?;
temp.configure(false, None, Some(x))?;
Ok(Tcp::V4(temp))
}
SocketAddr::V6(_) => todo!(),
}
}

pub(crate) fn accept(&self) -> io::Result<Self> {
match self {
Self::V4(client) => client.accept().map(Tcp::V4),
}
}

pub(crate) fn write(&self, buf: &[u8], timeout: Option<Duration>) -> io::Result<usize> {
match self {
Self::V4(client) => client.write(buf, timeout),
Expand Down
43 changes: 36 additions & 7 deletions library/std/src/sys/net/connection/uefi/tcp4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) struct Tcp4 {
protocol: NonNull<tcp4::Protocol>,
flag: AtomicBool,
#[expect(dead_code)]
service_binding: helpers::ServiceProtocol,
service_binding: Option<helpers::ServiceProtocol>,
}

const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] };
Expand All @@ -25,7 +25,7 @@ impl Tcp4 {
let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?;

Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) })
Ok(Self { service_binding: Some(service_binding), protocol, flag: AtomicBool::new(false) })
}

pub(crate) fn configure(
Expand All @@ -42,11 +42,13 @@ impl Tcp4 {
(DEFAULT_ADDR, 0)
};

// FIXME: Remove when passive connections with proper subnet handling are added
assert!(station_address.is_none());
let use_default_address = efi::Boolean::TRUE;
let (station_address, station_port) = (DEFAULT_ADDR, 0);
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0));
let use_default_address = station_address.is_none().into();
let (station_address, station_port) = if let Some(x) = station_address {
(helpers::ipv4_to_r_efi(*x.ip()), x.port())
} else {
(DEFAULT_ADDR, 0)
};
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(255, 255, 255, 0));

let mut config_data = tcp4::ConfigData {
type_of_service: TYPE_OF_SERVICE,
Expand Down Expand Up @@ -85,6 +87,33 @@ impl Tcp4 {
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) }
}

pub(crate) fn accept(&self) -> io::Result<Self> {
let evt = unsafe { self.create_evt() }?;
let completion_token =
tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
let mut listen_token =
tcp4::ListenToken { completion_token, new_child_handle: crate::ptr::null_mut() };

let protocol = self.protocol.as_ptr();
let r = unsafe { ((*protocol).accept)(protocol, &mut listen_token) };
if r.is_error() {
return Err(io::Error::from_raw_os_error(r.as_usize()));
}

unsafe { self.wait_or_cancel(None, &mut listen_token.completion_token) }?;

if completion_token.status.is_error() {
Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
} else {
let handle = NonNull::new(listen_token.new_child_handle).unwrap();
let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?;

// The spec does not seem to state if we need to call ServiceBinding->DestroyChild for
// this handle
Ok(Self { service_binding: None, protocol, flag: AtomicBool::new(false) })
}
}

pub(crate) fn connect(&self, timeout: Option<Duration>) -> io::Result<()> {
let evt = unsafe { self.create_evt() }?;
let completion_token =
Expand Down
Loading