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