Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fb33457

Browse files
committedMay 25, 2025·
Added sendmmsg and recvmmsg (#574) (#575)
1 parent 4c1cf6b commit fb33457

File tree

4 files changed

+493
-1
lines changed

4 files changed

+493
-1
lines changed
 

‎src/lib.rs

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,230 @@ impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
701701
"MsgHdrMut".fmt(fmt)
702702
}
703703
}
704+
705+
/// Configuration of a `sendmmsg(2)` system call.
706+
///
707+
/// This wraps `mmsghdr` on Unix. Also see [`MMsgHdrMut`] for the variant used by `recvmmsg(2)`.
708+
/// This API is not available on Windows.
709+
#[cfg(any(
710+
target_os = "aix",
711+
target_os = "android",
712+
target_os = "freebsd",
713+
target_os = "fuchsia",
714+
target_os = "linux",
715+
target_os = "netbsd",
716+
target_os = "openbsd",
717+
))]
718+
pub struct MMsgHdr<'addr, 'bufs, 'control> {
719+
inner: sys::mmsghdr,
720+
#[allow(clippy::type_complexity)]
721+
_lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
722+
}
723+
724+
#[cfg(any(
725+
target_os = "aix",
726+
target_os = "android",
727+
target_os = "freebsd",
728+
target_os = "fuchsia",
729+
target_os = "linux",
730+
target_os = "netbsd",
731+
target_os = "openbsd",
732+
))]
733+
impl<'addr, 'bufs, 'control> MMsgHdr<'addr, 'bufs, 'control> {
734+
/// Create a new `MMsgHdr` with all empty/zero fields.
735+
#[allow(clippy::new_without_default)]
736+
pub fn new() -> MMsgHdr<'addr, 'bufs, 'control> {
737+
// SAFETY: all zero is valid for `mmsghdr`.
738+
MMsgHdr {
739+
inner: unsafe { mem::zeroed() },
740+
_lifetimes: PhantomData,
741+
}
742+
}
743+
744+
/// Create a new `MMsgHdr` from a `MsgHdr`.
745+
pub fn from_msghdr(msghdr: MsgHdr<'addr, 'bufs, 'control>) -> MMsgHdr<'addr, 'bufs, 'control> {
746+
MMsgHdr {
747+
inner: sys::mmsghdr {
748+
msg_hdr: msghdr.inner,
749+
msg_len: 0,
750+
},
751+
_lifetimes: PhantomData,
752+
}
753+
}
754+
755+
/// Set the address (name) of the message.
756+
///
757+
/// Corresponds to setting `msg_name` and `msg_namelen` on Unix.
758+
pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
759+
sys::set_msghdr_name(&mut self.inner.msg_hdr, addr);
760+
self
761+
}
762+
763+
/// Set the buffer(s) of the message.
764+
///
765+
/// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix.
766+
pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
767+
let ptr = bufs.as_ptr() as *mut _;
768+
sys::set_msghdr_iov(&mut self.inner.msg_hdr, ptr, bufs.len());
769+
self
770+
}
771+
772+
/// Set the control buffer of the message.
773+
///
774+
/// Corresponds to setting `msg_control` and `msg_controllen` on Unix.
775+
pub fn with_control(mut self, buf: &'control [u8]) -> Self {
776+
let ptr = buf.as_ptr() as *mut _;
777+
sys::set_msghdr_control(&mut self.inner.msg_hdr, ptr, buf.len());
778+
self
779+
}
780+
781+
/// Set the flags of the message.
782+
///
783+
/// Corresponds to setting `msg_flags` on Unix.
784+
pub fn with_flags(mut self, flags: sys::c_int) -> Self {
785+
sys::set_msghdr_flags(&mut self.inner.msg_hdr, flags);
786+
self
787+
}
788+
789+
/// Gets the number of sent bytes.
790+
///
791+
/// Corresponds to `msg_len` on Unix.
792+
pub fn data_len(&self) -> usize {
793+
self.inner.msg_len as usize
794+
}
795+
}
796+
797+
#[cfg(any(
798+
target_os = "aix",
799+
target_os = "android",
800+
target_os = "freebsd",
801+
target_os = "fuchsia",
802+
target_os = "linux",
803+
target_os = "netbsd",
804+
target_os = "openbsd",
805+
))]
806+
impl<'name, 'bufs, 'control> fmt::Debug for MMsgHdr<'name, 'bufs, 'control> {
807+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
808+
"MMsgHdr".fmt(fmt)
809+
}
810+
}
811+
812+
/// Configuration of a `recvmmsg(2)` system call.
813+
///
814+
/// This wraps `mmsghdr` on Unix. Also see [`MMsgHdr`] for the variant used by `sendmmsg(2)`.
815+
/// This API is not available on Windows.
816+
#[cfg(any(
817+
target_os = "aix",
818+
target_os = "android",
819+
target_os = "freebsd",
820+
target_os = "fuchsia",
821+
target_os = "linux",
822+
target_os = "netbsd",
823+
target_os = "openbsd",
824+
))]
825+
pub struct MMsgHdrMut<'addr, 'bufs, 'control> {
826+
inner: sys::mmsghdr,
827+
#[allow(clippy::type_complexity)]
828+
_lifetimes: PhantomData<(
829+
&'addr mut SockAddr,
830+
&'bufs mut MaybeUninitSlice<'bufs>,
831+
&'control mut [u8],
832+
)>,
833+
}
834+
835+
#[cfg(any(
836+
target_os = "aix",
837+
target_os = "android",
838+
target_os = "freebsd",
839+
target_os = "fuchsia",
840+
target_os = "linux",
841+
target_os = "netbsd",
842+
target_os = "openbsd",
843+
))]
844+
impl<'addr, 'bufs, 'control> MMsgHdrMut<'addr, 'bufs, 'control> {
845+
/// Create a new `MMsgHdrMut` with all empty/zero fields.
846+
#[allow(clippy::new_without_default)]
847+
pub fn new() -> MMsgHdrMut<'addr, 'bufs, 'control> {
848+
// SAFETY: all zero is valid for `mmsghdr`.
849+
MMsgHdrMut {
850+
inner: unsafe { mem::zeroed() },
851+
_lifetimes: PhantomData,
852+
}
853+
}
854+
855+
/// Create a new `MMsgHdrMut` from a `MsgHdrMut`.
856+
pub fn from_msghdrmut(msghdrmut: MsgHdrMut<'addr, 'bufs, 'control>) -> MMsgHdrMut<'addr, 'bufs, 'control> {
857+
MMsgHdrMut {
858+
inner: sys::mmsghdr {
859+
msg_hdr: msghdrmut.inner,
860+
msg_len: 0,
861+
},
862+
_lifetimes: PhantomData,
863+
}
864+
}
865+
866+
/// Set the mutable address (name) of the message.
867+
///
868+
/// Corresponds to setting `msg_name` and `msg_namelen` on Unix.
869+
#[allow(clippy::needless_pass_by_ref_mut)]
870+
pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
871+
sys::set_msghdr_name(&mut self.inner.msg_hdr, addr);
872+
self
873+
}
874+
875+
/// Set the mutable buffer(s) of the message.
876+
///
877+
/// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix.
878+
pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
879+
sys::set_msghdr_iov(
880+
&mut self.inner.msg_hdr,
881+
bufs.as_mut_ptr().cast(),
882+
bufs.len(),
883+
);
884+
self
885+
}
886+
887+
/// Set the mutable control buffer of the message.
888+
///
889+
/// Corresponds to setting `msg_control` and `msg_controllen` on Unix.
890+
pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
891+
sys::set_msghdr_control(&mut self.inner.msg_hdr, buf.as_mut_ptr().cast(), buf.len());
892+
self
893+
}
894+
895+
/// Returns the flags of the message.
896+
pub fn flags(&self) -> RecvFlags {
897+
sys::msghdr_flags(&self.inner.msg_hdr)
898+
}
899+
900+
/// Gets the length of the control buffer.
901+
///
902+
/// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`.
903+
///
904+
/// Corresponds to `msg_controllen` on Unix.
905+
pub fn control_len(&self) -> usize {
906+
sys::msghdr_control_len(&self.inner.msg_hdr)
907+
}
908+
909+
/// Gets the number of received bytes.
910+
///
911+
/// Corresponds to `msg_len` on Unix.
912+
pub fn data_len(&self) -> usize {
913+
self.inner.msg_len as usize
914+
}
915+
}
916+
917+
#[cfg(any(
918+
target_os = "aix",
919+
target_os = "android",
920+
target_os = "freebsd",
921+
target_os = "fuchsia",
922+
target_os = "linux",
923+
target_os = "netbsd",
924+
target_os = "openbsd",
925+
))]
926+
impl<'name, 'bufs, 'control> fmt::Debug for MMsgHdrMut<'name, 'bufs, 'control> {
927+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
928+
"MMsgHdrMut".fmt(fmt)
929+
}
930+
}

