Skip to content

Commit d653b7b

Browse files
de-vri-esThomasdezeeuw
authored andcommitted
Implement vectored I/O, except for target_os = "redox".
1 parent 4dacd25 commit d653b7b

File tree

4 files changed

+455
-2
lines changed

4 files changed

+455
-2
lines changed

src/socket.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
use std::fmt;
1010
use std::io::{self, Read, Write};
11+
#[cfg(not(target_os = "redox"))]
12+
use std::io::{IoSlice, IoSliceMut};
1113
use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown};
1214
#[cfg(all(feature = "all", unix))]
1315
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
@@ -260,6 +262,21 @@ impl Socket {
260262
self.inner().recv(buf, flags)
261263
}
262264

265+
/// Identical to [`recv_with_flags`] but reads into a slice of buffers.
266+
///
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+
///
270+
/// [`recv_with_flags`]: #method.recv_with_flags
271+
#[cfg(not(target_os = "redox"))]
272+
pub fn recv_vectored(
273+
&self,
274+
bufs: &mut [IoSliceMut<'_>],
275+
flags: i32,
276+
) -> io::Result<(usize, bool)> {
277+
self.inner().recv_vectored(bufs, flags)
278+
}
279+
263280
/// Receives out-of-band (OOB) data on the socket from the remote address to
264281
/// which it is connected by setting the `MSG_OOB` flag for this call.
265282
///
@@ -300,6 +317,21 @@ impl Socket {
300317
self.inner().recv_from(buf, flags)
301318
}
302319

320+
/// Identical to [`recv_from_with_flags`] but reads into a slice of buffers.
321+
///
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+
///
325+
/// [`recv_from_with_flags`]: #method.recv_from_with_flags
326+
#[cfg(not(target_os = "redox"))]
327+
pub fn recv_from_vectored(
328+
&self,
329+
bufs: &mut [IoSliceMut<'_>],
330+
flags: i32,
331+
) -> io::Result<(usize, bool, SockAddr)> {
332+
self.inner().recv_from_vectored(bufs, flags)
333+
}
334+
303335
/// Receives data from the socket, without removing it from the queue.
304336
///
305337
/// Successive calls return the same data. This is accomplished by passing
@@ -329,6 +361,14 @@ impl Socket {
329361
self.inner().send(buf, flags)
330362
}
331363

364+
/// Identical to [`send_with_flags`] but writes from a slice of buffers.
365+
///
366+
/// [`send_with_flags`]: #method.send_with_flags
367+
#[cfg(not(target_os = "redox"))]
368+
pub fn send_vectored(&self, bufs: &[IoSlice<'_>], flags: i32) -> io::Result<usize> {
369+
self.inner().send_vectored(bufs, flags)
370+
}
371+
332372
/// Sends out-of-band (OOB) data on the socket to connected peer
333373
/// by setting the `MSG_OOB` flag for this call.
334374
///
@@ -358,6 +398,19 @@ impl Socket {
358398
self.inner().send_to(buf, flags, addr)
359399
}
360400

401+
/// Identical to [`send_with_flags`] but writes from a slice of buffers.
402+
///
403+
/// [`send_with_flags`]: #method.send_with_flags
404+
#[cfg(not(target_os = "redox"))]
405+
pub fn send_to_vectored(
406+
&self,
407+
bufs: &[IoSlice<'_>],
408+
addr: &SockAddr,
409+
flags: i32,
410+
) -> io::Result<usize> {
411+
self.inner().send_to_vectored(bufs, flags, addr)
412+
}
413+
361414
// ================================================
362415

363416
/// Gets the value of the `IP_TTL` option for this socket.

src/sys/unix.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
#[cfg(not(target_os = "redox"))]
10+
use std::io::{IoSlice, IoSliceMut};
911
use std::io::{Read, Write};
1012
use std::net::Shutdown;
1113
use std::net::{self, Ipv4Addr, Ipv6Addr};
@@ -79,6 +81,20 @@ macro_rules! syscall {
7981
}};
8082
}
8183

84+
#[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))]
85+
type IovLen = usize;
86+
87+
#[cfg(any(
88+
target_os = "dragonfly",
89+
target_os = "freebsd",
90+
target_os = "ios",
91+
all(target_os = "linux", target_env = "musl",),
92+
target_os = "macos",
93+
target_os = "netbsd",
94+
target_os = "openbsd",
95+
))]
96+
type IovLen = c_int;
97+
8298
/// Unix only API.
8399
impl Domain {
84100
/// Domain for Unix socket communication, corresponding to `AF_UNIX`.
@@ -488,6 +504,51 @@ impl Socket {
488504
Ok((n as usize, addr))
489505
}
490506

507+
#[cfg(not(target_os = "redox"))]
508+
pub fn recv_vectored(
509+
&self,
510+
bufs: &mut [IoSliceMut<'_>],
511+
flags: c_int,
512+
) -> io::Result<(usize, bool)> {
513+
let mut msg = libc::msghdr {
514+
msg_name: std::ptr::null_mut(),
515+
msg_namelen: 0,
516+
msg_iov: bufs.as_mut_ptr().cast(),
517+
msg_iovlen: bufs.len().min(IovLen::MAX as usize) as IovLen,
518+
msg_control: std::ptr::null_mut(),
519+
msg_controllen: 0,
520+
msg_flags: 0,
521+
};
522+
523+
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))
526+
}
527+
528+
#[cfg(not(target_os = "redox"))]
529+
pub fn recv_from_vectored(
530+
&self,
531+
bufs: &mut [IoSliceMut<'_>],
532+
flags: c_int,
533+
) -> io::Result<(usize, bool, SockAddr)> {
534+
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
535+
let mut msg = libc::msghdr {
536+
msg_name: &mut storage as *mut libc::sockaddr_storage as *mut c_void,
537+
msg_namelen: mem::size_of_val(&storage) as socklen_t,
538+
msg_iov: bufs.as_mut_ptr().cast(),
539+
msg_iovlen: bufs.len().min(IovLen::MAX as usize) as IovLen,
540+
msg_control: std::ptr::null_mut(),
541+
msg_controllen: 0,
542+
msg_flags: 0,
543+
};
544+
545+
let n = syscall!(recvmsg(self.fd, &mut msg as *mut _, flags))?;
546+
let truncated = msg.msg_flags & libc::MSG_TRUNC != 0;
547+
let addr =
548+
unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, msg.msg_namelen) };
549+
Ok((n as usize, truncated, addr))
550+
}
551+
491552
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
492553
let n = syscall!(send(
493554
self.fd,
@@ -510,6 +571,43 @@ impl Socket {
510571
Ok(n as usize)
511572
}
512573

574+
#[cfg(not(target_os = "redox"))]
575+
pub fn send_vectored(&self, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
576+
let mut msg = libc::msghdr {
577+
msg_name: std::ptr::null_mut(),
578+
msg_namelen: 0,
579+
msg_iov: bufs.as_ptr() as *mut libc::iovec,
580+
msg_iovlen: bufs.len().min(IovLen::MAX as usize) as IovLen,
581+
msg_control: std::ptr::null_mut(),
582+
msg_controllen: 0,
583+
msg_flags: 0,
584+
};
585+
586+
let n = syscall!(sendmsg(self.fd, &mut msg as *mut libc::msghdr, flags))?;
587+
Ok(n as usize)
588+
}
589+
590+
#[cfg(not(target_os = "redox"))]
591+
pub fn send_to_vectored(
592+
&self,
593+
bufs: &[IoSlice<'_>],
594+
flags: c_int,
595+
addr: &SockAddr,
596+
) -> io::Result<usize> {
597+
let mut msg = libc::msghdr {
598+
msg_name: addr.as_ptr() as *mut c_void,
599+
msg_namelen: addr.len(),
600+
msg_iov: bufs.as_ptr() as *mut libc::iovec,
601+
msg_iovlen: bufs.len().min(IovLen::MAX as usize) as IovLen,
602+
msg_control: std::ptr::null_mut(),
603+
msg_controllen: 0,
604+
msg_flags: 0,
605+
};
606+
607+
let n = syscall!(sendmsg(self.fd, &mut msg as *mut libc::msghdr, flags))?;
608+
Ok(n as usize)
609+
}
610+
513611
pub fn ttl(&self) -> io::Result<u32> {
514612
unsafe {
515613
let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?;

src/sys/windows.rs

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use std::cmp;
1010
use std::fmt;
1111
use std::io;
12-
use std::io::{Read, Write};
12+
use std::io::{IoSlice, IoSliceMut, Read, Write};
1313
use std::mem;
1414
use std::net::Shutdown;
1515
use std::net::{self, Ipv4Addr, Ipv6Addr};
@@ -338,6 +338,77 @@ impl Socket {
338338
}
339339
}
340340

341+
pub fn recv_vectored(
342+
&self,
343+
bufs: &mut [IoSliceMut<'_>],
344+
flags: c_int,
345+
) -> io::Result<(usize, bool)> {
346+
let mut nread = 0;
347+
let mut flags = flags as DWORD;
348+
let ret = unsafe {
349+
sock::WSARecv(
350+
self.socket,
351+
bufs.as_mut_ptr() as *mut WSABUF,
352+
bufs.len().min(DWORD::MAX as usize) as DWORD,
353+
&mut nread,
354+
&mut flags,
355+
ptr::null_mut(),
356+
None,
357+
)
358+
};
359+
360+
let nread = nread as usize;
361+
if ret == 0 {
362+
Ok((nread, false))
363+
} else {
364+
let error = last_error();
365+
match error.raw_os_error() {
366+
Some(sock::WSAESHUTDOWN) => Ok((0, false)),
367+
Some(sock::WSAEMSGSIZE) => Ok((nread, true)),
368+
_ => Err(error),
369+
}
370+
}
371+
}
372+
373+
pub fn recv_from_vectored(
374+
&self,
375+
bufs: &mut [IoSliceMut<'_>],
376+
flags: c_int,
377+
) -> io::Result<(usize, bool, SockAddr)> {
378+
let mut nread = 0;
379+
let mut flags = flags as DWORD;
380+
let mut storage: SOCKADDR_STORAGE = unsafe { mem::zeroed() };
381+
let mut addrlen = mem::size_of_val(&storage) as c_int;
382+
let ret = unsafe {
383+
sock::WSARecvFrom(
384+
self.socket,
385+
bufs.as_mut_ptr() as *mut WSABUF,
386+
bufs.len().min(DWORD::MAX as usize) as DWORD,
387+
&mut nread,
388+
&mut flags,
389+
&mut storage as *mut SOCKADDR_STORAGE as *mut SOCKADDR,
390+
&mut addrlen,
391+
ptr::null_mut(),
392+
None,
393+
)
394+
};
395+
396+
let truncated;
397+
if ret == 0 {
398+
truncated = false;
399+
} else {
400+
let error = last_error();
401+
if error.raw_os_error() == Some(sock::WSAEMSGSIZE) {
402+
truncated = true;
403+
} else {
404+
return Err(error);
405+
}
406+
}
407+
408+
let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen) };
409+
Ok((nread as usize, truncated, addr))
410+
}
411+
341412
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
342413
unsafe {
343414
let n = {
@@ -376,6 +447,51 @@ impl Socket {
376447
}
377448
}
378449

450+
pub fn send_vectored(&self, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
451+
let mut nsent = 0;
452+
let ret = unsafe {
453+
sock::WSASend(
454+
self.socket,
455+
bufs.as_ptr() as *mut WSABUF,
456+
bufs.len().min(DWORD::MAX as usize) as DWORD,
457+
&mut nsent,
458+
flags as DWORD,
459+
std::ptr::null_mut(),
460+
None,
461+
)
462+
};
463+
match ret {
464+
0 => Ok(nsent as usize),
465+
_ => Err(last_error()),
466+
}
467+
}
468+
469+
pub fn send_to_vectored(
470+
&self,
471+
bufs: &[IoSlice<'_>],
472+
flags: c_int,
473+
addr: &SockAddr,
474+
) -> io::Result<usize> {
475+
let mut nsent = 0;
476+
let ret = unsafe {
477+
sock::WSASendTo(
478+
self.socket,
479+
bufs.as_ptr() as *mut WSABUF,
480+
bufs.len().min(DWORD::MAX as usize) as DWORD,
481+
&mut nsent,
482+
flags as DWORD,
483+
addr.as_ptr(),
484+
addr.len(),
485+
std::ptr::null_mut(),
486+
None,
487+
)
488+
};
489+
match ret {
490+
0 => Ok(nsent as usize),
491+
_ => Err(last_error()),
492+
}
493+
}
494+
379495
// ================================================
380496

381497
pub fn ttl(&self) -> io::Result<u32> {

0 commit comments

Comments
 (0)