From 2bb51d6757adb099fa862febe1ab6d8d278a5191 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Wed, 15 May 2024 20:27:58 +0300 Subject: [PATCH] tor: fix service availability check --- src/gui/views/wallets/wallet/transport.rs | 28 ++-- src/tor/tor.rs | 164 ++++++++++++---------- src/wallet/wallet.rs | 9 +- 3 files changed, 112 insertions(+), 89 deletions(-) diff --git a/src/gui/views/wallets/wallet/transport.rs b/src/gui/views/wallets/wallet/transport.rs index 94fa053..2e078a2 100644 --- a/src/gui/views/wallets/wallet/transport.rs +++ b/src/gui/views/wallets/wallet/transport.rs @@ -18,6 +18,8 @@ use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea}; use egui::os::OperatingSystem; use egui::scroll_area::ScrollBarVisibility; use parking_lot::RwLock; +use tor_rtcompat::BlockOn; +use tor_rtcompat::tokio::TokioNativeTlsRuntime; use grin_core::core::{amount_from_hr_string, amount_to_hr_string}; use grin_wallet_libwallet::SlatepackAddress; @@ -402,7 +404,7 @@ impl WalletTransport { ui.add_space(6.0); } - /// Draw Tor send content. + /// Draw Tor receive content. fn tor_receive_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, @@ -495,7 +497,7 @@ impl WalletTransport { }); } - /// Draw Tor receive content. + /// Draw Tor send content. fn tor_send_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { // Setup layout size. let mut rect = ui.available_rect_before_wrap(); @@ -684,12 +686,13 @@ impl WalletTransport { let send_success = self.tor_success.clone(); let mut wallet = wallet.clone(); thread::spawn(move || { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap() + let runtime = TokioNativeTlsRuntime::create().unwrap(); + let runtime_tor = runtime.clone(); + runtime .block_on(async { - if wallet.send_tor(a, &addr).await.is_some() { + if wallet.send_tor(a, &addr, runtime_tor) + .await + .is_some() { let mut w_send_success = send_success.write(); *w_send_success = true; } else { @@ -742,15 +745,16 @@ impl WalletTransport { let send_success = self.tor_success.clone(); let mut wallet = wallet.clone(); thread::spawn(move || { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap() + let runtime = TokioNativeTlsRuntime::create().unwrap(); + let runtime_tor = runtime.clone(); + runtime .block_on(async { let addr_str = addr_text.as_str(); let addr = &SlatepackAddress::try_from(addr_str) .unwrap(); - if wallet.send_tor(a, &addr).await.is_some() { + if wallet.send_tor(a, &addr, runtime_tor) + .await + .is_some() { let mut w_send_success = send_success.write(); *w_send_success = true; } else { diff --git a/src/tor/tor.rs b/src/tor/tor.rs index 818cf56..0ab7971 100644 --- a/src/tor/tor.rs +++ b/src/tor/tor.rs @@ -32,7 +32,7 @@ use sha2::Sha512; use tokio::time::{sleep, sleep_until}; use tor_config::CfgPath; use tor_rtcompat::tokio::TokioNativeTlsRuntime; -use tor_rtcompat::Runtime; +use tor_rtcompat::{BlockOn, PreferredRuntime, Runtime}; use tor_hsrproxy::OnionServiceReverseProxy; use tor_hsrproxy::config::{Encapsulation, ProxyAction, ProxyPattern, ProxyRule, TargetAddr, ProxyConfigBuilder}; use tor_hsservice::config::OnionServiceConfigBuilder; @@ -68,7 +68,9 @@ pub struct Tor { /// Starting Onion services identifiers. starting_services: Arc>>, /// Failed Onion services identifiers. - failed_services: Arc>> + failed_services: Arc>>, + /// Checking Onion services identifiers. + checking_services: Arc>> } impl Default for Tor { @@ -76,14 +78,15 @@ impl Default for Tor { Self { running_services: Arc::new(RwLock::new(BTreeMap::new())), starting_services: Arc::new(RwLock::new(BTreeSet::new())), - failed_services: Arc::new(RwLock::new(BTreeSet::new())) + failed_services: Arc::new(RwLock::new(BTreeSet::new())), + checking_services: Arc::new(RwLock::new(BTreeSet::new())) } } } impl Tor { async fn build_client(runtime: TokioNativeTlsRuntime) - -> (TorClient, TorClientConfig) { + -> (TorClient, TorClientConfig) { // Create Tor client config. let mut builder = TorClientConfigBuilder::from_directories(TorConfig::state_path(), @@ -101,16 +104,15 @@ impl Tor { // Create connected Tor client from config. let config = builder.build().unwrap(); (TorClient::with_runtime(runtime) - .config(config.clone()) - .create_bootstrapped() - .await - .unwrap(), config) + .config(config.clone()) + .create_bootstrapped() + .await + .unwrap(), config) } /// Send post request using Tor. - pub async fn post(body: String, url: String) -> Option { + pub async fn post(body: String, url: String, runtime: TokioNativeTlsRuntime) -> Option { // Create client. - let runtime = TokioNativeTlsRuntime::create().unwrap(); let (client, _) = Self::build_client(runtime).await; // Create http tor-powered client to post data. let tls_connector = TlsConnector::builder().unwrap().build().unwrap(); @@ -156,6 +158,12 @@ impl Tor { r_services.contains(id) } + /// Check if Onion service is checking. + pub fn is_service_checking(id: &String) -> bool { + let r_services = TOR_SERVER_STATE.checking_services.read().unwrap(); + r_services.contains(id) + } + /// Stop running Onion service. pub fn stop_service(id: &String) { let mut w_services = TOR_SERVER_STATE.running_services.write().unwrap(); @@ -180,70 +188,79 @@ impl Tor { } let service_id = id.clone(); - let runtime = TokioNativeTlsRuntime::create().unwrap(); - let runtime_client = runtime.clone(); - runtime.spawn(async move { - let (client, config) = Self::build_client(runtime_client.clone()).await; - // Add service key to keystore. - let hs_nickname = HsNickname::new(service_id.clone()).unwrap(); - Self::add_service_key(config.fs_mistrust(), &key, &hs_nickname); - // Launch Onion service. - let service_config = OnionServiceConfigBuilder::default() - .nickname(hs_nickname.clone()) - .build() - .unwrap(); - let (service, request) = client.launch_onion_service(service_config).unwrap(); - - // Launch service proxy. - let addr = SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), port); - tokio::spawn( - Self::run_service_proxy(addr, client, service.clone(), request, hs_nickname.clone()) - ).await.unwrap(); - - // Check service availability. - let url = format!("http://{}", service.onion_name().unwrap().to_string()); - std::thread::spawn(move || { - thread::sleep(Duration::from_millis(3000)); - let runtime = TokioNativeTlsRuntime::create().unwrap(); - let runtime_client = runtime.clone(); - runtime.spawn(async move { - loop { - if !Self::is_service_running(&service_id) && - !Self::is_service_starting(&service_id) { - break; - } - // Create client. - let (client, _) = Self::build_client(runtime_client.clone()).await; - - // Create http tor-powered client to ping service. - let tls_connector = TlsConnector::builder().unwrap().build().unwrap(); - let tor_connector = ArtiHttpConnector::new(client, tls_connector); - let http = hyper::Client::builder().build::<_, Body>(tor_connector); - - match http.get(Uri::from_str(url.as_str()).unwrap()).await { - Ok(_) => { - // Remove service from starting. - let mut w_services = TOR_SERVER_STATE.starting_services.write().unwrap(); - w_services.remove(&service_id); - - println!("check success"); - }, - Err(e) => { - // Put service to starting. - let mut w_services = TOR_SERVER_STATE.starting_services.write().unwrap(); - w_services.insert(service_id.clone()); - - println!("check err: {}", e); - }, - } - if !Self::is_service_running(&service_id) && - !Self::is_service_starting(&service_id) { - break; - } + thread::spawn(move || { + let runtime = TokioNativeTlsRuntime::create().unwrap(); + let runtime_client = runtime.clone(); + runtime.spawn(async move { + let (client, config) = Self::build_client(runtime_client.clone()).await; + // Add service key to keystore. + let hs_nickname = HsNickname::new(service_id.clone()).unwrap(); + Self::add_service_key(config.fs_mistrust(), &key, &hs_nickname); + // Launch Onion service. + let service_config = OnionServiceConfigBuilder::default() + .nickname(hs_nickname.clone()) + .build() + .unwrap(); + let (service, request) = client.launch_onion_service(service_config).unwrap(); + + // Launch service proxy. + let addr = SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), port); + tokio::spawn( + Self::run_service_proxy(addr, client, service.clone(), request, hs_nickname.clone()) + ).await.unwrap(); + + // Check service availability if not checking. + if Self::is_service_checking(&service_id) { + return; + } + let url = format!("http://{}/v2/foreign", service.onion_name().unwrap().to_string()); + thread::spawn(move || { + let runtime = TokioNativeTlsRuntime::create().unwrap(); + let client_runtime = runtime.clone(); + // Put service to checking. + { + let mut w_services = TOR_SERVER_STATE.checking_services.write().unwrap(); + w_services.insert(service_id.clone()); } - }).unwrap(); - }); - }).unwrap(); + runtime + .spawn(async move { + loop { + println!("start loop"); + // Create client. + let (client, _) = Self::build_client(client_runtime.clone()).await; + + // Create http tor-powered client to ping service. + let tls_connector = TlsConnector::builder().unwrap().build().unwrap(); + let tor_connector = ArtiHttpConnector::new(client, tls_connector); + let http = hyper::Client::builder().build::<_, Body>(tor_connector); + + println!("start get {}", url); + match http.get(Uri::from_str(url.as_str()).unwrap()).await { + Ok(_) => { + // Remove service from starting. + let mut w_services = TOR_SERVER_STATE.starting_services.write().unwrap(); + w_services.remove(&service_id); + println!("OK"); + }, + Err(e) => { + // Put service to starting. + let mut w_services = TOR_SERVER_STATE.starting_services.write().unwrap(); + w_services.insert(service_id.clone()); + println!("err: {}", e); + }, + } + if !Self::is_service_running(&service_id) && + !Self::is_service_starting(&service_id) { + // Remove service from checking. + let mut w_services = TOR_SERVER_STATE.checking_services.write().unwrap(); + w_services.remove(&service_id); + break; + } + } + }).unwrap(); + }); + }).unwrap(); + }); } /// Launch Onion service proxy. @@ -282,7 +299,6 @@ impl Tor { .handle_requests(runtime, nickname.clone(), request) .await { Ok(()) => { - println!("service stopped"); // Remove service from running. let mut w_services = TOR_SERVER_STATE.running_services.write().unwrap(); diff --git a/src/wallet/wallet.rs b/src/wallet/wallet.rs index 58658ce..06be0b5 100644 --- a/src/wallet/wallet.rs +++ b/src/wallet/wallet.rs @@ -24,6 +24,8 @@ use std::thread::Thread; use std::time::Duration; use futures::channel::oneshot; use serde_json::{json, Value}; +use tor_rtcompat::tokio::TokioNativeTlsRuntime; +use rand::Rng; use grin_api::{ApiServer, Router}; use grin_chain::SyncStatus; @@ -40,7 +42,6 @@ use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient}; use grin_wallet_libwallet::{address, Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, RetrieveTxQueryArgs, RetrieveTxQuerySortField, RetrieveTxQuerySortOrder, Slate, SlatepackAddress, SlateState, SlateVersion, StatusMessage, TxLogEntry, TxLogEntryType, VersionedSlate, WalletInst, WalletLCProvider}; use grin_wallet_libwallet::api_impl::owner::{cancel_tx, retrieve_summary_info, retrieve_txs}; use grin_wallet_util::OnionV3Address; -use rand::Rng; use crate::AppConfig; use crate::node::{Node, NodeConfig}; @@ -675,7 +676,9 @@ impl Wallet { } /// Send amount to provided address with Tor transport. - pub async fn send_tor(&mut self, amount: u64, addr: &SlatepackAddress) -> Option { + pub async fn send_tor(&mut self, + amount: u64, addr: &SlatepackAddress, + runtime: TokioNativeTlsRuntime) -> Option { // Initialize transaction. let send_res = self.send(amount); @@ -706,7 +709,7 @@ impl Wallet { }).to_string(); // Send request to receiver. - let req_res = Tor::post(body, url).await; + let req_res = Tor::post(body, url, runtime).await; if req_res.is_none() { cancel_tx(); return None;