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