unix: Extend UnixStream and UnixDatagram to send and receive file descriptors
Add the functions `recv_vectored_fds` and `send_vectored_fds` to send and receive file descriptors, by using `recvmsg` and `sendmsg` system call.
This commit is contained in:
parent
7477d445c8
commit
0b3c9d8465
3 changed files with 1111 additions and 0 deletions
|
@ -25,7 +25,10 @@ use crate::net::{self, Shutdown};
|
|||
use crate::os::unix::ffi::OsStrExt;
|
||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::path::Path;
|
||||
use crate::ptr::null_mut;
|
||||
use crate::slice::from_raw_parts;
|
||||
use crate::sys::net::Socket;
|
||||
use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter};
|
||||
use crate::sys::{self, cvt};
|
||||
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
@ -114,6 +117,62 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl
|
|||
Ok((addr, len as libc::socklen_t))
|
||||
}
|
||||
|
||||
fn recv_vectored_with_ancillary_from(
|
||||
socket: &Socket,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
|
||||
unsafe {
|
||||
let mut msg_name: libc::sockaddr_un = mem::zeroed();
|
||||
|
||||
let mut msg = libc::msghdr {
|
||||
msg_name: &mut msg_name as *mut _ as *mut _,
|
||||
msg_namelen: mem::size_of::<libc::sockaddr_un>() as libc::socklen_t,
|
||||
msg_iov: bufs.as_mut_ptr().cast(),
|
||||
msg_iovlen: bufs.len(),
|
||||
msg_control: ancillary.buffer.as_mut_ptr().cast(),
|
||||
msg_controllen: ancillary.buffer.len(),
|
||||
msg_flags: 0,
|
||||
};
|
||||
|
||||
let count = socket.recv_msg(&mut msg)?;
|
||||
|
||||
ancillary.length = msg.msg_controllen;
|
||||
ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
|
||||
|
||||
let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
|
||||
let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
|
||||
|
||||
Ok((count, truncated, addr))
|
||||
}
|
||||
}
|
||||
|
||||
fn send_vectored_with_ancillary_to(
|
||||
socket: &Socket,
|
||||
path: Option<&Path>,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let (mut msg_name, msg_namelen) =
|
||||
if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) };
|
||||
|
||||
let mut msg = libc::msghdr {
|
||||
msg_name: &mut msg_name as *mut _ as *mut _,
|
||||
msg_namelen,
|
||||
msg_iov: bufs.as_mut_ptr().cast(),
|
||||
msg_iovlen: bufs.len(),
|
||||
msg_control: ancillary.buffer.as_mut_ptr().cast(),
|
||||
msg_controllen: ancillary.length,
|
||||
msg_flags: 0,
|
||||
};
|
||||
|
||||
ancillary.truncated = false;
|
||||
|
||||
socket.send_msg(&mut msg)
|
||||
}
|
||||
}
|
||||
|
||||
enum AddressKind<'a> {
|
||||
Unnamed,
|
||||
Pathname(&'a Path),
|
||||
|
@ -269,6 +328,556 @@ impl fmt::Debug for SocketAddr {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
impl<'a> Iterator for ScmRights<'a> {
|
||||
type Item = RawFd;
|
||||
|
||||
fn next(&mut self) -> Option<RawFd> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
impl<'a> Iterator for ScmCredentials<'a> {
|
||||
type Item = libc::ucred;
|
||||
|
||||
fn next(&mut self) -> Option<libc::ucred> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub enum AncillaryData<'a> {
|
||||
ScmRights(ScmRights<'a>),
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
ScmCredentials(ScmCredentials<'a>),
|
||||
}
|
||||
|
||||
impl<'a> AncillaryData<'a> {
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
fn as_rights(data: &'a [u8]) -> Self {
|
||||
let ancillary_data_iter = AncillaryDataIter::new(data);
|
||||
let scm_rights = ScmRights(ancillary_data_iter);
|
||||
AncillaryData::ScmRights(scm_rights)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
fn as_credentials(data: &'a [u8]) -> Self {
|
||||
let ancillary_data_iter = AncillaryDataIter::new(data);
|
||||
let scm_credentials = ScmCredentials(ancillary_data_iter);
|
||||
AncillaryData::ScmCredentials(scm_credentials)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
impl<'a> AncillaryData<'a> {
|
||||
fn from(cmsg: &'a libc::cmsghdr) -> Self {
|
||||
unsafe {
|
||||
let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
|
||||
let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
|
||||
let data = libc::CMSG_DATA(cmsg).cast();
|
||||
let data = from_raw_parts(data, data_len);
|
||||
|
||||
if (*cmsg).cmsg_level == libc::SOL_SOCKET {
|
||||
match (*cmsg).cmsg_type {
|
||||
libc::SCM_RIGHTS => AncillaryData::as_rights(data),
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data),
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
))]
|
||||
libc::SCM_CREDS => AncillaryData::as_credentials(data),
|
||||
_ => panic!("Unknown cmsg type"),
|
||||
}
|
||||
} else {
|
||||
panic!("Unknown cmsg level");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub struct Messages<'a> {
|
||||
buffer: &'a [u8],
|
||||
current: Option<&'a libc::cmsghdr>,
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
impl<'a> Iterator for Messages<'a> {
|
||||
type Item = AncillaryData<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<AncillaryData<'a>> {
|
||||
unsafe {
|
||||
let msg = libc::msghdr {
|
||||
msg_name: null_mut(),
|
||||
msg_namelen: 0,
|
||||
msg_iov: null_mut(),
|
||||
msg_iovlen: 0,
|
||||
msg_control: self.buffer.as_ptr() as *mut _,
|
||||
msg_controllen: self.buffer.len(),
|
||||
msg_flags: 0,
|
||||
};
|
||||
|
||||
let cmsg = if let Some(current) = self.current {
|
||||
libc::CMSG_NXTHDR(&msg, current)
|
||||
} else {
|
||||
libc::CMSG_FIRSTHDR(&msg)
|
||||
};
|
||||
|
||||
let cmsg = cmsg.as_ref()?;
|
||||
self.current = Some(cmsg);
|
||||
let ancillary_data = AncillaryData::from(cmsg);
|
||||
Some(ancillary_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Unix socket Ancillary data struct.
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixStream::connect("/tmp/sock")?;
|
||||
///
|
||||
/// let mut fds = [0; 8];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
///
|
||||
/// let mut buf = [1; 8];
|
||||
/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
|
||||
/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
///
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
#[derive(Debug)]
|
||||
pub struct SocketAncillary<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
length: usize,
|
||||
truncated: bool,
|
||||
}
|
||||
|
||||
impl<'a> SocketAncillary<'a> {
|
||||
/// Create an ancillary data with the given buffer.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![allow(unused_mut)]
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::SocketAncillary;
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn new(buffer: &'a mut [u8]) -> Self {
|
||||
SocketAncillary { buffer, length: 0, truncated: false }
|
||||
}
|
||||
|
||||
/// Returns the capacity of the buffer.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.buffer.len()
|
||||
}
|
||||
|
||||
/// Returns the number of used bytes.
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn len(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn messages(&'a self) -> Messages<'a> {
|
||||
Messages { buffer: &self.buffer[..self.length], current: None }
|
||||
}
|
||||
|
||||
/// Is `true` if during a recv operation the ancillary was truncated.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixStream::connect("/tmp/sock")?;
|
||||
///
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
///
|
||||
/// let mut buf = [1; 8];
|
||||
/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
|
||||
/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
///
|
||||
/// println!("Is truncated: {}", ancillary.truncated());
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn truncated(&self) -> bool {
|
||||
self.truncated
|
||||
}
|
||||
|
||||
/// Add file descriptors to the ancillary data.
|
||||
///
|
||||
/// The function returns `true` if there was enough space in the buffer.
|
||||
/// If there was not enough space then no file descriptors was appended.
|
||||
/// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
|
||||
/// and type `SCM_RIGHTS`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary};
|
||||
/// use std::os::unix::io::AsRawFd;
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixStream::connect("/tmp/sock")?;
|
||||
///
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// ancillary.add_fds(&[sock.as_raw_fd()][..]);
|
||||
///
|
||||
/// let mut buf = [1; 8];
|
||||
/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
|
||||
/// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(
|
||||
target_os = "haiku",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
|
||||
self.truncated = false;
|
||||
add_to_ancillary_data(
|
||||
&mut self.buffer,
|
||||
&mut self.length,
|
||||
fds,
|
||||
libc::SOL_SOCKET,
|
||||
libc::SCM_RIGHTS,
|
||||
)
|
||||
}
|
||||
|
||||
/// Add credentials to the ancillary data.
|
||||
///
|
||||
/// The function returns `true` if there was enough space in the buffer.
|
||||
/// If there was not enough space then no credentials was appended.
|
||||
/// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
|
||||
/// and type `SCM_CREDENTIALS`.
|
||||
///
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool {
|
||||
self.truncated = false;
|
||||
add_to_ancillary_data(
|
||||
&mut self.buffer,
|
||||
&mut self.length,
|
||||
creds,
|
||||
libc::SOL_SOCKET,
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
))]
|
||||
libc::SCM_CREDENTIALS,
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
))]
|
||||
libc::SCM_CREDS,
|
||||
)
|
||||
}
|
||||
|
||||
/// Clears the ancillary data, removing all values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixStream::connect("/tmp/sock")?;
|
||||
///
|
||||
/// let mut fds1 = [0; 8];
|
||||
/// let mut fds2 = [0; 8];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
///
|
||||
/// let mut buf = [1; 8];
|
||||
/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
|
||||
///
|
||||
/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ancillary.clear();
|
||||
///
|
||||
/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn clear(&mut self) {
|
||||
self.length = 0;
|
||||
self.truncated = false;
|
||||
}
|
||||
}
|
||||
|
||||
struct AsciiEscaped<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> fmt::Display for AsciiEscaped<'a> {
|
||||
|
@ -646,6 +1255,91 @@ impl UnixStream {
|
|||
self.0.shutdown(how)
|
||||
}
|
||||
|
||||
/// Receives data and ancillary data from socket.
|
||||
///
|
||||
/// On success, returns the number of bytes read.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock")?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let mut fds = [0; 8];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
/// println!("received {}", size);
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn recv_vectored_with_ancillary(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<usize> {
|
||||
let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
/// Sends data and ancillary data on the socket.
|
||||
///
|
||||
/// On success, returns the number of bytes written.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixStream, SocketAncillary};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock")?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let fds = [0, 1, 2];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// ancillary.add_fds(&fds[..]);
|
||||
/// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn send_vectored_with_ancillary(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<usize> {
|
||||
send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
|
||||
}
|
||||
|
||||
/// Receives data on the socket from the remote address to which it is
|
||||
/// connected, without removing that data from the queue. On success,
|
||||
/// returns the number of bytes peeked.
|
||||
|
@ -1439,6 +2133,102 @@ impl UnixDatagram {
|
|||
self.0.read(buf)
|
||||
}
|
||||
|
||||
/// Receives data and ancillary data from socket.
|
||||
///
|
||||
/// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixDatagram::unbound()?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let mut fds = [0; 8];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
|
||||
/// println!("received {}", size);
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn recv_vectored_with_ancillary_from(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<(usize, bool, SocketAddr)> {
|
||||
let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
|
||||
let addr = addr?;
|
||||
|
||||
Ok((count, truncated, addr))
|
||||
}
|
||||
|
||||
/// Receives data and ancillary data from socket.
|
||||
///
|
||||
/// On success, returns the number of bytes read and if the data was truncated.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixDatagram::unbound()?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let mut fds = [0; 8];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
|
||||
/// println!("received {}", size);
|
||||
/// for ancillary_data in ancillary.messages() {
|
||||
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
|
||||
/// for fd in scm_rights {
|
||||
/// println!("receive file descriptor: {}", fd);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn recv_vectored_with_ancillary(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<(usize, bool)> {
|
||||
let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
|
||||
addr?;
|
||||
|
||||
Ok((count, truncated))
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the specified address.
|
||||
///
|
||||
/// On success, returns the number of bytes written.
|
||||
|
@ -1498,6 +2288,83 @@ impl UnixDatagram {
|
|||
self.0.write(buf)
|
||||
}
|
||||
|
||||
/// Sends data and ancillary data on the socket to the specified address.
|
||||
///
|
||||
/// On success, returns the number of bytes written.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixDatagram, SocketAncillary};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixDatagram::unbound()?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let fds = [0, 1, 2];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// ancillary.add_fds(&fds[..]);
|
||||
/// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
path: P,
|
||||
) -> io::Result<usize> {
|
||||
send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
|
||||
}
|
||||
|
||||
/// Sends data and ancillary data on the socket.
|
||||
///
|
||||
/// On success, returns the number of bytes written.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_socket_ancillary_data)]
|
||||
/// use std::os::unix::net::{UnixDatagram, SocketAncillary};
|
||||
/// use std::io::IoSliceMut;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixDatagram::unbound()?;
|
||||
/// let mut buf1 = [1; 8];
|
||||
/// let mut buf2 = [2; 16];
|
||||
/// let mut buf3 = [3; 8];
|
||||
/// let mut bufs = &mut [
|
||||
/// IoSliceMut::new(&mut buf1),
|
||||
/// IoSliceMut::new(&mut buf2),
|
||||
/// IoSliceMut::new(&mut buf3),
|
||||
/// ][..];
|
||||
/// let fds = [0, 1, 2];
|
||||
/// let mut ancillary_buffer = [0; 128];
|
||||
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
|
||||
/// ancillary.add_fds(&fds[..]);
|
||||
/// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
|
||||
pub fn send_vectored_with_ancillary(
|
||||
&self,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
ancillary: &mut SocketAncillary<'_>,
|
||||
) -> io::Result<usize> {
|
||||
send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
|
||||
}
|
||||
|
||||
/// Sets the read timeout for the socket.
|
||||
///
|
||||
/// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
|
||||
|
|
|
@ -452,3 +452,155 @@ fn test_unix_datagram_peek_from() {
|
|||
assert_eq!(size, 11);
|
||||
assert_eq!(msg, &buf[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_send_vectored_fds_unix_stream() {
|
||||
let (s1, s2) = or_panic!(UnixStream::pair());
|
||||
|
||||
let mut buf1 = [1; 8];
|
||||
let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
|
||||
|
||||
let mut ancillary1_buffer = [0; 128];
|
||||
let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
|
||||
assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
|
||||
|
||||
let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
|
||||
assert_eq!(usize, 8);
|
||||
|
||||
let mut buf2 = [0; 8];
|
||||
let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
|
||||
|
||||
let mut ancillary2_buffer = [0; 128];
|
||||
let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
|
||||
|
||||
let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
|
||||
assert_eq!(usize, 8);
|
||||
assert_eq!(buf1, buf2);
|
||||
|
||||
let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
|
||||
assert_eq!(ancillary_data_vec.len(), 1);
|
||||
if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() {
|
||||
let fd_vec = Vec::from_iter(scm_rights);
|
||||
assert_eq!(fd_vec.len(), 1);
|
||||
unsafe {
|
||||
libc::close(fd_vec[0]);
|
||||
}
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_send_vectored_with_ancillary_to_unix_datagram() {
|
||||
fn getpid() -> libc::pid_t {
|
||||
unsafe { libc::getpid() }
|
||||
}
|
||||
|
||||
fn getuid() -> libc::uid_t {
|
||||
unsafe { libc::getuid() }
|
||||
}
|
||||
|
||||
fn getgid() -> libc::gid_t {
|
||||
unsafe { libc::getgid() }
|
||||
}
|
||||
|
||||
let dir = tmpdir();
|
||||
let path1 = dir.path().join("sock1");
|
||||
let path2 = dir.path().join("sock2");
|
||||
|
||||
let bsock1 = or_panic!(UnixDatagram::bind(&path1));
|
||||
let bsock2 = or_panic!(UnixDatagram::bind(&path2));
|
||||
|
||||
unsafe {
|
||||
let optval: libc::c_int = 1;
|
||||
libc::setsockopt(
|
||||
bsock2.as_raw_fd(),
|
||||
libc::SOL_SOCKET,
|
||||
libc::SO_PASSCRED,
|
||||
&optval as *const _ as *const _,
|
||||
mem::size_of::<libc::c_int>() as u32,
|
||||
);
|
||||
}
|
||||
|
||||
let mut buf1 = [1; 8];
|
||||
let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
|
||||
|
||||
let mut ancillary1_buffer = [0; 128];
|
||||
let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
|
||||
let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() };
|
||||
assert!(ancillary1.add_creds(&[cred1][..]));
|
||||
|
||||
let usize =
|
||||
or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2));
|
||||
assert_eq!(usize, 8);
|
||||
|
||||
let mut buf2 = [0; 8];
|
||||
let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
|
||||
|
||||
let mut ancillary2_buffer = [0; 128];
|
||||
let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
|
||||
|
||||
let (usize, truncated, _addr) =
|
||||
or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
|
||||
assert_eq!(ancillary2.truncated(), false);
|
||||
assert_eq!(usize, 8);
|
||||
assert_eq!(truncated, false);
|
||||
assert_eq!(buf1, buf2);
|
||||
|
||||
let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
|
||||
assert_eq!(ancillary_data_vec.len(), 1);
|
||||
if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() {
|
||||
let cred_vec = Vec::from_iter(scm_credentials);
|
||||
assert_eq!(cred_vec.len(), 1);
|
||||
assert_eq!(cred1.pid, cred_vec[0].pid);
|
||||
assert_eq!(cred1.uid, cred_vec[0].uid);
|
||||
assert_eq!(cred1.gid, cred_vec[0].gid);
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_send_vectored_with_ancillary_unix_datagram() {
|
||||
let dir = tmpdir();
|
||||
let path1 = dir.path().join("sock1");
|
||||
let path2 = dir.path().join("sock2");
|
||||
|
||||
let bsock1 = or_panic!(UnixDatagram::bind(&path1));
|
||||
let bsock2 = or_panic!(UnixDatagram::bind(&path2));
|
||||
|
||||
let mut buf1 = [1; 8];
|
||||
let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
|
||||
|
||||
let mut ancillary1_buffer = [0; 128];
|
||||
let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
|
||||
assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
|
||||
|
||||
or_panic!(bsock1.connect(&path2));
|
||||
let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
|
||||
assert_eq!(usize, 8);
|
||||
|
||||
let mut buf2 = [0; 8];
|
||||
let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
|
||||
|
||||
let mut ancillary2_buffer = [0; 128];
|
||||
let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
|
||||
|
||||
let (usize, truncated) =
|
||||
or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
|
||||
assert_eq!(usize, 8);
|
||||
assert_eq!(truncated, false);
|
||||
assert_eq!(buf1, buf2);
|
||||
|
||||
let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
|
||||
assert_eq!(ancillary_data_vec.len(), 1);
|
||||
if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() {
|
||||
let fd_vec = Vec::from_iter(scm_rights);
|
||||
assert_eq!(fd_vec.len(), 1);
|
||||
unsafe {
|
||||
libc::close(fd_vec[0]);
|
||||
}
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
use crate::net::{Shutdown, SocketAddr};
|
||||
use crate::ptr::null_mut;
|
||||
use crate::str;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
|
||||
|
@ -18,6 +20,86 @@ pub extern crate libc as netc;
|
|||
|
||||
pub type wrlen_t = size_t;
|
||||
|
||||
pub struct AncillaryDataIter<'a, T> {
|
||||
data: &'a [u8],
|
||||
phantom: crate::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> AncillaryDataIter<'a, T> {
|
||||
pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
|
||||
AncillaryDataIter { data, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
let mut unit = mem::zeroed();
|
||||
if mem::size_of::<T>() <= self.data.len() {
|
||||
let unit_ptr: *mut T = &mut unit;
|
||||
libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::<T>());
|
||||
self.data = &self.data[mem::size_of::<T>()..];
|
||||
Some(unit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_to_ancillary_data<T: core::clone::Clone>(
|
||||
buffer: &mut [u8],
|
||||
length: &mut usize,
|
||||
source: &[T],
|
||||
cmsg_level: libc::c_int,
|
||||
cmsg_type: libc::c_int,
|
||||
) -> bool {
|
||||
let len = (source.len() * mem::size_of::<T>()) as u32;
|
||||
|
||||
unsafe {
|
||||
let additional_space = libc::CMSG_SPACE(len) as usize;
|
||||
if *length + additional_space > buffer.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space);
|
||||
|
||||
*length += additional_space;
|
||||
|
||||
let msg = libc::msghdr {
|
||||
msg_name: null_mut(),
|
||||
msg_namelen: 0,
|
||||
msg_iov: null_mut(),
|
||||
msg_iovlen: 0,
|
||||
msg_control: buffer.as_mut_ptr().cast(),
|
||||
msg_controllen: *length,
|
||||
msg_flags: 0,
|
||||
};
|
||||
|
||||
let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
|
||||
let mut previous_cmsg = cmsg;
|
||||
while !cmsg.is_null() {
|
||||
previous_cmsg = cmsg;
|
||||
cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
|
||||
}
|
||||
|
||||
if previous_cmsg.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*previous_cmsg).cmsg_level = cmsg_level;
|
||||
(*previous_cmsg).cmsg_type = cmsg_type;
|
||||
(*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize;
|
||||
|
||||
let data = libc::CMSG_DATA(previous_cmsg).cast();
|
||||
|
||||
libc::memcpy(data, source.as_ptr().cast(), len as usize);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub struct Socket(FileDesc);
|
||||
|
||||
pub fn init() {}
|
||||
|
@ -237,6 +319,11 @@ impl Socket {
|
|||
self.recv_from_with_flags(buf, 0)
|
||||
}
|
||||
|
||||
pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
|
||||
let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
self.recv_from_with_flags(buf, MSG_PEEK)
|
||||
}
|
||||
|
@ -254,6 +341,11 @@ impl Socket {
|
|||
self.0.is_write_vectored()
|
||||
}
|
||||
|
||||
pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
|
||||
let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
|
||||
let timeout = match dur {
|
||||
Some(dur) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue