breadx/connection/
mod.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
6//! Implementation of the [`Connection`] type, which is used as a byte
7//! transport for the actual X11 protocol.
8//!
9//! X11 communication can take place over "any reliable byte stream"
10//! ([source]). Although this byte stream is most often a TCP connection
11//! or a Unix domain socket, it can be anything else. The [`Connection`]
12//! trait aims to define the interface for this byte stream.
13//!
14//! Note that in the overwhelming majority of cases, [`NameConnection`] will
15//! fulfill all of your connection-related needs. All other connection types
16//! exist to give the user as much freedom as possible in using the protocol.
17//!
18//! ## Details
19//!
20//! In X11, the requirements for a byte stream include:
21//!
22//! - Being able to write bytes.
23//! - Being able to read bytes.
24//! - Being able to read bytes without blocking.
25//!
26//! In addition, certain extensions requires the ability to pass file
27//! descriptors between the client and the server. This is not a requirement.
28//!
29//! - [`StdConnection`] (enabled with the `std` feature) is a wrapper around
30//!   any type that implements [`Read`] and [`Write`]. In addition, it also
31//!   requires [`AsRawFd`] on Unix and [`AsRawSocket`] on Windows, in order to
32//!   take advantage of system APIs for non-blocking I/O.
33//! - [`SendmsgConnection`] (requires Unix) is a wrapper around a Unix domain
34//!   socket that includes message passing functionality.
35//! - [`BufConnection`] is a wrapper around anything that implements [`Connection`]
36//!   that buffers all data written to and read from it.
37//!
38//! [`Connection`]: crate::connection::Connection
39//! [source]: https://www.x.org/releases/X11R7.5/doc/x11proto/proto.pdf
40//! [`NameConnection`]: crate::name::NameConnection
41//! [`StdConnection`]: crate::connection::StdConnection
42//! [`Read`]: std::io::Read
43//! [`Write`]: std::io::Write
44//! [`AsRawFd`]: std::os::unix::io::AsRawFd
45//! [`AsRawSocket`]: std::os::windows::io::AsRawSocket
46//! [`SendmsgConnection`]: crate::connection::SendmsgConnection
47//! [`BufConnection`]: crate::connection::BufConnection
48
49use crate::{Error, Fd, InvalidState, Result};
50use alloc::vec::Vec;
51
52mod buffered;
53pub use buffered::BufConnection;
54
55cfg_std_unix! {
56    mod sendmsg;
57    pub use sendmsg::SendmsgConnection;
58}
59
60cfg_test! {
61    mod test;
62    pub(crate) use test::with_test_connection;
63}
64
65cfg_std! {
66    pub(crate) type IoSlice<'a> = std::io::IoSlice<'a>;
67    pub(crate) type IoSliceMut<'a> = std::io::IoSliceMut<'a>;
68
69    mod std_wrapper;
70    pub use std_wrapper::StdConnection;
71}
72
73cfg_no_std! {
74    pub(crate) type IoSlice<'a> = &'a [u8];
75    pub(crate) type IoSliceMut<'a> = &'a mut [u8];
76}
77
78/// A "suitable byte stream" where communication with the X11 server can occur.
79///
80/// See the [module level documentation](index.html) for more details.
81pub trait Connection {
82    /// Write a series of I/O slices and a series of file descriptors to
83    /// the X11 server.
84    ///
85    /// This calls the platform's writing utility to write the slices and
86    /// file descriptors, and returns the number of bytes written. If
87    /// the call succeeded, the `fds` array should be empty after operation.
88    ///
89    /// If the `fds` array is empty, this function call is allowed to
90    /// degenerate to a standard vectored write.
91    ///
92    /// # Blocking
93    ///
94    /// This operation may block under normal circumstances. However, if this
95    /// type implements `AsRawFd` or `AsRawSocket`, and if `set_nonblocking`
96    /// or an equivalent method has been called on this object earlier, then
97    /// this operation should not block, and return a `WouldBlock` error if
98    /// it would.
99    ///
100    /// # Errors
101    ///
102    /// Some `Connection` implementations do not support FD passing. If an
103    /// FD is passed into these implementations, an `unsupported()` [`Error`]
104    /// will be raised.
105    ///
106    /// In addition, any platform I/O errors will be bubbled up to the user.
107    fn send_slices_and_fds(&mut self, slices: &[IoSlice<'_>], fds: &mut Vec<Fd>) -> Result<usize>;
108
109    /// Write a series of I/O slices to the X11 server.
110    ///
111    /// This calls the platform's writing utility to write the slices, and
112    /// returns the number of bytes written. By default, this is implemented
113    /// as a call to `send_slices_and_fds` without any file descriptors.
114    /// Certain implementations can optimize away having to keep track
115    /// of file descriptors.
116    ///
117    /// # Blocking
118    ///
119    /// Same as `send_slices_and_fds`.
120    ///
121    /// # Errors
122    ///
123    /// Same as `send_slices_and_fds`.
124    fn send_slices(&mut self, slices: &[IoSlice<'_>]) -> Result<usize> {
125        self.send_slices_and_fds(slices, &mut Vec::new())
126    }
127
128    /// Write a slice of data to the X11 server.
129    ///
130    /// This calls the platform's writing utility to write the slice, and
131    /// returs the number of bytes written. By default, this is implemented
132    /// as a call to `send_slices`.
133    ///
134    /// # Blocking
135    ///
136    /// Same as `send_slices_and_fds`.
137    ///
138    /// # Errors
139    ///
140    /// Same as `send_slices`.
141    fn send_slice(&mut self, slice: &[u8]) -> Result<usize> {
142        self.send_slices(&[new_io_slice(slice)])
143    }
144
145    /// Read data to a series of I/O slices and a buffer for file
146    /// descriptors.
147    ///
148    /// This calls the platform's reading utility to read into the buffers,
149    /// and returns the total number of bytes read.
150    ///
151    /// # Blocking
152    ///
153    /// This operation may block under normal circumstances. However, if this
154    /// type implements `AsRawFd` or `AsRawSocket`, and if `set_nonblocking`
155    /// or an equivalent method has been called on this object earlier, then
156    /// this operation should not block, and return a `WouldBlock` error if
157    /// it would.
158    ///
159    /// # Errors
160    ///
161    /// Any platform I/O errors will be bubbled up to the user.
162    fn recv_slices_and_fds(
163        &mut self,
164        slices: &mut [IoSliceMut<'_>],
165        fds: &mut Vec<Fd>,
166    ) -> Result<usize>;
167
168    /// Read data to a single I/O slice and a buffer for file
169    /// descriptors.
170    ///
171    /// This calls the platform's reading utility to read into the buffers,
172    /// and returns the total number of bytes read. By default, this is
173    /// implemented as a call to `recv_slices_and_fds` with a single
174    /// slice.
175    ///
176    /// # Blocking
177    ///
178    /// Same as `recv_slices_and_fds`.
179    ///
180    /// # Errors
181    ///
182    /// Any platform I/O errors will be bubbled up to the user.
183    fn recv_slice_and_fds(&mut self, slice: &mut [u8], fds: &mut Vec<Fd>) -> Result<usize> {
184        self.recv_slices_and_fds(&mut [new_io_slice_mut(slice)], fds)
185    }
186
187    /// Read data for a single I/O slice.
188    ///
189    /// This calls the platform's reading utility to read into the buffer,
190    /// and returns the total number of bytes read. By default, this is
191    /// implemented as a call to `recv_slice_and_fds` with a single slice.
192    ///
193    /// # Blocking
194    ///
195    /// Same as `recv_slices_and_fds`.
196    ///
197    /// # Errors
198    ///
199    /// If `recv_slice_and_fds` returns any file descriptors, this
200    /// function will return an `invalid_state()` error. It is encouraged
201    /// for implementors to override this behavior so that this check is
202    /// not necessary.
203    ///
204    /// In addition, any platform I/O errors will be bubbled up to the
205    /// user.
206    fn recv_slice(&mut self, slice: &mut [u8]) -> Result<usize> {
207        let mut fds = Vec::new();
208        let result = self.recv_slice_and_fds(slice, &mut fds);
209
210        // check to ensure fds is empty
211        if fds.is_empty() {
212            result
213        } else {
214            Err(Error::make_invalid_state(InvalidState::UnexpectedFds))
215        }
216    }
217
218    /// Flush all data in this connection's buffer.
219    ///
220    /// # Blocking
221    ///
222    /// Unless this connection has been set into non-blocking mode, this
223    /// method is expected to block until all bytes in the buffer are
224    /// written.
225    ///
226    /// # Errors
227    ///
228    /// Any platform I/O errors will be bubbled up to the user.
229    fn flush(&mut self) -> Result<()>;
230
231    /// Receive data from the X11 server into a set of I/O slices, in a
232    /// non-blocking manner.
233    ///
234    /// # Blocking
235    ///
236    /// Even if the connection is in blocking mode, this function should
237    /// never block.
238    ///
239    /// # Errors
240    ///
241    /// This will return a `WouldBlock` I/O error if the function would
242    /// block. Otherwise, it should bubble up any platform I/O errors.
243    fn non_blocking_recv_slices_and_fds(
244        &mut self,
245        slices: &mut [IoSliceMut<'_>],
246        fds: &mut Vec<Fd>,
247    ) -> Result<usize>;
248
249    /// Receive data from the X11 server into a single slice, in a
250    /// non-blocking manner.
251    ///
252    /// # Errors
253    ///
254    /// Same as `non_blocking_recv_slices_and_fds`.
255    fn non_blocking_recv_slice_and_fds(
256        &mut self,
257        slice: &mut [u8],
258        fds: &mut Vec<Fd>,
259    ) -> Result<usize> {
260        self.non_blocking_recv_slices_and_fds(&mut [new_io_slice_mut(slice)], fds)
261    }
262
263    /// Shutdown this connection.
264    ///
265    /// This should have the same effect as dropping this object, but
266    /// any OS errors should be able to be caught.
267    ///
268    /// # Blocking
269    ///
270    /// This function should never block.
271    ///
272    /// # Errors
273    ///
274    /// Any OS errors should be bubbled up to the user.
275    fn shutdown(&self) -> Result<()>;
276}
277
278// implement Connection for all &mut impl Connection
279impl<C: Connection + ?Sized> Connection for &mut C {
280    fn send_slices_and_fds(&mut self, slices: &[IoSlice<'_>], fds: &mut Vec<Fd>) -> Result<usize> {
281        (**self).send_slices_and_fds(slices, fds)
282    }
283
284    fn send_slices(&mut self, slices: &[IoSlice<'_>]) -> Result<usize> {
285        (**self).send_slices(slices)
286    }
287
288    fn send_slice(&mut self, slice: &[u8]) -> Result<usize> {
289        (**self).send_slice(slice)
290    }
291
292    fn recv_slices_and_fds(
293        &mut self,
294        slices: &mut [IoSliceMut<'_>],
295        fds: &mut Vec<Fd>,
296    ) -> Result<usize> {
297        (**self).recv_slices_and_fds(slices, fds)
298    }
299
300    fn recv_slice_and_fds(&mut self, slice: &mut [u8], fds: &mut Vec<Fd>) -> Result<usize> {
301        (**self).recv_slice_and_fds(slice, fds)
302    }
303
304    fn recv_slice(&mut self, slice: &mut [u8]) -> Result<usize> {
305        (**self).recv_slice(slice)
306    }
307
308    fn flush(&mut self) -> Result<()> {
309        (**self).flush()
310    }
311
312    fn non_blocking_recv_slices_and_fds(
313        &mut self,
314        slices: &mut [IoSliceMut<'_>],
315        fds: &mut Vec<Fd>,
316    ) -> Result<usize> {
317        (**self).non_blocking_recv_slices_and_fds(slices, fds)
318    }
319
320    fn non_blocking_recv_slice_and_fds(
321        &mut self,
322        slice: &mut [u8],
323        fds: &mut Vec<Fd>,
324    ) -> Result<usize> {
325        (**self).non_blocking_recv_slice_and_fds(slice, fds)
326    }
327
328    fn shutdown(&self) -> Result<()> {
329        (**self).shutdown()
330    }
331}
332
333cfg_std! {
334    pub(crate) fn new_io_slice(sl: &[u8]) -> IoSlice<'_> {
335        IoSlice::new(sl)
336    }
337
338    pub(crate) fn new_io_slice_mut(sl: &mut [u8]) -> IoSliceMut<'_> {
339        IoSliceMut::new(sl)
340    }
341
342    pub(crate) fn advance_io(sl: &mut IoSlice<'_>, bytes: usize) {
343        advance::advance(sl, bytes);
344    }
345}
346
347cfg_no_std! {
348    pub(crate) fn new_io_slice(sl: &[u8]) -> IoSlice<'_> {
349        sl
350    }
351
352    pub(crate) fn new_io_slice_mut(sl: &mut [u8]) -> IoSliceMut<'_> {
353        sl
354    }
355
356    pub(crate) fn advance_io(sl: &mut IoSlice<'_>, bytes: usize) {
357        *sl = &sl[bytes..];
358    }
359}