fix(cli): harden managed frontend cutover
This commit is contained in:
8 files changed
+399
-329
No files matched your search
@@ -94,8 +94,8 @@ use crate::{
|
||||
///
|
||||
/// `Client` exposes the protocol steps directly: connect a UDP socket, open a
|
||||
/// session, send probes, receive replies, poll timeouts, and close. Callers
|
||||
/// that do not need to own this loop can use [`ManagedClient`](crate::ManagedClient)
|
||||
/// instead.
|
||||
/// that do not need to own this loop can use the unified managed API in
|
||||
/// [`crate::managed`] when the `tokio` feature is enabled.
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
runtime: SessionMachine,
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
//! values usually indicate client/server clock skew.
|
||||
//!
|
||||
//! [`Client`] is the runtime-free low-level blocking adapter. With the
|
||||
//! `tokio` feature, [`AsyncClient`] provides the corresponding Tokio adapter;
|
||||
//! [`managed`] contains the unified managed task/handle implementation and
|
||||
//! [`managed::BlockingManagedClient`] owns its dedicated runtime thread for
|
||||
//! synchronous managed callers.
|
||||
//! `tokio` feature, `AsyncClient` provides the corresponding Tokio adapter;
|
||||
//! [`managed`] contains the unified managed task/handle implementation,
|
||||
//! including the dedicated-runtime blocking frontend for synchronous callers.
|
||||
//!
|
||||
#![cfg_attr(
|
||||
not(all(target_os = "linux", feature = "ancillary")),
|
||||
|
||||
@@ -105,62 +105,6 @@ fn recv_datagram_fd(
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
pub(crate) fn recv_datagram_from(
|
||||
socket: &UdpSocket,
|
||||
buf: &mut [u8],
|
||||
) -> Result<ReceivedDatagramFrom, io::Error> {
|
||||
let mut control = ControlBuffer::new();
|
||||
let mut name: libc::sockaddr_storage = unsafe { mem::zeroed() };
|
||||
let mut iov = libc::iovec {
|
||||
iov_base: buf.as_mut_ptr().cast(),
|
||||
iov_len: buf.len(),
|
||||
};
|
||||
let mut msg: libc::msghdr = unsafe { mem::zeroed() };
|
||||
msg.msg_name = (&mut name as *mut libc::sockaddr_storage).cast();
|
||||
msg.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
|
||||
msg.msg_iov = &mut iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = control.as_mut_ptr().cast();
|
||||
msg.msg_controllen = control.len();
|
||||
|
||||
let len = unsafe {
|
||||
// SAFETY: `msg` points to one writable iovec backed by `buf`, a
|
||||
// writable source-address buffer, and a writable control buffer. All
|
||||
// buffers live until `recvmsg` returns. The socket file descriptor is
|
||||
// borrowed from a valid `UdpSocket`.
|
||||
libc::recvmsg(socket.as_raw_fd(), &mut msg, 0)
|
||||
};
|
||||
if len < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let len = usize::try_from(len).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"recvmsg returned an unrepresentable datagram length",
|
||||
)
|
||||
})?;
|
||||
let received_at = ClientTimestamp::now();
|
||||
let source = unsafe {
|
||||
// SAFETY: `name` and `msg_namelen` were initialized by a successful
|
||||
// `recvmsg` call above.
|
||||
socket_addr_from_storage(&name, msg.msg_namelen)?
|
||||
};
|
||||
let meta = unsafe {
|
||||
// SAFETY: `msg` was initialized by a successful `recvmsg` call. The
|
||||
// parser only reads cmsghdr entries within `msg_controllen` and ignores
|
||||
// short or unrelated control messages.
|
||||
parse_receive_meta(&msg)
|
||||
};
|
||||
|
||||
Ok(ReceivedDatagramFrom {
|
||||
len,
|
||||
source,
|
||||
received_at,
|
||||
meta,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn parse_receive_meta(msg: &libc::msghdr) -> ReceiveMeta {
|
||||
let mut meta = ReceiveMeta::default();
|
||||
let mut cmsg = libc::CMSG_FIRSTHDR(msg);
|
||||
@@ -182,53 +126,6 @@ unsafe fn parse_receive_meta(msg: &libc::msghdr) -> ReceiveMeta {
|
||||
meta
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
unsafe fn socket_addr_from_storage(
|
||||
storage: &libc::sockaddr_storage,
|
||||
len: libc::socklen_t,
|
||||
) -> io::Result<SocketAddr> {
|
||||
match i32::from(storage.ss_family) {
|
||||
libc::AF_INET => {
|
||||
if usize::try_from(len).unwrap_or(0) < mem::size_of::<libc::sockaddr_in>() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"short IPv4 source address from recvmsg",
|
||||
));
|
||||
}
|
||||
let addr = ptr::read_unaligned(
|
||||
(storage as *const libc::sockaddr_storage).cast::<libc::sockaddr_in>(),
|
||||
);
|
||||
let ip = Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr));
|
||||
let port = u16::from_be(addr.sin_port);
|
||||
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
|
||||
}
|
||||
libc::AF_INET6 => {
|
||||
if usize::try_from(len).unwrap_or(0) < mem::size_of::<libc::sockaddr_in6>() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"short IPv6 source address from recvmsg",
|
||||
));
|
||||
}
|
||||
let addr = ptr::read_unaligned(
|
||||
(storage as *const libc::sockaddr_storage).cast::<libc::sockaddr_in6>(),
|
||||
);
|
||||
let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
|
||||
let port = u16::from_be(addr.sin6_port);
|
||||
let flowinfo = u32::from_be(addr.sin6_flowinfo);
|
||||
Ok(SocketAddr::V6(SocketAddrV6::new(
|
||||
ip,
|
||||
port,
|
||||
flowinfo,
|
||||
addr.sin6_scope_id,
|
||||
)))
|
||||
}
|
||||
family => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!("unsupported source address family from recvmsg: {family}"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_traffic_class_cmsg(cmsg: &libc::cmsghdr) -> bool {
|
||||
(cmsg.cmsg_level == libc::IPPROTO_IP && cmsg.cmsg_type == libc::IP_TOS)
|
||||
|| (cmsg.cmsg_level == libc::IPPROTO_IPV6 && cmsg.cmsg_type == libc::IPV6_TCLASS)
|
||||
|
||||
Reference in new issue
Block a user