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