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