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"), not(target_os = "netbsd")))]
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();
35 msg.msg_iovlen = bufs.len() as _;
36 msg.msg_controllen = ancillary.buffer.len() as _;
37 // macos requires that the control pointer is null when the len is 0.
38 if msg.msg_controllen > 0 {
39 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
42 let count = socket.recv_msg(&mut msg)?;
44 ancillary.length = msg.msg_controllen as usize;
45 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
47 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
48 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
50 Ok((count, truncated, addr))
54 pub(super) fn send_vectored_with_ancillary_to(
58 ancillary: &mut SocketAncillary<'_>,
59 ) -> io::Result<usize> {
61 let (mut msg_name, msg_namelen) =
62 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
64 let mut msg: libc::msghdr = zeroed();
65 msg.msg_name = &mut msg_name as *mut _ as *mut _;
66 msg.msg_namelen = msg_namelen;
67 msg.msg_iov = bufs.as_ptr() as *mut _;
68 msg.msg_iovlen = bufs.len() as _;
69 msg.msg_controllen = ancillary.length as _;
70 // macos requires that the control pointer is null when the len is 0.
71 if msg.msg_controllen > 0 {
72 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
75 ancillary.truncated = false;
77 socket.send_msg(&mut msg)
81 fn add_to_ancillary_data<T>(
85 cmsg_level: libc::c_int,
86 cmsg_type: libc::c_int,
88 let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
89 if let Ok(source_len) = u32::try_from(source_len) {
99 let additional_space = libc::CMSG_SPACE(source_len) as usize;
101 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
107 if new_length > buffer.len() {
111 buffer[*length..new_length].fill(0);
113 *length = new_length;
115 let mut msg: libc::msghdr = zeroed();
116 msg.msg_control = buffer.as_mut_ptr().cast();
117 msg.msg_controllen = *length as _;
119 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
120 let mut previous_cmsg = cmsg;
121 while !cmsg.is_null() {
122 previous_cmsg = cmsg;
123 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
125 // Most operating systems, but not Linux or emscripten, return the previous pointer
126 // when its length is zero. Therefore, check if the previous pointer is the same as
128 if eq(cmsg, previous_cmsg) {
133 if previous_cmsg.is_null() {
137 (*previous_cmsg).cmsg_level = cmsg_level;
138 (*previous_cmsg).cmsg_type = cmsg_type;
139 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
141 let data = libc::CMSG_DATA(previous_cmsg).cast();
143 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
148 struct AncillaryDataIter<'a, T> {
150 phantom: PhantomData<T>,
153 impl<'a, T> AncillaryDataIter<'a, T> {
154 /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
158 /// `data` must contain a valid control message.
159 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
160 AncillaryDataIter { data, phantom: PhantomData }
164 impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
167 fn next(&mut self) -> Option<T> {
168 if size_of::<T>() <= self.data.len() {
170 let unit = read_unaligned(self.data.as_ptr().cast());
171 self.data = &self.data[size_of::<T>()..];
180 #[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
181 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
183 pub struct SocketCred(());
186 #[cfg(any(target_os = "android", target_os = "linux",))]
187 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
189 pub struct SocketCred(libc::ucred);
191 #[cfg(target_os = "netbsd")]
192 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
194 pub struct SocketCred(libc::sockcred);
196 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
197 #[cfg(any(target_os = "android", target_os = "linux"))]
199 /// Create a Unix credential struct.
201 /// PID, UID and GID is set to 0.
202 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
204 pub fn new() -> SocketCred {
205 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
209 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
210 pub fn set_pid(&mut self, pid: libc::pid_t) {
214 /// Get the current PID.
216 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
217 pub fn get_pid(&self) -> libc::pid_t {
222 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
223 pub fn set_uid(&mut self, uid: libc::uid_t) {
227 /// Get the current UID.
229 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
230 pub fn get_uid(&self) -> libc::uid_t {
235 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
236 pub fn set_gid(&mut self, gid: libc::gid_t) {
240 /// Get the current GID.
242 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
243 pub fn get_gid(&self) -> libc::gid_t {
248 #[cfg(target_os = "netbsd")]
250 /// Create a Unix credential struct.
252 /// PID, UID and GID is set to 0.
253 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
254 pub fn new() -> SocketCred {
255 SocketCred(libc::sockcred {
262 sc_groups: [0u32; 1],
267 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
268 pub fn set_pid(&mut self, pid: libc::pid_t) {
272 /// Get the current PID.
273 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
274 pub fn get_pid(&self) -> libc::pid_t {
279 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
280 pub fn set_uid(&mut self, uid: libc::uid_t) {
284 /// Get the current UID.
285 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
286 pub fn get_uid(&self) -> libc::uid_t {
291 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
292 pub fn set_gid(&mut self, gid: libc::gid_t) {
296 /// Get the current GID.
297 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
298 pub fn get_gid(&self) -> libc::gid_t {
303 /// This control message contains file descriptors.
305 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
306 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
307 pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
309 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
310 impl<'a> Iterator for ScmRights<'a> {
313 fn next(&mut self) -> Option<RawFd> {
318 #[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
319 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
320 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
322 /// This control message contains unix credentials.
324 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
325 #[cfg(any(target_os = "android", target_os = "linux",))]
326 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
327 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
329 #[cfg(target_os = "netbsd")]
330 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
331 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
333 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
334 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
335 impl<'a> Iterator for ScmCredentials<'a> {
336 type Item = SocketCred;
338 fn next(&mut self) -> Option<SocketCred> {
339 Some(SocketCred(self.0.next()?))
343 /// The error type which is returned from parsing the type a control message.
346 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
347 pub enum AncillaryError {
348 Unknown { cmsg_level: i32, cmsg_type: i32 },
351 /// This enum represent one control message of variable type.
352 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
353 pub enum AncillaryData<'a> {
354 ScmRights(ScmRights<'a>),
355 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
356 ScmCredentials(ScmCredentials<'a>),
359 impl<'a> AncillaryData<'a> {
360 /// Create an `AncillaryData::ScmRights` variant.
364 /// `data` must contain a valid control message and the control message must be type of
365 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
366 unsafe fn as_rights(data: &'a [u8]) -> Self {
367 let ancillary_data_iter = AncillaryDataIter::new(data);
368 let scm_rights = ScmRights(ancillary_data_iter);
369 AncillaryData::ScmRights(scm_rights)
372 /// Create an `AncillaryData::ScmCredentials` variant.
376 /// `data` must contain a valid control message and the control message must be type of
377 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
378 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
379 unsafe fn as_credentials(data: &'a [u8]) -> Self {
380 let ancillary_data_iter = AncillaryDataIter::new(data);
381 let scm_credentials = ScmCredentials(ancillary_data_iter);
382 AncillaryData::ScmCredentials(scm_credentials)
385 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
387 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
388 let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
389 let data = libc::CMSG_DATA(cmsg).cast();
390 let data = from_raw_parts(data, data_len);
392 match (*cmsg).cmsg_level {
393 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
394 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
395 #[cfg(any(target_os = "android", target_os = "linux",))]
396 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
397 #[cfg(target_os = "netbsd")]
398 libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
400 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
404 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
411 /// This struct is used to iterate through the control messages.
412 #[must_use = "iterators are lazy and do nothing unless consumed"]
413 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
414 pub struct Messages<'a> {
416 current: Option<&'a libc::cmsghdr>,
419 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
420 impl<'a> Iterator for Messages<'a> {
421 type Item = Result<AncillaryData<'a>, AncillaryError>;
423 fn next(&mut self) -> Option<Self::Item> {
425 let mut msg: libc::msghdr = zeroed();
426 msg.msg_control = self.buffer.as_ptr() as *mut _;
427 msg.msg_controllen = self.buffer.len() as _;
429 let cmsg = if let Some(current) = self.current {
430 libc::CMSG_NXTHDR(&msg, current)
432 libc::CMSG_FIRSTHDR(&msg)
435 let cmsg = cmsg.as_ref()?;
437 // Most operating systems, but not Linux or emscripten, return the previous pointer
438 // when its length is zero. Therefore, check if the previous pointer is the same as
440 if let Some(current) = self.current {
441 if eq(current, cmsg) {
446 self.current = Some(cmsg);
447 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
448 Some(ancillary_result)
453 /// A Unix socket Ancillary data struct.
457 /// #![feature(unix_socket_ancillary_data)]
458 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
459 /// use std::io::IoSliceMut;
461 /// fn main() -> std::io::Result<()> {
462 /// let sock = UnixStream::connect("/tmp/sock")?;
464 /// let mut fds = [0; 8];
465 /// let mut ancillary_buffer = [0; 128];
466 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
468 /// let mut buf = [1; 8];
469 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
470 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
472 /// for ancillary_result in ancillary.messages() {
473 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
474 /// for fd in scm_rights {
475 /// println!("receive file descriptor: {fd}");
482 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
484 pub struct SocketAncillary<'a> {
485 buffer: &'a mut [u8],
490 impl<'a> SocketAncillary<'a> {
491 /// Create an ancillary data with the given buffer.
496 /// # #![allow(unused_mut)]
497 /// #![feature(unix_socket_ancillary_data)]
498 /// use std::os::unix::net::SocketAncillary;
499 /// let mut ancillary_buffer = [0; 128];
500 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
502 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
503 pub fn new(buffer: &'a mut [u8]) -> Self {
504 SocketAncillary { buffer, length: 0, truncated: false }
507 /// Returns the capacity of the buffer.
509 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
510 pub fn capacity(&self) -> usize {
514 /// Returns `true` if the ancillary data is empty.
516 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
517 pub fn is_empty(&self) -> bool {
521 /// Returns the number of used bytes.
523 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
524 pub fn len(&self) -> usize {
528 /// Returns the iterator of the control messages.
529 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
530 pub fn messages(&self) -> Messages<'_> {
531 Messages { buffer: &self.buffer[..self.length], current: None }
534 /// Is `true` if during a recv operation the ancillary was truncated.
539 /// #![feature(unix_socket_ancillary_data)]
540 /// use std::os::unix::net::{UnixStream, SocketAncillary};
541 /// use std::io::IoSliceMut;
543 /// fn main() -> std::io::Result<()> {
544 /// let sock = UnixStream::connect("/tmp/sock")?;
546 /// let mut ancillary_buffer = [0; 128];
547 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
549 /// let mut buf = [1; 8];
550 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
551 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
553 /// println!("Is truncated: {}", ancillary.truncated());
558 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
559 pub fn truncated(&self) -> bool {
563 /// Add file descriptors to the ancillary data.
565 /// The function returns `true` if there was enough space in the buffer.
566 /// If there was not enough space then no file descriptors was appended.
567 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
568 /// and type `SCM_RIGHTS`.
573 /// #![feature(unix_socket_ancillary_data)]
574 /// use std::os::unix::net::{UnixStream, SocketAncillary};
575 /// use std::os::unix::io::AsRawFd;
576 /// use std::io::IoSlice;
578 /// fn main() -> std::io::Result<()> {
579 /// let sock = UnixStream::connect("/tmp/sock")?;
581 /// let mut ancillary_buffer = [0; 128];
582 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
583 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
585 /// let mut buf = [1; 8];
586 /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
587 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
591 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
592 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
593 self.truncated = false;
594 add_to_ancillary_data(
603 /// Add credentials to the ancillary data.
605 /// The function returns `true` if there was enough space in the buffer.
606 /// If there was not enough space then no credentials was appended.
607 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
608 /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
610 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
611 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
612 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
613 self.truncated = false;
614 add_to_ancillary_data(
619 #[cfg(not(target_os = "netbsd"))]
620 libc::SCM_CREDENTIALS,
621 #[cfg(target_os = "netbsd")]
626 /// Clears the ancillary data, removing all values.
631 /// #![feature(unix_socket_ancillary_data)]
632 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
633 /// use std::io::IoSliceMut;
635 /// fn main() -> std::io::Result<()> {
636 /// let sock = UnixStream::connect("/tmp/sock")?;
638 /// let mut fds1 = [0; 8];
639 /// let mut fds2 = [0; 8];
640 /// let mut ancillary_buffer = [0; 128];
641 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
643 /// let mut buf = [1; 8];
644 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
646 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
647 /// for ancillary_result in ancillary.messages() {
648 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
649 /// for fd in scm_rights {
650 /// println!("receive file descriptor: {fd}");
655 /// ancillary.clear();
657 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
658 /// for ancillary_result in ancillary.messages() {
659 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
660 /// for fd in scm_rights {
661 /// println!("receive file descriptor: {fd}");
668 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
669 pub fn clear(&mut self) {
671 self.truncated = false;