]> git.proxmox.com Git - rustc.git/blame - library/std/src/os/unix/net/ancillary.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / library / std / src / os / unix / net / ancillary.rs
CommitLineData
fc512014
XL
1use super::{sockaddr_un, SocketAddr};
2use crate::convert::TryFrom;
6a06907d 3use crate::io::{self, IoSlice, IoSliceMut};
fc512014
XL
4use crate::marker::PhantomData;
5use crate::mem::{size_of, zeroed};
6use crate::os::unix::io::RawFd;
7use crate::path::Path;
cdc7bbd5 8use crate::ptr::{eq, read_unaligned};
fc512014
XL
9use crate::slice::from_raw_parts;
10use crate::sys::net::Socket;
11
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)]
15mod libc {
16 pub use libc::c_int;
17 pub struct ucred;
18 pub struct cmsghdr;
19 pub type pid_t = i32;
20 pub type gid_t = u32;
21 pub type uid_t = u32;
22}
23
24pub(super) fn recv_vectored_with_ancillary_from(
25 socket: &Socket,
26 bufs: &mut [IoSliceMut<'_>],
27 ancillary: &mut SocketAncillary<'_>,
28) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
29 unsafe {
30 let mut msg_name: libc::sockaddr_un = zeroed();
fc512014
XL
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();
136023e0
XL
35 msg.msg_iovlen = bufs.len() as _;
36 msg.msg_controllen = ancillary.buffer.len() as _;
17df50a5 37 // macos requires that the control pointer is null when the len is 0.
cdc7bbd5
XL
38 if msg.msg_controllen > 0 {
39 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
40 }
fc512014
XL
41
42 let count = socket.recv_msg(&mut msg)?;
43
44 ancillary.length = msg.msg_controllen as usize;
45 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
46
47 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
48 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
49
50 Ok((count, truncated, addr))
51 }
52}
53
54pub(super) fn send_vectored_with_ancillary_to(
55 socket: &Socket,
56 path: Option<&Path>,
6a06907d 57 bufs: &[IoSlice<'_>],
fc512014
XL
58 ancillary: &mut SocketAncillary<'_>,
59) -> io::Result<usize> {
60 unsafe {
61 let (mut msg_name, msg_namelen) =
62 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
63
64 let mut msg: libc::msghdr = zeroed();
65 msg.msg_name = &mut msg_name as *mut _ as *mut _;
66 msg.msg_namelen = msg_namelen;
6a06907d 67 msg.msg_iov = bufs.as_ptr() as *mut _;
136023e0
XL
68 msg.msg_iovlen = bufs.len() as _;
69 msg.msg_controllen = ancillary.length as _;
17df50a5 70 // macos requires that the control pointer is null when the len is 0.
cdc7bbd5
XL
71 if msg.msg_controllen > 0 {
72 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
73 }
fc512014
XL
74
75 ancillary.truncated = false;
76
77 socket.send_msg(&mut msg)
78 }
79}
80
81fn add_to_ancillary_data<T>(
82 buffer: &mut [u8],
83 length: &mut usize,
84 source: &[T],
85 cmsg_level: libc::c_int,
86 cmsg_type: libc::c_int,
87) -> bool {
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) {
90 source_len
91 } else {
92 return false;
93 }
94 } else {
95 return false;
96 };
97
98 unsafe {
99 let additional_space = libc::CMSG_SPACE(source_len) as usize;
100
101 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
102 new_length
103 } else {
104 return false;
105 };
106
107 if new_length > buffer.len() {
108 return false;
109 }
110
111 buffer[*length..new_length].fill(0);
112
113 *length = new_length;
114
115 let mut msg: libc::msghdr = zeroed();
116 msg.msg_control = buffer.as_mut_ptr().cast();
136023e0 117 msg.msg_controllen = *length as _;
fc512014
XL
118
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);
cdc7bbd5
XL
124
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
127 // the current one.
128 if eq(cmsg, previous_cmsg) {
129 break;
fc512014
XL
130 }
131 }
132
133 if previous_cmsg.is_null() {
134 return false;
135 }
136
137 (*previous_cmsg).cmsg_level = cmsg_level;
138 (*previous_cmsg).cmsg_type = cmsg_type;
136023e0 139 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
fc512014
XL
140
141 let data = libc::CMSG_DATA(previous_cmsg).cast();
142
143 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
144 }
145 true
146}
147
148struct AncillaryDataIter<'a, T> {
149 data: &'a [u8],
150 phantom: PhantomData<T>,
151}
152
153impl<'a, T> AncillaryDataIter<'a, T> {
154 /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
155 ///
156 /// # Safety
157 ///
158 /// `data` must contain a valid control message.
159 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
160 AncillaryDataIter { data, phantom: PhantomData }
161 }
162}
163
164impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
165 type Item = T;
166
167 fn next(&mut self) -> Option<T> {
168 if size_of::<T>() <= self.data.len() {
169 unsafe {
170 let unit = read_unaligned(self.data.as_ptr().cast());
171 self.data = &self.data[size_of::<T>()..];
172 Some(unit)
173 }
174 } else {
175 None
176 }
177 }
178}
179
180/// Unix credential.
181#[cfg(any(doc, target_os = "android", target_os = "linux",))]
182#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
183#[derive(Clone)]
184pub struct SocketCred(libc::ucred);
185
186#[cfg(any(doc, target_os = "android", target_os = "linux",))]
187impl SocketCred {
188 /// Create a Unix credential struct.
189 ///
190 /// PID, UID and GID is set to 0.
191 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
c295e0f8 192 #[must_use]
fc512014
XL
193 pub fn new() -> SocketCred {
194 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
195 }
196
197 /// Set the PID.
198 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
199 pub fn set_pid(&mut self, pid: libc::pid_t) {
200 self.0.pid = pid;
201 }
202
203 /// Get the current PID.
204 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
205 pub fn get_pid(&self) -> libc::pid_t {
206 self.0.pid
207 }
208
209 /// Set the UID.
210 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
211 pub fn set_uid(&mut self, uid: libc::uid_t) {
212 self.0.uid = uid;
213 }
214
215 /// Get the current UID.
216 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
217 pub fn get_uid(&self) -> libc::uid_t {
218 self.0.uid
219 }
220
221 /// Set the GID.
222 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
223 pub fn set_gid(&mut self, gid: libc::gid_t) {
224 self.0.gid = gid;
225 }
226
227 /// Get the current GID.
228 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
229 pub fn get_gid(&self) -> libc::gid_t {
230 self.0.gid
231 }
232}
233
234/// This control message contains file descriptors.
235///
236/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
237#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
238pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
239
240#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
241impl<'a> Iterator for ScmRights<'a> {
242 type Item = RawFd;
243
244 fn next(&mut self) -> Option<RawFd> {
245 self.0.next()
246 }
247}
248
249/// This control message contains unix credentials.
250///
251/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
252#[cfg(any(doc, target_os = "android", target_os = "linux",))]
253#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
254pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
255
256#[cfg(any(doc, target_os = "android", target_os = "linux",))]
257#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
258impl<'a> Iterator for ScmCredentials<'a> {
259 type Item = SocketCred;
260
261 fn next(&mut self) -> Option<SocketCred> {
262 Some(SocketCred(self.0.next()?))
263 }
264}
265
266/// The error type which is returned from parsing the type a control message.
267#[non_exhaustive]
268#[derive(Debug)]
269#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
270pub enum AncillaryError {
271 Unknown { cmsg_level: i32, cmsg_type: i32 },
272}
273
274/// This enum represent one control message of variable type.
275#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
276pub enum AncillaryData<'a> {
277 ScmRights(ScmRights<'a>),
278 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
279 ScmCredentials(ScmCredentials<'a>),
280}
281
282impl<'a> AncillaryData<'a> {
94222f64 283 /// Create an `AncillaryData::ScmRights` variant.
fc512014
XL
284 ///
285 /// # Safety
286 ///
287 /// `data` must contain a valid control message and the control message must be type of
288 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
289 unsafe fn as_rights(data: &'a [u8]) -> Self {
290 let ancillary_data_iter = AncillaryDataIter::new(data);
291 let scm_rights = ScmRights(ancillary_data_iter);
292 AncillaryData::ScmRights(scm_rights)
293 }
294
94222f64 295 /// Create an `AncillaryData::ScmCredentials` variant.
fc512014
XL
296 ///
297 /// # Safety
298 ///
299 /// `data` must contain a valid control message and the control message must be type of
300 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
301 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
302 unsafe fn as_credentials(data: &'a [u8]) -> Self {
303 let ancillary_data_iter = AncillaryDataIter::new(data);
304 let scm_credentials = ScmCredentials(ancillary_data_iter);
305 AncillaryData::ScmCredentials(scm_credentials)
306 }
307
308 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
309 unsafe {
136023e0
XL
310 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
311 let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
fc512014 312 let data = libc::CMSG_DATA(cmsg).cast();
136023e0 313 let data = from_raw_parts(data, data_len);
fc512014
XL
314
315 match (*cmsg).cmsg_level {
316 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
317 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
318 #[cfg(any(target_os = "android", target_os = "linux",))]
319 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
320 cmsg_type => {
321 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
322 }
323 },
324 cmsg_level => {
325 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
326 }
327 }
328 }
329 }
330}
331
332/// This struct is used to iterate through the control messages.
333#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
334pub struct Messages<'a> {
335 buffer: &'a [u8],
336 current: Option<&'a libc::cmsghdr>,
337}
338
339#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
340impl<'a> Iterator for Messages<'a> {
341 type Item = Result<AncillaryData<'a>, AncillaryError>;
342
343 fn next(&mut self) -> Option<Self::Item> {
344 unsafe {
345 let mut msg: libc::msghdr = zeroed();
346 msg.msg_control = self.buffer.as_ptr() as *mut _;
136023e0 347 msg.msg_controllen = self.buffer.len() as _;
fc512014
XL
348
349 let cmsg = if let Some(current) = self.current {
350 libc::CMSG_NXTHDR(&msg, current)
351 } else {
352 libc::CMSG_FIRSTHDR(&msg)
353 };
354
355 let cmsg = cmsg.as_ref()?;
cdc7bbd5
XL
356
357 // Most operating systems, but not Linux or emscripten, return the previous pointer
358 // when its length is zero. Therefore, check if the previous pointer is the same as
359 // the current one.
360 if let Some(current) = self.current {
361 if eq(current, cmsg) {
362 return None;
fc512014
XL
363 }
364 }
365
366 self.current = Some(cmsg);
367 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
368 Some(ancillary_result)
369 }
370 }
371}
372
373/// A Unix socket Ancillary data struct.
374///
375/// # Example
376/// ```no_run
377/// #![feature(unix_socket_ancillary_data)]
378/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
379/// use std::io::IoSliceMut;
380///
381/// fn main() -> std::io::Result<()> {
382/// let sock = UnixStream::connect("/tmp/sock")?;
383///
384/// let mut fds = [0; 8];
385/// let mut ancillary_buffer = [0; 128];
386/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
387///
388/// let mut buf = [1; 8];
389/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
390/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
391///
392/// for ancillary_result in ancillary.messages() {
393/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
394/// for fd in scm_rights {
395/// println!("receive file descriptor: {}", fd);
396/// }
397/// }
398/// }
399/// Ok(())
400/// }
401/// ```
402#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
403#[derive(Debug)]
404pub struct SocketAncillary<'a> {
405 buffer: &'a mut [u8],
406 length: usize,
407 truncated: bool,
408}
409
410impl<'a> SocketAncillary<'a> {
411 /// Create an ancillary data with the given buffer.
412 ///
413 /// # Example
414 ///
415 /// ```no_run
416 /// # #![allow(unused_mut)]
417 /// #![feature(unix_socket_ancillary_data)]
418 /// use std::os::unix::net::SocketAncillary;
419 /// let mut ancillary_buffer = [0; 128];
420 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
421 /// ```
422 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
423 pub fn new(buffer: &'a mut [u8]) -> Self {
424 SocketAncillary { buffer, length: 0, truncated: false }
425 }
426
427 /// Returns the capacity of the buffer.
428 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
429 pub fn capacity(&self) -> usize {
430 self.buffer.len()
431 }
432
cdc7bbd5
XL
433 /// Returns `true` if the ancillary data is empty.
434 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
435 pub fn is_empty(&self) -> bool {
436 self.length == 0
437 }
438
fc512014
XL
439 /// Returns the number of used bytes.
440 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
441 pub fn len(&self) -> usize {
442 self.length
443 }
444
445 /// Returns the iterator of the control messages.
446 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
447 pub fn messages(&self) -> Messages<'_> {
448 Messages { buffer: &self.buffer[..self.length], current: None }
449 }
450
451 /// Is `true` if during a recv operation the ancillary was truncated.
452 ///
453 /// # Example
454 ///
455 /// ```no_run
456 /// #![feature(unix_socket_ancillary_data)]
457 /// use std::os::unix::net::{UnixStream, SocketAncillary};
458 /// use std::io::IoSliceMut;
459 ///
460 /// fn main() -> std::io::Result<()> {
461 /// let sock = UnixStream::connect("/tmp/sock")?;
462 ///
463 /// let mut ancillary_buffer = [0; 128];
464 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
465 ///
466 /// let mut buf = [1; 8];
467 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
468 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
469 ///
470 /// println!("Is truncated: {}", ancillary.truncated());
471 /// Ok(())
472 /// }
473 /// ```
474 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
475 pub fn truncated(&self) -> bool {
476 self.truncated
477 }
478
479 /// Add file descriptors to the ancillary data.
480 ///
481 /// The function returns `true` if there was enough space in the buffer.
482 /// If there was not enough space then no file descriptors was appended.
483 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
484 /// and type `SCM_RIGHTS`.
485 ///
486 /// # Example
487 ///
488 /// ```no_run
489 /// #![feature(unix_socket_ancillary_data)]
490 /// use std::os::unix::net::{UnixStream, SocketAncillary};
491 /// use std::os::unix::io::AsRawFd;
6a06907d 492 /// use std::io::IoSlice;
fc512014
XL
493 ///
494 /// fn main() -> std::io::Result<()> {
495 /// let sock = UnixStream::connect("/tmp/sock")?;
496 ///
497 /// let mut ancillary_buffer = [0; 128];
498 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
499 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
500 ///
501 /// let mut buf = [1; 8];
6a06907d 502 /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
fc512014
XL
503 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
504 /// Ok(())
505 /// }
506 /// ```
507 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
508 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
509 self.truncated = false;
510 add_to_ancillary_data(
511 &mut self.buffer,
512 &mut self.length,
513 fds,
514 libc::SOL_SOCKET,
515 libc::SCM_RIGHTS,
516 )
517 }
518
519 /// Add credentials to the ancillary data.
520 ///
521 /// The function returns `true` if there was enough space in the buffer.
522 /// If there was not enough space then no credentials was appended.
523 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
524 /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
525 ///
526 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
527 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
528 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
529 self.truncated = false;
530 add_to_ancillary_data(
531 &mut self.buffer,
532 &mut self.length,
533 creds,
534 libc::SOL_SOCKET,
535 libc::SCM_CREDENTIALS,
536 )
537 }
538
539 /// Clears the ancillary data, removing all values.
540 ///
541 /// # Example
542 ///
543 /// ```no_run
544 /// #![feature(unix_socket_ancillary_data)]
545 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
546 /// use std::io::IoSliceMut;
547 ///
548 /// fn main() -> std::io::Result<()> {
549 /// let sock = UnixStream::connect("/tmp/sock")?;
550 ///
551 /// let mut fds1 = [0; 8];
552 /// let mut fds2 = [0; 8];
553 /// let mut ancillary_buffer = [0; 128];
554 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
555 ///
556 /// let mut buf = [1; 8];
557 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
558 ///
559 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
560 /// for ancillary_result in ancillary.messages() {
561 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
562 /// for fd in scm_rights {
563 /// println!("receive file descriptor: {}", fd);
564 /// }
565 /// }
566 /// }
567 ///
568 /// ancillary.clear();
569 ///
570 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
571 /// for ancillary_result in ancillary.messages() {
572 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
573 /// for fd in scm_rights {
574 /// println!("receive file descriptor: {}", fd);
575 /// }
576 /// }
577 /// }
578 /// Ok(())
579 /// }
580 /// ```
581 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
582 pub fn clear(&mut self) {
583 self.length = 0;
584 self.truncated = false;
585 }
586}