1//! Generic connection-related types and definitions.
2//!
3//! This module contains the `Connection` trait and related definitions. The code in this module is
4//! used by each concrete implementation of the X11 protocol.
5
6use std::convert::{TryFrom, TryInto};
7use std::io::IoSlice;
8
9use x11rb_protocol::x11_utils::{ReplyFDsRequest, ReplyRequest, VoidRequest};
10
11use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
12use crate::errors::{ConnectionError, ParseError, ReplyError, ReplyOrIdError};
13use crate::protocol::xproto::Setup;
14use crate::protocol::Event;
15use crate::utils::RawFdContainer;
16use crate::x11_utils::{ExtensionInformation, TryParse, TryParseFd, X11Error};
17
18pub use x11rb_protocol::{DiscardMode, RawEventAndSeqNumber, SequenceNumber};
19
20mod impls;
21
22// Used to avoid too-complex types.
23/// A combination of a buffer and a list of file descriptors.
24pub type BufWithFds<B> = (B, Vec<RawFdContainer>);
25/// An event and its sequence number.
26pub type EventAndSeqNumber = (Event, SequenceNumber);
27
28/// Either a raw reply or a raw error response to an X11 request.
29#[derive(Debug)]
30pub enum ReplyOrError<R, E = R>
31where
32 R: std::fmt::Debug,
33 E: AsRef<[u8]> + std::fmt::Debug,
34{
35 /// The reply to an X11 request.
36 Reply(R),
37
38 /// An error caused by an X11 request.
39 Error(E),
40}
41
42/// A connection to an X11 server for sending requests.
43///
44/// This trait only contains functions that are used by other parts of this library. This means
45/// that users of this library will most likely not need these functions, unless they want to
46/// implement their own X11 connection.
47pub trait RequestConnection {
48 /// Type used as buffer to store raw replies or events before
49 /// they are parsed.
50 type Buf: AsRef<[u8]> + std::fmt::Debug + Send + Sync + 'static;
51
52 /// Send a request with a reply to the server.
53 ///
54 /// The `bufs` parameter describes the raw bytes that should be sent. The returned cookie
55 /// allows to get the response.
56 ///
57 /// The `fds` parameter contains a list of file descriptors that should be sent with the
58 /// request. Ownership of these FDs is transferred to the connection. This means that the
59 /// connection will close the FDs after they were sent.
60 ///
61 /// Users of this library will most likely not want to use this function directly. Instead, the
62 /// generated code will take the supplied arguments, construct byte buffers, and call this
63 /// method.
64 ///
65 /// The provided buffers must contain at least a single element and the first buffer must have
66 /// at least four bytes. The length field must be set correctly, unless the request is larger
67 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
68 /// automatically uses the BIG-REQUESTS extension for such large requests.
69 ///
70 /// In any case, the request may not be larger than the server's maximum request length.
71 fn send_request_with_reply<R>(
72 &self,
73 bufs: &[IoSlice<'_>],
74 fds: Vec<RawFdContainer>,
75 ) -> Result<Cookie<'_, Self, R>, ConnectionError>
76 where
77 R: TryParse;
78
79 /// Send a request with a reply to the server.
80 ///
81 /// This function is a wrapper around [`RequestConnection::send_request_with_reply`]. This
82 /// function gets a [`ReplyRequest`] as its argument to specify the request to send.
83 fn send_trait_request_with_reply<R>(
84 &self,
85 request: R,
86 ) -> Result<Cookie<'_, Self, <R as ReplyRequest>::Reply>, ConnectionError>
87 where
88 R: ReplyRequest,
89 {
90 let opcode = match R::EXTENSION_NAME {
91 None => 0,
92 Some(extension) => {
93 self.extension_information(extension)?
94 .ok_or(ConnectionError::UnsupportedExtension)?
95 .major_opcode
96 }
97 };
98 let (buf, fds) = request.serialize(opcode);
99 self.send_request_with_reply(&[IoSlice::new(&buf)], fds)
100 }
101
102 /// Send a request with a reply containing file descriptors to the server.
103 ///
104 /// The `bufs` parameter describes the raw bytes that should be sent. The returned cookie
105 /// allows to get the response.
106 ///
107 /// The `fds` parameter contains a list of file descriptors that should be sent with the
108 /// request. Ownership of these FDs is transferred to the connection. This means that the
109 /// connection will close the FDs after they were sent.
110 ///
111 /// Users of this library will most likely not want to use this function directly. Instead, the
112 /// generated code will take the supplied arguments, construct byte buffers, and call this
113 /// method.
114 ///
115 /// The provided buffers must contain at least a single element and the first buffer must have
116 /// at least four bytes. The length field must be set correctly, unless the request is larger
117 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
118 /// automatically uses the BIG-REQUESTS extension for such large requests.
119 ///
120 /// In any case, the request may not be larger than the server's maximum request length.
121 fn send_request_with_reply_with_fds<R>(
122 &self,
123 bufs: &[IoSlice<'_>],
124 fds: Vec<RawFdContainer>,
125 ) -> Result<CookieWithFds<'_, Self, R>, ConnectionError>
126 where
127 R: TryParseFd;
128
129 /// Send a request with a reply containing file descriptors to the server.
130 ///
131 /// This function is a wrapper around [`RequestConnection::send_request_with_reply_with_fds`].
132 /// This function gets a [`ReplyFDsRequest`] as its argument to specify the request to send.
133 fn send_trait_request_with_reply_with_fds<R>(
134 &self,
135 request: R,
136 ) -> Result<CookieWithFds<'_, Self, R::Reply>, ConnectionError>
137 where
138 R: ReplyFDsRequest,
139 {
140 let opcode = match R::EXTENSION_NAME {
141 None => 0,
142 Some(extension) => {
143 self.extension_information(extension)?
144 .ok_or(ConnectionError::UnsupportedExtension)?
145 .major_opcode
146 }
147 };
148 let (buf, fds) = request.serialize(opcode);
149 self.send_request_with_reply_with_fds(&[IoSlice::new(&buf)], fds)
150 }
151
152 /// Send a request without a reply to the server.
153 ///
154 /// The `bufs` parameter describes the raw bytes that should be sent. The sequence number of
155 /// the request is returned, but most likely not useful to users.
156 ///
157 /// The `fds` parameter contains a list of file descriptors that should be sent with the
158 /// request. Ownership of these FDs is transferred to the connection. This means that the
159 /// connection will close the FDs after they were sent.
160 ///
161 /// Users of this library will most likely not want to use this function directly. Instead, the
162 /// generated code will take the supplied arguments, construct byte buffers, and call this
163 /// method.
164 ///
165 /// The provided buffers must contain at least a single element and the first buffer must have
166 /// at least four bytes. The length field must be set correctly, unless the request is larger
167 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
168 /// automatically uses the BIG-REQUESTS extension for such large requests.
169 ///
170 /// In any case, the request may not be larger than the server's maximum request length.
171 fn send_request_without_reply(
172 &self,
173 bufs: &[IoSlice<'_>],
174 fds: Vec<RawFdContainer>,
175 ) -> Result<VoidCookie<'_, Self>, ConnectionError>;
176
177 /// Send a request without a reply to the server.
178 ///
179 /// This function is a wrapper around [`RequestConnection::send_request_without_reply`]. This
180 /// function gets a [`VoidRequest`] as its argument to specify the request to send.
181 fn send_trait_request_without_reply<R>(
182 &self,
183 request: R,
184 ) -> Result<VoidCookie<'_, Self>, ConnectionError>
185 where
186 R: VoidRequest,
187 {
188 let opcode = match R::EXTENSION_NAME {
189 None => 0,
190 Some(extension) => {
191 self.extension_information(extension)?
192 .ok_or(ConnectionError::UnsupportedExtension)?
193 .major_opcode
194 }
195 };
196 let (buf, fds) = request.serialize(opcode);
197 self.send_request_without_reply(&[IoSlice::new(&buf)], fds)
198 }
199
200 /// A reply to an error should be discarded.
201 ///
202 /// This method is automatically called by the `Drop` implementation on `Cookie` so that any
203 /// replies that are received later can be ignored.
204 ///
205 /// Users of this library will most likely not want to use this function directly.
206 fn discard_reply(&self, sequence: SequenceNumber, kind: RequestKind, mode: DiscardMode);
207
208 /// Prefetches information about an extension.
209 ///
210 /// If the information of a extension is not cached yet, this function sends a
211 /// `QueryExtension` request, but it does not wait for the reply.
212 ///
213 /// You can use `extension_information()` to get the reply of such request.
214 ///
215 /// Using this function can help to reduce round-trip latency, but you can use
216 /// `extension_information()` directly without calling this function first.
217 fn prefetch_extension_information(
218 &self,
219 extension_name: &'static str,
220 ) -> Result<(), ConnectionError>;
221
222 /// Get information about an extension.
223 ///
224 /// To send a request for some extension, information about the extension (major opcode,
225 /// first event code and first error code) is necessary. This function provides this
226 /// information.
227 ///
228 /// The returned object is guaranteed to have a non-zero `present` field. Extensions that are
229 /// not present are instead returned as `None`.
230 fn extension_information(
231 &self,
232 extension_name: &'static str,
233 ) -> Result<Option<ExtensionInformation>, ConnectionError>;
234
235 /// Wait for the reply to a request.
236 ///
237 /// The given sequence number identifies the request for which replies are expected. If the X11
238 /// server answered the request with an error, that error is returned as an `Err`.
239 ///
240 /// Users of this library will most likely not want to use this function directly.
241 fn wait_for_reply_or_error(&self, sequence: SequenceNumber) -> Result<Self::Buf, ReplyError> {
242 match self.wait_for_reply_or_raw_error(sequence)? {
243 ReplyOrError::Reply(reply) => Ok(reply),
244 ReplyOrError::Error(error) => {
245 Err(ReplyError::X11Error(self.parse_error(error.as_ref())?))
246 }
247 }
248 }
249
250 /// Wait for the reply to a request.
251 ///
252 /// The given sequence number identifies the request for which replies are expected. If the X11
253 /// server answered the request with an error, that error is returned as an `Err`.
254 ///
255 /// Users of this library will most likely not want to use this function directly.
256 fn wait_for_reply_or_raw_error(
257 &self,
258 sequence: SequenceNumber,
259 ) -> Result<ReplyOrError<Self::Buf>, ConnectionError>;
260
261 /// Wait for the reply to a request.
262 ///
263 /// The given sequence number identifies the request for which replies are expected. If the X11
264 /// server answered the request with an error, this function returns `None` and the error is
265 /// instead returned by `wait_for_event()` or `poll_for_event()`.
266 ///
267 /// Users of this library will most likely not want to use this function directly.
268 fn wait_for_reply(
269 &self,
270 sequence: SequenceNumber,
271 ) -> Result<Option<Self::Buf>, ConnectionError>;
272
273 /// Wait for the reply to a request that has FDs.
274 ///
275 /// The given sequence number identifies the request for which replies are expected.
276 ///
277 /// Users of this library will most likely not want to use this function directly.
278 fn wait_for_reply_with_fds(
279 &self,
280 sequence: SequenceNumber,
281 ) -> Result<BufWithFds<Self::Buf>, ReplyError> {
282 match self.wait_for_reply_with_fds_raw(sequence)? {
283 ReplyOrError::Reply(reply) => Ok(reply),
284 ReplyOrError::Error(error) => {
285 Err(ReplyError::X11Error(self.parse_error(error.as_ref())?))
286 }
287 }
288 }
289
290 /// Wait for the reply to a request that has FDs.
291 ///
292 /// The given sequence number identifies the request for which replies are expected.
293 ///
294 /// Users of this library will most likely not want to use this function directly.
295 fn wait_for_reply_with_fds_raw(
296 &self,
297 sequence: SequenceNumber,
298 ) -> Result<ReplyOrError<BufWithFds<Self::Buf>, Self::Buf>, ConnectionError>;
299
300 /// Check whether a request that does not have a reply caused an X11 error.
301 ///
302 /// The given sequence number identifies the request for which the check should be performed.
303 ///
304 /// Users of this library will most likely not want to use this function directly.
305 fn check_for_error(&self, sequence: SequenceNumber) -> Result<(), ReplyError> {
306 match self.check_for_raw_error(sequence)? {
307 Some(err) => Err(self.parse_error(err.as_ref())?.into()),
308 None => Ok(()),
309 }
310 }
311
312 /// Check whether a request that does not have a reply caused an X11 error.
313 ///
314 /// The given sequence number identifies the request for which the check should be performed.
315 ///
316 /// Users of this library will most likely not want to use this function directly.
317 fn check_for_raw_error(
318 &self,
319 sequence: SequenceNumber,
320 ) -> Result<Option<Self::Buf>, ConnectionError>;
321
322 /// Prefetches the maximum request length.
323 ///
324 /// If the maximum request length is not cached yet, this function sends a `BigRequests::Enable`
325 /// request, but it does not wait for the reply.
326 ///
327 /// You can use `maximum_request_bytes()` to get the result of this request.
328 ///
329 /// Using this function can help to reduce round-trip latency, but you can use
330 /// `maximum_request_bytes()` directly without calling this function first.
331 ///
332 /// Since this uses the `BigRequests` extension, the information about that extension needs to
333 /// available. Otherwise, this has to wait for the reply when calling
334 /// `extension_information()`.
335 ///
336 /// To prefetch the necessary information, you can do the following:
337 /// ```no_run
338 /// use x11rb::connection::RequestConnection;
339 /// use x11rb::errors::ConnectionError;
340 /// use x11rb::protocol::bigreq;
341 /// # fn do_it(conn: impl RequestConnection) -> Result<(), ConnectionError> {
342 /// // conn is a RequestConnection
343 /// conn.prefetch_extension_information(bigreq::X11_EXTENSION_NAME)?;
344 /// # Ok(())
345 /// # }
346 /// ```
347 fn prefetch_maximum_request_bytes(&self);
348
349 /// The maximum number of bytes that the X11 server accepts in a request.
350 fn maximum_request_bytes(&self) -> usize;
351
352 /// Parse a generic error.
353 fn parse_error(&self, error: &[u8]) -> Result<X11Error, ParseError>;
354
355 /// Parse a generic event.
356 fn parse_event(&self, event: &[u8]) -> Result<Event, ParseError>;
357}
358
359/// A connection to an X11 server.
360pub trait Connection: RequestConnection {
361 /// Wait for a new event from the X11 server.
362 fn wait_for_event(&self) -> Result<Event, ConnectionError> {
363 Ok(self.wait_for_event_with_sequence()?.0)
364 }
365
366 /// Wait for a new raw/unparsed event from the X11 server.
367 fn wait_for_raw_event(&self) -> Result<Self::Buf, ConnectionError> {
368 Ok(self.wait_for_raw_event_with_sequence()?.0)
369 }
370
371 /// Wait for a new event from the X11 server.
372 fn wait_for_event_with_sequence(&self) -> Result<EventAndSeqNumber, ConnectionError> {
373 let (event, seq) = self.wait_for_raw_event_with_sequence()?;
374 let event = self.parse_event(event.as_ref())?;
375 Ok((event, seq))
376 }
377
378 /// Wait for a new raw/unparsed event from the X11 server.
379 fn wait_for_raw_event_with_sequence(
380 &self,
381 ) -> Result<RawEventAndSeqNumber<Self::Buf>, ConnectionError>;
382
383 /// Poll for a new event from the X11 server.
384 fn poll_for_event(&self) -> Result<Option<Event>, ConnectionError> {
385 Ok(self.poll_for_event_with_sequence()?.map(|r| r.0))
386 }
387
388 /// Poll for a new raw/unparsed event from the X11 server.
389 fn poll_for_raw_event(&self) -> Result<Option<Self::Buf>, ConnectionError> {
390 Ok(self.poll_for_raw_event_with_sequence()?.map(|r| r.0))
391 }
392
393 /// Poll for a new event from the X11 server.
394 fn poll_for_event_with_sequence(&self) -> Result<Option<EventAndSeqNumber>, ConnectionError> {
395 Ok(match self.poll_for_raw_event_with_sequence()? {
396 Some((event, seq)) => Some((self.parse_event(event.as_ref())?, seq)),
397 None => None,
398 })
399 }
400
401 /// Poll for a new unparsed/raw event from the X11 server.
402 fn poll_for_raw_event_with_sequence(
403 &self,
404 ) -> Result<Option<RawEventAndSeqNumber<Self::Buf>>, ConnectionError>;
405
406 /// Send all pending requests to the server.
407 ///
408 /// Implementations of this trait may buffer requests for batched sending. When this method is
409 /// called, all pending requests are sent.
410 ///
411 /// You do not have to call this method before `wait_for_reply()`. If the request you want to
412 /// wait for was not yet sent, it will be sent by `wait_for_reply()`.
413 fn flush(&self) -> Result<(), ConnectionError>;
414
415 /// Get the setup information sent by the X11 server.
416 ///
417 /// The setup information contains X11 server, for example the window id of the root window.
418 fn setup(&self) -> &Setup;
419
420 /// Generate a new X11 identifier.
421 ///
422 /// This method can, for example, be used for creating a new window. First, this method is
423 /// called to generate an identifier. Next, `xproto::create_window` can be called to
424 /// actually create the window.
425 fn generate_id(&self) -> Result<u32, ReplyOrIdError>;
426}
427
428/// Does a request have a response?
429#[derive(Debug, Copy, Clone, PartialEq, Eq)]
430pub enum RequestKind {
431 /// The request has no response, i.e. its type is "void".
432 IsVoid,
433 /// The request has a response.
434 HasResponse,
435}
436
437/// Check the request length and use BIG-REQUESTS if necessary.
438///
439/// Users of this library will most likely not want to use this function directly.
440///
441/// This function is used by implementations of `RequestConnection` for sending requests. It
442/// examines the given request buffers and checks that the length field is set correctly.
443///
444/// If the request has more than 2^18 bytes, this function handles using the BIG-REQUESTS
445/// extension. The request is rewritten to include the correct length field. For this case, the
446/// `storage` parameter is needed. This function uses it to store the necessary buffers.
447///
448/// When using this function, it is recommended to allocate the `storage` parameter with
449/// `Default::default()`.
450///
451/// Example usage:
452/// ```
453/// use std::io::IoSlice;
454/// use x11rb::connection::{BufWithFds, RequestConnection, compute_length_field};
455/// use x11rb::cookie::{Cookie, CookieWithFds, VoidCookie};
456/// use x11rb::errors::{ParseError, ConnectionError};
457/// use x11rb::utils::RawFdContainer;
458/// use x11rb::x11_utils::{ExtensionInformation, TryParse, TryParseFd};
459/// use x11rb_protocol::SequenceNumber;
460/// # use x11rb::connection::ReplyOrError;
461///
462/// struct MyConnection();
463///
464/// impl RequestConnection for MyConnection {
465/// type Buf = Vec<u8>;
466///
467/// // [snip, other functions here]
468/// # fn discard_reply(&self, sequence: SequenceNumber,
469/// # kind: x11rb::connection::RequestKind,
470/// # mode: x11rb_protocol::DiscardMode) {
471/// # unimplemented!()
472/// # }
473/// # fn prefetch_extension_information(
474/// # &self,
475/// # extension_name: &'static str,
476/// # ) -> Result<(), ConnectionError> {
477/// # unimplemented!()
478/// # }
479/// # fn extension_information(&self, ext: &'static str)
480/// # -> Result<Option<ExtensionInformation>, ConnectionError> {
481/// # unimplemented!()
482/// # }
483/// # fn wait_for_reply_or_raw_error(&self, sequence: SequenceNumber)
484/// # -> Result<ReplyOrError<Vec<u8>>, ConnectionError> {
485/// # unimplemented!()
486/// # }
487/// # fn wait_for_reply(&self, sequence: SequenceNumber)
488/// # -> Result<Option<Vec<u8>>, x11rb::errors::ConnectionError> {
489/// # unimplemented!()
490/// # }
491/// # fn wait_for_reply_with_fds_raw(&self, sequence: SequenceNumber)
492/// # -> Result<ReplyOrError<BufWithFds<Vec<u8>>, Vec<u8>>, ConnectionError> {
493/// # unimplemented!()
494/// # }
495/// # fn check_for_raw_error(&self, sequence: SequenceNumber)
496/// # ->Result<Option<Vec<u8>>, ConnectionError> {
497/// # unimplemented!()
498/// # }
499/// # fn maximum_request_bytes(&self) -> usize {
500/// # unimplemented!()
501/// # }
502/// # fn prefetch_maximum_request_bytes(&self) {
503/// # unimplemented!()
504/// # }
505/// # fn parse_error(&self, _error: &[u8]) -> Result<x11rb::x11_utils::X11Error, ParseError> {
506/// # unimplemented!()
507/// # }
508/// # fn parse_event(&self, _event: &[u8]) -> Result<x11rb::protocol::Event, ParseError> {
509/// # unimplemented!()
510/// # }
511///
512/// fn send_request_with_reply<R>(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
513/// -> Result<Cookie<Self, R>, ConnectionError>
514/// where R: TryParse {
515/// Ok(Cookie::new(self, self.send_request(bufs, fds, true, false)?))
516/// }
517///
518/// fn send_request_with_reply_with_fds<R>(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
519/// -> Result<CookieWithFds<Self, R>, ConnectionError>
520/// where R: TryParseFd {
521/// Ok(CookieWithFds::new(self, self.send_request(bufs, fds, true, true)?))
522/// }
523///
524/// fn send_request_without_reply(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
525/// -> Result<VoidCookie<Self>, ConnectionError> {
526/// Ok(VoidCookie::new(self, self.send_request(bufs, fds, false, false)?))
527/// }
528/// }
529///
530/// impl MyConnection {
531/// fn send_request(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>,
532/// has_reply: bool, reply_has_fds: bool)
533/// -> Result<SequenceNumber, ConnectionError>
534/// {
535/// let mut storage = Default::default();
536/// let bufs = compute_length_field(self, bufs, &mut storage)?;
537/// unimplemented!("Now send bufs and fds to the X11 server");
538/// }
539/// }
540/// ```
541pub fn compute_length_field<'b>(
542 conn: &impl RequestConnection,
543 request_buffers: &'b [IoSlice<'b>],
544 storage: &'b mut (Vec<IoSlice<'b>>, [u8; 8]),
545) -> Result<&'b [IoSlice<'b>], ConnectionError> {
546 // Compute the total length of the request
547 let length: usize = request_buffers.iter().map(|buf| buf.len()).sum();
548 assert_eq!(
549 length % 4,
550 0,
551 "The length of X11 requests must be a multiple of 4, got {}",
552 length
553 );
554 let wire_length = length / 4;
555
556 let first_buf = &request_buffers[0];
557
558 // If the length fits into an u16, just return the request as-is
559 if let Ok(wire_length) = u16::try_from(wire_length) {
560 // Check that the request contains the correct length field
561 let length_field = u16::from_ne_bytes([first_buf[2], first_buf[3]]);
562 assert_eq!(
563 wire_length, length_field,
564 "Length field contains incorrect value"
565 );
566 return Ok(request_buffers);
567 }
568
569 // Check that the total length is not too large
570 if length > conn.maximum_request_bytes() {
571 return Err(ConnectionError::MaximumRequestLengthExceeded);
572 }
573
574 // Okay, we need to use big requests (thus four extra bytes, "+1" below)
575 let wire_length: u32 = wire_length
576 .checked_add(1)
577 .ok_or(ConnectionError::MaximumRequestLengthExceeded)?
578 .try_into()
579 .expect("X11 request larger than 2^34 bytes?!?");
580 let wire_length = wire_length.to_ne_bytes();
581
582 // Now construct the new IoSlices
583
584 // Replacement for the first four bytes of the request
585 storage.1.copy_from_slice(&[
586 // First part of the request
587 first_buf[0],
588 first_buf[1],
589 // length field zero indicates big requests
590 0,
591 0,
592 // New bytes: extended length
593 wire_length[0],
594 wire_length[1],
595 wire_length[2],
596 wire_length[3],
597 ]);
598 storage.0.push(IoSlice::new(&storage.1));
599
600 // The remaining part of the first buffer of the request
601 storage.0.push(IoSlice::new(&first_buf[4..]));
602
603 // and the rest of the request
604 storage.0.extend(
605 request_buffers[1..]
606 .iter()
607 .map(std::ops::Deref::deref)
608 .map(IoSlice::new),
609 );
610
611 Ok(&storage.0[..])
612}
613