‎src/socket.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
2424
#[cfg(all(unix, not(target_os = "redox")))]
2525
use crate::MsgHdrMut;
2626
use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
27+
#[cfg(any(
28+
target_os = "aix",
29+
target_os = "android",
30+
target_os = "freebsd",
31+
target_os = "fuchsia",
32+
target_os = "linux",
33+
target_os = "netbsd",
34+
target_os = "openbsd",
35+
))]
36+
use crate::{MMsgHdr, MMsgHdrMut};
2737
#[cfg(not(target_os = "redox"))]
2838
use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
2939

@@ -648,6 +658,27 @@ impl Socket {
648658
sys::recvmsg(self.as_raw(), msg, flags)
649659
}
650660

661+
/// Receive a list of messages on a socket using a message structure.
662+
/// Note that the timeout is buggy on Linux, see BUGS section in the Linux manual page.
663+
#[doc = man_links!(recvmmsg(2))]
664+
#[cfg(any(
665+
target_os = "aix",
666+
target_os = "android",
667+
target_os = "freebsd",
668+
target_os = "fuchsia",
669+
target_os = "linux",
670+
target_os = "netbsd",
671+
target_os = "openbsd",
672+
))]
673+
pub fn recvmmsg(
674+
&self,
675+
msgs: &mut [MMsgHdrMut<'_, '_, '_>],
676+
flags: sys::c_int,
677+
timeout: Option<Duration>,
678+
) -> io::Result<usize> {
679+
sys::recvmmsg(self.as_raw(), msgs, flags, timeout)
680+
}
681+
651682
/// Sends data on the socket to a connected peer.
652683
///
653684
/// This is typically used on TCP sockets or datagram sockets which have
@@ -749,6 +780,25 @@ impl Socket {
749780
pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
750781
sys::sendmsg(self.as_raw(), msg, flags)
751782
}
783+
784+
/// Send a list of messages on a socket using a message structure.
785+
#[doc = man_links!(sendmmsg(2))]
786+
#[cfg(any(
787+
target_os = "aix",
788+
target_os = "android",
789+
target_os = "freebsd",
790+
target_os = "fuchsia",
791+
target_os = "linux",
792+
target_os = "netbsd",
793+
target_os = "openbsd",
794+
))]
795+
pub fn sendmmsg(
796+
&self,
797+
msgs: &mut [MMsgHdr<'_, '_, '_>],
798+
flags: sys::c_int,
799+
) -> io::Result<usize> {
800+
sys::sendmmsg(self.as_raw(), msgs, flags)
801+
}
752802
}
753803

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

