1//! Types and routines used to manipulate arguments from the wire format
2
3use std::collections::VecDeque;
4use std::convert::TryInto;
5use std::ffi::CStr;
6use std::os::unix::io::RawFd;
7use std::os::unix::io::{BorrowedFd, OwnedFd};
8
9use crate::protocol::{Argument, ArgumentType, Message};
10
11use smallvec::SmallVec;
12
13/// Error generated when trying to serialize a message into buffers
14#[derive(Debug)]
15pub 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
22impl std::error::Error for MessageWriteError {}
23
24impl 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)]
44pub 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
53impl std::error::Error for MessageParseError {}
54
55impl 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
73pub 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)]
153pub 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
246fn 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)]
254mod 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