diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-03-29 13:58:36 +0800 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-03-29 13:58:36 +0800 |
| commit | 075f980a12f3b7e81da93928d475278b67b0cc47 (patch) | |
| tree | 36956188d66ab35d1ef98327eefcbae32c8fa1f9 /talpid_ipc/src | |
| parent | 1898a8e604ccfec4cb30c48dcfb75654898210d3 (diff) | |
| parent | d331b520a1abb2e9fecef3844cf9c029a86ad361 (diff) | |
| download | mullvadvpn-075f980a12f3b7e81da93928d475278b67b0cc47.tar.xz mullvadvpn-075f980a12f3b7e81da93928d475278b67b0cc47.zip | |
Merge branch http-ipc
Diffstat (limited to 'talpid_ipc/src')
| -rw-r--r-- | talpid_ipc/src/http_ipc.rs | 116 | ||||
| -rw-r--r-- | talpid_ipc/src/lib.rs | 2 |
2 files changed, 118 insertions, 0 deletions
diff --git a/talpid_ipc/src/http_ipc.rs b/talpid_ipc/src/http_ipc.rs new file mode 100644 index 0000000000..15304e87fa --- /dev/null +++ b/talpid_ipc/src/http_ipc.rs @@ -0,0 +1,116 @@ +extern crate tiny_http; +extern crate serde_json; + +use super::{ErrorKind, Result, ResultExt, IpcServerId}; +use serde; +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +pub struct HttpServerHandle { + pub address: IpcServerId, + stop_tx: mpsc::SyncSender<u8>, +} +impl HttpServerHandle { + pub fn stop(&self) { + let _ = self.stop_tx.send(0); + } +} +impl Drop for HttpServerHandle { + fn drop(&mut self) { + self.stop(); + } +} + +pub fn start_server<T, U, F>(on_message: F) -> Result<HttpServerHandle> + where T: serde::Deserialize + 'static, + U: serde::Serialize, + F: FnMut(Result<T>) -> U + Send + 'static +{ + for port in 5000..5010 { + let addr = format!("127.0.0.1:{}", port); + + if let Ok(server) = start_http_server(&addr) { + let (stop_tx, stop_rx) = mpsc::sync_channel(0); + let handle = HttpServerHandle { + stop_tx: stop_tx, + address: format!("http://{}", addr), + }; + + start_receive_loop(on_message, server, stop_rx); + debug!("Started a HTTP IPC server on {}", addr); + return Ok(handle); + } + } + bail!(ErrorKind::CouldNotStartServer) +} + +fn start_http_server(addr: &str) -> Result<tiny_http::Server> { + tiny_http::Server::http(addr).map_err(|e| ErrorKind::Msg(e.to_string()).into()) +} + +fn start_receive_loop<T, U, F>(mut on_message: F, + http_server: tiny_http::Server, + stop_rx: mpsc::Receiver<u8>) + where T: serde::Deserialize + 'static, + U: serde::Serialize, + F: FnMut(Result<T>) -> U + Send + 'static +{ + thread::spawn(move || loop { + if should_stop(&stop_rx) { + debug!("Stopping the server"); + break; + } + + receive(&mut on_message, &http_server); + }); +} + +fn should_stop(stop_rx: &mpsc::Receiver<u8>) -> bool { + match stop_rx.try_recv() { + Err(mpsc::TryRecvError::Empty) => false, + _ => true, + } +} + +fn receive<T, U, F>(on_message: &mut F, http_server: &tiny_http::Server) + where T: serde::Deserialize + 'static, + U: serde::Serialize, + F: FnMut(Result<T>) -> U + Send + 'static +{ + let req_res = http_server.recv_timeout(Duration::from_millis(1000)); + match req_res { + Ok(Some(mut request)) => { + let read_res = parse_request(&mut request); + let response = on_message(read_res); + let reply_res = send_response(&response, request); + + if let Err(e) = reply_res { + error!("Failed sending reply to request, {}", e); + } + } + Ok(None) => (), + Err(e) => error!("Failed receiving request: {}", e), + } +} + +fn parse_request<T: serde::Deserialize>(request: &mut tiny_http::Request) -> Result<T> { + let reader = request.as_reader(); + let mut buffer = String::new(); + reader.read_to_string(&mut buffer).chain_err(|| ErrorKind::ParseFailure)?; + + debug!("Got IPC request: {}", buffer); + + serde_json::from_str(&buffer).chain_err(|| ErrorKind::ParseFailure) +} + +fn send_response<U: serde::Serialize>(response: &U, request: tiny_http::Request) -> Result<()> { + serde_json::to_string(response) + .chain_err(|| ErrorKind::ParseFailure) + .and_then(|response_as_string| { + + debug!("HTTP IPC responding with {:?}", response_as_string); + request.respond(tiny_http::Response::from_string(response_as_string)) + .chain_err(|| "Failed responding to HTTP request") + }) +} diff --git a/talpid_ipc/src/lib.rs b/talpid_ipc/src/lib.rs index 8f82417d58..1fcfe47962 100644 --- a/talpid_ipc/src/lib.rs +++ b/talpid_ipc/src/lib.rs @@ -15,6 +15,8 @@ mod ipc_impl; pub use self::ipc_impl::*; +pub mod http_ipc; + /// An Id created by the Ipc server that the client can use to connect to it pub type IpcServerId = String; |
