Skip to content

Commit

Permalink
Add IP_PKTINFO and IP_ORIGDSTADDR support, docs + renames
Browse files Browse the repository at this point in the history
  • Loading branch information
evanrittenhouse committed Jun 12, 2024
1 parent 5003df3 commit 4bc7d91
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 75 deletions.
2 changes: 0 additions & 2 deletions apps/src/bin/quiche-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ use std::io;

use std::net;

use std::os::fd::AsRawFd;

use std::io::prelude::*;

use std::collections::HashMap;
Expand Down
4 changes: 2 additions & 2 deletions apps/src/recvfrom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ pub fn detect_gro(socket: &mio::net::UdpSocket, _segment_size: usize) -> bool {
pub fn recv_from(
socket: &mio::net::UdpSocket, buf: &mut [u8],
) -> io::Result<RecvData> {
use dgram::RecvMsgCmsgSettings;
use dgram::RecvMsgSettings;
use std::os::unix::io::AsRawFd;

let mut recvmsg_cmsg_settings = RecvMsgCmsgSettings {
let mut recvmsg_cmsg_settings = RecvMsgSettings {
store_cmsgs: false,
cmsg_space: vec![],
};
Expand Down
4 changes: 2 additions & 2 deletions apps/src/sendto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ fn send_to_gso_pacing(
socket: &mio::net::UdpSocket, buf: &[u8], send_info: &quiche::SendInfo,
segment_size: usize,
) -> io::Result<usize> {
use dgram::SendMsgCmsgSettings;
use dgram::SendMsgSettings;
use std::os::unix::io::AsRawFd;

let sendmsg_settings = SendMsgCmsgSettings {
let sendmsg_settings = SendMsgSettings {
segment_size: Some(segment_size as u16),
tx_time: Some(send_info.at),
dst: Some(send_info.to),
Expand Down
55 changes: 46 additions & 9 deletions dgram/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,49 @@ use std::net::SocketAddr;
use std::time::Instant;
use std::time::SystemTime;

use libc::in6_pktinfo;
use libc::in_pktinfo;
use libc::sockaddr_in;
use libc::sockaddr_in6;
use nix::sys::socket::ControlMessageOwned;

/// Settings for handling control messages when sending data.
#[cfg(target_os = "linux")]
#[derive(Default, Copy, Clone)]
pub struct SendMsgCmsgSettings {
/// Segment sized used in a UDP_SEGMENT message
pub struct SendMsgSettings {
/// Segment sized used in a UDP_SEGMENT control message
pub segment_size: Option<u16>,
/// Send time used in a TX_TIME message
/// Send time used in a TX_TIME control message
pub tx_time: Option<Instant>,
/// Destination socket address
pub dst: Option<SocketAddr>,
/// Packet info used in an IP_PKTINFO control message
pub pkt_info: Option<IpPktInfo>,
}

/// Settings for handling control messages when receiving data.
#[cfg(target_os = "linux")]
#[derive(Clone, Default)]
pub struct RecvMsgCmsgSettings {
pub struct RecvMsgSettings {
// TODO: deprecate store_cmsgs and only store based on what cmsg_space can
// handle.
/// If cmsgs should be stored when receiving a message. If set, cmsgs will
/// be stored in the `cmsg_space` vector.
pub store_cmsgs: bool,
/// The vector where cmsgs will be stored, if store_cmsgs is set.
///
/// It is the caller's responsibility to create and clear the vector. The
/// `nix` crate recommends that the space be created with the
/// [`cmsg_space`] macro.
///
/// [`cmsg_space`]: https://docs.rs/nix/latest/nix/macro.cmsg_space.html
pub cmsg_space: Vec<u8>,
}

/// Output of a `recvmsg` call.
#[derive(Debug, Default)]
pub struct RecvData {
/// The number of bytes which `recvmsg` returned.
/// The number of bytes returned by `recvmsg`.
pub bytes: usize,
/// The peer address for this message.
pub peer_addr: Option<SocketAddr>,
Expand All @@ -44,9 +62,14 @@ pub struct RecvData {
/// 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
/// The `RX_TIME` control message data from the result of `recvmsg`, if it
/// exists.
pub rx_time: Option<SystemTime>,
/// The original IP destination address for the message.
///
/// This can be either an IPv4 or IPv6 address, depending on whether
/// `IPV4_ORIGDSTADDR` or `IPV6_ORIGDSTADDR` was received.
pub original_addr: Option<IpOrigDstAddr>,
cmsgs: Vec<ControlMessageOwned>,
}

Expand All @@ -60,11 +83,13 @@ impl RecvData {
metrics: None,
gro: None,
rx_time: None,
original_addr: None,
cmsgs: Vec::with_capacity(cmsg_space_len),
}
}

pub fn from_bytes(bytes: usize) -> Self {
/// A constructor which only sets the `bytes` field.
pub fn with_bytes(bytes: usize) -> Self {
Self {
bytes,
..Default::default()
Expand All @@ -89,14 +114,26 @@ pub struct RecvMetrics {
pub udp_packets_dropped: u64,
}

#[derive(Debug)]
pub enum IpOrigDstAddr {
V4(sockaddr_in),
V6(sockaddr_in6),
}

#[derive(Copy, Clone, Debug)]
pub enum IpPktInfo {
V4(in_pktinfo),
V6(in6_pktinfo),
}

#[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::RecvData;
pub(super) use crate::RecvMetrics;
pub(super) use crate::RecvMsgCmsgSettings;
pub(super) use crate::SendMsgCmsgSettings;
pub(super) use crate::RecvMsgSettings;
pub(super) use crate::SendMsgSettings;
pub(super) use nix::errno::Errno;
pub(super) use nix::sys::socket::getsockopt;
pub(super) use nix::sys::socket::recvmsg;
Expand Down
35 changes: 5 additions & 30 deletions dgram/src/sync.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::RecvData;
use crate::RecvMsgCmsgSettings;
use crate::SendMsgCmsgSettings;
use crate::RecvMsgSettings;
use crate::SendMsgSettings;
use std::io::Result;
use std::os::fd::AsFd;

Expand All @@ -9,13 +9,13 @@ use super::linux_imports::*;

#[cfg(target_os = "linux")]
pub fn send_to(
fd: &impl AsFd, send_buf: &[u8], sendmsg_settings: SendMsgCmsgSettings,
fd: &impl AsFd, send_buf: &[u8], sendmsg_settings: SendMsgSettings,
) -> Result<usize> {
// TODO: separate mio module that uses try_io?
let sent = send_msg(fd, send_buf, sendmsg_settings);

match sent {
Ok(s) => Ok(s),
// TODO: propagate or transform?
Err(Errno::EAGAIN) => Err(std::io::Error::last_os_error()),
Err(e) => Err(e.into()),
}
Expand All @@ -24,7 +24,7 @@ pub fn send_to(
#[cfg(target_os = "linux")]
pub fn recv_from(
fd: &impl AsFd, read_buf: &mut [u8], msg_flags: Option<MsgFlags>,
store_cmsg_settings: &mut RecvMsgCmsgSettings,
store_cmsg_settings: &mut RecvMsgSettings,
) -> Result<RecvData> {
let recvd = recv_msg(
fd,
Expand All @@ -39,28 +39,3 @@ pub fn recv_from(
Err(e) => Err(e.into()),
}
}

// TODO: these async functions shouldn't be here
#[cfg(not(target_os = "linux"))]
pub async fn send_to(
socket: &UdpSocket, client_addr: SocketAddr, send_buf: &[u8],
_segment_size: usize, _num_pkts: usize, _tx_time: Option<Instant>,
) -> Result<usize> {
socket.send_to(send_buf, client_addr)
}

// Signature changes because we can't use MessageFlags outside of a *NIX context
#[cfg(not(target_os = "linux"))]
pub async fn recv_from(
socket: &UdpSocket, read_buf: &mut [u8], _cmsg_space: &mut Vec<u8>,
) -> Result<RecvData> {
let recv = socket.recv(read_buf)?;

Ok(RecvData {
bytes: recv,
peer_addr: None,
metrics: None,
gro: None,
rx_time: None,
})
}
Loading

0 comments on commit 4bc7d91

Please sign in to comment.