Skip to content

Commit e78ae84

Browse files
de-vri-esThomasdezeeuw
authored andcommitted
Return new RecvFlags struct with vectored I/O.
The `RecvFlags` struct replaces the boolean to indicate if messages are truncated.
1 parent d653b7b commit e78ae84

File tree

5 files changed

+104
-30
lines changed

5 files changed

+104
-30
lines changed

src/lib.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,60 @@ impl From<Protocol> for c_int {
237237
p.0
238238
}
239239
}
240+
241+
/// Flags for incoming messages.
242+
///
243+
/// Flags provide additional information about incoming messages.
244+
#[cfg(not(target_os = "redox"))]
245+
#[derive(Copy, Clone, Eq, PartialEq)]
246+
pub struct RecvFlags(c_int);
247+
248+
#[cfg(not(target_os = "redox"))]
249+
impl RecvFlags {
250+
/// Check if the message terminates a record.
251+
///
252+
/// Not all socket types support the notion of records.
253+
/// For socket types that do support it (such as [`SEQPACKET`][Type::SEQPACKET]),
254+
/// a record is terminated by sending a message with the end-of-record flag set.
255+
///
256+
/// On Unix this corresponds to the MSG_EOR flag.
257+
#[cfg(unix)]
258+
pub fn is_end_of_record(self) -> bool {
259+
self.0 & sys::MSG_EOR != 0
260+
}
261+
262+
/// Check if the message contains out-of-band data.
263+
///
264+
/// This is useful for protocols where you receive out-of-band data
265+
/// mixed in with the normal data stream.
266+
///
267+
/// On Unix this corresponds to the MSG_OOB flag.
268+
#[cfg(unix)]
269+
pub fn is_out_of_band(self) -> bool {
270+
self.0 & sys::MSG_OOB != 0
271+
}
272+
273+
/// Check if the message contains a truncated datagram.
274+
///
275+
/// This flag is only used for datagram-based sockets,
276+
/// not for stream sockets.
277+
///
278+
/// On Unix this corresponds to the MSG_TRUNC flag.
279+
/// On Windows this corresponds to the WSAEMSGSIZE error code.
280+
pub fn is_trunctated(self) -> bool {
281+
self.0 & sys::MSG_TRUNC != 0
282+
}
283+
}
284+
285+
#[cfg(not(target_os = "redox"))]
286+
impl std::fmt::Debug for RecvFlags {
287+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288+
let mut dbg = f.debug_struct("RecvFlags");
289+
#[cfg(unix)]
290+
dbg.field("is_end_of_record", &self.is_end_of_record());
291+
#[cfg(unix)]
292+
dbg.field("is_out_of_band", &self.is_out_of_band());
293+
dbg.field("is_trunctated", &self.is_trunctated());
294+
dbg.finish()
295+
}
296+
}

src/socket.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use libc::MSG_OOB;
2121
use winapi::um::winsock2::MSG_OOB;
2222

2323
use crate::sys;
24+
#[cfg(not(target_os = "redox"))]
25+
use crate::RecvFlags;
2426
use crate::{Domain, Protocol, SockAddr, Type};
2527

