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}