1 | //! Types and routines used to manipulate arguments from the wire format |
2 | |
3 | use std::collections::VecDeque; |
4 | use std::ffi::CStr; |
5 | use std::os::unix::io::{BorrowedFd, OwnedFd, RawFd}; |
6 | |
7 | use crate::protocol::{Argument, ArgumentType, Message}; |
8 | |
9 | use smallvec::SmallVec; |
10 | |
11 | /// Error generated when trying to serialize a message into buffers |
12 | #[derive (Debug)] |
13 | pub enum MessageWriteError { |
14 | /// The buffer is too small to hold the message contents |
15 | BufferTooSmall, |
16 | /// The message contains a FD that could not be dup-ed |
17 | DupFdFailed(std::io::Error), |
18 | } |
19 | |
20 | impl std::error::Error for MessageWriteError {} |
21 | |
22 | impl std::fmt::Display for MessageWriteError { |
23 | #[cfg_attr (coverage, coverage(off))] |
24 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { |
25 | match self { |
26 | Self::BufferTooSmall => { |
27 | f.write_str(data:"The provided buffer is too small to hold message content." ) |
28 | } |
29 | Self::DupFdFailed(e: &Error) => { |
30 | write!( |
31 | f, |
32 | "The message contains a file descriptor that could not be dup()-ed ( {})." , |
33 | e |
34 | ) |
35 | } |
36 | } |
37 | } |
38 | } |
39 | |
40 | /// Error generated when trying to deserialize a message from buffers |
41 | #[derive (Debug, Clone)] |
42 | pub enum MessageParseError { |
43 | /// The message references a FD but the buffer FD is empty |
44 | MissingFD, |
45 | /// More data is needed to deserialize the message |
46 | MissingData, |
47 | /// The message is malformed and cannot be parsed |
48 | Malformed, |
49 | } |
50 | |
51 | impl std::error::Error for MessageParseError {} |
52 | |
53 | impl std::fmt::Display for MessageParseError { |
54 | #[cfg_attr (coverage, coverage(off))] |
55 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { |
56 | match *self { |
57 | Self::MissingFD => { |
58 | f.write_str(data:"The message references a FD but the buffer FD is empty." ) |
59 | } |
60 | Self::MissingData => f.write_str(data:"More data is needed to deserialize the message" ), |
61 | Self::Malformed => f.write_str(data:"The message is malformed and cannot be parsed" ), |
62 | } |
63 | } |
64 | } |
65 | |
66 | /// Serialize the contents of this message into provided buffers |
67 | /// |
68 | /// Returns the number of elements written in each buffer |
69 | /// |
70 | /// Any serialized Fd will be `dup()`-ed in the process |
71 | pub fn write_to_buffers( |
72 | msg: &Message<u32, RawFd>, |
73 | payload: &mut [u8], |
74 | fds: &mut Vec<OwnedFd>, |
75 | ) -> Result<usize, MessageWriteError> { |
76 | let orig_payload_len = payload.len(); |
77 | // Helper function to write a u32 or a RawFd to its buffer |
78 | fn write_buf(u: u32, payload: &mut [u8]) -> Result<&mut [u8], MessageWriteError> { |
79 | if payload.len() >= 4 { |
80 | let (head, tail) = payload.split_at_mut(4); |
81 | head.copy_from_slice(&u.to_ne_bytes()); |
82 | Ok(tail) |
83 | } else { |
84 | Err(MessageWriteError::BufferTooSmall) |
85 | } |
86 | } |
87 | |
88 | // Helper function to write byte arrays in payload |
89 | fn write_array_to_payload<'a>( |
90 | array: &[u8], |
91 | payload: &'a mut [u8], |
92 | ) -> Result<&'a mut [u8], MessageWriteError> { |
93 | // size header |
94 | let payload = write_buf(array.len() as u32, payload)?; |
95 | |
96 | // Handle padding |
97 | let len = next_multiple_of(array.len(), 4); |
98 | |
99 | if payload.len() < len { |
100 | return Err(MessageWriteError::BufferTooSmall); |
101 | } |
102 | |
103 | let (buffer_slice, rest) = payload.split_at_mut(len); |
104 | buffer_slice[..array.len()].copy_from_slice(array); |
105 | Ok(rest) |
106 | } |
107 | |
108 | let free_size = payload.len(); |
109 | if free_size < 2 * 4 { |
110 | return Err(MessageWriteError::BufferTooSmall); |
111 | } |
112 | |
113 | let (header, mut payload) = payload.split_at_mut(2 * 4); |
114 | |
115 | // write the contents in the buffer |
116 | for arg in &msg.args { |
117 | payload = match *arg { |
118 | Argument::Int(i) => write_buf(i as u32, payload)?, |
119 | Argument::Uint(u) => write_buf(u, payload)?, |
120 | Argument::Fixed(f) => write_buf(f as u32, payload)?, |
121 | Argument::Str(Some(ref s)) => write_array_to_payload(s.as_bytes_with_nul(), payload)?, |
122 | Argument::Str(None) => write_array_to_payload(&[], payload)?, |
123 | Argument::Object(o) => write_buf(o, payload)?, |
124 | Argument::NewId(n) => write_buf(n, payload)?, |
125 | Argument::Array(ref a) => write_array_to_payload(a, payload)?, |
126 | Argument::Fd(fd) => { |
127 | let dup_fd = unsafe { BorrowedFd::borrow_raw(fd) } |
128 | .try_clone_to_owned() |
129 | .map_err(MessageWriteError::DupFdFailed)?; |
130 | fds.push(dup_fd); |
131 | payload |
132 | } |
133 | }; |
134 | } |
135 | |
136 | let wrote_size = free_size - payload.len(); |
137 | header[..4].copy_from_slice(&msg.sender_id.to_ne_bytes()); |
138 | header[4..] |
139 | .copy_from_slice(&(((wrote_size as u32) << 16) | u32::from(msg.opcode)).to_ne_bytes()); |
140 | Ok(orig_payload_len - payload.len()) |
141 | } |
142 | |
143 | /// Attempts to parse a single wayland message with the given signature. |
144 | /// |
145 | /// If the buffers contains several messages, only the first one will be parsed, |
146 | /// and the unused tail of the buffers is returned. If a single message was present, |
147 | /// the returned slices should thus be empty. |
148 | /// |
149 | /// Errors if the message is malformed. |
150 | #[allow (clippy::type_complexity)] |
151 | pub fn parse_message<'a>( |
152 | raw: &'a [u8], |
153 | signature: &[ArgumentType], |
154 | fds: &mut VecDeque<OwnedFd>, |
155 | ) -> Result<(Message<u32, OwnedFd>, &'a [u8]), MessageParseError> { |
156 | // helper function to read arrays |
157 | fn read_array_from_payload( |
158 | array_len: usize, |
159 | payload: &[u8], |
160 | ) -> Result<(&[u8], &[u8]), MessageParseError> { |
161 | let len = next_multiple_of(array_len, 4); |
162 | if len > payload.len() { |
163 | return Err(MessageParseError::MissingData); |
164 | } |
165 | Ok((&payload[..array_len], &payload[len..])) |
166 | } |
167 | |
168 | if raw.len() < 2 * 4 { |
169 | return Err(MessageParseError::MissingData); |
170 | } |
171 | |
172 | let sender_id = u32::from_ne_bytes([raw[0], raw[1], raw[2], raw[3]]); |
173 | let word_2 = u32::from_ne_bytes([raw[4], raw[5], raw[6], raw[7]]); |
174 | let opcode = (word_2 & 0x0000_FFFF) as u16; |
175 | let len = (word_2 >> 16) as usize; |
176 | |
177 | if len < 2 * 4 { |
178 | return Err(MessageParseError::Malformed); |
179 | } else if len > raw.len() { |
180 | return Err(MessageParseError::MissingData); |
181 | } |
182 | |
183 | let fd_len = signature.iter().filter(|x| matches!(x, ArgumentType::Fd)).count(); |
184 | if fd_len > fds.len() { |
185 | return Err(MessageParseError::MissingFD); |
186 | } |
187 | |
188 | let (mut payload, rest) = raw.split_at(len); |
189 | payload = &payload[2 * 4..]; |
190 | |
191 | let arguments = signature |
192 | .iter() |
193 | .map(|argtype| { |
194 | if let ArgumentType::Fd = *argtype { |
195 | // don't consume input but fd |
196 | if let Some(front) = fds.pop_front() { |
197 | Ok(Argument::Fd(front)) |
198 | } else { |
199 | Err(MessageParseError::MissingFD) |
200 | } |
201 | } else if payload.len() >= 4 { |
202 | let (front, mut tail) = payload.split_at(4); |
203 | let front = u32::from_ne_bytes(front.try_into().unwrap()); |
204 | let arg = match *argtype { |
205 | ArgumentType::Int => Ok(Argument::Int(front as i32)), |
206 | ArgumentType::Uint => Ok(Argument::Uint(front)), |
207 | ArgumentType::Fixed => Ok(Argument::Fixed(front as i32)), |
208 | ArgumentType::Str(_) => { |
209 | read_array_from_payload(front as usize, tail).and_then(|(v, rest)| { |
210 | tail = rest; |
211 | if !v.is_empty() { |
212 | match CStr::from_bytes_with_nul(v) { |
213 | Ok(s) => Ok(Argument::Str(Some(Box::new(s.into())))), |
214 | Err(_) => Err(MessageParseError::Malformed), |
215 | } |
216 | } else { |
217 | Ok(Argument::Str(None)) |
218 | } |
219 | }) |
220 | } |
221 | ArgumentType::Object(_) => Ok(Argument::Object(front)), |
222 | ArgumentType::NewId => Ok(Argument::NewId(front)), |
223 | ArgumentType::Array => { |
224 | read_array_from_payload(front as usize, tail).map(|(v, rest)| { |
225 | tail = rest; |
226 | Argument::Array(Box::new(v.into())) |
227 | }) |
228 | } |
229 | ArgumentType::Fd => unreachable!(), |
230 | }; |
231 | payload = tail; |
232 | arg |
233 | } else { |
234 | Err(MessageParseError::MissingData) |
235 | } |
236 | }) |
237 | .collect::<Result<SmallVec<_>, MessageParseError>>()?; |
238 | |
239 | let msg = Message { sender_id, opcode, args: arguments }; |
240 | Ok((msg, rest)) |
241 | } |
242 | |
243 | // Stabalized in Rust 1.73 |
244 | fn next_multiple_of(lhs: usize, rhs: usize) -> usize { |
245 | match lhs % rhs { |
246 | 0 => lhs, |
247 | r: usize => lhs + (rhs - r), |
248 | } |
249 | } |
250 | |
251 | #[cfg (test)] |
252 | mod tests { |
253 | use super::*; |
254 | use crate::protocol::AllowNull; |
255 | use smallvec::smallvec; |
256 | use std::{ffi::CString, os::unix::io::IntoRawFd}; |
257 | |
258 | #[test ] |
259 | fn into_from_raw_cycle() { |
260 | let mut bytes_buffer = vec![0; 1024]; |
261 | let mut fd_buffer = Vec::new(); |
262 | |
263 | let msg = Message { |
264 | sender_id: 42, |
265 | opcode: 7, |
266 | args: smallvec![ |
267 | Argument::Uint(3), |
268 | Argument::Fixed(-89), |
269 | Argument::Str(Some(Box::new(CString::new(&b"I like trains!" [..]).unwrap()))), |
270 | Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()), |
271 | Argument::Object(88), |
272 | Argument::NewId(56), |
273 | Argument::Int(-25), |
274 | ], |
275 | }; |
276 | // write the message to the buffers |
277 | write_to_buffers(&msg, &mut bytes_buffer[..], &mut fd_buffer).unwrap(); |
278 | // read them back |
279 | let mut fd_buffer = VecDeque::from(fd_buffer); |
280 | let (rebuilt, _) = parse_message( |
281 | &bytes_buffer[..], |
282 | &[ |
283 | ArgumentType::Uint, |
284 | ArgumentType::Fixed, |
285 | ArgumentType::Str(AllowNull::No), |
286 | ArgumentType::Array, |
287 | ArgumentType::Object(AllowNull::No), |
288 | ArgumentType::NewId, |
289 | ArgumentType::Int, |
290 | ], |
291 | &mut fd_buffer, |
292 | ) |
293 | .unwrap(); |
294 | assert_eq!(rebuilt.map_fd(IntoRawFd::into_raw_fd), msg); |
295 | } |
296 | } |
297 | |