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::convert::TryFrom;
13use 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`.
94pub struct Connect {
95 // input buffer
96 buffer: Vec<u8>,
97 // position in the buffer that has been filled
98 advanced: usize,
99}
100
101const INITIAL_CAPACITY: usize = 8;
102
103// X11 interprets capital B as big endian, and lowercase l as little endian.
104#[cfg(target_endian = "little")]
105const BYTE_ORDER: u8 = b'l';
106#[cfg(not(target_endian = "little"))]
107const BYTE_ORDER: u8 = b'B';
108
109// protocol version
110const PROTOCOL_MAJOR_VERSION: u16 = 11;
111const PROTOCOL_MINOR_VERSION: u16 = 0;
112
113impl 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
246impl 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
257impl 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)]
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 use core::mem::drop;
273
274 fn test_setup() -> Setup {
275 let mut s = Setup {
276 status: 1,
277 protocol_major_version: 11,
278 protocol_minor_version: 0,
279 length: 0,
280 release_number: 0,
281 resource_id_base: 1,
282 resource_id_mask: 1,
283 motion_buffer_size: 0,
284 maximum_request_length: 0,
285 image_byte_order: ImageOrder::LSB_FIRST,
286 bitmap_format_bit_order: ImageOrder::LSB_FIRST,
287 bitmap_format_scanline_unit: 32,
288 bitmap_format_scanline_pad: 32,
289 min_keycode: 0,
290 max_keycode: 0,
291 vendor: b"Testing Setup".to_vec(),
292 pixmap_formats: vec![],
293 roots: vec![],
294 };
295 // +3 so it rounds up
296 s.length = ((s.serialize().len() - 8 + 3) / 4) as u16;
297 s
298 }
299
300 fn try_receive_bytes(item: &impl Serialize) -> Result<Setup, ConnectError> {
301 let mut connect = Connect::blank();
302
303 // feed in a setup
304 let mut item_bytes = vec![];
305 item.serialize_into(&mut item_bytes);
306
307 let mut i = 0;
308 loop {
309 i += 1;
310 if i > 500 {
311 panic!("too many iterations");
312 }
313
314 // copy bytes to connect
315 let buffer = connect.buffer();
316 let bytes_to_copy = std::cmp::min(item_bytes.len(), buffer.len());
317 buffer[..bytes_to_copy].copy_from_slice(&item_bytes[..bytes_to_copy]);
318
319 // drain the bytes that we've already copied
320 drop(item_bytes.drain(..bytes_to_copy));
321
322 // check advance
323 if connect.advance(bytes_to_copy) {
324 break;
325 }
326 }
327
328 connect.into_setup()
329 }
330
331 #[test]
332 fn test_connect_receive_setup() {
333 let setup = test_setup();
334 let b = try_receive_bytes(&setup);
335
336 match b {
337 Ok(s) => assert_eq!(s, setup),
338 Err(e) => panic!("{:?}", e),
339 }
340 }
341
342 #[test]
343 fn test_connect_receive_setup_authenticate() {
344 let setup = SetupAuthenticate {
345 status: 2,
346 reason: b"Needs more auth.".to_vec(),
347 };
348
349 let b = try_receive_bytes(&setup);
350 match b {
351 Ok(s) => panic!("{:?}", s),
352 Err(ConnectError::SetupAuthenticate(e)) => assert_eq!(e, setup),
353 Err(e) => panic!("{:?}", e),
354 }
355 }
356
357 #[test]
358 fn test_connect_receive_setup_failed() {
359 let mut setup = SetupFailed {
360 status: 0,
361 protocol_major_version: 11,
362 protocol_minor_version: 0,
363 length: 0,
364 reason: b"whatever".to_vec(),
365 };
366 setup.length = ((setup.serialize().len() - 8) / 4) as _;
367
368 let b = try_receive_bytes(&setup);
369 match b {
370 Ok(s) => panic!("{:?}", s),
371 Err(ConnectError::SetupFailed(e)) => assert_eq!(e, setup),
372 Err(e) => panic!("{:?}", e),
373 }
374 }
375}
376