1use super::{SocketAddr, sockaddr_un};
4use crate::io::{self, IoSlice, IoSliceMut};
5use crate::macros::rustdoc_skip_body;
6use crate::marker::PhantomData;
7use crate::mem::zeroed;
8use crate::os::unix::io::RawFd;
9use crate::path::Path;
10use crate::ptr::{eq, read_unaligned};
11use crate::slice::from_raw_parts;
12use crate::sys::net::Socket;
13
14#[cfg(all(
16 doc,
17 not(target_os = "linux"),
18 not(target_os = "android"),
19 not(target_os = "netbsd"),
20 not(target_os = "freebsd"),
21 not(target_os = "cygwin"),
22))]
23#[allow(non_camel_case_types)]
24mod libc {
25 pub use core::ffi::c_int;
26 pub struct ucred;
27 pub struct cmsghdr;
28 pub struct sockcred2;
29 pub type pid_t = i32;
30 pub type gid_t = u32;
31 pub type uid_t = u32;
32}
33
34#[rustdoc_skip_body]
35pub(super) fn recv_vectored_with_ancillary_from(
36 socket: &Socket,
37 bufs: &mut [IoSliceMut<'_>],
38 ancillary: &mut SocketAncillary<'_>,
39) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
40 unsafe {
41 let mut msg_name: libc::sockaddr_un = zeroed();
42 let mut msg: libc::msghdr = zeroed();
43 msg.msg_name = (&raw mut msg_name) as *mut _;
44 msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
45 msg.msg_iov = bufs.as_mut_ptr().cast();
46 msg.msg_iovlen = bufs.len() as _;
47 msg.msg_controllen = ancillary.buffer.len() as _;
48 if msg.msg_controllen > 0 {
50 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
51 }
52
53 let count = socket.recv_msg(&mut msg)?;
54
55 ancillary.length = msg.msg_controllen as usize;
56 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
57
58 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
59 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
60
61 Ok((count, truncated, addr))
62 }
63}
64
65#[rustdoc_skip_body]
66pub(super) fn send_vectored_with_ancillary_to(
67 socket: &Socket,
68 path: Option<&Path>,
69 bufs: &[IoSlice<'_>],
70 ancillary: &mut SocketAncillary<'_>,
71) -> io::Result<usize> {
72 unsafe {
73 let (mut msg_name, msg_namelen) =
74 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
75
76 let mut msg: libc::msghdr = zeroed();
77 msg.msg_name = (&raw mut msg_name) as *mut _;
78 msg.msg_namelen = msg_namelen;
79 msg.msg_iov = bufs.as_ptr() as *mut _;
80 msg.msg_iovlen = bufs.len() as _;
81 msg.msg_controllen = ancillary.length as _;
82 if msg.msg_controllen > 0 {
84 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
85 }
86
87 ancillary.truncated = false;
88
89 socket.send_msg(&mut msg)
90 }
91}
92
93#[rustdoc_skip_body]
94fn add_to_ancillary_data<T>(
95 buffer: &mut [u8],
96 length: &mut usize,
97 source: &[T],
98 cmsg_level: libc::c_int,
99 cmsg_type: libc::c_int,
100) -> bool {
101 #[cfg(not(target_os = "freebsd"))]
102 let cmsg_size = source.len().checked_mul(size_of::<T>());
103 #[cfg(target_os = "freebsd")]
104 let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
105
106 let source_len = if let Some(source_len) = cmsg_size {
107 if let Ok(source_len) = u32::try_from(source_len) {
108 source_len
109 } else {
110 return false;
111 }
112 } else {
113 return false;
114 };
115
116 unsafe {
117 let additional_space = libc::CMSG_SPACE(source_len) as usize;
118
119 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
120 new_length
121 } else {
122 return false;
123 };
124
125 if new_length > buffer.len() {
126 return false;
127 }
128
129 buffer[*length..new_length].fill(0);
130
131 *length = new_length;
132
133 let mut msg: libc::msghdr = zeroed();
134 msg.msg_control = buffer.as_mut_ptr().cast();
135 msg.msg_controllen = *length as _;
136
137 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
138 let mut previous_cmsg = cmsg;
139 while !cmsg.is_null() {
140 previous_cmsg = cmsg;
141 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
142
143 if eq(cmsg, previous_cmsg) {
147 break;
148 }
149 }
150
151 if previous_cmsg.is_null() {
152 return false;
153 }
154
155 (*previous_cmsg).cmsg_level = cmsg_level;
156 (*previous_cmsg).cmsg_type = cmsg_type;
157 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
158
159 let data = libc::CMSG_DATA(previous_cmsg).cast();
160
161 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
162 }
163 true
164}
165
166struct AncillaryDataIter<'a, T> {
167 data: &'a [u8],
168 phantom: PhantomData<T>,
169}
170
171impl<'a, T> AncillaryDataIter<'a, T> {
172 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
178 AncillaryDataIter { data, phantom: PhantomData }
179 }
180}
181
182impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
183 type Item = T;
184
185 fn next(&mut self) -> Option<T> {
186 if size_of::<T>() <= self.data.len() {
187 unsafe {
188 let unit = read_unaligned(self.data.as_ptr().cast());
189 self.data = &self.data[size_of::<T>()..];
190 Some(unit)
191 }
192 } else {
193 None
194 }
195 }
196}
197
198#[cfg(all(
199 doc,
200 not(target_os = "android"),
201 not(target_os = "linux"),
202 not(target_os = "netbsd"),
203 not(target_os = "freebsd"),
204 not(target_os = "cygwin"),
205))]
206#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
207#[derive(Clone)]
208pub struct SocketCred(());
209
210#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
212#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
213#[derive(Clone)]
214pub struct SocketCred(libc::ucred);
215
216#[cfg(target_os = "netbsd")]
217#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
218#[derive(Clone)]
219pub struct SocketCred(libc::sockcred);
220
221#[cfg(target_os = "freebsd")]
222#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
223#[derive(Clone)]
224pub struct SocketCred(libc::sockcred2);
225
226#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
227#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
228impl SocketCred {
229 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
233 #[must_use]
234 pub fn new() -> SocketCred {
235 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
236 }
237
238 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
240 pub fn set_pid(&mut self, pid: libc::pid_t) {
241 self.0.pid = pid;
242 }
243
244 #[must_use]
246 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
247 pub fn get_pid(&self) -> libc::pid_t {
248 self.0.pid
249 }
250
251 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
253 pub fn set_uid(&mut self, uid: libc::uid_t) {
254 self.0.uid = uid;
255 }
256
257 #[must_use]
259 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
260 pub fn get_uid(&self) -> libc::uid_t {
261 self.0.uid
262 }
263
264 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
266 pub fn set_gid(&mut self, gid: libc::gid_t) {
267 self.0.gid = gid;
268 }
269
270 #[must_use]
272 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
273 pub fn get_gid(&self) -> libc::gid_t {
274 self.0.gid
275 }
276}
277
278#[cfg(target_os = "freebsd")]
279impl SocketCred {
280 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
284 #[must_use]
285 pub fn new() -> SocketCred {
286 SocketCred(libc::sockcred2 {
287 sc_version: 0,
288 sc_pid: 0,
289 sc_uid: 0,
290 sc_euid: 0,
291 sc_gid: 0,
292 sc_egid: 0,
293 sc_ngroups: 0,
294 sc_groups: [0; 1],
295 })
296 }
297
298 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
300 pub fn set_pid(&mut self, pid: libc::pid_t) {
301 self.0.sc_pid = pid;
302 }
303
304 #[must_use]
306 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
307 pub fn get_pid(&self) -> libc::pid_t {
308 self.0.sc_pid
309 }
310
311 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
313 pub fn set_uid(&mut self, uid: libc::uid_t) {
314 self.0.sc_euid = uid;
315 }
316
317 #[must_use]
319 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
320 pub fn get_uid(&self) -> libc::uid_t {
321 self.0.sc_euid
322 }
323
324 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
326 pub fn set_gid(&mut self, gid: libc::gid_t) {
327 self.0.sc_egid = gid;
328 }
329
330 #[must_use]
332 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
333 pub fn get_gid(&self) -> libc::gid_t {
334 self.0.sc_egid
335 }
336}
337
338#[cfg(target_os = "netbsd")]
339impl SocketCred {
340 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
344 pub fn new() -> SocketCred {
345 SocketCred(libc::sockcred {
346 sc_pid: 0,
347 sc_uid: 0,
348 sc_euid: 0,
349 sc_gid: 0,
350 sc_egid: 0,
351 sc_ngroups: 0,
352 sc_groups: [0u32; 1],
353 })
354 }
355
356 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
358 pub fn set_pid(&mut self, pid: libc::pid_t) {
359 self.0.sc_pid = pid;
360 }
361
362 #[must_use]
364 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
365 pub fn get_pid(&self) -> libc::pid_t {
366 self.0.sc_pid
367 }
368
369 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
371 pub fn set_uid(&mut self, uid: libc::uid_t) {
372 self.0.sc_uid = uid;
373 }
374
375 #[must_use]
377 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
378 pub fn get_uid(&self) -> libc::uid_t {
379 self.0.sc_uid
380 }
381
382 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
384 pub fn set_gid(&mut self, gid: libc::gid_t) {
385 self.0.sc_gid = gid;
386 }
387
388 #[must_use]
390 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
391 pub fn get_gid(&self) -> libc::gid_t {
392 self.0.sc_gid
393 }
394}
395
396#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
400pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
401
402#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
403impl<'a> Iterator for ScmRights<'a> {
404 type Item = RawFd;
405
406 fn next(&mut self) -> Option<RawFd> {
407 self.0.next()
408 }
409}
410
411#[cfg(all(
412 doc,
413 not(target_os = "android"),
414 not(target_os = "linux"),
415 not(target_os = "netbsd"),
416 not(target_os = "freebsd"),
417 not(target_os = "cygwin"),
418))]
419#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
420pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
421
422#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
426#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
427pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
428
429#[cfg(target_os = "freebsd")]
430#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
431pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
432
433#[cfg(target_os = "netbsd")]
434#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
435pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
436
437#[cfg(any(
438 doc,
439 target_os = "android",
440 target_os = "linux",
441 target_os = "netbsd",
442 target_os = "freebsd",
443 target_os = "cygwin",
444))]
445#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
446impl<'a> Iterator for ScmCredentials<'a> {
447 type Item = SocketCred;
448
449 fn next(&mut self) -> Option<SocketCred> {
450 Some(SocketCred(self.0.next()?))
451 }
452}
453
454#[non_exhaustive]
456#[derive(Debug)]
457#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
458pub enum AncillaryError {
459 Unknown { cmsg_level: i32, cmsg_type: i32 },
460}
461
462#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
464pub enum AncillaryData<'a> {
465 ScmRights(ScmRights<'a>),
466 #[cfg(any(
467 doc,
468 target_os = "android",
469 target_os = "linux",
470 target_os = "netbsd",
471 target_os = "freebsd",
472 target_os = "cygwin",
473 ))]
474 ScmCredentials(ScmCredentials<'a>),
475}
476
477impl<'a> AncillaryData<'a> {
478 unsafe fn as_rights(data: &'a [u8]) -> Self {
485 let ancillary_data_iter = AncillaryDataIter::new(data);
486 let scm_rights = ScmRights(ancillary_data_iter);
487 AncillaryData::ScmRights(scm_rights)
488 }
489
490 #[cfg(any(
497 doc,
498 target_os = "android",
499 target_os = "linux",
500 target_os = "netbsd",
501 target_os = "freebsd",
502 target_os = "cygwin",
503 ))]
504 unsafe fn as_credentials(data: &'a [u8]) -> Self {
505 let ancillary_data_iter = AncillaryDataIter::new(data);
506 let scm_credentials = ScmCredentials(ancillary_data_iter);
507 AncillaryData::ScmCredentials(scm_credentials)
508 }
509
510 #[rustdoc_skip_body]
511 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
512 unsafe {
513 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
514 let data_len = cmsg.cmsg_len as usize - cmsg_len_zero;
515 let data = libc::CMSG_DATA(cmsg).cast();
516 let data = from_raw_parts(data, data_len);
517
518 match cmsg.cmsg_level {
519 libc::SOL_SOCKET => match cmsg.cmsg_type {
520 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
521 #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
522 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
523 #[cfg(target_os = "freebsd")]
524 libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
525 #[cfg(target_os = "netbsd")]
526 libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
527 cmsg_type => {
528 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
529 }
530 },
531 cmsg_level => {
532 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: cmsg.cmsg_type })
533 }
534 }
535 }
536 }
537}
538
539#[must_use = "iterators are lazy and do nothing unless consumed"]
541#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
542pub struct Messages<'a> {
543 buffer: &'a [u8],
544 current: Option<&'a libc::cmsghdr>,
545}
546
547#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
548impl<'a> Iterator for Messages<'a> {
549 type Item = Result<AncillaryData<'a>, AncillaryError>;
550
551 #[rustdoc_skip_body]
552 fn next(&mut self) -> Option<Self::Item> {
553 unsafe {
554 let mut msg: libc::msghdr = zeroed();
555 msg.msg_control = self.buffer.as_ptr() as *mut _;
556 msg.msg_controllen = self.buffer.len() as _;
557
558 let cmsg = if let Some(current) = self.current {
559 libc::CMSG_NXTHDR(&msg, current)
560 } else {
561 libc::CMSG_FIRSTHDR(&msg)
562 };
563
564 let cmsg = cmsg.as_ref()?;
565
566 if let Some(current) = self.current {
570 if eq(current, cmsg) {
571 return None;
572 }
573 }
574
575 self.current = Some(cmsg);
576 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
577 Some(ancillary_result)
578 }
579 }
580}
581
582#[cfg_attr(
587 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
588 doc = "```no_run"
589)]
590#[cfg_attr(
591 not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
592 doc = "```ignore (needs unix)"
593)]
594#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
620#[derive(Debug)]
621pub struct SocketAncillary<'a> {
622 buffer: &'a mut [u8],
623 length: usize,
624 truncated: bool,
625}
626
627impl<'a> SocketAncillary<'a> {
628 #[cfg_attr(
633 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
634 doc = "```no_run"
635 )]
636 #[cfg_attr(
637 not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
638 doc = "```ignore (needs unix)"
639 )]
640 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
647 pub fn new(buffer: &'a mut [u8]) -> Self {
648 SocketAncillary { buffer, length: 0, truncated: false }
649 }
650
651 #[must_use]
653 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
654 pub fn capacity(&self) -> usize {
655 self.buffer.len()
656 }
657
658 #[must_use]
660 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
661 pub fn is_empty(&self) -> bool {
662 self.length == 0
663 }
664
665 #[must_use]
667 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
668 pub fn len(&self) -> usize {
669 self.length
670 }
671
672 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
674 pub fn messages(&self) -> Messages<'_> {
675 Messages { buffer: &self.buffer[..self.length], current: None }
676 }
677
678 #[cfg_attr(
683 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
684 doc = "```no_run"
685 )]
686 #[cfg_attr(
687 not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
688 doc = "```ignore (needs unix)"
689 )]
690 #[must_use]
709 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
710 pub fn truncated(&self) -> bool {
711 self.truncated
712 }
713
714 #[cfg_attr(
724 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
725 doc = "```no_run"
726 )]
727 #[cfg_attr(
728 not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
729 doc = "```ignore (needs unix)"
730 )]
731 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
750 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
751 self.truncated = false;
752 add_to_ancillary_data(
753 self.buffer,
754 &mut self.length,
755 fds,
756 libc::SOL_SOCKET,
757 libc::SCM_RIGHTS,
758 )
759 }
760
761 #[cfg(any(
769 doc,
770 target_os = "android",
771 target_os = "linux",
772 target_os = "netbsd",
773 target_os = "freebsd",
774 target_os = "cygwin",
775 ))]
776 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
777 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
778 self.truncated = false;
779 add_to_ancillary_data(
780 self.buffer,
781 &mut self.length,
782 creds,
783 libc::SOL_SOCKET,
784 #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
785 libc::SCM_CREDENTIALS,
786 #[cfg(target_os = "freebsd")]
787 libc::SCM_CREDS2,
788 #[cfg(target_os = "netbsd")]
789 libc::SCM_CREDS,
790 )
791 }
792
793 #[cfg_attr(
798 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
799 doc = "```no_run"
800 )]
801 #[cfg_attr(
802 not(any(target_os = "android", target_os = "linux", target_os = "cygwin")),
803 doc = "```ignore (needs unix)"
804 )]
805 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
843 pub fn clear(&mut self) {
844 self.length = 0;
845 self.truncated = false;
846 }
847}