Skip to content

Commit 0cd03cc

Browse files
committed
Add Socket::sendmsg
Wrapper around sendmsg(2).
1 parent 56806e8 commit 0cd03cc

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

src/socket.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::time::Duration;
2323
use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
2424
use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
2525
#[cfg(not(target_os = "redox"))]
26-
use crate::{MaybeUninitSlice, RecvFlags};
26+
use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
2727

2828
/// Owned wrapper around a system socket.
2929
///
@@ -725,6 +725,14 @@ impl Socket {
725725
) -> io::Result<usize> {
726726
sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
727727
}
728+
729+
/// Send a message on a socket using a message structure.
730+
#[doc = man_links!(sendmsg(2))]
731+
#[cfg(not(target_os = "redox"))]
732+
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
733+
pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
734+
sys::sendmsg(self.as_raw(), msg, flags)
735+
}
728736
}
729737

730738
/// Set `SOCK_CLOEXEC` and `NO_HANDLE_INHERIT` on the `ty`pe on platforms that

src/sys/unix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ pub(crate) fn send_to_vectored(
10641064
}
10651065

10661066
#[cfg(not(target_os = "redox"))]
1067-
fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1067+
pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
10681068
syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
10691069
}
10701070

src/sys/windows.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use windows_sys::Win32::Networking::WinSock::{
2828
};
2929
use windows_sys::Win32::System::Threading::INFINITE;
3030

31-
use crate::{RecvFlags, SockAddr, TcpKeepalive, Type};
31+
use crate::{MsgHdr, RecvFlags, SockAddr, TcpKeepalive, Type};
3232

3333
#[allow(non_camel_case_types)]
3434
pub(crate) type c_int = std::os::raw::c_int;
@@ -659,6 +659,23 @@ pub(crate) fn send_to_vectored(
659659
.map(|_| nsent as usize)
660660
}
661661

662+
pub(crate) fn sendmsg(socket: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
663+
let mut nsent = 0;
664+
syscall!(
665+
WSASendMsg(
666+
socket,
667+
&msg.inner,
668+
flags as u32,
669+
&mut nsent,
670+
ptr::null_mut(),
671+
None,
672+
),
673+
PartialEq::eq,
674+
SOCKET_ERROR
675+
)
676+
.map(|_| nsent as usize)
677+
}
678+
662679
/// Wrapper around `getsockopt` to deal with platform specific timeouts.
663680
pub(crate) fn timeout_opt(fd: Socket, lvl: c_int, name: i32) -> io::Result<Option<Duration>> {
664681
unsafe { getsockopt(fd, lvl, name).map(from_ms) }

tests/socket.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,24 @@ fn send_from_recv_to_vectored() {
703703
assert_eq!(unsafe { assume_init(&swear) }, b"swear");
704704
}
705705

706+
#[test]
707+
#[cfg(not(target_os = "redox"))]
708+
fn sendmsg() {
709+
let (socket_a, socket_b) = udp_pair_unconnected();
710+
711+
const DATA: &[u8] = b"Hello, World!";
712+
713+
let bufs = &[IoSlice::new(DATA)];
714+
let addr_b = socket_b.local_addr().unwrap();
715+
let msg = socket2::MsgHdr::new().with_addr(&addr_b).with_buffers(bufs);
716+
let sent = socket_a.sendmsg(&msg, 0).unwrap();
717+
assert_eq!(sent, DATA.len());
718+
719+
let mut buf = Vec::with_capacity(DATA.len() + 1);
720+
let received = socket_b.recv(buf.spare_capacity_mut()).unwrap();
721+
assert_eq!(received, DATA.len());
722+
}
723+
706724
#[test]
707725
#[cfg(not(target_os = "redox"))]
708726
fn recv_vectored_truncated() {

0 commit comments

Comments
 (0)