sandbox_ipc/
lib.rs

1//! Convenient and powerful cross-platform IPC primitives, designed with privilege separation in mind.
2//!
3//! The core of this crate is the `MessageChannel`. It not only automatically serializes and deserializes messages via
4//! `serde`, but can even send OS resources like files to other processes. To get started, spawn a child process with
5//! `MessageChannel::establish_with_child` and transmit the initial channel with an environment variable:
6//!  
7//! ```rust,no_run
8//! extern crate futures;
9//! extern crate tokio;
10//! extern crate sandbox_ipc as ipc;
11//! extern crate serde_json as json;
12//! 
13//! use std::{fs, env};
14//! use std::process::Command;
15//! use std::io::Write;
16//!
17//! use ipc::io::SendableFile;
18//! use futures::prelude::*; 
19//! use tokio::runtime::Runtime;
20//! 
21//! const CHANNEL_ENV_VAR: &str = "ENV_IPC_CHANNEL";
22//! 
23//! fn main() {
24//!     // IO operations are done within a Tokio event loop
25//!     let mut core = Runtime::new().unwrap();
26//!     
27//!     let mut child_command = Command::new("some_child_executable");
28//!     let (channel, child) = ipc::MessageChannel::<SendableFile, i32>::establish_with_child(
29//!         &mut child_command, 8192, core.reactor(), |command, child_channel| {
30//!             command
31//!                 .env(CHANNEL_ENV_VAR, json::to_string(child_channel).unwrap())
32//!                 .spawn()
33//!         }
34//!     ).unwrap();
35//! 
36//!     let secret_file = fs::File::create("secret_file.txt").unwrap();
37//!     let channel = core.block_on(channel.send(SendableFile(secret_file))).unwrap();
38//! 
39//!     let (reason, _channel) = core.block_on(channel.into_future()).map_err(|(err, _)| err).unwrap();
40//!     let reason = reason.unwrap();
41//!     assert_eq!(42i32, reason);
42//! }
43//! 
44//! fn child_main() {
45//!     let mut core = Runtime::new().unwrap();
46//! 
47//!     let channel: ipc::ChildMessageChannel = 
48//!         json::from_str(&env::var(CHANNEL_ENV_VAR).unwrap()).unwrap();
49//!     let channel = channel.into_channel::<i32, SendableFile>(core.reactor()).unwrap();
50//! 
51//!     let (secret_file, channel) = core.block_on(channel.into_future())
52//!         .map_err(|(err, _)| err).unwrap();
53//!     let SendableFile(mut secret_file) = secret_file.unwrap();
54//! 
55//!     write!(&mut secret_file, "psst").unwrap();
56//! 
57//!     let _channel = core.block_on(channel.send(42i32)).unwrap();
58//! }
59//! ```
60//! 
61
62#[macro_use] extern crate log;
63extern crate uuid;
64extern crate rand;
65#[macro_use] extern crate lazy_static;
66
67extern crate serde;
68#[macro_use] extern crate serde_derive;
69extern crate bincode;
70
71extern crate tokio_reactor;
72#[macro_use] extern crate tokio_io;
73
74mod tokio {
75    pub(crate) use ::tokio_reactor as reactor;
76    pub(crate) use ::tokio_io as io;
77    #[cfg(test)]
78    pub(crate) use ::tokio_all::runtime;
79}
80extern crate futures;
81
82#[cfg(target_os = "windows")]
83extern crate winapi;
84#[cfg(target_os = "windows")]
85#[macro_use] extern crate winhandle;
86#[cfg(target_os = "windows")]
87extern crate widestring;
88
89#[cfg(test)]
90extern crate tokio as tokio_all;
91
92mod channel;
93pub mod io;
94pub mod sync;
95pub mod shm;
96
97mod ser;
98
99pub use channel::*;
100
101pub mod os {
102    #[cfg(target_os = "windows")]
103    pub mod windows {
104        pub use platform::*;
105    }
106}
107
108#[cfg(target_os = "windows")]
109#[path = "windows/mod.rs"]
110mod platform;
111
112#[cfg(unix)]
113#[path = "unix/mod.rs"]
114mod platform;
115
116#[inline]
117#[cfg(test)] // Temporary, while Queue isn't well tested
118fn align(x: usize, y: usize) -> usize {
119    if x > 0 && y > 0 {
120        (x + (y - 1)) & !(y - 1)
121    } else {
122        0
123    }
124}
125
126#[cfg(test)]
127fn check_send(_t: &Send) {
128}
129
130// TODO: specialize for platform
131#[cfg(any(test, target_os = "windows"))] // Temporary, while Queue isn't well tested
132const CACHE_LINE: usize = 64;
133
134#[cfg(target_pointer_width = "32")]
135const USIZE_SIZE: usize = 4;
136#[cfg(target_pointer_width = "64")]
137const USIZE_SIZE: usize = 8;
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    use std::{thread};
144
145    use tokio::reactor::Reactor;
146
147    #[test]
148    fn raw_message_channel_pair() {
149        let reactor = Reactor::new().unwrap();
150        let (_a, _b) = RawMessageChannel::pair(&reactor.handle()).unwrap();
151    }
152
153    #[test]
154    fn named_message_channel_pair() {
155        let reactor = Reactor::new().unwrap();
156        let server = platform::NamedMessageChannel::new(&reactor.handle()).unwrap();
157
158        let name = server.name().to_os_string();
159        println!("named socket: {:?}", name);
160        let client_thread = thread::spawn(move || {
161            let reactor = Reactor::new().unwrap();
162            let _client = platform::NamedMessageChannel::connect(&name, None, &reactor.handle()).unwrap();
163        });
164
165        let _server = server.accept(None).unwrap();
166        client_thread.join().unwrap();
167    }
168}