1 | //! Helper types for implementing an X11 client. |
2 | |
3 | use alloc::collections::VecDeque; |
4 | use alloc::vec::Vec; |
5 | |
6 | use crate::utils::RawFdContainer; |
7 | use crate::{DiscardMode, SequenceNumber}; |
8 | |
9 | /// A combination of a buffer and a list of file descriptors. |
10 | pub type BufWithFds = crate::BufWithFds<Vec<u8>>; |
11 | |
12 | /// The raw bytes of an X11 event and its sequence number. |
13 | pub type RawEventAndSeqNumber = crate::RawEventAndSeqNumber<Vec<u8>>; |
14 | |
15 | /// Information about the reply to an X11 request. |
16 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
17 | pub enum ReplyFdKind { |
18 | /// The request does not have a reply. |
19 | NoReply, |
20 | /// The request has a reply and that reply does *not* contain any file descriptors. |
21 | ReplyWithoutFDs, |
22 | /// The request has a reply and that reply *does* contain file descriptor(s). |
23 | ReplyWithFDs, |
24 | } |
25 | |
26 | /// Information about the result of polling for a reply packet. |
27 | #[derive (Debug, Clone)] |
28 | pub enum PollReply { |
29 | /// It is not clear yet what the result will be; try again later. |
30 | TryAgain, |
31 | /// There will be no reply; polling is done. |
32 | NoReply, |
33 | /// Here is the result of the polling; polling is done. |
34 | Reply(Vec<u8>), |
35 | } |
36 | |
37 | #[derive (Debug, Clone, Copy, Eq, PartialEq)] |
38 | struct SentRequest { |
39 | seqno: SequenceNumber, |
40 | discard_mode: Option<DiscardMode>, |
41 | has_fds: bool, |
42 | } |
43 | |
44 | /// A pure-rust, sans-I/O implementation of the X11 protocol. |
45 | /// |
46 | /// This object is designed to be used in combination with an I/O backend, in |
47 | /// order to keep state for the X11 protocol. |
48 | #[derive (Debug)] |
49 | pub struct Connection { |
50 | // The sequence number of the last request that was written |
51 | last_sequence_written: SequenceNumber, |
52 | // Sorted(!) list with information on requests that were written, but no answer received yet. |
53 | sent_requests: VecDeque<SentRequest>, |
54 | |
55 | // The sequence number of the next reply that is expected to come in |
56 | next_reply_expected: SequenceNumber, |
57 | |
58 | // The sequence number of the last reply/error/event that was read |
59 | last_sequence_read: SequenceNumber, |
60 | // Events that were read, but not yet returned to the API user |
61 | pending_events: VecDeque<(SequenceNumber, Vec<u8>)>, |
62 | // Replies that were read, but not yet returned to the API user |
63 | pending_replies: VecDeque<(SequenceNumber, BufWithFds)>, |
64 | |
65 | // FDs that were read, but not yet assigned to any reply |
66 | pending_fds: VecDeque<RawFdContainer>, |
67 | } |
68 | |
69 | impl Default for Connection { |
70 | fn default() -> Self { |
71 | Self::new() |
72 | } |
73 | } |
74 | |
75 | impl Connection { |
76 | /// Create a new `Connection`. |
77 | /// |
78 | /// It is assumed that the connection was just established. This means that the next request |
79 | /// that is sent will have sequence number one. |
80 | pub fn new() -> Self { |
81 | Connection { |
82 | last_sequence_written: 0, |
83 | next_reply_expected: 0, |
84 | last_sequence_read: 0, |
85 | sent_requests: VecDeque::new(), |
86 | pending_events: VecDeque::new(), |
87 | pending_replies: VecDeque::new(), |
88 | pending_fds: VecDeque::new(), |
89 | } |
90 | } |
91 | |
92 | /// Send a request to the X11 server. |
93 | /// |
94 | /// When this returns `None`, a sync with the server is necessary. Afterwards, the caller |
95 | /// should try again. |
96 | pub fn send_request(&mut self, kind: ReplyFdKind) -> Option<SequenceNumber> { |
97 | let has_response = match kind { |
98 | ReplyFdKind::NoReply => false, |
99 | ReplyFdKind::ReplyWithoutFDs => true, |
100 | ReplyFdKind::ReplyWithFDs => true, |
101 | }; |
102 | if self.next_reply_expected + SequenceNumber::from(u16::max_value()) - 1 |
103 | <= self.last_sequence_written |
104 | && !has_response |
105 | { |
106 | // The caller need to call send_sync(). Otherwise, we might not be able to reconstruct |
107 | // full sequence numbers for received packets. |
108 | return None; |
109 | } |
110 | |
111 | self.last_sequence_written += 1; |
112 | let seqno = self.last_sequence_written; |
113 | |
114 | if has_response { |
115 | self.next_reply_expected = self.last_sequence_written; |
116 | } |
117 | |
118 | let sent_request = SentRequest { |
119 | seqno, |
120 | discard_mode: None, |
121 | has_fds: kind == ReplyFdKind::ReplyWithFDs, |
122 | }; |
123 | self.sent_requests.push_back(sent_request); |
124 | |
125 | Some(seqno) |
126 | } |
127 | |
128 | /// Ignore the reply for a request that was previously sent. |
129 | pub fn discard_reply(&mut self, seqno: SequenceNumber, mode: DiscardMode) { |
130 | if let Ok(index) = self.sent_requests.binary_search_by_key(&seqno, |r| r.seqno) { |
131 | self.sent_requests[index].discard_mode = Some(mode); |
132 | } |
133 | match mode { |
134 | DiscardMode::DiscardReplyAndError => self.pending_replies.retain(|r| r.0 != seqno), |
135 | DiscardMode::DiscardReply => { |
136 | if let Some(index) = self.pending_replies.iter().position(|r| r.0 == seqno) { |
137 | while self |
138 | .pending_replies |
139 | .get(index) |
140 | .filter(|r| r.0 == seqno) |
141 | .is_some() |
142 | { |
143 | if let Some((_, packet)) = self.pending_replies.remove(index) { |
144 | if packet.0[0] == 0 { |
145 | // This is an error |
146 | self.pending_events.push_back((seqno, packet.0)); |
147 | } |
148 | } |
149 | } |
150 | } |
151 | } |
152 | } |
153 | } |
154 | |
155 | // Extract the sequence number from a packet read from the X11 server. The packet must be a |
156 | // reply, an event, or an error. All of these have a u16 sequence number in bytes 2 and 3... |
157 | // except for KeymapNotify events. |
158 | fn extract_sequence_number(&mut self, buffer: &[u8]) -> Option<SequenceNumber> { |
159 | use crate::protocol::xproto::KEYMAP_NOTIFY_EVENT; |
160 | if buffer[0] == KEYMAP_NOTIFY_EVENT { |
161 | return None; |
162 | } |
163 | // We get the u16 from the wire... |
164 | let number = u16::from_ne_bytes([buffer[2], buffer[3]]); |
165 | |
166 | // ...and use our state to reconstruct the high bytes |
167 | let high_bytes = self.last_sequence_read & !SequenceNumber::from(u16::max_value()); |
168 | let mut full_number = SequenceNumber::from(number) | high_bytes; |
169 | if full_number < self.last_sequence_read { |
170 | full_number += SequenceNumber::from(u16::max_value()) + 1; |
171 | } |
172 | |
173 | // Update our state |
174 | self.last_sequence_read = full_number; |
175 | if self.next_reply_expected < full_number { |
176 | // This is most likely an event/error that allows us to update our sequence number |
177 | // implicitly. Normally, only requests with a reply update this (in send_request()). |
178 | self.next_reply_expected = full_number; |
179 | } |
180 | Some(full_number) |
181 | } |
182 | |
183 | /// Add FDs that were received to the internal state. |
184 | /// |
185 | /// This must be called before the corresponding packets are enqueued. |
186 | pub fn enqueue_fds(&mut self, fds: Vec<RawFdContainer>) { |
187 | self.pending_fds.extend(fds); |
188 | } |
189 | |
190 | /// An X11 packet was received from the connection and is now enqueued into our state. |
191 | /// |
192 | /// Any FDs that were received must already be enqueued before this can be called. |
193 | pub fn enqueue_packet(&mut self, packet: Vec<u8>) { |
194 | let kind = packet[0]; |
195 | |
196 | // extract_sequence_number() updates our state and is thus important to call even when we |
197 | // do not need the sequence number |
198 | let seqno = self |
199 | .extract_sequence_number(&packet) |
200 | .unwrap_or(self.last_sequence_read); |
201 | |
202 | // Remove all entries for older requests |
203 | while let Some(request) = self.sent_requests.front() { |
204 | if request.seqno >= seqno { |
205 | break; |
206 | } |
207 | let _ = self.sent_requests.pop_front(); |
208 | } |
209 | let request = self.sent_requests.front().filter(|r| r.seqno == seqno); |
210 | |
211 | if kind == 0 { |
212 | // It is an error. Let's see where we have to send it to. |
213 | if let Some(request) = request { |
214 | match request.discard_mode { |
215 | Some(DiscardMode::DiscardReplyAndError) => { /* This error should be ignored */ |
216 | } |
217 | Some(DiscardMode::DiscardReply) => { |
218 | self.pending_events.push_back((seqno, packet)) |
219 | } |
220 | None => self |
221 | .pending_replies |
222 | .push_back((seqno, (packet, Vec::new()))), |
223 | } |
224 | } else { |
225 | // Unexpected error, send to main loop |
226 | self.pending_events.push_back((seqno, packet)); |
227 | } |
228 | } else if kind == 1 { |
229 | let fds = if request.filter(|r| r.has_fds).is_some() { |
230 | // This reply has FDs, the number of FDs is always in the second byte |
231 | let num_fds = usize::from(packet[1]); |
232 | // FIXME Turn this into some kind of "permanent error state" (so that |
233 | // everything fails with said error) instead of using a panic (this panic will |
234 | // likely poison some Mutex and produce an error state that way). |
235 | assert!( |
236 | num_fds <= self.pending_fds.len(), |
237 | "FIXME: The server sent us too few FDs. The connection is now unusable \ |
238 | since we will never be sure again which FD belongs to which reply." |
239 | ); |
240 | self.pending_fds.drain(..num_fds).collect() |
241 | } else { |
242 | Vec::new() |
243 | }; |
244 | |
245 | // It is a reply |
246 | if request.filter(|r| r.discard_mode.is_some()).is_some() { |
247 | // This reply should be discarded |
248 | } else { |
249 | self.pending_replies.push_back((seqno, (packet, fds))); |
250 | } |
251 | } else { |
252 | // It is an event |
253 | self.pending_events.push_back((seqno, packet)); |
254 | } |
255 | } |
256 | |
257 | /// Check if the server already sent an answer to the request with the given sequence number. |
258 | /// |
259 | /// This function is meant to be used for requests that have a reply. Such requests always |
260 | /// cause a reply or an error to be sent. |
261 | pub fn poll_for_reply_or_error(&mut self, sequence: SequenceNumber) -> Option<BufWithFds> { |
262 | for (index, (seqno, _packet)) in self.pending_replies.iter().enumerate() { |
263 | if *seqno == sequence { |
264 | return Some(self.pending_replies.remove(index).unwrap().1); |
265 | } |
266 | } |
267 | None |
268 | } |
269 | |
270 | /// Prepare for calling `poll_check_for_reply_or_error()`. |
271 | /// |
272 | /// To check if a request with a reply caused an error, one simply has to wait for the error or |
273 | /// reply to be received. However, this approach does not work for requests without errors: |
274 | /// Success is indicated by the absence of an error. |
275 | /// |
276 | /// Thus, this function returns true if a sync is necessary to ensure that a reply with a |
277 | /// higher sequence number will be received. Since the X11 server handles requests in-order, |
278 | /// if the reply to a later request is received, this means that the earlier request did not |
279 | /// fail. |
280 | pub fn prepare_check_for_reply_or_error(&mut self, sequence: SequenceNumber) -> bool { |
281 | self.next_reply_expected < sequence |
282 | } |
283 | |
284 | /// Check if the request with the given sequence number was already handled by the server. |
285 | /// |
286 | /// Before calling this function, you must call `prepare_check_for_reply_or_error()` with the |
287 | /// sequence number. |
288 | /// |
289 | /// This function can be used for requests with and without a reply. |
290 | pub fn poll_check_for_reply_or_error(&mut self, sequence: SequenceNumber) -> PollReply { |
291 | if let Some(result) = self.poll_for_reply_or_error(sequence) { |
292 | return PollReply::Reply(result.0); |
293 | } |
294 | |
295 | if self.last_sequence_read > sequence { |
296 | // We can be sure that there will be no reply/error |
297 | PollReply::NoReply |
298 | } else { |
299 | // Hm, we cannot be sure yet. Perhaps there will still be a reply/error |
300 | PollReply::TryAgain |
301 | } |
302 | } |
303 | |
304 | /// Find the reply for the request with the given sequence number. |
305 | /// |
306 | /// If the request caused an error, that error will be handled as an event. This means that a |
307 | /// latter call to `poll_for_event()` will return it. |
308 | pub fn poll_for_reply(&mut self, sequence: SequenceNumber) -> PollReply { |
309 | if let Some(reply) = self.poll_for_reply_or_error(sequence) { |
310 | if reply.0[0] == 0 { |
311 | self.pending_events.push_back((sequence, reply.0)); |
312 | PollReply::NoReply |
313 | } else { |
314 | PollReply::Reply(reply.0) |
315 | } |
316 | } else { |
317 | PollReply::TryAgain |
318 | } |
319 | } |
320 | |
321 | /// Get a pending event. |
322 | pub fn poll_for_event_with_sequence(&mut self) -> Option<RawEventAndSeqNumber> { |
323 | self.pending_events |
324 | .pop_front() |
325 | .map(|(seqno, event)| (event, seqno)) |
326 | } |
327 | } |
328 | |
329 | #[cfg (test)] |
330 | mod test { |
331 | use super::{Connection, ReplyFdKind}; |
332 | |
333 | #[test ] |
334 | fn insert_sync_no_reply() { |
335 | // The connection must send a sync (GetInputFocus) request every 2^16-1 requests (that do not |
336 | // have a reply). Thus, this test sends more than that and tests for the sync to appear. |
337 | |
338 | let mut connection = Connection::new(); |
339 | |
340 | for num in 1..0xffff { |
341 | let seqno = connection.send_request(ReplyFdKind::NoReply); |
342 | assert_eq!(Some(num), seqno); |
343 | } |
344 | // request 0xffff should be a sync, hence the next one is 0x10000 |
345 | let seqno = connection.send_request(ReplyFdKind::NoReply); |
346 | assert_eq!(None, seqno); |
347 | |
348 | let seqno = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
349 | assert_eq!(Some(0xffff), seqno); |
350 | |
351 | let seqno = connection.send_request(ReplyFdKind::NoReply); |
352 | assert_eq!(Some(0x10000), seqno); |
353 | } |
354 | |
355 | #[test ] |
356 | fn insert_no_sync_with_reply() { |
357 | // Compared to the previous test, this uses ReplyFdKind::ReplyWithoutFDs, so no sync needs to |
358 | // be inserted. |
359 | |
360 | let mut connection = Connection::new(); |
361 | |
362 | for num in 1..=0x10001 { |
363 | let seqno = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
364 | assert_eq!(Some(num), seqno); |
365 | } |
366 | } |
367 | |
368 | #[test ] |
369 | fn insert_no_sync_when_already_syncing() { |
370 | // This test sends enough ReplyFdKind::NoReply requests that a sync becomes necessary on |
371 | // the next request. Then it sends a ReplyFdKind::ReplyWithoutFDs request so that no sync is |
372 | // necessary. This is a regression test: Once upon a time, an unnecessary sync was done. |
373 | |
374 | let mut connection = Connection::new(); |
375 | |
376 | for num in 1..0xffff { |
377 | let seqno = connection.send_request(ReplyFdKind::NoReply); |
378 | assert_eq!(Some(num), seqno); |
379 | } |
380 | |
381 | let seqno = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
382 | assert_eq!(Some(0xffff), seqno); |
383 | } |
384 | |
385 | #[test ] |
386 | fn get_sync_replies() { |
387 | // This sends requests with a reply with seqno 1 and 1+2^16 and then checks that their |
388 | // replies are correctly mapped to the requests. |
389 | |
390 | let mut connection = Connection::new(); |
391 | |
392 | let first_reply = 1; |
393 | let second_reply = 0x10001; |
394 | |
395 | // First, send all the requests |
396 | |
397 | // First request is one with a reply |
398 | let seqno = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
399 | assert_eq!(Some(first_reply), seqno); |
400 | |
401 | // Then, there should be enough requests so that the next request will end up with sequence |
402 | // number 'second_reply' |
403 | for num in (first_reply + 1)..(second_reply - 1) { |
404 | let seqno = connection.send_request(ReplyFdKind::NoReply); |
405 | assert_eq!(Some(num), seqno); |
406 | } |
407 | |
408 | // Send one more request. This needs to be a sync request so that sequence numbers can be |
409 | // reconstructed correctly. The bug that we testing was that no sync was required, so this |
410 | // test handles both cases correctly. |
411 | let requested_extra_sync = connection.send_request(ReplyFdKind::NoReply).is_none(); |
412 | if requested_extra_sync { |
413 | let _ = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
414 | } |
415 | |
416 | let seqno = connection.send_request(ReplyFdKind::ReplyWithoutFDs); |
417 | assert_eq!(Some(second_reply), seqno); |
418 | |
419 | // Prepare a reply packet |
420 | let mut packet = [0; 32]; |
421 | // It is a reply |
422 | packet[0] = 1; |
423 | // Set the sequence number to 1 |
424 | packet[2..4].copy_from_slice(&1u16.to_ne_bytes()); |
425 | |
426 | // Enqueue the first reply. |
427 | connection.enqueue_packet(packet.to_vec()); |
428 | |
429 | // Send an extra reply if the code wanted one. This extra reply allows to detect that all |
430 | // replies to the first request were received (remember, there can be multiple replies to a |
431 | // single request!) |
432 | if requested_extra_sync { |
433 | packet[2..4].copy_from_slice(&((second_reply - 1) as u16).to_ne_bytes()); |
434 | connection.enqueue_packet(packet.to_vec()); |
435 | } |
436 | |
437 | // Set the sequence number for the second reply |
438 | packet[2..4].copy_from_slice(&(second_reply as u16).to_ne_bytes()); |
439 | connection.enqueue_packet(packet.to_vec()); |
440 | |
441 | // Now check that the sequence number for the last packet was reconstructed correctly. |
442 | assert!(connection.poll_for_reply_or_error(second_reply).is_some()); |
443 | } |
444 | } |
445 | |