‎src/sys/unix.rs

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ use libc::ssize_t;
8080
use libc::{in6_addr, in_addr};
8181

8282
use crate::{Domain, Protocol, SockAddr, SockAddrStorage, TcpKeepalive, Type};
83+
#[cfg(any(
84+
target_os = "aix",
85+
target_os = "android",
86+
target_os = "freebsd",
87+
target_os = "fuchsia",
88+
target_os = "linux",
89+
target_os = "netbsd",
90+
target_os = "openbsd",
91+
))]
92+
use crate::{MMsgHdr, MMsgHdrMut};
8393
#[cfg(not(target_os = "redox"))]
8494
use crate::{MsgHdr, MsgHdrMut, RecvFlags};
8595

@@ -739,6 +749,18 @@ pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
739749
msg.msg_controllen as _
740750
}
741751

752+
// Used in `MMsgHdr`.
753+
#[cfg(any(
754+
target_os = "aix",
755+
target_os = "android",
756+
target_os = "freebsd",
757+
target_os = "fuchsia",
758+
target_os = "linux",
759+
target_os = "netbsd",
760+
target_os = "openbsd",
761+
))]
762+
pub(crate) use libc::mmsghdr;
763+
742764
/// Unix only API.
743765
impl SockAddr {
744766
/// Constructs a `SockAddr` with the family `AF_VSOCK` and the provided CID/port.
@@ -1093,6 +1115,69 @@ pub(crate) fn recvmsg(
10931115
syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
10941116
}
10951117

1118+
// helper function for recvmmsg
1119+
#[cfg(any(
1120+
target_os = "aix",
1121+
target_os = "android",
1122+
target_os = "freebsd",
1123+
target_os = "fuchsia",
1124+
target_os = "linux",
1125+
target_os = "netbsd",
1126+
target_os = "openbsd",
1127+
))]
1128+
fn into_timespec(duration: Duration) -> libc::timespec {
1129+
// https://github.com/rust-lang/libc/issues/1848
1130+
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
1131+
libc::timespec {
1132+
tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1133+
tv_nsec: duration.subsec_nanos() as libc::c_long,
1134+
}
1135+
}
1136+
1137+
// type of the parameter specifying the number of mmsghdr elements in sendmmsg/recvmmsg syscalls
1138+
#[cfg(any(
1139+
target_os = "aix",
1140+
target_os = "android",
1141+
target_os = "fuchsia",
1142+
target_os = "linux",
1143+
target_os = "netbsd",
1144+
target_os = "openbsd",
1145+
))]
1146+
type MMsgHdrLen = libc::c_uint;
1147+
#[cfg(target_os = "freebsd")]
1148+
type MMsgHdrLen = usize;
1149+
1150+
#[cfg(any(
1151+
target_os = "aix",
1152+
target_os = "android",
1153+
target_os = "freebsd",
1154+
target_os = "fuchsia",
1155+
target_os = "linux",
1156+
target_os = "netbsd",
1157+
target_os = "openbsd",
1158+
))]
1159+
pub(crate) fn recvmmsg(
1160+
fd: Socket,
1161+
msgs: &mut [MMsgHdrMut<'_, '_, '_>],
1162+
flags: c_int,
1163+
timeout: Option<Duration>,
1164+
) -> io::Result<usize> {
1165+
let mut ts: libc::timespec;
1166+
let tp = match timeout {
1167+
Some(d) => {
1168+
ts = into_timespec(d);
1169+
&mut ts
1170+
}
1171+
None => std::ptr::null_mut(),
1172+
};
1173+
// MMsgHdrMut only contains libc::mmsghdr and PhantomData
1174+
let mp = msgs.as_mut_ptr() as *mut libc::mmsghdr;
1175+
// flags is unsigned in musl and ohos libc
1176+
#[cfg(any(target_env = "musl", target_env = "ohos"))]
1177+
let flags = flags.cast_unsigned();
1178+
syscall!(recvmmsg(fd, mp, msgs.len() as MMsgHdrLen, flags, tp)).map(|n| n as usize)
1179+
}
1180+
10961181
pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
10971182
syscall!(send(
10981183
fd,
@@ -1137,6 +1222,28 @@ pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io:
11371222
syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
11381223
}
11391224

1225+
#[cfg(any(
1226+
target_os = "aix",
1227+
target_os = "android",
1228+
target_os = "freebsd",
1229+
target_os = "fuchsia",
1230+
target_os = "linux",
1231+
target_os = "netbsd",
1232+
target_os = "openbsd",
1233+
))]
1234+
pub(crate) fn sendmmsg(
1235+
fd: Socket,
1236+
msgs: &mut [MMsgHdr<'_, '_, '_>],
1237+
flags: c_int,
1238+
) -> io::Result<usize> {
1239+
// MMsgHdr only contains libc::mmsghdr and PhantomData
1240+
let mp = msgs.as_mut_ptr() as *mut libc::mmsghdr;
1241+
// flags is unsigned in musl and ohos libc
1242+
#[cfg(any(target_env = "musl", target_env = "ohos"))]
1243+
let flags = flags.cast_unsigned();
1244+
syscall!(sendmmsg(fd, mp, msgs.len() as MMsgHdrLen, flags)).map(|n| n as usize)
1245+
}
1246+
11401247
/// Wrapper around `getsockopt` to deal with platform specific timeouts.
11411248
pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
11421249
unsafe { getsockopt(fd, opt, val).map(from_timeval) }
@@ -1166,7 +1273,7 @@ pub(crate) fn set_timeout_opt(
11661273
fn into_timeval(duration: Option<Duration>) -> libc::timeval {
11671274
match duration {
11681275
// https://github.com/rust-lang/libc/issues/1848
1169-
#[cfg_attr(target_env = "musl", allow(deprecated))]
1276+
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
11701277
Some(duration) => libc::timeval {
11711278
tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
11721279
tv_usec: duration.subsec_micros() as libc::suseconds_t,

‎tests/socket.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,114 @@ fn sendmsg() {
776776
assert_eq!(received, DATA.len());
777777
}
778778

779+
#[test]
780+
#[cfg(any(
781+
target_os = "aix",
782+
target_os = "android",
783+
target_os = "freebsd",
784+
target_os = "fuchsia",
785+
target_os = "linux",
786+
target_os = "netbsd",
787+
target_os = "openbsd",
788+
))]
789+
fn sendmmsg() {
790+
let (socket_a, socket_b) = udp_pair_unconnected();
791+
792+
const DATA1: &[u8] = b"Hello, ";
793+
const DATA2: &[u8] = b"World!";
794+
795+
let bufs1 = &[IoSlice::new(DATA1)];
796+
let bufs2 = &[IoSlice::new(DATA2)];
797+
let addr_b = socket_b.local_addr().unwrap();
798+
let mut msgs = Vec::new();
799+
msgs.push(
800+
socket2::MMsgHdr::new()
801+
.with_addr(&addr_b)
802+
.with_buffers(bufs1),
803+
);
804+
msgs.push(
805+
socket2::MMsgHdr::new()
806+
.with_addr(&addr_b)
807+
.with_buffers(bufs2),
808+
);
809+
let sent = socket_a.sendmmsg(&mut msgs, 0).unwrap();
810+
assert_eq!(sent, msgs.len());
811+
assert_eq!(msgs[0].data_len(), DATA1.len());
812+
assert_eq!(msgs[1].data_len(), DATA2.len());
813+
814+
let mut buf1 = Vec::with_capacity(DATA1.len() + 1);
815+
let mut buf2 = Vec::with_capacity(DATA2.len() + 1);
816+
let received1 = socket_b.recv(buf1.spare_capacity_mut()).unwrap();
817+
let received2 = socket_b.recv(buf2.spare_capacity_mut()).unwrap();
818+
assert_eq!(received1, DATA1.len());
819+
// SAFETY: recv filled the buffer and received1 is not exceeding the capacity
820+
unsafe {
821+
buf1.set_len(received1);
822+
}
823+
assert_eq!(&buf1[..], DATA1);
824+
assert_eq!(received2, DATA2.len());
825+
// SAFETY: recv filled the buffer and received2 is not exceeding the capacity
826+
unsafe {
827+
buf2.set_len(received2);
828+
}
829+
assert_eq!(&buf2[..], DATA2);
830+
}
831+
832+
#[test]
833+
#[cfg(any(
834+
target_os = "aix",
835+
target_os = "android",
836+
target_os = "freebsd",
837+
target_os = "fuchsia",
838+
target_os = "linux",
839+
target_os = "netbsd",
840+
target_os = "openbsd",
841+
))]
842+
fn recvmmsg() {
843+
let (socket_a, socket_b) = udp_pair_unconnected();
844+
845+
const DATA1: &[u8] = b"Hello, ";
846+
const DATA2: &[u8] = b"World!";
847+
848+
let bufs1 = &[IoSlice::new(DATA1)];
849+
let bufs2 = &[IoSlice::new(DATA2)];
850+
let addr_b = socket_b.local_addr().unwrap();
851+
let msg1 = socket2::MsgHdr::new()
852+
.with_addr(&addr_b)
853+
.with_buffers(bufs1);
854+
let msg2 = socket2::MsgHdr::new()
855+
.with_addr(&addr_b)
856+
.with_buffers(bufs2);
857+
let sent1 = socket_a.sendmsg(&msg1, 0).unwrap();
858+
let sent2 = socket_a.sendmsg(&msg2, 0).unwrap();
859+
assert_eq!(sent1, DATA1.len());
860+
assert_eq!(sent2, DATA2.len());
861+
862+
let mut buf1 = Vec::with_capacity(DATA1.len() + 1);
863+
let mut buf2 = Vec::with_capacity(DATA2.len() + 1);
864+
let mut iov1 = [socket2::MaybeUninitSlice::new(buf1.spare_capacity_mut())];
865+
let mut iov2 = [socket2::MaybeUninitSlice::new(buf2.spare_capacity_mut())];
866+
let mut msgs = Vec::new();
867+
msgs.push(socket2::MMsgHdrMut::new().with_buffers(&mut iov1[..]));
868+
msgs.push(socket2::MMsgHdrMut::new().with_buffers(&mut iov2[..]));
869+
let received = socket_b.recvmmsg(&mut msgs, 0, None).unwrap();
870+
assert_eq!(received, msgs.len());
871+
let received1 = msgs[0].data_len();
872+
let received2 = msgs[1].data_len();
873+
assert_eq!(received1, DATA1.len());
874+
// SAFETY: recvmmsg filled the buffer and received1 is not exceeding the capacity
875+
unsafe {
876+
buf1.set_len(received1);
877+
}
878+
assert_eq!(received2, DATA2.len());
879+
// SAFETY: recvmmsg filled the buffer and received1 is not exceeding the capacity
880+
unsafe {
881+
buf2.set_len(received2);
882+
}
883+
assert_eq!(&buf1[..], DATA1);
884+
assert_eq!(&buf2[..], DATA2);
885+
}
886+
779887
#[test]
780888
#[cfg(not(any(target_os = "redox", target_os = "vita")))]
781889
fn recv_vectored_truncated() {

0 commit comments

Comments
 (0)
Please sign in to comment.