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}