x11rb_protocol/
connect.rs

1//! Contains utilities for connection to the X11 server.
2
3use crate::errors::{ConnectError, ParseError};
4use crate::protocol::xproto::{Setup, SetupAuthenticate, SetupFailed, SetupRequest};
5use crate::x11_utils::{Serialize, TryParse};
6
7#[cfg(feature = "std")]
8use crate::xauth::{get_auth, Family};
9
10use alloc::{vec, vec::Vec};
11
12use core::fmt;
13
14/// The connection handshake used to connect to the X11 server.
15///
16/// In order to connect to the X11 server, the client must send the
17/// server a request containing important pieces of client data. In
18/// response, the server sends the client a response containing one
19/// of the following:
20///
21/// - An error indicating that the setup request is malformed, or the
22///   setup otherwise failed.
23/// - A request for further authorization data.
24/// - The [`Setup`](protocol/xproto/struct.Setup.html) for the connection,
25///   which contains server-specific information and is necessary for
26///   the client's ability to communicate with the server.
27///
28/// This handshake contains four relevant methods:
29///
30/// - `new`, which creates the handshake and also returns the setup request
31///   to send to the server.
32/// - `buffer`, which returns an `&mut [u8]` containing the buffer
33///   which is intended to hold the bytes received from the server.
34/// - `advance`, which takes a `usize` indicating how many bytes
35///   were received from the server and advances the buffer.
36/// - `into_setup`, which consumes this `Connect` and returns the
37///   full `Setup`.
38///
39/// # Examples
40///
41/// Let's say you have an object `stream` which implements `Read`
42/// and `Write`. In addition, you already have the connection family,
43/// the address of the connection, and the display. You can use the `Connect`
44/// to establish an X11 connection like so:
45///
46/// ```rust,no_run
47/// # #[cfg(feature = "std")]
48/// # {
49/// # use x11rb_protocol::connect::Connect;
50/// # use x11rb_protocol::xauth::Family;
51/// # use std::{error::Error, io::prelude::*};
52/// # fn main() -> Result<(), Box<dyn Error>> {
53/// # struct Stream;
54/// # impl Read for Stream {
55/// #    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
56/// #       Ok(buf.len())
57/// #    }
58/// # }
59/// # impl Write for Stream {
60/// #    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
61/// #       Ok(buf.len())
62/// #    }
63/// #    fn flush(&mut self) -> std::io::Result<()> {
64/// #       Ok(())
65/// #    }
66/// # }
67/// # let mut stream = Stream;
68/// let family = Family::INTERNET;
69/// let address = b"foobar";
70/// let display = 0;
71///
72/// let (mut connect, setup_request) = Connect::new(family, address, display)?;
73///
74/// // send the setup request to the server
75/// stream.write_all(&setup_request)?;
76///
77/// // receive the setup response from the server
78/// loop {
79///     let adv = stream.read(connect.buffer())?;
80///
81///     // if we've completed the setup, break out of the loop
82///     if connect.advance(adv) {
83///         break;
84///     }
85/// }
86///
87/// // get the setup used for our connection
88/// let setup = connect.into_setup()?;
89/// # Ok(())
90/// # }
91/// # }
92/// ```
93///
94/// If, instead, `stream` implements `AsyncRead` and `AsyncWrite`, the code
95/// would be identical, but with `.await` after `read` and `write_all`.
96pub struct Connect {
97    // input buffer
98    buffer: Vec<u8>,
99    // position in the buffer that has been filled
100    advanced: usize,
101}
102
103const INITIAL_CAPACITY: usize = 8;
104
105// X11 interprets capital B as big endian, and lowercase l as little endian.
106#[cfg(target_endian = "little")]
107const BYTE_ORDER: u8 = b'l';
108#[cfg(not(target_endian = "little"))]
109const BYTE_ORDER: u8 = b'B';
110
111// protocol version
112const PROTOCOL_MAJOR_VERSION: u16 = 11;
113const PROTOCOL_MINOR_VERSION: u16 = 0;
114
115impl Connect {
116    /// The initial state of a `Connect`.
117    fn blank() -> Self {
118        Self {
119            buffer: vec![0; INITIAL_CAPACITY],
120            advanced: 0,
121        }
122    }
123
124    /// Create a new `Connect` from the given authorization data.
125    ///
126    /// This uses the provided protocol name and data to establish the connection,
127    /// rather than the default protocol name and data found in `Xauthority`.
128    ///
129    /// # Example
130    ///
131    /// ```rust
132    /// # use x11rb_protocol::connect::Connect;
133    ///
134    /// let (connect, setup_request) = Connect::with_authorization(
135    ///     b"MIT-MAGIC-COOKIE-1".to_vec(),
136    ///     b"my_secret_password".to_vec(),
137    /// );
138    /// ```
139    pub fn with_authorization(protocol_name: Vec<u8>, protocol_data: Vec<u8>) -> (Self, Vec<u8>) {
140        // craft the setup request
141        let sr = SetupRequest {
142            byte_order: BYTE_ORDER,
143            protocol_major_version: PROTOCOL_MAJOR_VERSION,
144            protocol_minor_version: PROTOCOL_MINOR_VERSION,
145            authorization_protocol_name: protocol_name,
146            authorization_protocol_data: protocol_data,
147        };
148
149        // return it
150        (Self::blank(), sr.serialize())
151    }
152
153    /// Create a new `Connect` from the information necessary to connect to the X11 server.
154    ///
155    /// This returns the connection handshake object as well as the setup request to send to the server.
156    #[cfg(feature = "std")]
157    pub fn new(
158        family: Family,
159        address: &[u8],
160        display: u16,
161    ) -> Result<(Self, Vec<u8>), ConnectError> {
162        match get_auth(family, address, display)? {
163            Some((name, data)) => Ok(Self::with_authorization(name, data)),
164            None => {
165                // fall through to no authorization
166                Ok(Self::with_authorization(Vec::new(), Vec::new()))
167            }
168        }
169    }
170
171    /// Returns the buffer that needs to be filled with incoming data from the server.
172    ///
173    /// After filling this buffer (using a method like `Read::read`), call [`Self::advance`] with
174    /// the number of bytes read to indicate that the buffer has been filled.
175    pub fn buffer(&mut self) -> &mut [u8] {
176        &mut self.buffer[self.advanced..]
177    }
178
179    /// Advance the internal buffer, given the number of bytes that have been read.
180    pub fn advance(&mut self, bytes: usize) -> bool {
181        self.advanced += bytes;
182        debug_assert!(self.buffer.len() >= self.advanced);
183
184        // if we've read up to the initial capacity, tell how many more bytes
185        // we need to read
186        if self.advanced == INITIAL_CAPACITY {
187            // remaining length is at byte range 6-7 in 4-bytes
188            let length = u16::from_ne_bytes([self.buffer[6], self.buffer[7]]);
189            let length = length as usize * 4;
190
191            // allocate more room
192            // use reserve_exact because this will be the final
193            // length of the vector
194            self.buffer.reserve_exact(length);
195            self.buffer.resize(length + self.buffer.len(), 0);
196            false
197        } else {
198            self.advanced == self.buffer.len()
199        }
200    }
201
202    /// Returns the setup provided by the server.
203    ///
204    /// # Errors
205    ///
206    /// - If this method is called before the server returns all of the required data,
207    ///   it returns `ConnectError::NotEnoughData`.
208    /// - If the server fails to establish the X11 connection, the `ConnectError::SetupFailed`
209    ///   variant is returned.
210    /// - If the server failed to authenticate the user, the `ConnectError::SetupAuthenticate`
211    ///   error is returned.
212    /// - If the server failed to parse any of the above responses, the
213    ///   `ConnectError::ParseError` error is returned.
214    pub fn into_setup(self) -> Result<Setup, ConnectError> {
215        // if we aren't full yet, panic
216        if self.advanced != self.buffer.len() {
217            return Err(ConnectError::Incomplete {
218                expected: self.buffer.len(),
219                received: self.advanced,
220            });
221        }
222
223        // parse the setup response
224        match self.buffer[0] {
225            0 => {
226                // an error has occurred
227                let (failed, _) = SetupFailed::try_parse(&self.buffer)?;
228                Err(ConnectError::SetupFailed(failed))
229            }
230            1 => {
231                // the setup is valid!
232                let (success, _) = Setup::try_parse(&self.buffer)?;
233                Ok(success)
234            }
235            2 => {
236                // we need further authentication
237                let (more_auth, _) = SetupAuthenticate::try_parse(&self.buffer)?;
238                Err(ConnectError::SetupAuthenticate(more_auth))
239            }
240            _ => {
241                // this is undefined
242                Err(ParseError::InvalidValue.into())
243            }
244        }
245    }
246}
247
248impl fmt::Debug for Connect {
249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250        f.debug_struct("Connect")
251            .field(
252                "buffer",
253                &format_args!("{}/{}", self.advanced, self.buffer.len()),
254            )
255            .finish()
256    }
257}
258
259impl TryFrom<Connect> for Setup {
260    type Error = ConnectError;
261
262    fn try_from(connect: Connect) -> Result<Self, Self::Error> {
263        connect.into_setup()
264    }
265}
266
267#[cfg(test)]
268#[cfg(all(feature = "extra-traits", feature = "std"))]
269mod tests {
270    use super::Connect;
271    use crate::errors::ConnectError;
272    use crate::protocol::xproto::{ImageOrder, Setup, SetupAuthenticate, SetupFailed};
273    use crate::x11_utils::Serialize;
274    use alloc::vec;
275
276    fn test_setup() -> Setup {
277        let mut s = Setup {
278            status: 1,
279            protocol_major_version: 11,
280            protocol_minor_version: 0,
281            length: 0,
282            release_number: 0,
283            resource_id_base: 1,
284            resource_id_mask: 1,
285            motion_buffer_size: 0,
286            maximum_request_length: 0,
287            image_byte_order: ImageOrder::LSB_FIRST,
288            bitmap_format_bit_order: ImageOrder::LSB_FIRST,
289            bitmap_format_scanline_unit: 32,
290            bitmap_format_scanline_pad: 32,
291            min_keycode: 0,
292            max_keycode: 0,
293            vendor: b"Testing Setup".to_vec(),
294            pixmap_formats: vec![],
295            roots: vec![],
296        };
297        // +3 so it rounds up
298        s.length = ((s.serialize().len() - 8 + 3) / 4) as u16;
299        s
300    }
301
302    fn try_receive_bytes(item: &impl Serialize) -> Result<Setup, ConnectError> {
303        let mut connect = Connect::blank();
304
305        // feed in a setup
306        let mut item_bytes = vec![];
307        item.serialize_into(&mut item_bytes);
308
309        let mut i = 0;
310        loop {
311            i += 1;
312            if i > 500 {
313                panic!("too many iterations");
314            }
315
316            // copy bytes to connect
317            let buffer = connect.buffer();
318            let bytes_to_copy = std::cmp::min(item_bytes.len(), buffer.len());
319            buffer[..bytes_to_copy].copy_from_slice(&item_bytes[..bytes_to_copy]);
320
321            // drain the bytes that we've already copied
322            drop(item_bytes.drain(..bytes_to_copy));
323
324            // check advance
325            if connect.advance(bytes_to_copy) {
326                break;
327            }
328        }
329
330        connect.into_setup()
331    }
332
333    #[test]
334    fn test_connect_receive_setup() {
335        let setup = test_setup();
336        let b = try_receive_bytes(&setup);
337
338        match b {
339            Ok(s) => assert_eq!(s, setup),
340            Err(e) => panic!("{:?}", e),
341        }
342    }
343
344    #[test]
345    fn test_connect_receive_setup_authenticate() {
346        let setup = SetupAuthenticate {
347            status: 2,
348            reason: b"Needs more auth.".to_vec(),
349        };
350
351        let b = try_receive_bytes(&setup);
352        match b {
353            Ok(s) => panic!("{:?}", s),
354            Err(ConnectError::SetupAuthenticate(e)) => assert_eq!(e, setup),
355            Err(e) => panic!("{:?}", e),
356        }
357    }
358
359    #[test]
360    fn test_connect_receive_setup_failed() {
361        let mut setup = SetupFailed {
362            status: 0,
363            protocol_major_version: 11,
364            protocol_minor_version: 0,
365            length: 0,
366            reason: b"whatever".to_vec(),
367        };
368        setup.length = ((setup.serialize().len() - 8) / 4) as _;
369
370        let b = try_receive_bytes(&setup);
371        match b {
372            Ok(s) => panic!("{:?}", s),
373            Err(ConnectError::SetupFailed(e)) => assert_eq!(e, setup),
374            Err(e) => panic!("{:?}", e),
375        }
376    }
377}