1 use super::{sockaddr_un, SocketAddr};
2 use crate::io::{self, IoSlice, IoSliceMut};
3 use crate::marker::PhantomData;
4 use crate::mem::{size_of, zeroed};
5 use crate::os::unix::io::RawFd;
7 use crate::ptr::{eq, read_unaligned};
8 use crate::slice::from_raw_parts;
9 use crate::sys::net::Socket;
11 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
12 #[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
13 #[allow(non_camel_case_types)]
23 pub(super) fn recv_vectored_with_ancillary_from(
25 bufs: &mut [IoSliceMut<'_>],
26 ancillary: &mut SocketAncillary<'_>,
27 ) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
29 let mut msg_name: libc::sockaddr_un = zeroed();
30 let mut msg: libc::msghdr = zeroed();
31 msg.msg_name = &mut msg_name as *mut _ as *mut _;
32 msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
33 msg.msg_iov = bufs.as_mut_ptr().cast();
34 msg.msg_iovlen = bufs.len() as _;
35 msg.msg_controllen = ancillary.buffer.len() as _;
36 // macos requires that the control pointer is null when the len is 0.
37 if msg.msg_controllen > 0 {
38 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
41 let count = socket.recv_msg(&mut msg)?;
43 ancillary.length = msg.msg_controllen as usize;
44 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
46 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
47 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
49 Ok((count, truncated, addr))
53 pub(super) fn send_vectored_with_ancillary_to(
57 ancillary: &mut SocketAncillary<'_>,
58 ) -> io::Result<usize> {
60 let (mut msg_name, msg_namelen) =
61 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
63 let mut msg: libc::msghdr = zeroed();
64 msg.msg_name = &mut msg_name as *mut _ as *mut _;
65 msg.msg_namelen = msg_namelen;
66 msg.msg_iov = bufs.as_ptr() as *mut _;
67 msg.msg_iovlen = bufs.len() as _;
68 msg.msg_controllen = ancillary.length as _;
69 // macos requires that the control pointer is null when the len is 0.
70 if msg.msg_controllen > 0 {
71 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
74 ancillary.truncated = false;
76 socket.send_msg(&mut msg)
80 fn add_to_ancillary_data<T>(
84 cmsg_level: libc::c_int,
85 cmsg_type: libc::c_int,
87 let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
88 if let Ok(source_len) = u32::try_from(source_len) {
98 let additional_space = libc::CMSG_SPACE(source_len) as usize;
100 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
106 if new_length > buffer.len() {
110 buffer[*length..new_length].fill(0);
112 *length = new_length;
114 let mut msg: libc::msghdr = zeroed();
115 msg.msg_control = buffer.as_mut_ptr().cast();
116 msg.msg_controllen = *length as _;
118 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
119 let mut previous_cmsg = cmsg;
120 while !cmsg.is_null() {
121 previous_cmsg = cmsg;
122 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
124 // Most operating systems, but not Linux or emscripten, return the previous pointer
125 // when its length is zero. Therefore, check if the previous pointer is the same as
127 if eq(cmsg, previous_cmsg) {
132 if previous_cmsg.is_null() {
136 (*previous_cmsg).cmsg_level = cmsg_level;
137 (*previous_cmsg).cmsg_type = cmsg_type;
138 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
140 let data = libc::CMSG_DATA(previous_cmsg).cast();
142 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
147 struct AncillaryDataIter<'a, T> {
149 phantom: PhantomData<T>,
152 impl<'a, T> AncillaryDataIter<'a, T> {
153 /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
157 /// `data` must contain a valid control message.
158 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
159 AncillaryDataIter { data, phantom: PhantomData }
163 impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
166 fn next(&mut self) -> Option<T> {
167 if size_of::<T>() <= self.data.len() {
169 let unit = read_unaligned(self.data.as_ptr().cast());
170 self.data = &self.data[size_of::<T>()..];
179 #[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
180 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
182 pub struct SocketCred(());
185 #[cfg(any(target_os = "android", target_os = "linux",))]
186 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
188 pub struct SocketCred(libc::ucred);
190 #[cfg(target_os = "netbsd")]
191 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
193 pub struct SocketCred(libc::sockcred);
195 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
196 #[cfg(any(target_os = "android", target_os = "linux"))]
198 /// Create a Unix credential struct.
200 /// PID, UID and GID is set to 0.
201 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
203 pub fn new() -> SocketCred {
204 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
208 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
209 pub fn set_pid(&mut self, pid: libc::pid_t) {
213 /// Get the current PID.
215 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
216 pub fn get_pid(&self) -> libc::pid_t {
221 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
222 pub fn set_uid(&mut self, uid: libc::uid_t) {
226 /// Get the current UID.
228 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
229 pub fn get_uid(&self) -> libc::uid_t {
234 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
235 pub fn set_gid(&mut self, gid: libc::gid_t) {
239 /// Get the current GID.
241 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
242 pub fn get_gid(&self) -> libc::gid_t {
247 #[cfg(target_os = "netbsd")]
249 /// Create a Unix credential struct.
251 /// PID, UID and GID is set to 0.
252 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
253 pub fn new() -> SocketCred {
254 SocketCred(libc::sockcred {
261 sc_groups: [0u32; 1],
266 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
267 pub fn set_pid(&mut self, pid: libc::pid_t) {
271 /// Get the current PID.
272 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
273 pub fn get_pid(&self) -> libc::pid_t {
278 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
279 pub fn set_uid(&mut self, uid: libc::uid_t) {
283 /// Get the current UID.
284 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
285 pub fn get_uid(&self) -> libc::uid_t {
290 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
291 pub fn set_gid(&mut self, gid: libc::gid_t) {
295 /// Get the current GID.
296 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
297 pub fn get_gid(&self) -> libc::gid_t {
302 /// This control message contains file descriptors.
304 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
305 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
306 pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
308 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
309 impl<'a> Iterator for ScmRights<'a> {
312 fn next(&mut self) -> Option<RawFd> {
317 #[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
318 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
319 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
321 /// This control message contains unix credentials.
323 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
324 #[cfg(any(target_os = "android", target_os = "linux",))]
325 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
326 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
328 #[cfg(target_os = "netbsd")]
329 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
330 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
332 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
333 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
334 impl<'a> Iterator for ScmCredentials<'a> {
335 type Item = SocketCred;
337 fn next(&mut self) -> Option<SocketCred> {
338 Some(SocketCred(self.0.next()?))
342 /// The error type which is returned from parsing the type a control message.
345 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
346 pub enum AncillaryError {
347 Unknown { cmsg_level: i32, cmsg_type: i32 },
350 /// This enum represent one control message of variable type.
351 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
352 pub enum AncillaryData<'a> {
353 ScmRights(ScmRights<'a>),
354 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
355 ScmCredentials(ScmCredentials<'a>),
358 impl<'a> AncillaryData<'a> {
359 /// Create an `AncillaryData::ScmRights` variant.
363 /// `data` must contain a valid control message and the control message must be type of
364 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
365 unsafe fn as_rights(data: &'a [u8]) -> Self {
366 let ancillary_data_iter = AncillaryDataIter::new(data);
367 let scm_rights = ScmRights(ancillary_data_iter);
368 AncillaryData::ScmRights(scm_rights)
371 /// Create an `AncillaryData::ScmCredentials` variant.
375 /// `data` must contain a valid control message and the control message must be type of
376 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
377 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
378 unsafe fn as_credentials(data: &'a [u8]) -> Self {
379 let ancillary_data_iter = AncillaryDataIter::new(data);
380 let scm_credentials = ScmCredentials(ancillary_data_iter);
381 AncillaryData::ScmCredentials(scm_credentials)
384 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
386 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
387 let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
388 let data = libc::CMSG_DATA(cmsg).cast();
389 let data = from_raw_parts(data, data_len);
391 match (*cmsg).cmsg_level {
392 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
393 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
394 #[cfg(any(target_os = "android", target_os = "linux",))]
395 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
396 #[cfg(target_os = "netbsd")]
397 libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
399 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
403 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
410 /// This struct is used to iterate through the control messages.
411 #[must_use = "iterators are lazy and do nothing unless consumed"]
412 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
413 pub struct Messages<'a> {
415 current: Option<&'a libc::cmsghdr>,
418 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
419 impl<'a> Iterator for Messages<'a> {
420 type Item = Result<AncillaryData<'a>, AncillaryError>;
422 fn next(&mut self) -> Option<Self::Item> {
424 let mut msg: libc::msghdr = zeroed();
425 msg.msg_control = self.buffer.as_ptr() as *mut _;
426 msg.msg_controllen = self.buffer.len() as _;
428 let cmsg = if let Some(current) = self.current {
429 libc::CMSG_NXTHDR(&msg, current)
431 libc::CMSG_FIRSTHDR(&msg)
434 let cmsg = cmsg.as_ref()?;
436 // Most operating systems, but not Linux or emscripten, return the previous pointer
437 // when its length is zero. Therefore, check if the previous pointer is the same as
439 if let Some(current) = self.current {
440 if eq(current, cmsg) {
445 self.current = Some(cmsg);
446 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
447 Some(ancillary_result)
452 /// A Unix socket Ancillary data struct.
456 /// #![feature(unix_socket_ancillary_data)]
457 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
458 /// use std::io::IoSliceMut;
460 /// fn main() -> std::io::Result<()> {
461 /// let sock = UnixStream::connect("/tmp/sock")?;
463 /// let mut fds = [0; 8];
464 /// let mut ancillary_buffer = [0; 128];
465 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
467 /// let mut buf = [1; 8];
468 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
469 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
471 /// for ancillary_result in ancillary.messages() {
472 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
473 /// for fd in scm_rights {
474 /// println!("receive file descriptor: {fd}");
481 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
483 pub struct SocketAncillary<'a> {
484 buffer: &'a mut [u8],
489 impl<'a> SocketAncillary<'a> {
490 /// Create an ancillary data with the given buffer.
495 /// # #![allow(unused_mut)]
496 /// #![feature(unix_socket_ancillary_data)]
497 /// use std::os::unix::net::SocketAncillary;
498 /// let mut ancillary_buffer = [0; 128];
499 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
501 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
502 pub fn new(buffer: &'a mut [u8]) -> Self {
503 SocketAncillary { buffer, length: 0, truncated: false }
506 /// Returns the capacity of the buffer.
508 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
509 pub fn capacity(&self) -> usize {
513 /// Returns `true` if the ancillary data is empty.
515 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
516 pub fn is_empty(&self) -> bool {
520 /// Returns the number of used bytes.
522 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
523 pub fn len(&self) -> usize {
527 /// Returns the iterator of the control messages.
528 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
529 pub fn messages(&self) -> Messages<'_> {
530 Messages { buffer: &self.buffer[..self.length], current: None }
533 /// Is `true` if during a recv operation the ancillary was truncated.
538 /// #![feature(unix_socket_ancillary_data)]
539 /// use std::os::unix::net::{UnixStream, SocketAncillary};
540 /// use std::io::IoSliceMut;
542 /// fn main() -> std::io::Result<()> {
543 /// let sock = UnixStream::connect("/tmp/sock")?;
545 /// let mut ancillary_buffer = [0; 128];
546 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
548 /// let mut buf = [1; 8];
549 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
550 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
552 /// println!("Is truncated: {}", ancillary.truncated());
557 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
558 pub fn truncated(&self) -> bool {
562 /// Add file descriptors to the ancillary data.
564 /// The function returns `true` if there was enough space in the buffer.
565 /// If there was not enough space then no file descriptors was appended.
566 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
567 /// and type `SCM_RIGHTS`.
572 /// #![feature(unix_socket_ancillary_data)]
573 /// use std::os::unix::net::{UnixStream, SocketAncillary};
574 /// use std::os::unix::io::AsRawFd;
575 /// use std::io::IoSlice;
577 /// fn main() -> std::io::Result<()> {
578 /// let sock = UnixStream::connect("/tmp/sock")?;
580 /// let mut ancillary_buffer = [0; 128];
581 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
582 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
584 /// let mut buf = [1; 8];
585 /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
586 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
590 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
591 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
592 self.truncated = false;
593 add_to_ancillary_data(
602 /// Add credentials to the ancillary data.
604 /// The function returns `true` if there was enough space in the buffer.
605 /// If there was not enough space then no credentials was appended.
606 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
607 /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
609 #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
610 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
611 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
612 self.truncated = false;
613 add_to_ancillary_data(
618 #[cfg(not(target_os = "netbsd"))]
619 libc::SCM_CREDENTIALS,
620 #[cfg(target_os = "netbsd")]
625 /// Clears the ancillary data, removing all values.
630 /// #![feature(unix_socket_ancillary_data)]
631 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
632 /// use std::io::IoSliceMut;
634 /// fn main() -> std::io::Result<()> {
635 /// let sock = UnixStream::connect("/tmp/sock")?;
637 /// let mut fds1 = [0; 8];
638 /// let mut fds2 = [0; 8];
639 /// let mut ancillary_buffer = [0; 128];
640 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
642 /// let mut buf = [1; 8];
643 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
645 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
646 /// for ancillary_result in ancillary.messages() {
647 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
648 /// for fd in scm_rights {
649 /// println!("receive file descriptor: {fd}");
654 /// ancillary.clear();
656 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
657 /// for ancillary_result in ancillary.messages() {
658 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
659 /// for fd in scm_rights {
660 /// println!("receive file descriptor: {fd}");
667 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
668 pub fn clear(&mut self) {
670 self.truncated = false;