2628
/// Owned wrapper around a system socket.
@@ -264,16 +266,16 @@ impl Socket {
264266

265267
/// Identical to [`recv_with_flags`] but reads into a slice of buffers.
266268
///
267-
/// In addition to the number of bytes read, this function a flag to indicate if a received datagram was truncated.
268-
/// For stream sockets, the flag has no meaning.
269+
/// In addition to the number of bytes read, this function return the flags for the received message.
270+
/// See [`RecvFlags`] for more information about the flags.
269271
///
270272
/// [`recv_with_flags`]: #method.recv_with_flags
271273
#[cfg(not(target_os = "redox"))]
272274
pub fn recv_vectored(
273275
&self,
274276
bufs: &mut [IoSliceMut<'_>],
275277
flags: i32,
276-
) -> io::Result<(usize, bool)> {
278+
) -> io::Result<(usize, RecvFlags)> {
277279
self.inner().recv_vectored(bufs, flags)
278280
}
279281

@@ -319,16 +321,16 @@ impl Socket {
319321

320322
/// Identical to [`recv_from_with_flags`] but reads into a slice of buffers.
321323
///
322-
/// In addition to the number of bytes read, this function a flag to indicate if a received datagram was truncated.
323-
/// For stream sockets, the flag has no meaning.
324+
/// In addition to the number of bytes read, this function return the flags for the received message.
325+
/// See [`RecvFlags`] for more information about the flags.
324326
///
325327
/// [`recv_from_with_flags`]: #method.recv_from_with_flags
326328
#[cfg(not(target_os = "redox"))]
327329
pub fn recv_from_vectored(
328330
&self,
329331
bufs: &mut [IoSliceMut<'_>],
330332
flags: i32,
331-
) -> io::Result<(usize, bool, SockAddr)> {
333+
) -> io::Result<(usize, RecvFlags, SockAddr)> {
332334
self.inner().recv_from_vectored(bufs, flags)
333335
}
334336

src/sys/unix.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use std::{cmp, fmt, io, mem};
2525

2626
use libc::{self, c_void, ssize_t};
2727

28+
#[cfg(not(target_os = "redox"))]
29+
use crate::RecvFlags;
2830
use crate::{Domain, Type};
2931

3032
pub use libc::c_int;
@@ -81,6 +83,10 @@ macro_rules! syscall {
8183
}};
8284
}
8385

86+
// Re-export message flags for the RecvFlags struct.
87+
#[cfg(not(target_os = "redox"))]
88+
pub(crate) use libc::{MSG_EOR, MSG_OOB, MSG_TRUNC};
89+
8490
#[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))]
8591
type IovLen = usize;
8692

@@ -509,7 +515,7 @@ impl Socket {
509515
&self,
510516
bufs: &mut [IoSliceMut<'_>],
511517
flags: c_int,
512-
) -> io::Result<(usize, bool)> {
518+
) -> io::Result<(usize, RecvFlags)> {
513519
let mut msg = libc::msghdr {
514520
msg_name: std::ptr::null_mut(),
515521
msg_namelen: 0,
@@ -521,16 +527,15 @@ impl Socket {
521527
};
522528

523529
let n = syscall!(recvmsg(self.fd, &mut msg as *mut _, flags))?;
524-
let truncated = msg.msg_flags & libc::MSG_TRUNC != 0;
525-
Ok((n as usize, truncated))
530+
Ok((n as usize, RecvFlags(msg.msg_flags)))
526531
}
527532

528533
#[cfg(not(target_os = "redox"))]
529534
pub fn recv_from_vectored(
530535
&self,
531536
bufs: &mut [IoSliceMut<'_>],
532537
flags: c_int,
533-
) -> io::Result<(usize, bool, SockAddr)> {
538+
) -> io::Result<(usize, RecvFlags, SockAddr)> {
534539
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
535540
let mut msg = libc::msghdr {
536541
msg_name: &mut storage as *mut libc::sockaddr_storage as *mut c_void,
@@ -543,10 +548,9 @@ impl Socket {
543548
};
544549

545550
let n = syscall!(recvmsg(self.fd, &mut msg as *mut _, flags))?;
546-
let truncated = msg.msg_flags & libc::MSG_TRUNC != 0;
547551
let addr =
548552
unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, msg.msg_namelen) };
549-
Ok((n as usize, truncated, addr))
553+
Ok((n as usize, RecvFlags(msg.msg_flags), addr))
550554
}
551555

552556
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {

src/sys/windows.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use winapi::um::processthreadsapi::GetCurrentProcessId;
3030
use winapi::um::winbase::INFINITE;
3131
use winapi::um::winsock2 as sock;
3232

33-
use crate::SockAddr;
33+
use crate::{RecvFlags, SockAddr};
3434

3535
const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
3636
const MSG_PEEK: c_int = 0x2;
@@ -42,6 +42,9 @@ const WSA_FLAG_OVERLAPPED: DWORD = 0x01;
4242

4343
pub use winapi::ctypes::c_int;
4444

45+
/// Fake MSG_TRUNC flag for the [`RecvFlags`] struct.
46+
pub(crate) const MSG_TRUNC: c_int = sock::WSAEMSGSIZE;
47+
4548
// Used in `Domain`.
4649
pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6};
4750
// Used in `Type`.
@@ -342,7 +345,7 @@ impl Socket {
342345
&self,
343346
bufs: &mut [IoSliceMut<'_>],
344347
flags: c_int,
345-
) -> io::Result<(usize, bool)> {
348+
) -> io::Result<(usize, RecvFlags)> {
346349
let mut nread = 0;
347350
let mut flags = flags as DWORD;
348351
let ret = unsafe {
@@ -359,12 +362,12 @@ impl Socket {
359362

360363
let nread = nread as usize;
361364
if ret == 0 {
362-
Ok((nread, false))
365+
Ok((nread, RecvFlags(0)))
363366
} else {
364367
let error = last_error();
365368
match error.raw_os_error() {
366-
Some(sock::WSAESHUTDOWN) => Ok((0, false)),
367-
Some(sock::WSAEMSGSIZE) => Ok((nread, true)),
369+
Some(sock::WSAESHUTDOWN) => Ok((0, RecvFlags(0))),
370+
Some(sock::WSAEMSGSIZE) => Ok((nread, RecvFlags(MSG_TRUNC))),
368371
_ => Err(error),
369372
}
370373
}
@@ -374,7 +377,7 @@ impl Socket {
374377
&self,
375378
bufs: &mut [IoSliceMut<'_>],
376379
flags: c_int,
377-
) -> io::Result<(usize, bool, SockAddr)> {
380+
) -> io::Result<(usize, RecvFlags, SockAddr)> {
378381
let mut nread = 0;
379382
let mut flags = flags as DWORD;
380383
let mut storage: SOCKADDR_STORAGE = unsafe { mem::zeroed() };
@@ -393,20 +396,20 @@ impl Socket {
393396
)
394397
};
395398

396-
let truncated;
399+
let flags;
397400
if ret == 0 {
398-
truncated = false;
401+
flags = RecvFlags(0);
399402
} else {
400403
let error = last_error();
401404
if error.raw_os_error() == Some(sock::WSAEMSGSIZE) {
402-
truncated = true;
405+
flags = RecvFlags(MSG_TRUNC)
403406
} else {
404407
return Err(error);
405408
}
406409
}
407410

408411
let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen) };
409-
Ok((nread as usize, truncated, addr))
412+
Ok((nread as usize, flags, addr))
410413
}
411414

412415
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {

src/tests.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ fn send_recv_vectored() {
176176
let mut yell = [0u8; 4];
177177
let mut ow = [0u8; 2];
178178

179-
let (received, truncated) = socket_b
179+
let (received, flags) = socket_b
180180
.recv_vectored(
181181
&mut [
182182
IoSliceMut::new(&mut the),
@@ -190,7 +190,11 @@ fn send_recv_vectored() {
190190
)
191191
.unwrap();
192192
assert_eq!(received, 23);
193-
assert_eq!(truncated, false);
193+
#[cfg(all(unix, not(target_os = "redox")))]
194+
assert_eq!(flags.is_end_of_record(), false);
195+
#[cfg(all(unix, not(target_os = "redox")))]
196+
assert_eq!(flags.is_out_of_band(), false);
197+
assert_eq!(flags.is_trunctated(), false);
194198

195199
assert_eq!(&the, b"the");
196200
assert_eq!(&wee, b"wee");
@@ -226,7 +230,7 @@ fn send_from_recv_to_vectored() {
226230
let mut has = [0u8; 3];
227231
let mut men = [0u8; 3];
228232
let mut swear = [0u8; 5];
229-
let (received, truncated, addr) = socket_b
233+
let (received, flags, addr) = socket_b
230234
.recv_from_vectored(
231235
&mut [
232236
IoSliceMut::new(&mut surgeon),
@@ -239,7 +243,11 @@ fn send_from_recv_to_vectored() {
239243
.unwrap();
240244

241245
assert_eq!(received, 18);
242-
assert_eq!(truncated, false);
246+
#[cfg(all(unix, not(target_os = "redox")))]
247+
assert_eq!(flags.is_end_of_record(), false);
248+
#[cfg(all(unix, not(target_os = "redox")))]
249+
assert_eq!(flags.is_out_of_band(), false);
250+
assert_eq!(flags.is_trunctated(), false);
243251
assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
244252
assert_eq!(&surgeon, b"surgeon");
245253
assert_eq!(&has, b"has");
@@ -261,11 +269,11 @@ fn recv_vectored_truncated() {
261269

262270
let mut buffer = [0u8; 24];
263271

264-
let (received, truncated) = socket_b
272+
let (received, flags) = socket_b
265273
.recv_vectored(&mut [IoSliceMut::new(&mut buffer)], 0)
266274
.unwrap();
267275
assert_eq!(received, 24);
268-
assert_eq!(truncated, true);
276+
assert_eq!(flags.is_trunctated(), true);
269277
assert_eq!(&buffer, b"do not feed the gremlins");
270278
}
271279

@@ -285,11 +293,11 @@ fn recv_from_vectored_truncated() {
285293

286294
let mut buffer = [0u8; 24];
287295

288-
let (received, truncated, addr) = socket_b
296+
let (received, flags, addr) = socket_b
289297
.recv_from_vectored(&mut [IoSliceMut::new(&mut buffer)], 0)
290298
.unwrap();
291299
assert_eq!(received, 24);
292-
assert_eq!(truncated, true);
300+
assert_eq!(flags.is_trunctated(), true);
293301
assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
294302
assert_eq!(&buffer, b"do not feed the gremlins");
295303
}

0 commit comments

Comments
 (0)