tokio_unix_ipc/
serde.rs

1//! This module provides extensions to serde for IPC.
2//!
3//! This crate uses serde for serialization of data across the process
4//! boundary.  Internally this uses [bincode](https://github.com/bincode-org/bincode)
5//! as transfer format.  File handles can also be serialized by using
6//! [`Handle`] and [`HandleRef`].
7//!
8#![cfg_attr(
9    feature = "serde-structural",
10    doc = r"
11Because bincode has various limitations in the structures that can
12be serialized, the [`Structural`] wrapper is available which forces
13structural serialization (currently uses msgpack).  This requires the
14`serde-structural` feature.
15"
16)]
17use std::cell::RefCell;
18use std::io;
19use std::mem;
20use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
21use std::sync::Mutex;
22
23use serde_::{de, ser};
24use serde_::{de::DeserializeOwned, Deserialize, Serialize};
25
26thread_local! {
27    static IPC_FDS: RefCell<Vec<Vec<RawFd>>> = const {RefCell::new(Vec::new())};
28}
29
30/// Can transfer a unix file handle across processes.
31///
32/// The basic requirement is that you have an object that can be converted
33/// into a raw file handle and back.  This for instance is the case for
34/// regular file objects, sockets and many more things.
35///
36/// Once the handle has been serialized the handle no longer lets you
37/// extract the value contained in it.
38///
39/// For customizing the serialization of libraries the
40/// [`HandleRef`](struct.HandleRef.html) object should be used instead.
41pub struct Handle<F>(Mutex<Option<F>>);
42
43/// A raw reference to a handle.
44///
45/// This serializes the same way as a `Handle` but only uses a raw
46/// fd to represent it.  Useful to implement custom serializers.
47pub struct HandleRef(pub RawFd);
48
49impl<F: FromRawFd + IntoRawFd> Handle<F> {
50    /// Wraps the value in a handle.
51    pub fn new(f: F) -> Self {
52        f.into()
53    }
54
55    fn extract_raw_fd(&self) -> RawFd {
56        self.0
57            .lock()
58            .unwrap()
59            .take()
60            .map(|x| x.into_raw_fd())
61            .expect("cannot serialize handle twice")
62    }
63
64    /// Extracts the internal value.
65    pub fn into_inner(self) -> F {
66        self.0.lock().unwrap().take().expect("handle was moved")
67    }
68}
69
70impl<F: FromRawFd + IntoRawFd> From<F> for Handle<F> {
71    fn from(f: F) -> Self {
72        Handle(Mutex::new(Some(f)))
73    }
74}
75
76impl Serialize for HandleRef {
77    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: ser::Serializer,
80    {
81        if is_ipc_mode() {
82            let fd = self.0;
83            let idx = register_fd(fd);
84            idx.serialize(serializer)
85        } else {
86            Err(ser::Error::custom("can only serialize in ipc mode"))
87        }
88    }
89}
90
91impl<F: FromRawFd + IntoRawFd> Serialize for Handle<F> {
92    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93    where
94        S: ser::Serializer,
95    {
96        HandleRef(self.extract_raw_fd()).serialize(serializer)
97    }
98}
99
100impl<'de, F: FromRawFd + IntoRawFd> Deserialize<'de> for Handle<F> {
101    fn deserialize<D>(deserializer: D) -> Result<Handle<F>, D::Error>
102    where
103        D: de::Deserializer<'de>,
104    {
105        if is_ipc_mode() {
106            let idx = u32::deserialize(deserializer)?;
107            let fd = lookup_fd(idx).ok_or_else(|| de::Error::custom("fd not found in mapping"))?;
108            unsafe { Ok(Handle(Mutex::new(Some(FromRawFd::from_raw_fd(fd))))) }
109        } else {
110            Err(de::Error::custom("can only deserialize in ipc mode"))
111        }
112    }
113}
114
115struct ResetIpcSerde;
116
117impl Drop for ResetIpcSerde {
118    fn drop(&mut self) {
119        IPC_FDS.with(|x| x.borrow_mut().pop());
120    }
121}
122
123fn enter_ipc_mode<F: FnOnce() -> R, R>(f: F, fds: &mut Vec<RawFd>) -> R {
124    IPC_FDS.with(|x| x.borrow_mut().push(fds.clone()));
125    let reset = ResetIpcSerde;
126    let rv = f();
127    *fds = IPC_FDS.with(|x| x.borrow_mut().pop()).unwrap_or_default();
128    mem::forget(reset);
129    rv
130}
131
132fn register_fd(fd: RawFd) -> u32 {
133    IPC_FDS.with(|x| {
134        let mut x = x.borrow_mut();
135        let fds = x.last_mut().unwrap();
136        let rv = fds.len() as u32;
137        fds.push(fd);
138        rv
139    })
140}
141
142fn lookup_fd(idx: u32) -> Option<RawFd> {
143    IPC_FDS.with(|x| x.borrow().last().and_then(|l| l.get(idx as usize).copied()))
144}
145
146/// Checks if serde is in IPC mode.
147///
148/// This can be used to customize the behavior of serialization/deserialization
149/// implementations for the use with unix-ipc.
150pub fn is_ipc_mode() -> bool {
151    IPC_FDS.with(|x| !x.borrow().is_empty())
152}
153
154#[allow(clippy::boxed_local)]
155fn bincode_to_io_error(err: bincode::Error) -> io::Error {
156    match *err {
157        bincode::ErrorKind::Io(err) => err,
158        err => io::Error::new(io::ErrorKind::InvalidData, err.to_string()),
159    }
160}
161
162/// Serializes something for IPC communication.
163///
164/// This uses bincode for serialization.  Because UNIX sockets require that
165/// file descriptors are transmitted separately they are accumulated in a
166/// separate buffer.
167pub fn serialize<S: Serialize>(s: S) -> io::Result<(Vec<u8>, Vec<RawFd>)> {
168    let mut fds = Vec::new();
169    let mut out = Vec::new();
170    enter_ipc_mode(|| bincode::serialize_into(&mut out, &s), &mut fds)
171        .map_err(bincode_to_io_error)?;
172    Ok((out, fds))
173}
174
175/// Deserializes something for IPC communication.
176///
177/// File descriptors need to be provided for deserialization if handleds are
178/// involved.
179pub fn deserialize<D: DeserializeOwned>(bytes: &[u8], fds: &[RawFd]) -> io::Result<D> {
180    let mut fds = fds.to_owned();
181    let result =
182        enter_ipc_mode(|| bincode::deserialize(bytes), &mut fds).map_err(bincode_to_io_error)?;
183    Ok(result)
184}
185
186macro_rules! implement_handle_serialization {
187    ($ty:ty) => {
188        impl $crate::_serde_ref::Serialize for $ty {
189            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190            where
191                S: $crate::_serde_ref::ser::Serializer,
192            {
193                $crate::_serde_ref::Serialize::serialize(
194                    &$crate::serde::HandleRef(self.extract_raw_fd()),
195                    serializer,
196                )
197            }
198        }
199        impl<'de> Deserialize<'de> for $ty {
200            fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error>
201            where
202                D: $crate::_serde_ref::de::Deserializer<'de>,
203            {
204                let handle: $crate::serde::Handle<$ty> =
205                    $crate::_serde_ref::Deserialize::deserialize(deserializer)?;
206                Ok(handle.into_inner())
207            }
208        }
209    };
210}
211
212implement_handle_serialization!(crate::RawSender);
213implement_handle_serialization!(crate::RawReceiver);
214
215macro_rules! implement_typed_handle_serialization {
216    ($ty:ty) => {
217        impl<T: Serialize + DeserializeOwned> $crate::_serde_ref::Serialize for $ty {
218            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219            where
220                S: $crate::_serde_ref::ser::Serializer,
221            {
222                $crate::_serde_ref::Serialize::serialize(
223                    &$crate::serde::HandleRef(self.extract_raw_fd()),
224                    serializer,
225                )
226            }
227        }
228        impl<'de, T: Serialize + DeserializeOwned> Deserialize<'de> for $ty {
229            fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error>
230            where
231                D: $crate::_serde_ref::de::Deserializer<'de>,
232            {
233                let handle: $crate::serde::Handle<$ty> =
234                    $crate::_serde_ref::Deserialize::deserialize(deserializer)?;
235                Ok(handle.into_inner())
236            }
237        }
238    };
239}
240
241implement_typed_handle_serialization!(crate::Sender<T>);
242implement_typed_handle_serialization!(crate::Receiver<T>);
243
244#[cfg(feature = "serde-structural")]
245mod structural {
246    use super::*;
247
248    /// Utility wrapper to force values through structural serialization.
249    ///
250    /// By default `tokio-unix-ipc` will use
251    /// [`bincode`](https://github.com/servo/bincode) to serialize data across
252    /// process boundaries. This has some limitations which can cause
253    /// serialization or deserialization to fail for some types.
254    ///
255    /// Since the serde ecosystem has some types which require structural
256    /// serialization (eg: msgpack, JSON etc.) this type can be used to
257    /// work around some known bugs:
258    ///
259    /// * serde flatten not being supported: [bincode#245](https://github.com/servo/bincode/issues/245)
260    /// * vectors with unknown length not supported: [bincode#167](https://github.com/servo/bincode/issues/167)
261    ///
262    /// This requires the `serde-structural` feature.
263    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
264    pub struct Structural<T>(pub T);
265
266    impl<T: Serialize> Serialize for Structural<T> {
267        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268        where
269            S: ser::Serializer,
270        {
271            let msgpack =
272                rmp_serde::to_vec(&self.0).map_err(|e| ser::Error::custom(e.to_string()))?;
273            serializer.serialize_bytes(&msgpack)
274        }
275    }
276
277    impl<'de, T: DeserializeOwned> Deserialize<'de> for Structural<T> {
278        fn deserialize<D>(deserializer: D) -> Result<Structural<T>, D::Error>
279        where
280            D: de::Deserializer<'de>,
281        {
282            let msgpack = Vec::<u8>::deserialize(deserializer)
283                .map_err(|e| de::Error::custom(e.to_string()))?;
284            Ok(Structural(
285                rmp_serde::from_slice(&msgpack).map_err(|e| de::Error::custom(e.to_string()))?,
286            ))
287        }
288    }
289}
290
291#[cfg(feature = "serde-structural")]
292pub use self::structural::*;
293
294#[test]
295fn test_basic() {
296    use std::io::Read;
297    let f = std::fs::File::open("src/serde.rs").unwrap();
298    let handle = Handle::from(f);
299    let (bytes, fds) = serialize(handle).unwrap();
300    let f2: Handle<std::fs::File> = deserialize(&bytes, &fds).unwrap();
301    let mut out = Vec::new();
302    f2.into_inner().read_to_end(&mut out).unwrap();
303    assert!(out.len() > 100);
304}
305
306#[test]
307#[cfg(feature = "serde-structural")]
308fn test_structural() {
309    #[derive(Serialize, Deserialize, Debug, PartialEq)]
310    #[serde(crate = "serde_")]
311    struct InnerStruct {
312        value: u64,
313    }
314
315    #[derive(Serialize, Deserialize, Debug, PartialEq)]
316    #[serde(crate = "serde_")]
317    struct BadStruct {
318        #[serde(flatten)]
319        inner: InnerStruct,
320    }
321
322    let (bytes, fds) = serialize(Structural(BadStruct {
323        inner: InnerStruct { value: 42 },
324    }))
325    .unwrap();
326    let value: Structural<BadStruct> = deserialize(&bytes, &fds).unwrap();
327    assert_eq!(
328        value.0,
329        BadStruct {
330            inner: InnerStruct { value: 42 },
331        }
332    );
333}