blob: 5dd4a4b954ce59504c066634145c4350840205a3 [file]
// Copyright 2026 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! I/O model for Unix-like systems
//!
//! It is strongly recommended that the non-blocking I/O is enabled by calling
//! [`std::net::TcpStream::set_nonblocking`] to `true`.
use std::{
io,
os::{
fd::{
AsRawFd,
RawFd, //
},
unix::net::UnixDatagram, //
},
task::{
Context,
Poll, //
}, //
};
#[cfg(feature = "libc")]
use crate::ffi::{
mut_slice_into_ffi_raw_parts,
slice_into_ffi_raw_parts, //
};
use crate::io::stdio::{
DatagramSocket,
PollFor, //
};
use super::{
AbstractReader,
AbstractSocket,
AbstractSocketResult,
AbstractWriter, //
};
// ============
// Datagrams
// ============
/// A datagram socket.
pub struct StdDatagram<Socket, Reactor> {
reactor: Reactor,
socket: Socket,
}
impl<S, R> StdDatagram<S, R> {
/// Construct a new Unix Datagram.
pub fn new(socket: S, reactor: R) -> Self {
Self { socket, reactor }
}
}
impl<Socket: DatagramSocket, Reactor: PollFor<Socket> + Send> AbstractReader
for StdDatagram<Socket, Reactor>
{
fn read(
&mut self,
mut async_ctx: Option<&mut Context<'_>>,
buffer: &mut [u8],
) -> AbstractSocketResult {
loop {
match (self.socket.recv(buffer), async_ctx.as_mut()) {
(AbstractSocketResult::Retry, Some(ctx)) => match self.reactor.poll_read(ctx) {
Poll::Pending => return AbstractSocketResult::Retry,
Poll::Ready(Ok(_)) => {}
Poll::Ready(Err(e)) => {
return AbstractSocketResult::Err(Box::new(e));
}
},
(res, _) => return res,
}
}
}
}
impl<Socket: DatagramSocket, Reactor: PollFor<Socket> + Send> AbstractWriter
for StdDatagram<Socket, Reactor>
{
fn write(
&mut self,
mut async_ctx: Option<&mut Context<'_>>,
buffer: &[u8],
) -> AbstractSocketResult {
loop {
match (self.socket.send(buffer), async_ctx.as_mut()) {
(AbstractSocketResult::Retry, Some(ctx)) => {
if matches!(self.reactor.poll_write(ctx), Poll::Pending) {
return AbstractSocketResult::Retry;
}
}
(res, _) => return res,
}
}
}
fn flush(&mut self, _: Option<&mut Context<'_>>) -> AbstractSocketResult {
AbstractSocketResult::Ok(0)
}
}
impl<Socket: DatagramSocket, Reactor: PollFor<Socket> + Send> AbstractSocket
for StdDatagram<Socket, Reactor>
{
}
impl DatagramSocket for UnixDatagram {
fn send(&mut self, datagram: &[u8]) -> AbstractSocketResult {
loop {
return match UnixDatagram::send(self, datagram) {
Ok(bytes) => AbstractSocketResult::Ok(bytes),
Err(e) => crate::retry_on_interrupt!(e),
};
}
}
fn recv(&mut self, datagram: &mut [u8]) -> AbstractSocketResult {
loop {
return match UnixDatagram::recv(self, datagram) {
Ok(bytes) => AbstractSocketResult::Ok(bytes),
Err(e) if matches!(e.kind(), io::ErrorKind::Interrupted) => continue,
Err(e) => crate::retry_on_interrupt!(e),
};
}
}
}
/// A wrapper to operate the IO object through file descriptor.
///
/// # Notice to **BSD** datagram socket users
///
/// Whether a `SIGPIPE` signal will be raised is controlled at socket configuration time with
/// `setsocketopt` plus `SO_NOSIGPIPE`.
/// If the signal should be suppressed, it should be configured before using this type.
pub struct UseFd<Io: AsRawFd>(pub Io);
#[cfg(feature = "libc")]
impl<Io: AsRawFd> io::Read for UseFd<Io> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let (ptr, len) = mut_slice_into_ffi_raw_parts(buf);
let ret = unsafe {
// Safety: `ptr` has been valid with the sufficient capacity of length `len`.
libc::read(self.as_raw_fd(), ptr as _, len)
};
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret as usize)
}
}
}
#[cfg(feature = "libc")]
impl<Io: AsRawFd> io::Write for UseFd<Io> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let (ptr, len) = slice_into_ffi_raw_parts(buf);
let ret = unsafe {
// Safety: `ptr` has been valid for length `len`.
libc::write(self.as_raw_fd(), ptr as _, len)
};
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "libc")]
impl<Io: AsRawFd + Send> DatagramSocket for UseFd<Io> {
fn send(&mut self, datagram: &[u8]) -> AbstractSocketResult {
let (buf, len) = slice_into_ffi_raw_parts(datagram);
#[cfg(any(target_os = "linux", target_os = "android"))]
let flag = libc::MSG_NOSIGNAL;
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "macos",
target_os = "ios",
))]
let flag = 0;
#[cfg(any(windows, target_os = "none"))]
let flag = 0;
loop {
let rc = unsafe {
// Safety: the socket file descriptor is exclusively owned.
libc::send(self.as_raw_fd(), buf as _, len, flag)
};
return if rc < 0 {
let err = io::Error::last_os_error();
crate::retry_on_interrupt!(err)
} else {
AbstractSocketResult::Ok(rc as usize)
};
}
}
fn recv(&mut self, datagram: &mut [u8]) -> AbstractSocketResult {
let (buf, len) = mut_slice_into_ffi_raw_parts(datagram);
loop {
let rc = unsafe {
// Safety: the socket file descriptor is exclusively owned.
libc::recv(self.as_raw_fd(), buf as _, len, 0)
};
return if rc < 0 {
let err = io::Error::last_os_error();
crate::retry_on_interrupt!(err)
} else {
AbstractSocketResult::Ok(rc as usize)
};
}
}
}
impl<Io: AsRawFd> AsRawFd for UseFd<Io> {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}