Skip to main content

udsx/
udsx_unix_stream.rs

1/*
2==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
3
4UDSx
5
6Copyright (C) 2019, 2021-2023  Anonymous
7
8There are several releases over multiple years,
9they are listed as ranges, such as: "2021-2023".
10
11This program is free software: you can redistribute it and/or modify
12it under the terms of the GNU Lesser General Public License as published by
13the Free Software Foundation, either version 3 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public License
22along with this program.  If not, see <https://www.gnu.org/licenses/>.
23
24::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
25*/
26
27//! # `UdsxUnixStream`
28
29use {
30    core::mem,
31    std::{
32        io::{self, Error, ErrorKind, IoSlice, IoSliceMut},
33        os::unix::{
34            io::{AsRawFd, FromRawFd, RawFd},
35            net::{AncillaryData, SocketAncillary, UnixStream},
36        },
37        process::Stdio,
38    },
39    crate::Result,
40};
41
42const RAW_FD_SIZE: usize = mem::size_of::<RawFd>();
43
44/// # Extensions for `UnixStream`
45///
46/// ## Notes
47///
48/// - IDs are used for verification, they must not be empty.
49/// - In tests, IDs with size from one byte up to 64 bytes work fine. So you can use something like SHA3-512 hashes as your IDs.
50pub trait UdsxUnixStream {
51
52    /// # Sends streams
53    ///
54    /// ## Notes
55    ///
56    /// Too much streams will make an error (see `cmsg(3)`).
57    ///
58    /// ## See also
59    ///
60    /// [`recv_streams()`][fn:recv_streams]
61    ///
62    /// [fn:recv_streams]: #tymethod.recv_streams
63    fn send_streams<B, I>(&self, id: B, streams: I) -> Result<()> where B: AsRef<[u8]>, I: IntoIterator<Item=RawFd>;
64
65    /// # Sends all standard streams: input, output, error
66    ///
67    /// ## See also
68    ///
69    /// [`recv_ioe()`][fn:recv_ioe]
70    ///
71    /// [fn:recv_ioe]: #tymethod.recv_ioe
72    fn send_ioe<B>(&self, id: B) -> Result<()> where B: AsRef<[u8]>;
73
74    /// # Receives streams
75    ///
76    /// `count` is number of streams you want to receive. This must match what client sends.
77    ///
78    /// ## See also
79    ///
80    /// [`send_streams()`][fn:send_streams]
81    ///
82    /// [fn:send_streams]: #tymethod.send_streams
83    unsafe fn recv_streams<B, T>(&self, id: B, count: usize) -> Result<Vec<T>> where B: AsRef<[u8]>, T: FromRawFd;
84
85    /// # Receives standard streams sent by [`send_ioe()`][fn:send_ioe]
86    ///
87    /// Results are: input, output and error streams.
88    ///
89    /// [fn:send_ioe]: #tymethod.send_ioe
90    unsafe fn recv_ioe<B>(&self, id: B) -> Result<(Stdio, Stdio, Stdio)> where B: AsRef<[u8]>;
91
92}
93
94impl UdsxUnixStream for UnixStream {
95
96    fn send_streams<B, I>(&self, id: B, streams: I) -> Result<()> where B: AsRef<[u8]>, I: IntoIterator<Item=RawFd> {
97        verify_id(&id)?;
98
99        let streams: Vec<_> = streams.into_iter().collect();
100
101        let mut ancillary_buf = vec!(0; make_size_of_streams(streams.len())?);
102        let mut ancillary = SocketAncillary::new(&mut ancillary_buf);
103        if ancillary.add_fds(&streams) == false {
104            return Err(Error::new(ErrorKind::Other, __!()));
105        }
106        self.send_vectored_with_ancillary(&[IoSlice::new(id.as_ref())], &mut ancillary)?;
107
108        Ok(())
109    }
110
111    fn send_ioe<B>(&self, id: B) -> Result<()> where B: AsRef<[u8]> {
112        self.send_streams(id, [io::stdin().as_raw_fd(), io::stdout().as_raw_fd(), io::stderr().as_raw_fd()])
113    }
114
115    unsafe fn recv_streams<B, T>(&self, id: B, count: usize) -> Result<Vec<T>> where B: AsRef<[u8]>, T: FromRawFd {
116        verify_id(&id)?;
117
118        let mut ancillary_buf = vec!(0; make_size_of_streams(count)?);
119        let mut ancillary = SocketAncillary::new(&mut ancillary_buf);
120
121        // Receive and verify
122        let id = id.as_ref();
123        if id != {
124            let mut io_slices = vec!(0; id.len());
125            {
126                let mut io_slices = [IoSliceMut::new(&mut io_slices)];
127                self.recv_vectored_with_ancillary(&mut io_slices, &mut ancillary)?;
128            }
129            io_slices
130        } {
131            return Err(Error::new(ErrorKind::InvalidData, __!("Invalid ID of streams")));
132        }
133
134        let mut result = Vec::with_capacity(count);
135        for messages in ancillary.messages() {
136            let data = messages.map_err(|e| Error::new(ErrorKind::Other, __!("{:?}", e)))?;
137            match data {
138                AncillaryData::ScmRights(scm_rights) => scm_rights.for_each(|fd| result.push(T::from_raw_fd(fd))),
139                AncillaryData::ScmCredentials(_) => return Err(
140                    Error::new(ErrorKind::InvalidData, __!("Expected ScmRights, got ScmCredentials"))
141                ),
142            };
143        }
144
145        Ok(result)
146    }
147
148    unsafe fn recv_ioe<B>(&self, id: B) -> Result<(Stdio, Stdio, Stdio)> where B: AsRef<[u8]> {
149        const COUNT: usize = 3;
150
151        let mut result = self.recv_streams::<_, Stdio>(id, COUNT)?;
152        match result.len() {
153            COUNT => Ok((result.remove(0), result.remove(0), result.remove(0))),
154            other => Err(Error::new(ErrorKind::InvalidData, __!(
155                "recv_streams() returned a vector of {other} item(s); expected: {count}", other=other, count=COUNT,
156            ))),
157        }
158    }
159
160}
161
162/// # Verifies ID
163fn verify_id<B>(id: B) -> Result<()> where B: AsRef<[u8]> {
164    if id.as_ref().is_empty() {
165        Err(Error::new(ErrorKind::InvalidData, __!("ID must not be empty")))
166    } else {
167        Ok(())
168    }
169}
170
171/// # Makes size of streams with `count` items
172fn make_size_of_streams(count: usize) -> Result<usize> {
173    // This was gotten by tests
174    const FACTOR: usize = 6;
175
176    match RAW_FD_SIZE.checked_mul(count).map(|x| x.checked_mul(FACTOR)) {
177        Some(Some(result)) => Ok(result),
178        _ => Err(Error::new(ErrorKind::InvalidData, __!("Stream has too much items: {count}", count=count))),
179    }
180}