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}