Skip to content

Commit

Permalink
API changes
Browse files Browse the repository at this point in the history
1) Remove Mio layer and replace it with a sync FD layer
2) Move RecvData, RecvMetrics, and StoreCmsgSettings to `lib`, since
   syscalls is private
3) Rework the signature of `recv_msg` to take a `StoreCmsgSettings` to
   allow applications to handle custom cmsgs
  • Loading branch information
evanrittenhouse committed May 2, 2024
1 parent 38aa4c5 commit 8ea3dd9
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 125 deletions.
33 changes: 24 additions & 9 deletions apps/src/sendto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,30 @@ fn send_to_gso_pacing(
) -> io::Result<usize> {
use dgram::GsoSettings;

dgram::sync::send_to(
socket,
buf,
Some(GsoSettings {
segment_size: segment_size as u16,
}),
Some(send_info.at),
&send_info.to,
)
loop {
// Important to use try_io so events keep coming even if we see
// EAGAIN/EWOULDBLOCK
let res = socket.try_io(|| {
// mio::net::UdpSocket doesn't implement AsFd (yet?).
let fd = unsafe {
std::os::fd::BorrowedFd::borrow_raw(socket.as_raw_fd())

Check failure on line 64 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche

no method named `as_raw_fd` found for reference `&mio::net::UdpSocket` in the current scope

Check failure on line 64 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche (boringssl-boring-crate)

no method named `as_raw_fd` found for reference `&mio::net::UdpSocket` in the current scope

Check failure on line 64 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche_multiarch (aarch64-unknown-linux-gnu)

no method named `as_raw_fd` found for reference `&mio::net::UdpSocket` in the current scope
};

dgram::sync::send_to(
socket,

Check failure on line 68 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche

the trait bound `mio::net::UdpSocket: AsFd` is not satisfied

Check failure on line 68 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche (boringssl-boring-crate)

the trait bound `mio::net::UdpSocket: AsFd` is not satisfied

Check failure on line 68 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche_multiarch (aarch64-unknown-linux-gnu)

the trait bound `mio::net::UdpSocket: AsFd` is not satisfied
buf,
Some(GsoSettings {
segment_size: segment_size as u16,
}),
Some(send_info.at),
&send_info.to,
)
});

if let Ok(sent) = res {
return sent.map_err(Into::into);

Check failure on line 79 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche

no method named `map_err` found for type `usize` in the current scope

Check failure on line 79 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche (boringssl-boring-crate)

no method named `map_err` found for type `usize` in the current scope

Check failure on line 79 in apps/src/sendto.rs

View workflow job for this annotation

GitHub Actions / quiche_multiarch (aarch64-unknown-linux-gnu)

no method named `map_err` found for type `usize` in the current scope
}
}
}

/// For non-Linux platforms.
Expand Down
75 changes: 75 additions & 0 deletions dgram/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,91 @@ mod syscalls;
#[cfg(feature = "async")]
pub mod tokio;

use std::net::SocketAddr;
use std::time::SystemTime;

use nix::sys::socket::ControlMessageOwned;

Check failure on line 10 in dgram/src/lib.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (x86_64-pc-windows-msvc)

failed to resolve: could not find `sys` in `nix`

Check failure on line 10 in dgram/src/lib.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (i686-pc-windows-msvc)

failed to resolve: could not find `sys` in `nix`

#[derive(Default, Copy, Clone)]
pub struct GsoSettings {
pub segment_size: u16,
}

#[cfg(target_os = "linux")]
#[derive(Default)]
pub struct StoreCmsgSettings {
store_cmsgs: bool,
cmsg_space: Vec<u8>,
}

/// Output of a `recvmsg` call.
#[derive(Default)]
pub struct RecvData {
/// The number of bytes which `recvmsg` returned.
pub bytes: usize,
/// The peer address for this message.
pub peer_addr: Option<SocketAddr>,
/// Metrics for this `recvmsg` call.
///
/// If no valid metrics exist - for example, when the RXQOVFL sockopt is not
/// set - this will be `None`.
pub metrics: Option<RecvMetrics>,
/// The `UDP_GRO_SEGMENTS` control message data from the result of
/// `recvmsg`, if it exist.
pub gro: Option<u16>,
/// The RX_TIME control message data from the result of `recvmsg`, if it
/// exists.
pub rx_time: Option<SystemTime>,
cmsgs: Vec<ControlMessageOwned>,
}

impl RecvData {
pub fn new(
peer_addr: Option<SocketAddr>, bytes: usize, cmsg_space_len: usize,
) -> Self {
Self {
peer_addr,
bytes,
metrics: None,
gro: None,
rx_time: None,
cmsgs: Vec::with_capacity(cmsg_space_len),
}
}

pub fn from_bytes(bytes: usize) -> Self {
Self {
bytes,
..Default::default()
}
}

/// Returns the list of cmsgs which were returned from calling `recvmsg`. If
/// `recvmsg` was called with `recv_cmsgs` set to to `false`, this will
/// return an empty slice.
pub fn cmsgs(&self) -> &[ControlMessageOwned] {
&self.cmsgs
}
}

