Skip to content

Commit 2957656

Browse files
bors[bot]Junho Choi
andauthored
Merge #1455
1455: Support SO_RXQ_OVFL socket option (android/fuchsia/linux) r=asomers a=junhochoi This PR implements support of RXQ_OVFL flag and parsing ControlMessage to get the packet drop counter of UDP socket. Co-authored-by: Junho Choi <junho@cloudflare.com>
2 parents d9d447d + 0b596a1 commit 2957656

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1414
(#[1457](https://github.com/nix-rust/nix/pull/1457))
1515
- Added `renameat2` for Linux
1616
(#[1458](https://github.com/nix-rust/nix/pull/1458))
17+
- Added `RxqOvfl` support on Linux, Fuchsia and Android.
18+
(#[1455](https://github.com/nix-rust/nix/pull/1455))
1719

1820
### Changed
1921
- `ptsname_r` now returns a lossily-converted string in the event of bad UTF,

src/sys/socket/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,17 @@ pub enum ControlMessageOwned {
610610
#[cfg(target_os = "linux")]
611611
UdpGroSegments(u16),
612612

613+
/// SO_RXQ_OVFL indicates that an unsigned 32 bit value
614+
/// ancilliary msg (cmsg) should be attached to recieved
615+
/// skbs indicating the number of packets dropped by the
616+
/// socket between the last recieved packet and this
617+
/// received packet.
618+
///
619+
/// `RxqOvfl` socket option should be enabled on a socket
620+
/// to allow receiving the drop counter.
621+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
622+
RxqOvfl(u32),
623+
613624
/// Catch-all variant for unimplemented cmsg types.
614625
#[doc(hidden)]
615626
Unknown(UnknownCmsg),
@@ -708,6 +719,11 @@ impl ControlMessageOwned {
708719
let gso_size: u16 = ptr::read_unaligned(p as *const _);
709720
ControlMessageOwned::UdpGroSegments(gso_size)
710721
},
722+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
723+
(libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
724+
let drop_counter = ptr::read_unaligned(p as *const u32);
725+
ControlMessageOwned::RxqOvfl(drop_counter)
726+
},
711727
(_, _) => {
712728
let sl = slice::from_raw_parts(p, len);
713729
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
@@ -826,6 +842,14 @@ pub enum ControlMessage<'a> {
826842
target_os = "android",
827843
target_os = "ios",))]
828844
Ipv6PacketInfo(&'a libc::in6_pktinfo),
845+
846+
/// SO_RXQ_OVFL indicates that an unsigned 32 bit value
847+
/// ancilliary msg (cmsg) should be attached to recieved
848+
/// skbs indicating the number of packets dropped by the
849+
/// socket between the last recieved packet and this
850+
/// received packet.
851+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
852+
RxqOvfl(&'a u32),
829853
}
830854

831855
// An opaque structure used to prevent cmsghdr from being a public type
@@ -916,6 +940,10 @@ impl<'a> ControlMessage<'a> {
916940
target_os = "netbsd", target_os = "freebsd",
917941
target_os = "android", target_os = "ios",))]
918942
ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
943+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
944+
ControlMessage::RxqOvfl(drop_count) => {
945+
drop_count as *const _ as *const u8
946+
},
919947
};
920948
unsafe {
921949
ptr::copy_nonoverlapping(
@@ -964,6 +992,10 @@ impl<'a> ControlMessage<'a> {
964992
target_os = "netbsd", target_os = "freebsd",
965993
target_os = "android", target_os = "ios",))]
966994
ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
995+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
996+
ControlMessage::RxqOvfl(drop_count) => {
997+
mem::size_of_val(drop_count)
998+
},
967999
}
9681000
}
9691001

@@ -988,6 +1020,8 @@ impl<'a> ControlMessage<'a> {
9881020
target_os = "netbsd", target_os = "freebsd",
9891021
target_os = "android", target_os = "ios",))]
9901022
ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
1023+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1024+
ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
9911025
}
9921026
}
9931027

