breadx/display/
raw_request.rs

1//               Copyright John Nunley, 2022.
2// Distributed under the Boost Software License, Version 1.0.
3//       (See accompanying file LICENSE or copy at
4//         https://www.boost.org/LICENSE_1_0.txt)
5
6use crate::{
7    connection::{advance_io, new_io_slice, IoSlice},
8    Error, Fd, Result,
9};
10use alloc::{boxed::Box, vec::Vec};
11use core::{convert::TryFrom, mem};
12use x11rb_protocol::{
13    connection::ReplyFdKind,
14    x11_utils::{ReplyFDsRequest, ReplyRequest, Request, TryParseFd, VoidRequest},
15    DiscardMode,
16};
17
18/// The raw request.
19///
20/// This structure essentially acts as a monomorphization of the
21/// [`Request`] trait. It contains all of the information needed
22/// to send the request, such as the raw bytes, whether it has a
23/// reply, and the name of the extension.
24///
25/// [`Request`]: crate::x11_utils::Request
26pub struct RawRequest<'target, 'req> {
27    // invariants:
28    //
29    // - always two empty slices before any actual data
30    // - third data slice has at least four bytes
31    data: &'target mut [IoSlice<'req>],
32    fds: Vec<Fd>,
33    // the number of bytes into data that we've advanced
34    advanced: usize,
35    variant: ReplyFdKind,
36    extension_name: Option<&'static str>,
37    discard_reply: bool,
38    /// Scratch space buffer for use in formatting.
39    buffer: Option<&'req mut [u8; 8]>,
40}
41
42/// A self-contained request.
43///
44/// Useful for futures.
45pub(crate) struct BufferedRequest {
46    data: Vec<u8>,
47    fds: Vec<Fd>,
48    advanced: usize,
49    variant: ReplyFdKind,
50    discard_reply: bool,
51    extension_name: Option<&'static str>,
52    buffer: [u8; 8],
53}
54
55fn from_request<R: Request, Ret>(
56    request: R,
57    variant: ReplyFdKind,
58    discard_reply: bool,
59    f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
60) -> Ret {
61    // use u8::MAX as a placeholder
62    let (serialized, fds) = request.serialize(u8::MAX);
63
64    // slices to use
65    let mut slices = [
66        new_io_slice(&[]),
67        new_io_slice(&[]),
68        new_io_slice(&serialized),
69    ];
70
71    // buffer to use for formatting
72    let mut buffer = [0; 8];
73
74    let mut req = RawRequest::new(&mut slices, fds, variant, R::EXTENSION_NAME, &mut buffer);
75    if discard_reply {
76        req.discard_reply();
77    }
78
79    f(req)
80}
81
82/// Create a new `RawRequest` from a `VoidRequest` type.
83pub fn from_void_request<R: VoidRequest, Ret>(
84    request: R,
85    discard_reply: bool,
86    f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
87) -> Ret {
88    from_request(request, ReplyFdKind::NoReply, discard_reply, f)
89}
90
91/// Create a new `RawRequest` from a `ReplyRequest` type.
92pub fn from_reply_request<R: ReplyRequest, Ret>(
93    request: R,
94    f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
95) -> Ret {
96    from_request(request, ReplyFdKind::ReplyWithoutFDs, false, f)
97}
98
99/// Create a new `RawRequest` from a `ReplyFDsRequest` type.
100pub fn from_reply_fds_request<R: ReplyFDsRequest, Ret>(
101    request: R,
102    f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
103) -> Ret {
104    from_request(request, ReplyFdKind::ReplyWithFDs, false, f)
105}
106
107impl<'target, 'req> RawRequest<'target, 'req> {
108    /// Create a new `RawRequest` from its raw parts.
109    ///
110    /// # Panics
111    ///
112    /// Panics if:
113    ///
114    /// - There are less than three slices.
115    /// - The third slice is not at least four bytes long.
116    pub fn new(
117        data: &'target mut [IoSlice<'req>],
118        fds: Vec<Fd>,
119        variant: ReplyFdKind,
120        extension_name: Option<&'static str>,
121        buffer: &'req mut [u8; 8],
122    ) -> Self {
123        assert!(data.len() >= 3);
124        assert!(data[2].len() >= 4);
125
126        Self {
127            data,
128            fds,
129            advanced: 0,
130            variant,
131            extension_name,
132            discard_reply: false,
133            buffer: Some(buffer),
134        }
135    }
136
137    /// Discard the reply.
138    fn discard_reply(&mut self) {
139        self.discard_reply = true;
140    }
141
142    #[must_use]
143    pub fn discard_mode(&self) -> Option<DiscardMode> {
144        if self.discard_reply {
145            Some(DiscardMode::DiscardReply)
146        } else {
147            None
148        }
149    }
150
151    /// Get the variant of the request.
152    #[must_use]
153    pub fn variant(&self) -> ReplyFdKind {
154        self.variant
155    }
156
157    /// Once the `RawRequest` is finished, this function will
158    /// return the parts that can be sent over the wire.
159    #[must_use]
160    pub fn into_raw_parts(self) -> (Box<[u8]>, Vec<Fd>) {
161        let BufferedRequest { data, fds, .. } = self.into();
162
163        (data.into_boxed_slice(), fds)
164    }
165
166    /// Compute the length of this request.
167    ///
168    /// # Panics
169    ///
170    /// - If this function was already called on this request.
171    #[allow(clippy::cast_possible_truncation)]
172    pub fn format(&mut self, ext_opcode: Option<u8>, max_len: usize) -> Result<()> {
173        let len = self.len();
174
175        // format!
176        let x_len = len / 4;
177
178        if x_len > max_len {
179            return Err(Error::make_large_request(x_len, max_len));
180        }
181
182        // see if we can use truncated notation
183        if let Ok(x_len) = u16::try_from(x_len) {
184            let [l1, l2] = x_len.to_ne_bytes();
185
186            // copy first two bytes of data into the buffer
187            let buffer = self.buffer.as_mut().unwrap();
188            buffer[0] = match ext_opcode {
189                Some(x) => x,
190                None => self.data[2][0],
191            };
192            buffer[1] = self.data[2][1];
193            buffer[2] = l1;
194            buffer[3] = l2;
195
196            // set/advance buffer
197            let buffer = self.buffer.take().unwrap();
198            self.data[1] = new_io_slice(&buffer[..4]);
199            advance_io(&mut self.data[2], 4);
200        } else {
201            let length_bytes = ((x_len + 1) as u32).to_ne_bytes();
202
203            // copy existing data to the buffer
204            let buffer = self.buffer.as_mut().unwrap();
205            buffer[0] = match ext_opcode {
206                Some(x) => x,
207                None => self.data[2][0],
208            };
209            buffer[1] = self.data[2][1];
210            buffer[2] = 0;
211            buffer[3] = 0;
212            buffer[4..8].copy_from_slice(&length_bytes);
213
214            self.data[1] = new_io_slice(self.buffer.take().unwrap());
215            advance_io(&mut self.data[2], 4);
216        }
217
218        Ok(())
219    }
220
221    /// The extension name for the opcode.
222    #[must_use]
223    pub fn extension(&self) -> Option<&'static str> {
224        self.extension_name
225    }
226
227    /// Get the total amount of data.
228    pub fn len(&self) -> usize {
229        self.data
230            .iter()
231            .map(|buf| buf.len())
232            .fold(0, usize::saturating_add)
233    }
234
235    /// Tell whether this request is empty.
236    #[must_use]
237    pub fn is_empty(&self) -> bool {
238        self.data.iter().all(|buf| buf.is_empty())
239    }
240
241    /// Get the parts of this data that will be sent over the wire.
242    #[allow(clippy::mut_mut)]
243    pub fn mut_parts(&mut self) -> (&mut &'target mut [IoSlice<'req>], &mut Vec<Fd>) {
244        (&mut self.data, &mut self.fds)
245    }
246
247    /// Advance this request by the given number of bytes.
248    pub fn advance(&mut self, bytes: usize) {
249        // keep track of how many bytes we advanced by
250        self.advanced += bytes;
251
252        // determine how many slices from the front we can
253        // remove
254        let mut to_remove = 0;
255        let mut total_len = 0;
256
257        for buf in self.data.iter() {
258            if total_len + buf.len() > bytes {
259                break;
260            }
261            total_len += buf.len();
262            to_remove += 1;
263        }
264
265        tracing::trace!(
266            "Advancing by {} bytes, removing {} slices and {} bytes",
267            bytes,
268            to_remove,
269            bytes - total_len,
270        );
271        /*tracing::trace!(
272            "Remaining slices: {:?}",
273            self.data.iter().map(|buf| buf.len()).collect::<Vec<_>>()
274        );*/
275
276        // replace the bytes
277        self.data = &mut mem::take(&mut self.data)[to_remove..];
278
279        // advance the last buffer if we need to
280        if !self.data.is_empty() {
281            advance_io(&mut self.data[0], bytes - total_len);
282        }
283    }
284}
285
286impl BufferedRequest {
287    pub(crate) fn take<Ret>(&mut self, f: impl FnOnce(RawRequest<'_, '_>) -> Ret) -> Ret {
288        // create a RawRequest borrowed from this request
289        let raw = RawRequest {
290            buffer: Some(&mut self.buffer),
291            data: &mut [
292                new_io_slice(&[]),
293                new_io_slice(&[]),
294                new_io_slice(&self.data[self.advanced..]),
295            ],
296            fds: mem::take(&mut self.fds),
297            advanced: self.advanced,
298            variant: self.variant,
299            discard_reply: self.discard_reply,
300            extension_name: self.extension_name,
301        };
302
303        // run the function
304        f(raw)
305    }
306}
307
308cfg_async! {
309    impl BufferedRequest {
310        pub(crate) fn borrow<Ret>(&mut self, f: impl FnOnce(&mut RawRequest<'_, '_>) -> Ret) -> Ret {
311            // create a RawRequest borrowed from this request
312            tracing::trace!(data_len = self.data.len());
313            let mut raw = RawRequest {
314                buffer: Some(&mut self.buffer),
315                data: &mut [
316                    new_io_slice(&[]),
317                    new_io_slice(&[]),
318                    new_io_slice(&self.data[self.advanced..]),
319                ],
320                fds: mem::take(&mut self.fds),
321                advanced: self.advanced,
322                variant: self.variant,
323                discard_reply: self.discard_reply,
324                extension_name: self.extension_name,
325            };
326
327            // run the function
328            let ret = f(&mut raw);
329
330            // merge the buffer into the request if we've formatted it
331            let merge_buffer = if raw.data.len() > 2 && raw.data[1].len() > 0 {
332                Some(raw.data[1].len())
333            } else {
334                None
335            };
336
337            // if the request has already advanced past our cursor,
338            // we're done
339            self.advanced = raw.advanced;
340            self.fds = mem::take(&mut raw.fds);
341
342            if self.advanced >= self.data.len() {
343                self.data.clear();
344                return ret;
345            }
346
347            if let Some(merge_len) = merge_buffer {
348                // splice the buffer variable to the beginning of our slice
349                tracing::trace!(merge_len, "merging buffer into data");
350                self.data
351                    .splice(0..4, self.buffer[..merge_len].iter().copied());
352            }
353
354            tracing::trace!("{:?}", &self.data);
355
356            ret
357        }
358    }
359}
360
361impl<'target, 'req> From<RawRequest<'target, 'req>> for BufferedRequest {
362    fn from(raw: RawRequest<'target, 'req>) -> Self {
363        // collect the data into a single buffer
364        let mut data = Vec::with_capacity(raw.len() + 4);
365        for buf in raw.data.iter() {
366            data.extend_from_slice(buf);
367        }
368
369        Self {
370            data,
371            advanced: raw.advanced,
372            variant: raw.variant,
373            extension_name: raw.extension_name,
374            fds: raw.fds,
375            discard_reply: raw.discard_reply,
376            buffer: match raw.buffer {
377                Some(buf) => *buf,
378                None => [0; 8],
379            },
380        }
381    }
382}
383
384/// The raw reply.
385pub struct RawReply {
386    data: Box<[u8]>,
387    fds: Vec<Fd>,
388}
389
390impl RawReply {
391    #[must_use]
392    pub fn new(data: Box<[u8]>, fds: Vec<Fd>) -> Self {
393        Self { data, fds }
394    }
395
396    pub fn into_reply<T: TryParseFd>(mut self) -> Result<T> {
397        let (val, _) =
398            T::try_parse_fd(&self.data, &mut self.fds).map_err(Error::make_parse_error)?;
399        Ok(val)
400    }
401}