1 | //! Contains utilities for connection to the X11 server. |
2 | |
3 | use crate::errors::{ConnectError, ParseError}; |
4 | use crate::protocol::xproto::{Setup, SetupAuthenticate, SetupFailed, SetupRequest}; |
5 | use crate::x11_utils::{Serialize, TryParse}; |
6 | |
7 | #[cfg (feature = "std" )] |
8 | use crate::xauth::{get_auth, Family}; |
9 | |
10 | use alloc::{vec, vec::Vec}; |
11 | |
12 | use 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`. |
93 | pub struct Connect { |
94 | // input buffer |
95 | buffer: Vec<u8>, |
96 | // position in the buffer that has been filled |
97 | advanced: usize, |
98 | } |
99 | |
100 | const INITIAL_CAPACITY: usize = 8; |
101 | |
102 | // X11 interprets capital B as big endian, and lowercase l as little endian. |
103 | #[cfg (target_endian = "little" )] |
104 | const BYTE_ORDER: u8 = b'l' ; |
105 | #[cfg (not(target_endian = "little" ))] |
106 | const BYTE_ORDER: u8 = b'B' ; |
107 | |
108 | // protocol version |
109 | const PROTOCOL_MAJOR_VERSION: u16 = 11; |
110 | const PROTOCOL_MINOR_VERSION: u16 = 0; |
111 | |
112 | impl 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 | |
245 | impl fmt::Debug for Connect { |
246 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
247 | f&mut DebugStruct<'_, '_>.debug_struct("Connect" ) |
248 | .field( |
249 | name:"buffer" , |
250 | &format_args!(" {}/ {}" , self.advanced, self.buffer.len()), |
251 | ) |
252 | .finish() |
253 | } |
254 | } |
255 | |
256 | impl 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" )] |
266 | mod 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 | } |
375 | |