@@ -1023,6 +1057,10 @@ impl<'a> ControlMessage<'a> {
10231057
target_os = "netbsd", target_os = "freebsd",
10241058
target_os = "android", target_os = "ios",))]
10251059
ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
1060+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1061+
ControlMessage::RxqOvfl(_) => {
1062+
libc::SO_RXQ_OVFL
1063+
},
10261064
}
10271065
}
10281066

src/sys/socket/sockopt.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, boo
328328
sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
329329
#[cfg(target_os = "linux")]
330330
sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
331+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
332+
sockopt_impl!(Both, RxqOvfl, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
331333

332334
#[cfg(any(target_os = "android", target_os = "linux"))]
333335
#[derive(Copy, Clone, Debug)]

test/sys/test_socket.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,3 +1645,86 @@ fn test_recvmmsg_timestampns() {
16451645
// Close socket
16461646
nix::unistd::close(in_socket).unwrap();
16471647
}
1648+
1649+
// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
1650+
// support is suspected.
1651+
#[cfg_attr(not(any(target_arch = "x86_64")), ignore)]
1652+
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1653+
#[test]
1654+
fn test_recvmsg_rxq_ovfl() {
1655+
use nix::Error;
1656+
use nix::sys::socket::*;
1657+
use nix::sys::uio::IoVec;
1658+
use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf};
1659+
1660+
let message = [0u8; 2048];
1661+
let bufsize = message.len() * 2;
1662+
1663+
let in_socket = socket(
1664+
AddressFamily::Inet,
1665+
SockType::Datagram,
1666+
SockFlag::empty(),
1667+
None).unwrap();
1668+
let out_socket = socket(
1669+
AddressFamily::Inet,
1670+
SockType::Datagram,
1671+
SockFlag::empty(),
1672+
None).unwrap();
1673+
1674+
let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
1675+
bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
1676+
1677+
let address = getsockname(in_socket).unwrap();
1678+
connect(out_socket, &address).unwrap();
1679+
1680+
// Set SO_RXQ_OVFL flag.
1681+
setsockopt(in_socket, RxqOvfl, &1).unwrap();
1682+
1683+
// Set the receiver buffer size to hold only 2 messages.
1684+
setsockopt(in_socket, RcvBuf, &bufsize).unwrap();
1685+
1686+
let mut drop_counter = 0;
1687+
1688+
for _ in 0..2 {
1689+
let iov = [IoVec::from_slice(&message)];
1690+
let flags = MsgFlags::empty();
1691+
1692+
// Send the 3 messages (the receiver buffer can only hold 2 messages)
1693+
// to create an overflow.
1694+
for _ in 0..3 {
1695+
let l = sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap();
1696+
assert_eq!(message.len(), l);
1697+
}
1698+
1699+
// Receive the message and check the drop counter if any.
1700+
loop {
1701+
let mut buffer = vec![0u8; message.len()];
1702+
let mut cmsgspace = nix::cmsg_space!(u32);
1703+
1704+
let iov = [IoVec::from_mut_slice(&mut buffer)];
1705+
1706+
match recvmsg(
1707+
in_socket,
1708+
&iov,
1709+
Some(&mut cmsgspace),
1710+
MsgFlags::MSG_DONTWAIT) {
1711+
Ok(r) => {
1712+
drop_counter = match r.cmsgs().next() {
1713+
Some(ControlMessageOwned::RxqOvfl(drop_counter)) => drop_counter,
1714+
Some(_) => panic!("Unexpected control message"),
1715+
None => 0,
1716+
};
1717+
},
1718+
Err(Error::EAGAIN) => { break; },
1719+
_ => { panic!("unknown recvmsg() error"); },
1720+
}
1721+
}
1722+
}
1723+
1724+
// One packet lost.
1725+
assert_eq!(drop_counter, 1);
1726+
1727+
// Close sockets
1728+
nix::unistd::close(in_socket).unwrap();
1729+
nix::unistd::close(out_socket).unwrap();
1730+
}

0 commit comments

Comments
 (0)