summaryrefslogtreecommitdiffhomepage
path: root/talpid_ipc/src
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-03-29 13:58:36 +0800
committerErik Larkö <erik@mullvad.net>2017-03-29 13:58:36 +0800
commit075f980a12f3b7e81da93928d475278b67b0cc47 (patch)
tree36956188d66ab35d1ef98327eefcbae32c8fa1f9 /talpid_ipc/src
parent1898a8e604ccfec4cb30c48dcfb75654898210d3 (diff)
parentd331b520a1abb2e9fecef3844cf9c029a86ad361 (diff)
downloadmullvadvpn-075f980a12f3b7e81da93928d475278b67b0cc47.tar.xz
mullvadvpn-075f980a12f3b7e81da93928d475278b67b0cc47.zip
Merge branch http-ipc
Diffstat (limited to 'talpid_ipc/src')
-rw-r--r--talpid_ipc/src/http_ipc.rs116
-rw-r--r--talpid_ipc/src/lib.rs2
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;