1 use super::{sockaddr_un, SocketAddr};
2 use crate::convert::TryFrom;
3 use crate::io::{self, IoSlice, IoSliceMut};
4 use crate::marker::PhantomData;
5 use crate::mem::{size_of, zeroed};
6 use crate::os::unix::io::RawFd;
8 use crate::ptr::{eq, read_unaligned};
9 use crate::slice::from_raw_parts;
10 use crate::sys::net::Socket;
12 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
13 #[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))]
14 #[allow(non_camel_case_types)]
24 pub(super) fn recv_vectored_with_ancillary_from(
26 bufs: &mut [IoSliceMut<'_>],
27 ancillary: &mut SocketAncillary<'_>,
28 ) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
30 let mut msg_name: libc::sockaddr_un = zeroed();
31 let mut msg: libc::msghdr = zeroed();
32 msg.msg_name = &mut msg_name as *mut _ as *mut _;
33 msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
34 msg.msg_iov = bufs.as_mut_ptr().cast();
36 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
37 msg.msg_iovlen = bufs.len() as libc::size_t;
38 msg.msg_controllen = ancillary.buffer.len() as libc::size_t;
40 target_os = "dragonfly",
41 target_os = "emscripten",
42 target_os = "freebsd",
43 all(target_os = "linux", target_env = "musl",),
46 target_os = "openbsd",
48 msg.msg_iovlen = bufs.len() as libc::c_int;
49 msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
52 // macos requires that the control pointer is null when the len is 0.
53 if msg.msg_controllen > 0 {
54 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
57 let count = socket.recv_msg(&mut msg)?;
59 ancillary.length = msg.msg_controllen as usize;
60 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
62 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
63 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
65 Ok((count, truncated, addr))
69 pub(super) fn send_vectored_with_ancillary_to(
73 ancillary: &mut SocketAncillary<'_>,
74 ) -> io::Result<usize> {
76 let (mut msg_name, msg_namelen) =
77 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
79 let mut msg: libc::msghdr = zeroed();
80 msg.msg_name = &mut msg_name as *mut _ as *mut _;
81 msg.msg_namelen = msg_namelen;
82 msg.msg_iov = bufs.as_ptr() as *mut _;
84 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
85 msg.msg_iovlen = bufs.len() as libc::size_t;
86 msg.msg_controllen = ancillary.length as libc::size_t;
88 target_os = "dragonfly",
89 target_os = "emscripten",
90 target_os = "freebsd",
91 all(target_os = "linux", target_env = "musl",),
94 target_os = "openbsd",
96 msg.msg_iovlen = bufs.len() as libc::c_int;
97 msg.msg_controllen = ancillary.length as libc::socklen_t;
100 // macos requires that the control pointer is null when the len is 0.
101 if msg.msg_controllen > 0 {
102 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
105 ancillary.truncated = false;
107 socket.send_msg(&mut msg)
111 fn add_to_ancillary_data<T>(
115 cmsg_level: libc::c_int,
116 cmsg_type: libc::c_int,
118 let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
119 if let Ok(source_len) = u32::try_from(source_len) {
129 let additional_space = libc::CMSG_SPACE(source_len) as usize;
131 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
137 if new_length > buffer.len() {
141 buffer[*length..new_length].fill(0);
143 *length = new_length;
145 let mut msg: libc::msghdr = zeroed();
146 msg.msg_control = buffer.as_mut_ptr().cast();
148 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
149 msg.msg_controllen = *length as libc::size_t;
151 target_os = "dragonfly",
152 target_os = "emscripten",
153 target_os = "freebsd",
154 all(target_os = "linux", target_env = "musl",),
156 target_os = "netbsd",
157 target_os = "openbsd",
159 msg.msg_controllen = *length as libc::socklen_t;
163 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
164 let mut previous_cmsg = cmsg;
165 while !cmsg.is_null() {
166 previous_cmsg = cmsg;
167 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
169 // Most operating systems, but not Linux or emscripten, return the previous pointer
170 // when its length is zero. Therefore, check if the previous pointer is the same as
172 if eq(cmsg, previous_cmsg) {
177 if previous_cmsg.is_null() {
181 (*previous_cmsg).cmsg_level = cmsg_level;
182 (*previous_cmsg).cmsg_type = cmsg_type;
184 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
185 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t;
187 target_os = "dragonfly",
188 target_os = "emscripten",
189 target_os = "freebsd",
190 all(target_os = "linux", target_env = "musl",),
192 target_os = "netbsd",
193 target_os = "openbsd",
195 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t;
199 let data = libc::CMSG_DATA(previous_cmsg).cast();
201 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
206 struct AncillaryDataIter<'a, T> {
208 phantom: PhantomData<T>,
211 impl<'a, T> AncillaryDataIter<'a, T> {
212 /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
216 /// `data` must contain a valid control message.
217 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
218 AncillaryDataIter { data, phantom: PhantomData }
222 impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
225 fn next(&mut self) -> Option<T> {
226 if size_of::<T>() <= self.data.len() {
228 let unit = read_unaligned(self.data.as_ptr().cast());
229 self.data = &self.data[size_of::<T>()..];
239 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
240 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
242 pub struct SocketCred(libc::ucred);
244 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
246 /// Create a Unix credential struct.
248 /// PID, UID and GID is set to 0.
249 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
250 pub fn new() -> SocketCred {
251 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
255 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
256 pub fn set_pid(&mut self, pid: libc::pid_t) {
260 /// Get the current PID.
261 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
262 pub fn get_pid(&self) -> libc::pid_t {
267 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
268 pub fn set_uid(&mut self, uid: libc::uid_t) {
272 /// Get the current UID.
273 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
274 pub fn get_uid(&self) -> libc::uid_t {
279 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
280 pub fn set_gid(&mut self, gid: libc::gid_t) {
284 /// Get the current GID.
285 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
286 pub fn get_gid(&self) -> libc::gid_t {
291 /// This control message contains file descriptors.
293 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
294 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
295 pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
297 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
298 impl<'a> Iterator for ScmRights<'a> {
301 fn next(&mut self) -> Option<RawFd> {
306 /// This control message contains unix credentials.
308 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
309 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
310 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
311 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
313 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
314 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
315 impl<'a> Iterator for ScmCredentials<'a> {
316 type Item = SocketCred;
318 fn next(&mut self) -> Option<SocketCred> {
319 Some(SocketCred(self.0.next()?))
323 /// The error type which is returned from parsing the type a control message.
326 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
327 pub enum AncillaryError {
328 Unknown { cmsg_level: i32, cmsg_type: i32 },
331 /// This enum represent one control message of variable type.
332 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
333 pub enum AncillaryData<'a> {
334 ScmRights(ScmRights<'a>),
335 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
336 ScmCredentials(ScmCredentials<'a>),
339 impl<'a> AncillaryData<'a> {
340 /// Create a `AncillaryData::ScmRights` variant.
344 /// `data` must contain a valid control message and the control message must be type of
345 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
346 unsafe fn as_rights(data: &'a [u8]) -> Self {
347 let ancillary_data_iter = AncillaryDataIter::new(data);
348 let scm_rights = ScmRights(ancillary_data_iter);
349 AncillaryData::ScmRights(scm_rights)
352 /// Create a `AncillaryData::ScmCredentials` variant.
356 /// `data` must contain a valid control message and the control message must be type of
357 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
358 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
359 unsafe fn as_credentials(data: &'a [u8]) -> Self {
360 let ancillary_data_iter = AncillaryDataIter::new(data);
361 let scm_credentials = ScmCredentials(ancillary_data_iter);
362 AncillaryData::ScmCredentials(scm_credentials)
365 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
369 target_os = "android",
370 all(target_os = "linux", target_env = "gnu"),
371 all(target_os = "linux", target_env = "uclibc"),
373 let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t;
375 target_os = "dragonfly",
376 target_os = "emscripten",
377 target_os = "freebsd",
378 all(target_os = "linux", target_env = "musl",),
380 target_os = "netbsd",
381 target_os = "openbsd",
383 let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t;
386 let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
387 let data = libc::CMSG_DATA(cmsg).cast();
388 let data = from_raw_parts(data, data_len as usize);
390 match (*cmsg).cmsg_level {
391 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
392 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
393 #[cfg(any(target_os = "android", target_os = "linux",))]
394 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
396 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
400 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
407 /// This struct is used to iterate through the control messages.
408 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
409 pub struct Messages<'a> {
411 current: Option<&'a libc::cmsghdr>,
414 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
415 impl<'a> Iterator for Messages<'a> {
416 type Item = Result<AncillaryData<'a>, AncillaryError>;
418 fn next(&mut self) -> Option<Self::Item> {
420 let mut msg: libc::msghdr = zeroed();
421 msg.msg_control = self.buffer.as_ptr() as *mut _;
423 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
424 msg.msg_controllen = self.buffer.len() as libc::size_t;
426 target_os = "dragonfly",
427 target_os = "emscripten",
428 target_os = "freebsd",
429 all(target_os = "linux", target_env = "musl",),
431 target_os = "netbsd",
432 target_os = "openbsd",
434 msg.msg_controllen = self.buffer.len() as libc::socklen_t;
438 let cmsg = if let Some(current) = self.current {
439 libc::CMSG_NXTHDR(&msg, current)
441 libc::CMSG_FIRSTHDR(&msg)
444 let cmsg = cmsg.as_ref()?;
446 // Most operating systems, but not Linux or emscripten, return the previous pointer
447 // when its length is zero. Therefore, check if the previous pointer is the same as
449 if let Some(current) = self.current {
450 if eq(current, cmsg) {
455 self.current = Some(cmsg);
456 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
457 Some(ancillary_result)
462 /// A Unix socket Ancillary data struct.
466 /// #![feature(unix_socket_ancillary_data)]
467 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
468 /// use std::io::IoSliceMut;
470 /// fn main() -> std::io::Result<()> {
471 /// let sock = UnixStream::connect("/tmp/sock")?;
473 /// let mut fds = [0; 8];
474 /// let mut ancillary_buffer = [0; 128];
475 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
477 /// let mut buf = [1; 8];
478 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
479 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
481 /// for ancillary_result in ancillary.messages() {
482 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
483 /// for fd in scm_rights {
484 /// println!("receive file descriptor: {}", fd);
491 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
493 pub struct SocketAncillary<'a> {
494 buffer: &'a mut [u8],
499 impl<'a> SocketAncillary<'a> {
500 /// Create an ancillary data with the given buffer.
505 /// # #![allow(unused_mut)]
506 /// #![feature(unix_socket_ancillary_data)]
507 /// use std::os::unix::net::SocketAncillary;
508 /// let mut ancillary_buffer = [0; 128];
509 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
511 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
512 pub fn new(buffer: &'a mut [u8]) -> Self {
513 SocketAncillary { buffer, length: 0, truncated: false }
516 /// Returns the capacity of the buffer.
517 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
518 pub fn capacity(&self) -> usize {
522 /// Returns `true` if the ancillary data is empty.
523 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
524 pub fn is_empty(&self) -> bool {
528 /// Returns the number of used bytes.
529 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
530 pub fn len(&self) -> usize {
534 /// Returns the iterator of the control messages.
535 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
536 pub fn messages(&self) -> Messages<'_> {
537 Messages { buffer: &self.buffer[..self.length], current: None }
540 /// Is `true` if during a recv operation the ancillary was truncated.
545 /// #![feature(unix_socket_ancillary_data)]
546 /// use std::os::unix::net::{UnixStream, SocketAncillary};
547 /// use std::io::IoSliceMut;
549 /// fn main() -> std::io::Result<()> {
550 /// let sock = UnixStream::connect("/tmp/sock")?;
552 /// let mut ancillary_buffer = [0; 128];
553 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
555 /// let mut buf = [1; 8];
556 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
557 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
559 /// println!("Is truncated: {}", ancillary.truncated());
563 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
564 pub fn truncated(&self) -> bool {
568 /// Add file descriptors to the ancillary data.
570 /// The function returns `true` if there was enough space in the buffer.
571 /// If there was not enough space then no file descriptors was appended.
572 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
573 /// and type `SCM_RIGHTS`.
578 /// #![feature(unix_socket_ancillary_data)]
579 /// use std::os::unix::net::{UnixStream, SocketAncillary};
580 /// use std::os::unix::io::AsRawFd;
581 /// use std::io::IoSlice;
583 /// fn main() -> std::io::Result<()> {
584 /// let sock = UnixStream::connect("/tmp/sock")?;
586 /// let mut ancillary_buffer = [0; 128];
587 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
588 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
590 /// let mut buf = [1; 8];
591 /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
592 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
596 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
597 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
598 self.truncated = false;
599 add_to_ancillary_data(
608 /// Add credentials to the ancillary data.
610 /// The function returns `true` if there was enough space in the buffer.
611 /// If there was not enough space then no credentials was appended.
612 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
613 /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
615 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
616 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
617 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
618 self.truncated = false;
619 add_to_ancillary_data(
624 libc::SCM_CREDENTIALS,
628 /// Clears the ancillary data, removing all values.
633 /// #![feature(unix_socket_ancillary_data)]
634 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
635 /// use std::io::IoSliceMut;
637 /// fn main() -> std::io::Result<()> {
638 /// let sock = UnixStream::connect("/tmp/sock")?;
640 /// let mut fds1 = [0; 8];
641 /// let mut fds2 = [0; 8];
642 /// let mut ancillary_buffer = [0; 128];
643 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
645 /// let mut buf = [1; 8];
646 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
648 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
649 /// for ancillary_result in ancillary.messages() {
650 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
651 /// for fd in scm_rights {
652 /// println!("receive file descriptor: {}", fd);
657 /// ancillary.clear();
659 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
660 /// for ancillary_result in ancillary.messages() {
661 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
662 /// for fd in scm_rights {
663 /// println!("receive file descriptor: {}", fd);
670 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
671 pub fn clear(&mut self) {
673 self.truncated = false;