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