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