/// Metrics for `recvmsg` calls.
#[derive(Default)]
pub struct RecvMetrics {
/// The number of packets dropped between the last received packet and this
/// one.
///
/// See SO_RXQOVFL for more.
pub udp_packets_dropped: u64,
}

#[cfg(target_os = "linux")]
mod linux_imports {
pub(super) use crate::syscalls::recv_msg;
pub(super) use crate::syscalls::send_msg;
pub(super) use crate::GsoSettings;
pub(super) use crate::RecvData;
pub(super) use crate::RecvMetrics;
pub(super) use crate::StoreCmsgSettings;
pub(super) use nix::errno::Errno;
pub(super) use nix::sys::socket::getsockopt;
pub(super) use nix::sys::socket::recvmsg;
Expand Down
81 changes: 26 additions & 55 deletions dgram/src/sync.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,47 @@
use crate::syscalls::RecvData;
use mio::net::UdpSocket;
use crate::RecvData;
use crate::StoreCmsgSettings;

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (armv7-linux-androideabi)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (aarch64-linux-android)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (i686-linux-android)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_ios (aarch64-apple-ios)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_macos (macos-14)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_ios (x86_64-apple-ios)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_macos (macos-latest)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (x86_64-pc-windows-msvc)

unresolved import `crate::StoreCmsgSettings`

Check failure on line 2 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (i686-pc-windows-msvc)

unresolved import `crate::StoreCmsgSettings`
use std::io::Result;
use std::net::SocketAddr;
use std::os::fd::AsFd;

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (armv7-linux-androideabi)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (aarch64-linux-android)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / android_ndk_lts (i686-linux-android)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_ios (aarch64-apple-ios)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_macos (macos-14)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_ios (x86_64-apple-ios)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_macos (macos-latest)

unused import: `std::os::fd::AsFd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (x86_64-pc-windows-msvc)

unresolved import `std::os::fd`

Check failure on line 5 in dgram/src/sync.rs

View workflow job for this annotation

GitHub Actions / quiche_windows (i686-pc-windows-msvc)

unresolved import `std::os::fd`
use std::time::Instant;

#[cfg(target_os = "linux")]
use super::linux_imports::*;

#[cfg(target_os = "linux")]
pub fn send_to(
socket: &UdpSocket, send_buf: &[u8], gso_settings: Option<GsoSettings>,
fd: &impl AsFd, send_buf: &[u8], gso_settings: Option<GsoSettings>,
tx_time: Option<Instant>, client_addr: &SocketAddr,
) -> Result<usize> {
loop {
// Important to use try_io so events keep coming even if we see
// EAGAIN/EWOULDBLOCK
let res = socket.try_io(|| {
// mio::net::UdpSocket doesn't implement AsFd (yet?).
let fd = unsafe {
std::os::fd::BorrowedFd::borrow_raw(socket.as_raw_fd())
};
let sent = send_msg(
fd,
send_buf,
gso_settings,
tx_time,
&SockaddrStorage::from(*client_addr),
);

let sent = send_msg(
fd,
send_buf,
gso_settings,
tx_time,
&SockaddrStorage::from(*client_addr),
);

match sent {
Err(Errno::EAGAIN) => Err(std::io::Error::last_os_error()),
_ => Ok(sent),
}
});

if let Ok(sent) = res {
return sent.map_err(Into::into);
}
match sent {
Err(Errno::EAGAIN) => Err(std::io::Error::last_os_error()),
_ => Ok(sent?),
}
}

#[cfg(target_os = "linux")]
pub async fn recv_from(
socket: &UdpSocket, read_buf: &mut [u8], cmsg_space: &mut Vec<u8>,
msg_flags: Option<MsgFlags>,
pub fn recv_from(
fd: &impl AsFd, read_buf: &mut [u8], msg_flags: Option<MsgFlags>,
store_cmsg_settings: &mut StoreCmsgSettings,
) -> Result<RecvData> {
loop {
// Important to use try_io so events keep coming even if we see
// EAGAIN/EWOULDBLOCK
let res = socket.try_io(|| {
// mio::net::UdpSocket doesn't implement AsFd (yet?).
let fd = unsafe {
std::os::fd::BorrowedFd::borrow_raw(socket.as_raw_fd())
};

let recvd = recv_msg(
fd,
read_buf,
cmsg_space,
msg_flags.unwrap_or(MsgFlags::empty()),
);

match recvd {
Err(Errno::EAGAIN) => Err(std::io::Error::last_os_error()),
_ => Ok(recvd),
}
});
let recvd = recv_msg(
fd,
read_buf,
msg_flags.unwrap_or(MsgFlags::empty()),
store_cmsg_settings,
);

if let Ok(recvd) = res {
return recvd.map_err(Into::into);
}
match recvd {
Err(Errno::EAGAIN) => Err(std::io::Error::last_os_error()),
_ => Ok(recvd?),
}
}

Expand Down
Loading

0 comments on commit 8ea3dd9

Please sign in to comment.