diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-03-27 12:35:49 +0800 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-04-07 13:08:25 +0800 |
| commit | f7b702c41da9ab31a80d1654b9b2c323e2a25ec5 (patch) | |
| tree | b22441036215270963e50d37dff7b60f2e88455d /talpid_ipc/src | |
| parent | 89723462dc879cb29fb917ff2f16ebb663217082 (diff) | |
| download | mullvadvpn-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.rs | 111 | ||||
| -rw-r--r-- | talpid_ipc/src/http_ipc/connection_info.rs | 41 | ||||
| -rw-r--r-- | talpid_ipc/src/http_ipc/mod.rs | 73 |
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") + } + } +} |
