1 //! Types and routines used to manipulate arguments from the wire format
2
3 use std::ffi::{CStr, CString};
4 use std::os::unix::io::RawFd;
5 use std::ptr;
6
7 use nix::errno::Errno;
8 use nix::{Error as NixError, Result as NixResult};
9
10 use smallvec::SmallVec;
11
12 // The value of 4 is chosen for the following reasons:
13 // - almost all messages have 4 arguments or less
14 // - there are some potentially spammy events that have 3/4 arguments (wl_touch.move has 4 for example)
15 //
16 // This brings the size of Message to 11*usize (instead of 4*usize with a regular vec), but eliminates
17 // almost all allocations that may occur during the processing of messages, both client-side and server-side.
18 const INLINE_ARGS: usize = 4;
19
20 /// Wire metadata of a given message
21 #[derive(Copy, Clone, Debug)]
22 pub struct MessageDesc {
23 /// Name of this message
24 pub name: &'static str,
25 /// Signature of the message
26 pub signature: &'static [ArgumentType],
27 /// Minimum required version of the interface
28 pub since: u32,
29 /// Whether this message is a destructor
30 pub destructor: bool,
31 }
32
33 /// Enum of possible argument types as recognized by the wire
34 #[derive(Copy, Clone, PartialEq, Debug)]
35 pub enum ArgumentType {
36 /// i32
37 Int,
38 /// u32
39 Uint,
40 /// fixed point, 1/256 precision
41 Fixed,
42 /// CString
43 Str,
44 /// id of a wayland object
45 Object,
46 /// id of a newly created wayland object
47 NewId,
48 /// Vec<u8>
49 Array,
50 /// RawFd
51 Fd,
52 }
53
54 /// Enum of possible argument as recognized by the wire, including values
55 #[derive(Clone, PartialEq, Debug)]
56 #[allow(clippy::box_vec)]
57 pub enum Argument {
58 /// i32
59 Int(i32),
60 /// u32
61 Uint(u32),
62 /// fixed point, 1/256 precision
63 Fixed(i32),
64 /// CString
65 ///
66 /// The value is boxed to reduce the stack size of Argument. The performance
67 /// impact is negligible as `string` arguments are pretty rare in the protocol.
68 Str(Box<CString>),
69 /// id of a wayland object
70 Object(u32),
71 /// id of a newly created wayland object
72 NewId(u32),
73 /// Vec<u8>
74 ///
75 /// The value is boxed to reduce the stack size of Argument. The performance
76 /// impact is negligible as `array` arguments are pretty rare in the protocol.
77 Array(Box<Vec<u8>>),
78 /// RawFd
79 Fd(RawFd),
80 }
81
82 impl Argument {
83 /// Retrieve the type of a given argument instance
get_type(&self) -> ArgumentType84 pub fn get_type(&self) -> ArgumentType {
85 match *self {
86 Argument::Int(_) => ArgumentType::Int,
87 Argument::Uint(_) => ArgumentType::Uint,
88 Argument::Fixed(_) => ArgumentType::Fixed,
89 Argument::Str(_) => ArgumentType::Str,
90 Argument::Object(_) => ArgumentType::Object,
91 Argument::NewId(_) => ArgumentType::NewId,
92 Argument::Array(_) => ArgumentType::Array,
93 Argument::Fd(_) => ArgumentType::Fd,
94 }
95 }
96 }
97
98 impl std::fmt::Display for Argument {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 Argument::Int(value) => write!(f, "{}", value),
102 Argument::Uint(value) => write!(f, "{}", value),
103 Argument::Fixed(value) => write!(f, "{}", value),
104 Argument::Str(value) => write!(f, "{:?}", value),
105 Argument::Object(value) => write!(f, "{}", value),
106 Argument::NewId(value) => write!(f, "{}", value),
107 Argument::Array(value) => write!(f, "{:?}", value),
108 Argument::Fd(value) => write!(f, "{}", value),
109 }
110 }
111 }
112
113 /// A wire message
114 #[derive(Debug, Clone, PartialEq)]
115 pub struct Message {
116 /// ID of the object sending this message
117 pub sender_id: u32,
118 /// Opcode of the message
119 pub opcode: u16,
120 /// Arguments of the message
121 pub args: SmallVec<[Argument; INLINE_ARGS]>,
122 }
123
124 /// Error generated when trying to serialize a message into buffers
125 #[derive(Debug, Clone)]
126 pub enum MessageWriteError {
127 /// The buffer is too small to hold the message contents
128 BufferTooSmall,
129 /// The message contains a FD that could not be dup-ed
130 DupFdFailed(::nix::Error),
131 }
132
133 impl std::error::Error for MessageWriteError {}
134
135 impl std::fmt::Display for MessageWriteError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>136 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
137 match *self {
138 MessageWriteError::BufferTooSmall => {
139 f.write_str("The provided buffer is too small to hold message content.")
140 }
141 MessageWriteError::DupFdFailed(_) => {
142 f.write_str("The message contains a file descriptor that could not be dup()-ed.")
143 }
144 }
145 }
146 }
147
148 /// Error generated when trying to deserialize a message from buffers
149 #[derive(Debug, Clone)]
150 pub enum MessageParseError {
151 /// The message references a FD but the buffer FD is empty
152 MissingFD,
153 /// More data is needed to deserialize the message
154 MissingData,
155 /// The message is malformed and cannot be parsed
156 Malformed,
157 }
158
159 impl std::error::Error for MessageParseError {}
160
161 impl std::fmt::Display for MessageParseError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>162 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
163 match *self {
164 MessageParseError::MissingFD => {
165 f.write_str("The message references a FD but the buffer FD is empty.")
166 }
167 MessageParseError::MissingData => {
168 f.write_str("More data is needed to deserialize the message")
169 }
170 MessageParseError::Malformed => {
171 f.write_str("The message is malformed and cannot be parsed")
172 }
173 }
174 }
175 }
176
177 impl Message {
178 /// Serialize the contents of this message into provided buffers
179 ///
180 /// Returns the number of elements written in each buffer
181 ///
182 /// Any serialized Fd will be `dup()`-ed in the process
write_to_buffers( &self, payload: &mut [u32], mut fds: &mut [RawFd], ) -> Result<(usize, usize), MessageWriteError>183 pub fn write_to_buffers(
184 &self,
185 payload: &mut [u32],
186 mut fds: &mut [RawFd],
187 ) -> Result<(usize, usize), MessageWriteError> {
188 let orig_payload_len = payload.len();
189 let orig_fds_len = fds.len();
190 // Helper function to write a u32 or a RawFd to its buffer
191 fn write_buf<T>(u: T, payload: &mut [T]) -> Result<&mut [T], MessageWriteError> {
192 if let Some((head, tail)) = payload.split_first_mut() {
193 *head = u;
194 Ok(tail)
195 } else {
196 Err(MessageWriteError::BufferTooSmall)
197 }
198 }
199
200 // Helper function to write byte arrays in payload
201 fn write_array_to_payload<'a>(
202 array: &[u8],
203 payload: &'a mut [u32],
204 ) -> Result<&'a mut [u32], MessageWriteError> {
205 let array_len = array.len();
206 let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
207 // need enough space to store the whole array with padding and a size header
208 if payload.len() < 1 + word_len {
209 return Err(MessageWriteError::BufferTooSmall);
210 }
211 // size header
212 payload[0] = array_len as u32;
213 let (buffer_slice, rest) = payload[1..].split_at_mut(word_len);
214 unsafe {
215 ptr::copy(array.as_ptr(), buffer_slice.as_mut_ptr() as *mut u8, array_len);
216 }
217 Ok(rest)
218 }
219
220 let free_size = payload.len();
221 if free_size < 2 {
222 return Err(MessageWriteError::BufferTooSmall);
223 }
224
225 let (header, mut payload) = payload.split_at_mut(2);
226
227 // we store all fds we dup-ed in this, which will auto-close
228 // them on drop, if any of the `?` early-returns
229 let mut pending_fds = FdStore::new();
230
231 // write the contents in the buffer
232 for arg in &self.args {
233 // Just to make the borrow checker happy
234 let old_payload = payload;
235 match *arg {
236 Argument::Int(i) => payload = write_buf(i as u32, old_payload)?,
237 Argument::Uint(u) => payload = write_buf(u, old_payload)?,
238 Argument::Fixed(f) => payload = write_buf(f as u32, old_payload)?,
239 Argument::Str(ref s) => {
240 payload = write_array_to_payload(s.as_bytes_with_nul(), old_payload)?;
241 }
242 Argument::Object(o) => payload = write_buf(o, old_payload)?,
243 Argument::NewId(n) => payload = write_buf(n, old_payload)?,
244 Argument::Array(ref a) => {
245 payload = write_array_to_payload(&a, old_payload)?;
246 }
247 Argument::Fd(fd) => {
248 let old_fds = fds;
249 let dup_fd = dup_fd_cloexec(fd).map_err(MessageWriteError::DupFdFailed)?;
250 pending_fds.push(dup_fd);
251 fds = write_buf(dup_fd, old_fds)?;
252 payload = old_payload;
253 }
254 }
255 }
256
257 // we reached here, all writing was successful
258 // no FD needs to be closed
259 pending_fds.clear();
260
261 let wrote_size = (free_size - payload.len()) * 4;
262 header[0] = self.sender_id;
263 header[1] = ((wrote_size as u32) << 16) | u32::from(self.opcode);
264 Ok((orig_payload_len - payload.len(), orig_fds_len - fds.len()))
265 }
266
267 /// Attempts to parse a single wayland message with the given signature.
268 ///
269 /// If the buffers contains several messages, only the first one will be parsed,
270 /// and the unused tail of the buffers is returned. If a single message was present,
271 /// the returned slices should thus be empty.
272 ///
273 /// Errors if the message is malformed.
from_raw<'a, 'b>( raw: &'a [u32], signature: &[ArgumentType], fds: &'b [RawFd], ) -> Result<(Message, &'a [u32], &'b [RawFd]), MessageParseError>274 pub fn from_raw<'a, 'b>(
275 raw: &'a [u32],
276 signature: &[ArgumentType],
277 fds: &'b [RawFd],
278 ) -> Result<(Message, &'a [u32], &'b [RawFd]), MessageParseError> {
279 // helper function to read arrays
280 fn read_array_from_payload(
281 array_len: usize,
282 payload: &[u32],
283 ) -> Result<(&[u8], &[u32]), MessageParseError> {
284 let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
285 if word_len > payload.len() {
286 return Err(MessageParseError::MissingData);
287 }
288 let (array_contents, rest) = payload.split_at(word_len);
289 let array = unsafe {
290 ::std::slice::from_raw_parts(array_contents.as_ptr() as *const u8, array_len)
291 };
292 Ok((array, rest))
293 }
294
295 if raw.len() < 2 {
296 return Err(MessageParseError::MissingData);
297 }
298
299 let sender_id = raw[0];
300 let word_2 = raw[1];
301 let opcode = (word_2 & 0x0000_FFFF) as u16;
302 let len = (word_2 >> 16) as usize / 4;
303
304 if len < 2 || len > raw.len() {
305 return Err(MessageParseError::Malformed);
306 }
307
308 let (mut payload, rest) = raw.split_at(len);
309 payload = &payload[2..];
310 let mut fds = fds;
311
312 let arguments = signature
313 .iter()
314 .map(|argtype| {
315 if let ArgumentType::Fd = *argtype {
316 // don't consume input but fd
317 if let Some((&front, tail)) = fds.split_first() {
318 fds = tail;
319 Ok(Argument::Fd(front))
320 } else {
321 Err(MessageParseError::MissingFD)
322 }
323 } else if let Some((&front, mut tail)) = payload.split_first() {
324 let arg = match *argtype {
325 ArgumentType::Int => Ok(Argument::Int(front as i32)),
326 ArgumentType::Uint => Ok(Argument::Uint(front)),
327 ArgumentType::Fixed => Ok(Argument::Fixed(front as i32)),
328 ArgumentType::Str => read_array_from_payload(front as usize, tail)
329 .and_then(|(v, rest)| {
330 tail = rest;
331 match CStr::from_bytes_with_nul(v) {
332 Ok(s) => Ok(Argument::Str(Box::new(s.into()))),
333 Err(_) => Err(MessageParseError::Malformed),
334 }
335 }),
336 ArgumentType::Object => Ok(Argument::Object(front)),
337 ArgumentType::NewId => Ok(Argument::NewId(front)),
338 ArgumentType::Array => {
339 read_array_from_payload(front as usize, tail).map(|(v, rest)| {
340 tail = rest;
341 Argument::Array(Box::new(v.into()))
342 })
343 }
344 ArgumentType::Fd => unreachable!(),
345 };
346 payload = tail;
347 arg
348 } else {
349 Err(MessageParseError::MissingData)
350 }
351 })
352 .collect::<Result<SmallVec<_>, MessageParseError>>()?;
353
354 let msg = Message { sender_id, opcode, args: arguments };
355 Ok((msg, rest, fds))
356 }
357 }
358
359 /// Duplicate a `RawFd` and set the CLOEXEC flag on the copy
dup_fd_cloexec(fd: RawFd) -> NixResult<RawFd>360 pub fn dup_fd_cloexec(fd: RawFd) -> NixResult<RawFd> {
361 use nix::fcntl;
362 match fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD_CLOEXEC(0)) {
363 Ok(newfd) => Ok(newfd),
364 Err(NixError::Sys(Errno::EINVAL)) => {
365 // F_DUPFD_CLOEXEC is not recognized, kernel too old, fallback
366 // to setting CLOEXEC manually
367 let newfd = fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD(0))?;
368
369 let flags = fcntl::fcntl(newfd, fcntl::FcntlArg::F_GETFD);
370 let result = flags
371 .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
372 .and_then(|f| fcntl::fcntl(newfd, fcntl::FcntlArg::F_SETFD(f)));
373 match result {
374 Ok(_) => {
375 // setting the O_CLOEXEC worked
376 Ok(newfd)
377 }
378 Err(e) => {
379 // something went wrong in F_GETFD or F_SETFD
380 let _ = ::nix::unistd::close(newfd);
381 Err(e)
382 }
383 }
384 }
385 Err(e) => Err(e),
386 }
387 }
388
389 /*
390 * utility struct that closes every FD it contains on drop
391 */
392
393 struct FdStore {
394 fds: Vec<RawFd>,
395 }
396
397 impl FdStore {
new() -> FdStore398 fn new() -> FdStore {
399 FdStore { fds: Vec::new() }
400 }
push(&mut self, fd: RawFd)401 fn push(&mut self, fd: RawFd) {
402 self.fds.push(fd);
403 }
clear(&mut self)404 fn clear(&mut self) {
405 self.fds.clear();
406 }
407 }
408
409 impl Drop for FdStore {
drop(&mut self)410 fn drop(&mut self) {
411 use nix::unistd::close;
412 for fd in self.fds.drain(..) {
413 // not much can be done if we can't close that anyway...
414 let _ = close(fd);
415 }
416 }
417 }
418
419 #[cfg(test)]
420 mod tests {
421 use super::*;
422 use smallvec::smallvec;
423
424 #[test]
into_from_raw_cycle()425 fn into_from_raw_cycle() {
426 let mut bytes_buffer = vec![0; 1024];
427 let mut fd_buffer = vec![0; 10];
428
429 let msg = Message {
430 sender_id: 42,
431 opcode: 7,
432 args: smallvec![
433 Argument::Uint(3),
434 Argument::Fixed(-89),
435 Argument::Str(Box::new(CString::new(&b"I like trains!"[..]).unwrap())),
436 Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()),
437 Argument::Object(88),
438 Argument::NewId(56),
439 Argument::Int(-25),
440 ],
441 };
442 // write the message to the buffers
443 msg.write_to_buffers(&mut bytes_buffer[..], &mut fd_buffer[..]).unwrap();
444 // read them back
445 let (rebuilt, _, _) = Message::from_raw(
446 &bytes_buffer[..],
447 &[
448 ArgumentType::Uint,
449 ArgumentType::Fixed,
450 ArgumentType::Str,
451 ArgumentType::Array,
452 ArgumentType::Object,
453 ArgumentType::NewId,
454 ArgumentType::Int,
455 ],
456 &fd_buffer[..],
457 )
458 .unwrap();
459 assert_eq!(rebuilt, msg);
460 }
461 }
462