diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-03-07 07:19:30 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-03-07 07:19:30 +0100 |
| commit | 6fbf16b682fe6c399e5c7f5d5f4a8f96a5071093 (patch) | |
| tree | 522a35c6d9c6577d9b8016159382c4cb035900c4 | |
| parent | c354d79ea9634f77eb1a58b3c22d9e8f8229454f (diff) | |
| parent | a84b3c4086459a1fed5dfe7b4dc1359056e156d0 (diff) | |
| download | mullvadvpn-6fbf16b682fe6c399e5c7f5d5f4a8f96a5071093.tar.xz mullvadvpn-6fbf16b682fe6c399e5c7f5d5f4a8f96a5071093.zip | |
Merge branch 'serde'
| -rw-r--r-- | Cargo.lock | 38 | ||||
| -rw-r--r-- | talpid_ipc/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid_ipc/src/lib.rs | 12 | ||||
| -rw-r--r-- | talpid_ipc/src/nop_ipc.rs | 26 | ||||
| -rw-r--r-- | talpid_ipc/src/zmq_ipc.rs | 76 | ||||
| -rw-r--r-- | talpid_ipc/tests/zmq_integration_tests.rs | 26 |
6 files changed, 128 insertions, 52 deletions
diff --git a/Cargo.lock b/Cargo.lock index a7edc49b38..63d6b95fa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,6 +92,11 @@ dependencies = [ ] [[package]] +name = "dtoa" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "env_logger" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -119,6 +124,11 @@ version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "itoa" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -156,6 +166,11 @@ dependencies = [ ] [[package]] +name = "num-traits" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -183,6 +198,22 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "serde" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_json" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -213,6 +244,8 @@ version = "0.1.0" dependencies = [ "assert_matches 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", "zmq 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -322,19 +355,24 @@ dependencies = [ "checksum clap 2.20.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f89819450aa94325998aa83ce7ea142db11ad24c725d6bc48459845e0d6d9f18" "checksum clonablechild 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4a4946a850c1e921fbdd9a1f92bf1298c41a301c0f6e9bacbabf95ea7d6d0225" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03" "checksum error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "318cb3c71ee4cdea69fdc9e15c173b245ed6063e1709029e8fd32525a881120f" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0" +"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum metadeps 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829fffe7ea1d747e23f64be972991bc516b2f1ac2ae4a3b33d8bea150c410151" +"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc" +"checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" +"checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum term_size 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71662702fe5cd2cf95edd4ad655eea42f24a87a0e44059cbaa4e55260b7bc331" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" diff --git a/talpid_ipc/Cargo.toml b/talpid_ipc/Cargo.toml index 6bacc0f9a7..369abcb128 100644 --- a/talpid_ipc/Cargo.toml +++ b/talpid_ipc/Cargo.toml @@ -6,6 +6,8 @@ description = "IPC client and server for talpid" [dependencies] error-chain = "0.8" +serde = "0.9" +serde_json = "0.9" [target.'cfg(not(windows))'.dependencies] zmq = "0.8" diff --git a/talpid_ipc/src/lib.rs b/talpid_ipc/src/lib.rs index 324fb36f05..8698adb55c 100644 --- a/talpid_ipc/src/lib.rs +++ b/talpid_ipc/src/lib.rs @@ -1,6 +1,8 @@ #[macro_use] extern crate error_chain; +extern crate serde; + #[cfg(windows)] #[path = "nop_ipc.rs"] mod ipc_impl; @@ -11,23 +13,21 @@ mod ipc_impl; pub use self::ipc_impl::*; -/// The type signature for functions accepting messages from the server. -/// If the server fails in delivering the message for any reason it will -/// put the cause in the Err part of the `Result`. -pub type OnMessage<MessageType> = FnMut(Result<MessageType>) + Send + 'static; /// An Id created by the Ipc server that the client can use to connect to it -type IpcServerId = String; +pub type IpcServerId = String; error_chain!{ errors { ReadFailure { description("Could not read IPC message") } + ParseFailure { + description("Unable to serialize/deserialize message") + } CouldNotStartServer { description("Failed to start the IPC server") } - SendError { description("Unable to send message") } diff --git a/talpid_ipc/src/nop_ipc.rs b/talpid_ipc/src/nop_ipc.rs index 8faa58ea34..9a767f229d 100644 --- a/talpid_ipc/src/nop_ipc.rs +++ b/talpid_ipc/src/nop_ipc.rs @@ -1,4 +1,6 @@ -use super::{OnMessage, ErrorKind, Result, IpcServerId}; +use super::{ErrorKind, Result, IpcServerId}; + +use serde; /// This implementation only exists because we cannot get ZeroMQ to work on /// Windows. This is not a valid IPC implementation and us using @@ -6,17 +8,27 @@ use super::{OnMessage, ErrorKind, Result, IpcServerId}; /// /// We plan on trying with ZMQ again in the future. /// Erik, 2017-02-09 -fn start_new_server(_on_message: Box<OnMessage<Vec<u8>>>) -> Result<IpcServerId> { +pub fn start_new_server<T, F>(_on_message: F) -> Result<IpcServerId> + where T: serde::Deserialize + 'static, + F: FnMut(Result<T>) + Send + 'static +{ Err(ErrorKind::CouldNotStartServer.into()) } -pub struct IpcClient; -impl IpcClient { - pub fn new(server_id: IpcServerId) -> Self { - IpcClient +pub struct IpcClient<T> + where T: serde::Serialize +{ + _phantom: ::std::marker::PhantomData<T>, +} + +impl<T> IpcClient<T> + where T: serde::Serialize +{ + pub fn new(_server_id: IpcServerId) -> Self { + IpcClient { _phantom: ::std::marker::PhantomData } } - pub fn send(mut self, message: &[u8]) -> Result<()> { + pub fn send(&mut self, _message: &T) -> Result<()> { Err(ErrorKind::SendError.into()) } } diff --git a/talpid_ipc/src/zmq_ipc.rs b/talpid_ipc/src/zmq_ipc.rs index b7e77a15c4..f0111af254 100644 --- a/talpid_ipc/src/zmq_ipc.rs +++ b/talpid_ipc/src/zmq_ipc.rs @@ -1,21 +1,24 @@ extern crate zmq; +extern crate serde_json; + +use super::{ErrorKind, Result, ResultExt, IpcServerId}; + +use serde; -use super::{OnMessage, ErrorKind, Result, ResultExt, IpcServerId}; use std::thread; -/// Starts listening to incoming IPC connections on a random port. -/// Messages are sent to the `on_message` callback. If anything went wrong -/// when reading the message, the message will be an `Err`. -/// NOTE that this does not apply to errors regarding whether the server -/// could start or not, those are returned directly by this function. +/// Starts the server end of an IPC channel. The returned `IpcServerId` is the unique identifier +/// allowing an `IpcClient` to connect to this server instance. Returns an error if unable to set +/// up the server. /// -/// This function is non-blocking and thus spawns a thread where it -/// listens to messages. +/// Incoming messages are sent as `Ok` results to the `on_message` callback. IO errors will be sent +/// as `Err` results to the `on_message` callback. /// -/// The value returned from this function should be used by the clients to -/// the server. -pub fn start_new_server(on_message: Box<OnMessage<Vec<u8>>>) -> Result<IpcServerId> { - +/// This function is non-blocking and thus spawns a thread where it listens to messages. +pub fn start_new_server<T, F>(on_message: F) -> Result<IpcServerId> + where T: serde::Deserialize + 'static, + F: FnMut(Result<T>) + Send + 'static +{ for port in 5000..5010 { let connection_string = format!("tcp://127.0.0.1:{}", port); if let Ok(socket) = start_zmq_server(&connection_string) { @@ -36,29 +39,54 @@ fn start_zmq_server(connection_string: &str) -> zmq::Result<zmq::Socket> { Ok(socket) } -fn start_receive_loop(socket: zmq::Socket, - mut on_message: Box<OnMessage<Vec<u8>>>) - -> thread::JoinHandle<()> { - +fn start_receive_loop<T, F>(socket: zmq::Socket, mut on_message: F) -> thread::JoinHandle<()> + where T: serde::Deserialize + 'static, + F: FnMut(Result<T>) + Send + 'static +{ thread::spawn(move || loop { - let read_res = socket.recv_bytes(0).chain_err(|| ErrorKind::ReadFailure); + let read_res = socket.recv_bytes(0) + .chain_err(|| ErrorKind::ReadFailure) + .and_then(|a| parse_message(&a)); on_message(read_res); }) } -pub struct IpcClient { - server_address: IpcServerId, +fn parse_message<T>(message: &[u8]) -> Result<T> + where T: serde::Deserialize + 'static +{ + serde_json::from_slice(message).chain_err(|| ErrorKind::ParseFailure) +} + + +pub struct IpcClient<T> + where T: serde::Serialize +{ + server_id: IpcServerId, socket: Option<zmq::Socket>, + _phantom: ::std::marker::PhantomData<T>, } -impl IpcClient { + +impl<T> IpcClient<T> + where T: serde::Serialize +{ pub fn new(server_id: IpcServerId) -> Self { IpcClient { - server_address: server_id, + server_id: server_id, socket: None, + _phantom: ::std::marker::PhantomData, } } - pub fn send(&mut self, message: &[u8]) -> Result<()> { + pub fn send(&mut self, message: &T) -> Result<()> { + let bytes = Self::serialize(message)?; + self.send_bytes(bytes.as_slice()) + } + + fn serialize(t: &T) -> Result<Vec<u8>> { + serde_json::to_vec(t).chain_err(|| ErrorKind::ParseFailure) + } + + fn send_bytes(&mut self, message: &[u8]) -> Result<()> { if self.socket.is_none() { self.connect().chain_err(|| ErrorKind::SendError)?; } @@ -71,8 +99,8 @@ impl IpcClient { let ctx = zmq::Context::new(); let socket = ctx.socket(zmq::PUSH) .chain_err(|| "Could not create ZeroMQ PUSH socket".to_owned())?; - socket.connect(&self.server_address) - .chain_err(|| format!("Could not connect to {:?}", self.server_address))?; + socket.connect(&self.server_id) + .chain_err(|| format!("Could not connect to {:?}", self.server_id))?; self.socket = Some(socket); Ok(()) diff --git a/talpid_ipc/tests/zmq_integration_tests.rs b/talpid_ipc/tests/zmq_integration_tests.rs index 07469a8f50..498c3af820 100644 --- a/talpid_ipc/tests/zmq_integration_tests.rs +++ b/talpid_ipc/tests/zmq_integration_tests.rs @@ -1,38 +1,34 @@ -#[macro_use] -extern crate error_chain; - -#[macro_use] -extern crate assert_matches; - #[cfg(all(test, not(windows)))] mod zmq_integration_tests { + extern crate serde; extern crate talpid_ipc; - extern crate zmq; - use self::talpid_ipc::{Result, IpcClient}; + use self::talpid_ipc::{Result, IpcServerId, IpcClient}; + use std::sync::mpsc::{self, Receiver}; use std::time::Duration; #[test] fn can_connect_and_send_and_receive_messages() { - let (connection_string, new_messages_rx) = start_server(); + let (connection_string, new_messages_rx) = start_server::<String>(); let mut ipc_client = IpcClient::new(connection_string); - ipc_client.send(&[1, 3, 3, 7]).expect("Could not send message"); + let msg = "Hello".to_owned(); + ipc_client.send(&msg).expect("Could not send message"); let message = new_messages_rx.recv_timeout(Duration::from_millis(1000)) .expect("Did not receive a message"); - assert_eq!(message.unwrap(), - &[1, 3, 3, 7], - "Read data does not match sent data"); + assert_eq!(message.unwrap(), "Hello", "Got wrong message"); } - fn start_server() -> (String, Receiver<Result<Vec<u8>>>) { + fn start_server<T>() -> (IpcServerId, Receiver<Result<T>>) + where T: serde::Deserialize + Send + 'static + { let (tx, rx) = mpsc::channel(); let connection_string = - talpid_ipc::start_new_server(Box::new(move |message| { let _ = tx.send(message); })) + talpid_ipc::start_new_server(move |message: Result<T>| { let _ = tx.send(message); }) .expect("Could not start the server"); (connection_string, rx) |
