Skip to content

Commit 1eed9f4

Browse files
committed
Add preallocated buffer version of sendmsg
1 parent e5ac667 commit 1eed9f4

File tree

2 files changed

+92
-8
lines changed

2 files changed

+92
-8
lines changed

src/sys/socket/mod.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,20 @@ pub use self::addr::{SockaddrLike, SockaddrStorage};
3939
pub use self::addr::{AddressFamily, UnixAddr};
4040
#[cfg(not(solarish))]
4141
pub use self::addr::{AddressFamily, UnixAddr};
42-
#[cfg(not(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox")))]
42+
#[cfg(not(any(
43+
solarish,
44+
target_os = "haiku",
45+
target_os = "hurd",
46+
target_os = "redox"
47+
)))]
4348
#[cfg(feature = "net")]
4449
pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6};
45-
#[cfg(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox"))]
50+
#[cfg(any(
51+
solarish,
52+
target_os = "haiku",
53+
target_os = "hurd",
54+
target_os = "redox"
55+
))]
4656
#[cfg(feature = "net")]
4757
pub use self::addr::{SockaddrIn, SockaddrIn6};
4858

@@ -794,17 +804,17 @@ pub enum ControlMessageOwned {
794804
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
795805
Ipv6HopLimit(i32),
796806

797-
/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
807+
/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
798808
#[cfg(any(linux_android, target_os = "freebsd"))]
799809
#[cfg(feature = "net")]
800810
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
801811
Ipv4Tos(u8),
802812

803-
/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
813+
/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
804814
#[cfg(any(linux_android, target_os = "freebsd"))]
805815
#[cfg(feature = "net")]
806816
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
807-
Ipv6TClass(i32),
817+
Ipv6TClass(i32),
808818

809819
/// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
810820
/// packets from a single sender.
@@ -1577,7 +1587,7 @@ impl<'a> ControlMessage<'a> {
15771587
/// by ancillary data. Optionally direct the message at the given address,
15781588
/// as with sendto.
15791589
///
1580-
/// Allocates if cmsgs is nonempty.
1590+
/// Allocates if cmsgs is nonempty, use [`sendmsg_prealloc()`] if you want to use a pre-allocated buffer.
15811591
///
15821592
/// # Examples
15831593
/// When not directing to any specific address, use `()` for the generic type
@@ -1631,6 +1641,29 @@ pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
16311641
}
16321642

16331643

1644+
/// `sendmsg_prealloc()` is the same as [`sendmsg()`] but it accepts a preallocated
1645+
/// `cmsg` buffer vector.
1646+
///
1647+
/// Send data in scatter-gather vectors to a socket, possibly accompanied
1648+
/// by ancillary data. Optionally direct the message at the given address,
1649+
/// as with sendto.
1650+
pub fn sendmsg_prealloc<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
1651+
flags: MsgFlags, addr: Option<&S>, cmsg_buffer: &mut Vec<u8>) -> Result<usize>
1652+
where S: SockaddrLike
1653+
{
1654+
1655+
if cmsg_buffer.len() < cmsgs.len() {
1656+
return Err(Errno::ENOBUFS);
1657+
}
1658+
1659+
let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
1660+
1661+
let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
1662+
1663+
Errno::result(ret).map(|r| r as usize)
1664+
}
1665+
1666+
16341667
/// An extension of `sendmsg` that allows the caller to transmit multiple
16351668
/// messages on a socket using a single system call. This has performance
16361669
/// benefits for some applications.
@@ -2456,4 +2489,3 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
24562489
Errno::result(shutdown(df, how)).map(drop)
24572490
}
24582491
}
2459-

test/sys/test_socket.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@ pub fn test_sendmsg_ipv4packetinfo() {
12041204
}
12051205

12061206
let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
1207-
12081207
sendmsg(
12091208
sock.as_raw_fd(),
12101209
&iov,
@@ -1215,6 +1214,59 @@ pub fn test_sendmsg_ipv4packetinfo() {
12151214
.expect("sendmsg");
12161215
}
12171216

1217+
#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))]
1218+
#[test]
1219+
pub fn test_sendmsg_prealloc_ipv4packetinfo() {
1220+
use cfg_if::cfg_if;
1221+
use nix::sys::socket::{
1222+
bind, sendmsg_prealloc, socket, AddressFamily, ControlMessage,
1223+
MsgFlags, SockFlag, SockType, SockaddrIn,
1224+
};
1225+
use std::io::IoSlice;
1226+
1227+
let sock = socket(
1228+
AddressFamily::Inet,
1229+
SockType::Datagram,
1230+
SockFlag::empty(),
1231+
None,
1232+
)
1233+
.expect("socket failed");
1234+
1235+
let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000);
1236+
1237+
bind(sock.as_raw_fd(), &sock_addr).expect("bind failed");
1238+
1239+
let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1240+
let iov = [IoSlice::new(&slice)];
1241+
1242+
cfg_if! {
1243+
if #[cfg(target_os = "netbsd")] {
1244+
let pi = libc::in_pktinfo {
1245+
ipi_ifindex: 0, /* Unspecified interface */
1246+
ipi_addr: libc::in_addr { s_addr: 0 },
1247+
};
1248+
} else {
1249+
let pi = libc::in_pktinfo {
1250+
ipi_ifindex: 0, /* Unspecified interface */
1251+
ipi_addr: libc::in_addr { s_addr: 0 },
1252+
ipi_spec_dst: sock_addr.as_ref().sin_addr,
1253+
};
1254+
}
1255+
}
1256+
1257+
let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
1258+
let mut cmsg_buffer = vec![0 as u8; 32]; // same size as sendmsg_ipv4packetinfo
1259+
sendmsg_prealloc(
1260+
sock.as_raw_fd(),
1261+
&iov,
1262+
&cmsg,
1263+
MsgFlags::empty(),
1264+
Some(&sock_addr),
1265+
&mut cmsg_buffer,
1266+
)
1267+
.expect("sendmsg_prealloc");
1268+
}
1269+
12181270
// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
12191271
// This creates a (udp) socket bound to ip6-localhost, then sends a message to
12201272
// itself but uses Ipv6PacketInfo to force the source address to be

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy