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 #[cfg(target_os = "android")]
10 use crate::ptr
::read_unaligned
;
11 use crate::slice
::from_raw_parts
;
12 use crate::sys
::net
::Socket
;
14 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
15 #[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))]
16 #[allow(non_camel_case_types)]
26 pub(super) fn recv_vectored_with_ancillary_from(
28 bufs
: &mut [IoSliceMut
<'_
>],
29 ancillary
: &mut SocketAncillary
<'_
>,
30 ) -> io
::Result
<(usize, bool
, io
::Result
<SocketAddr
>)> {
32 let mut msg_name
: libc
::sockaddr_un
= zeroed();
34 let mut msg
: libc
::msghdr
= zeroed();
35 msg
.msg_name
= &mut msg_name
as *mut _
as *mut _
;
36 msg
.msg_namelen
= size_of
::<libc
::sockaddr_un
>() as libc
::socklen_t
;
37 msg
.msg_iov
= bufs
.as_mut_ptr().cast();
38 msg
.msg_control
= ancillary
.buffer
.as_mut_ptr().cast();
40 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
41 msg
.msg_iovlen
= bufs
.len() as libc
::size_t
;
42 msg
.msg_controllen
= ancillary
.buffer
.len() as libc
::size_t
;
44 target_os
= "dragonfly",
45 target_os
= "emscripten",
46 target_os
= "freebsd",
47 all(target_os
= "linux", target_env
= "musl",),
49 target_os
= "openbsd",
51 msg
.msg_iovlen
= bufs
.len() as libc
::c_int
;
52 msg
.msg_controllen
= ancillary
.buffer
.len() as libc
::socklen_t
;
56 let count
= socket
.recv_msg(&mut msg
)?
;
58 ancillary
.length
= msg
.msg_controllen
as usize;
59 ancillary
.truncated
= msg
.msg_flags
& libc
::MSG_CTRUNC
== libc
::MSG_CTRUNC
;
61 let truncated
= msg
.msg_flags
& libc
::MSG_TRUNC
== libc
::MSG_TRUNC
;
62 let addr
= SocketAddr
::from_parts(msg_name
, msg
.msg_namelen
);
64 Ok((count
, truncated
, addr
))
68 pub(super) fn send_vectored_with_ancillary_to(
72 ancillary
: &mut SocketAncillary
<'_
>,
73 ) -> io
::Result
<usize> {
75 let (mut msg_name
, msg_namelen
) =
76 if let Some(path
) = path { sockaddr_un(path)? }
else { (zeroed(), 0) }
;
78 let mut msg
: libc
::msghdr
= zeroed();
79 msg
.msg_name
= &mut msg_name
as *mut _
as *mut _
;
80 msg
.msg_namelen
= msg_namelen
;
81 msg
.msg_iov
= bufs
.as_ptr() as *mut _
;
82 msg
.msg_control
= ancillary
.buffer
.as_mut_ptr().cast();
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",),
93 target_os
= "openbsd",
95 msg
.msg_iovlen
= bufs
.len() as libc
::c_int
;
96 msg
.msg_controllen
= ancillary
.length
as libc
::socklen_t
;
100 ancillary
.truncated
= false;
102 socket
.send_msg(&mut msg
)
106 fn add_to_ancillary_data
<T
>(
110 cmsg_level
: libc
::c_int
,
111 cmsg_type
: libc
::c_int
,
113 let source_len
= if let Some(source_len
) = source
.len().checked_mul(size_of
::<T
>()) {
114 if let Ok(source_len
) = u32::try_from(source_len
) {
124 let additional_space
= libc
::CMSG_SPACE(source_len
) as usize;
126 let new_length
= if let Some(new_length
) = additional_space
.checked_add(*length
) {
132 if new_length
> buffer
.len() {
136 buffer
[*length
..new_length
].fill(0);
138 *length
= new_length
;
140 let mut msg
: libc
::msghdr
= zeroed();
141 msg
.msg_control
= buffer
.as_mut_ptr().cast();
143 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
144 msg
.msg_controllen
= *length
as libc
::size_t
;
146 target_os
= "dragonfly",
147 target_os
= "emscripten",
148 target_os
= "freebsd",
149 all(target_os
= "linux", target_env
= "musl",),
150 target_os
= "netbsd",
151 target_os
= "openbsd",
153 msg
.msg_controllen
= *length
as libc
::socklen_t
;
157 let mut cmsg
= libc
::CMSG_FIRSTHDR(&msg
);
158 let mut previous_cmsg
= cmsg
;
159 while !cmsg
.is_null() {
160 previous_cmsg
= cmsg
;
161 cmsg
= libc
::CMSG_NXTHDR(&msg
, cmsg
);
163 // Android return the same pointer if it is the last cmsg.
164 // Therefore, check it if the previous pointer is the same as the current one.
165 if #[cfg(target_os = "android")] {
166 if cmsg
== previous_cmsg
{
173 if previous_cmsg
.is_null() {
177 (*previous_cmsg
).cmsg_level
= cmsg_level
;
178 (*previous_cmsg
).cmsg_type
= cmsg_type
;
180 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
181 (*previous_cmsg
).cmsg_len
= libc
::CMSG_LEN(source_len
) as libc
::size_t
;
183 target_os
= "dragonfly",
184 target_os
= "emscripten",
185 target_os
= "freebsd",
186 all(target_os
= "linux", target_env
= "musl",),
187 target_os
= "netbsd",
188 target_os
= "openbsd",
190 (*previous_cmsg
).cmsg_len
= libc
::CMSG_LEN(source_len
) as libc
::socklen_t
;
194 let data
= libc
::CMSG_DATA(previous_cmsg
).cast();
196 libc
::memcpy(data
, source
.as_ptr().cast(), source_len
as usize);
201 struct AncillaryDataIter
<'a
, T
> {
203 phantom
: PhantomData
<T
>,
206 impl<'a
, T
> AncillaryDataIter
<'a
, T
> {
207 /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
211 /// `data` must contain a valid control message.
212 unsafe fn new(data
: &'a
[u8]) -> AncillaryDataIter
<'a
, T
> {
213 AncillaryDataIter { data, phantom: PhantomData }
217 impl<'a
, T
> Iterator
for AncillaryDataIter
<'a
, T
> {
220 fn next(&mut self) -> Option
<T
> {
221 if size_of
::<T
>() <= self.data
.len() {
223 let unit
= read_unaligned(self.data
.as_ptr().cast());
224 self.data
= &self.data
[size_of
::<T
>()..];
234 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
235 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
237 pub struct SocketCred(libc
::ucred
);
239 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
241 /// Create a Unix credential struct.
243 /// PID, UID and GID is set to 0.
244 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
245 pub fn new() -> SocketCred
{
246 SocketCred(libc
::ucred { pid: 0, uid: 0, gid: 0 }
)
250 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
251 pub fn set_pid(&mut self, pid
: libc
::pid_t
) {
255 /// Get the current PID.
256 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
257 pub fn get_pid(&self) -> libc
::pid_t
{
262 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
263 pub fn set_uid(&mut self, uid
: libc
::uid_t
) {
267 /// Get the current UID.
268 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
269 pub fn get_uid(&self) -> libc
::uid_t
{
274 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
275 pub fn set_gid(&mut self, gid
: libc
::gid_t
) {
279 /// Get the current GID.
280 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
281 pub fn get_gid(&self) -> libc
::gid_t
{
286 /// This control message contains file descriptors.
288 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
289 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
290 pub struct ScmRights
<'a
>(AncillaryDataIter
<'a
, RawFd
>);
292 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
293 impl<'a
> Iterator
for ScmRights
<'a
> {
296 fn next(&mut self) -> Option
<RawFd
> {
301 /// This control message contains unix credentials.
303 /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
304 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
305 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
306 pub struct ScmCredentials
<'a
>(AncillaryDataIter
<'a
, libc
::ucred
>);
308 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
309 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
310 impl<'a
> Iterator
for ScmCredentials
<'a
> {
311 type Item
= SocketCred
;
313 fn next(&mut self) -> Option
<SocketCred
> {
314 Some(SocketCred(self.0.next()?
))
318 /// The error type which is returned from parsing the type a control message.
321 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
322 pub enum AncillaryError
{
323 Unknown { cmsg_level: i32, cmsg_type: i32 }
,
326 /// This enum represent one control message of variable type.
327 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
328 pub enum AncillaryData
<'a
> {
329 ScmRights(ScmRights
<'a
>),
330 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
331 ScmCredentials(ScmCredentials
<'a
>),
334 impl<'a
> AncillaryData
<'a
> {
335 /// Create a `AncillaryData::ScmRights` variant.
339 /// `data` must contain a valid control message and the control message must be type of
340 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
341 unsafe fn as_rights(data
: &'a
[u8]) -> Self {
342 let ancillary_data_iter
= AncillaryDataIter
::new(data
);
343 let scm_rights
= ScmRights(ancillary_data_iter
);
344 AncillaryData
::ScmRights(scm_rights
)
347 /// Create a `AncillaryData::ScmCredentials` variant.
351 /// `data` must contain a valid control message and the control message must be type of
352 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
353 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
354 unsafe fn as_credentials(data
: &'a
[u8]) -> Self {
355 let ancillary_data_iter
= AncillaryDataIter
::new(data
);
356 let scm_credentials
= ScmCredentials(ancillary_data_iter
);
357 AncillaryData
::ScmCredentials(scm_credentials
)
360 fn try_from_cmsghdr(cmsg
: &'a libc
::cmsghdr
) -> Result
<Self, AncillaryError
> {
364 target_os
= "android",
365 all(target_os
= "linux", target_env
= "gnu"),
366 all(target_os
= "linux", target_env
= "uclibc"),
368 let cmsg_len_zero
= libc
::CMSG_LEN(0) as libc
::size_t
;
370 target_os
= "dragonfly",
371 target_os
= "emscripten",
372 target_os
= "freebsd",
373 all(target_os
= "linux", target_env
= "musl",),
374 target_os
= "netbsd",
375 target_os
= "openbsd",
377 let cmsg_len_zero
= libc
::CMSG_LEN(0) as libc
::socklen_t
;
380 let data_len
= (*cmsg
).cmsg_len
- cmsg_len_zero
;
381 let data
= libc
::CMSG_DATA(cmsg
).cast();
382 let data
= from_raw_parts(data
, data_len
as usize);
384 match (*cmsg
).cmsg_level
{
385 libc
::SOL_SOCKET
=> match (*cmsg
).cmsg_type
{
386 libc
::SCM_RIGHTS
=> Ok(AncillaryData
::as_rights(data
)),
387 #[cfg(any(target_os = "android", target_os = "linux",))]
388 libc
::SCM_CREDENTIALS
=> Ok(AncillaryData
::as_credentials(data
)),
390 Err(AncillaryError
::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }
)
394 Err(AncillaryError
::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type }
)
401 /// This struct is used to iterate through the control messages.
402 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
403 pub struct Messages
<'a
> {
405 current
: Option
<&'a libc
::cmsghdr
>,
408 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
409 impl<'a
> Iterator
for Messages
<'a
> {
410 type Item
= Result
<AncillaryData
<'a
>, AncillaryError
>;
412 fn next(&mut self) -> Option
<Self::Item
> {
414 let mut msg
: libc
::msghdr
= zeroed();
415 msg
.msg_control
= self.buffer
.as_ptr() as *mut _
;
417 if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
418 msg
.msg_controllen
= self.buffer
.len() as libc
::size_t
;
420 target_os
= "dragonfly",
421 target_os
= "emscripten",
422 target_os
= "freebsd",
423 all(target_os
= "linux", target_env
= "musl",),
424 target_os
= "netbsd",
425 target_os
= "openbsd",
427 msg
.msg_controllen
= self.buffer
.len() as libc
::socklen_t
;
431 let cmsg
= if let Some(current
) = self.current
{
432 libc
::CMSG_NXTHDR(&msg
, current
)
434 libc
::CMSG_FIRSTHDR(&msg
)
437 let cmsg
= cmsg
.as_ref()?
;
439 // Android return the same pointer if it is the last cmsg.
440 // Therefore, check it if the previous pointer is the same as the current one.
441 if #[cfg(target_os = "android")] {
442 if let Some(current
) = self.current
{
443 if eq(current
, cmsg
) {
450 self.current
= Some(cmsg
);
451 let ancillary_result
= AncillaryData
::try_from_cmsghdr(cmsg
);
452 Some(ancillary_result
)
457 /// A Unix socket Ancillary data struct.
461 /// #![feature(unix_socket_ancillary_data)]
462 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
463 /// use std::io::IoSliceMut;
465 /// fn main() -> std::io::Result<()> {
466 /// let sock = UnixStream::connect("/tmp/sock")?;
468 /// let mut fds = [0; 8];
469 /// let mut ancillary_buffer = [0; 128];
470 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
472 /// let mut buf = [1; 8];
473 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
474 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
476 /// for ancillary_result in ancillary.messages() {
477 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
478 /// for fd in scm_rights {
479 /// println!("receive file descriptor: {}", fd);
486 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
488 pub struct SocketAncillary
<'a
> {
489 buffer
: &'a
mut [u8],
494 impl<'a
> SocketAncillary
<'a
> {
495 /// Create an ancillary data with the given buffer.
500 /// # #![allow(unused_mut)]
501 /// #![feature(unix_socket_ancillary_data)]
502 /// use std::os::unix::net::SocketAncillary;
503 /// let mut ancillary_buffer = [0; 128];
504 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
506 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
507 pub fn new(buffer
: &'a
mut [u8]) -> Self {
508 SocketAncillary { buffer, length: 0, truncated: false }
511 /// Returns the capacity of the buffer.
512 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
513 pub fn capacity(&self) -> usize {
517 /// Returns the number of used bytes.
518 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
519 pub fn len(&self) -> usize {
523 /// Returns the iterator of the control messages.
524 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
525 pub fn messages(&self) -> Messages
<'_
> {
526 Messages { buffer: &self.buffer[..self.length], current: None }
529 /// Is `true` if during a recv operation the ancillary was truncated.
534 /// #![feature(unix_socket_ancillary_data)]
535 /// use std::os::unix::net::{UnixStream, SocketAncillary};
536 /// use std::io::IoSliceMut;
538 /// fn main() -> std::io::Result<()> {
539 /// let sock = UnixStream::connect("/tmp/sock")?;
541 /// let mut ancillary_buffer = [0; 128];
542 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
544 /// let mut buf = [1; 8];
545 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
546 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
548 /// println!("Is truncated: {}", ancillary.truncated());
552 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
553 pub fn truncated(&self) -> bool
{
557 /// Add file descriptors to the ancillary data.
559 /// The function returns `true` if there was enough space in the buffer.
560 /// If there was not enough space then no file descriptors was appended.
561 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
562 /// and type `SCM_RIGHTS`.
567 /// #![feature(unix_socket_ancillary_data)]
568 /// use std::os::unix::net::{UnixStream, SocketAncillary};
569 /// use std::os::unix::io::AsRawFd;
570 /// use std::io::IoSlice;
572 /// fn main() -> std::io::Result<()> {
573 /// let sock = UnixStream::connect("/tmp/sock")?;
575 /// let mut ancillary_buffer = [0; 128];
576 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
577 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
579 /// let mut buf = [1; 8];
580 /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
581 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
585 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
586 pub fn add_fds(&mut self, fds
: &[RawFd
]) -> bool
{
587 self.truncated
= false;
588 add_to_ancillary_data(
597 /// Add credentials to the ancillary data.
599 /// The function returns `true` if there was enough space in the buffer.
600 /// If there was not enough space then no credentials was appended.
601 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
602 /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
604 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
605 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
606 pub fn add_creds(&mut self, creds
: &[SocketCred
]) -> bool
{
607 self.truncated
= false;
608 add_to_ancillary_data(
613 libc
::SCM_CREDENTIALS
,
617 /// Clears the ancillary data, removing all values.
622 /// #![feature(unix_socket_ancillary_data)]
623 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
624 /// use std::io::IoSliceMut;
626 /// fn main() -> std::io::Result<()> {
627 /// let sock = UnixStream::connect("/tmp/sock")?;
629 /// let mut fds1 = [0; 8];
630 /// let mut fds2 = [0; 8];
631 /// let mut ancillary_buffer = [0; 128];
632 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
634 /// let mut buf = [1; 8];
635 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
637 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
638 /// for ancillary_result in ancillary.messages() {
639 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
640 /// for fd in scm_rights {
641 /// println!("receive file descriptor: {}", fd);
646 /// ancillary.clear();
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);
659 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
660 pub fn clear(&mut self) {
662 self.truncated
= false;