summaryrefslogtreecommitdiffhomepage
path: root/talpid_ipc/src
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-03-27 12:35:49 +0800
committerErik Larkö <erik@mullvad.net>2017-04-07 13:08:25 +0800
commitf7b702c41da9ab31a80d1654b9b2c323e2a25ec5 (patch)
treeb22441036215270963e50d37dff7b60f2e88455d /talpid_ipc/src
parent89723462dc879cb29fb917ff2f16ebb663217082 (diff)
downloadmullvadvpn-f7b702c41da9ab31a80d1654b9b2c323e2a25ec5.tar.xz
mullvadvpn-f7b702c41da9ab31a80d1654b9b2c323e2a25ec5.zip
Created the talpid_daemon crate and put the frontend IPC stuff there
Diffstat (limited to 'talpid_ipc/src')
-rw-r--r--talpid_ipc/src/http_ipc.rs111
-rw-r--r--talpid_ipc/src/http_ipc/connection_info.rs41
-rw-r--r--talpid_ipc/src/http_ipc/mod.rs73
3 files changed, 114 insertions, 111 deletions
diff --git a/talpid_ipc/src/http_ipc.rs b/talpid_ipc/src/http_ipc.rs
deleted file mode 100644
index 7613f9fa82..0000000000
--- a/talpid_ipc/src/http_ipc.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-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<()>,
-}
-impl HttpServerHandle {
- pub fn stop(&self) {
- let _ = self.stop_tx.send(());
- }
-}
-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<()>)
- where T: serde::Deserialize + 'static,
- U: serde::Serialize,
- F: FnMut(Result<T>) -> U + Send + 'static
-{
- thread::spawn(move || {
- while !should_stop(&stop_rx) {
- receive(&mut on_message, &http_server);
- }
- debug!("Stopping the HTTP IPC server");
- });
-}
-
-fn should_stop(stop_rx: &mpsc::Receiver<()>) -> bool {
- stop_rx.try_recv() != Err(mpsc::TryRecvError::Empty)
-}
-
-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/http_ipc/connection_info.rs b/talpid_ipc/src/http_ipc/connection_info.rs
new file mode 100644
index 0000000000..99d87c0603
--- /dev/null
+++ b/talpid_ipc/src/http_ipc/connection_info.rs
@@ -0,0 +1,41 @@
+use std::fs::{File, OpenOptions};
+use std::io::Write;
+use std::path::PathBuf;
+
+/// The path to the file where we write the connection infp
+const IPC_CONNECTION_INFO_FILE: &'static str = "./.ipc_connection_info";
+
+error_chain! {
+ errors {
+ OpenFileFailed(file_name: PathBuf) {
+ description("Could not open file")
+ display("Could not open {}", file_name.to_string_lossy())
+ }
+ WriteConnectionInfoFailed(file_name: PathBuf) {
+ description("Could not write connection info file")
+ display("Could not write to {}", file_name.to_string_lossy())
+ }
+ }
+}
+
+pub fn write(connection_info: &str) -> Result<()> {
+ let file_location = PathBuf::from(IPC_CONNECTION_INFO_FILE);
+ let mut file = open_file(&file_location)?;
+ let res = file.write_all(connection_info.as_bytes())
+ .chain_err(|| ErrorKind::WriteConnectionInfoFailed(file_location.clone()));
+
+ debug!("Wrote IPC connection info ({}) to {}",
+ connection_info,
+ file_location.to_string_lossy());
+
+ res
+}
+
+fn open_file(file_name: &PathBuf) -> Result<File> {
+ OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(file_name)
+ .chain_err(|| ErrorKind::OpenFileFailed(file_name.to_owned()))
+}
diff --git a/talpid_ipc/src/http_ipc/mod.rs b/talpid_ipc/src/http_ipc/mod.rs
new file mode 100644
index 0000000000..24e177a755
--- /dev/null
+++ b/talpid_ipc/src/http_ipc/mod.rs
@@ -0,0 +1,73 @@
+extern crate jsonrpc_core;
+extern crate jsonrpc_http_server;
+
+use self::jsonrpc_http_server::{ServerBuilder, Server};
+use std::net::{SocketAddr, IpAddr, Ipv4Addr};
+
+mod connection_info;
+
+pub struct ServerHandle {
+ pub address: String,
+ server: Server,
+}
+
+impl ServerHandle {
+ pub fn stop(self) {
+ self.server.close();
+ }
+}
+
+pub fn start(build_router: fn() -> jsonrpc_core::IoHandler) -> Result<ServerHandle> {
+ let server = start_server(build_router)?;
+
+ let write_res = connection_info::write(&server.address)
+ .chain_err(|| ErrorKind::FailedToWriteConnectionInfo);
+ if let Err(e) = write_res {
+ debug!("Could not write the connection info, killing the IPC server");
+ server.stop();
+
+ return Err(e);
+ }
+
+ info!("Started Ipc server on: {:?}", server.address);
+ Ok(server)
+}
+
+fn start_server(build_router: fn() -> jsonrpc_core::IoHandler) -> Result<ServerHandle> {
+
+ let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+ for port in 5000..5010 {
+ let server_config = ServerBuilder::new(build_router()).allow_only_bind_host();
+
+ let socket_addr = SocketAddr::new(ip, port);
+ let start_res = attempt_to_start(server_config, &socket_addr);
+
+ match start_res {
+ Ok(server) => {
+ return Ok(ServerHandle {
+ address: format!("http://{}", socket_addr),
+ server: server,
+ });
+ }
+ Err(Error(ErrorKind::UnableToStartServer, _)) => (),
+ Err(e) => return Err(e),
+ }
+ }
+ bail!(ErrorKind::UnableToStartServer)
+}
+
+fn attempt_to_start(server_config: ServerBuilder, address: &SocketAddr) -> Result<Server> {
+ server_config.start_http(&address)
+ .chain_err(|| ErrorKind::UnableToStartServer)
+}
+
+error_chain! {
+ errors {
+ FailedToWriteConnectionInfo {
+ description("Unable to write IPC connection info")
+ }
+ UnableToStartServer {
+ description("Failed to start the server")
+ }
+ }
+}