Skip to content

Commit

Permalink
fix: Compilation without feature flags, clippy warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
binarybaron committed Nov 29, 2024
1 parent 87f0e41 commit 9ca6ffc
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 43 deletions.
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ tracing = "0.1.40"
tor-hsservice = { version = "0.24.0", optional = true }
tor-cell = { version = "0.24.0", optional = true }
tor-proto = { version = "0.24.0", optional = true }
data-encoding = { version = "2.6.0", optional = true }
data-encoding = { version = "2.6.0" }

[dev-dependencies]
libp2p = { version = "0.53", default-features = false, features = ["tokio", "noise", "yamux", "ping", "macros", "tcp", "tls"] }
Expand All @@ -35,8 +35,7 @@ listen-onion-service = [
"arti-client/onion-service-service",
"dep:tor-hsservice",
"dep:tor-cell",
"dep:tor-proto",
"dep:data-encoding"
"dep:tor-proto"
]

[[example]]
Expand Down
8 changes: 4 additions & 4 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ pub fn safe_extract(multiaddr: &Multiaddr) -> Option<TorAddr> {

fn libp2p_onion_address_to_domain_and_port<'a>(
onion_address: &'a Onion3Addr<'_>,
) -> Option<(&'a str, u16)> {
) -> (&'a str, u16) {
// Here we convert from Onion3Addr to TorAddr
// We need to leak the string because it's a temporary string that would otherwise be freed
let hash = data_encoding::BASE32.encode(onion_address.hash());
let onion_domain = format!("{}.onion", hash);
let onion_domain = format!("{hash}.onion");
let onion_domain = Box::leak(onion_domain.into_boxed_str());

Some((onion_domain, onion_address.port()))
(onion_domain, onion_address.port())
}

fn try_to_domain_and_port<'a>(
Expand All @@ -72,7 +72,7 @@ fn try_to_domain_and_port<'a>(
Protocol::Dns(domain) | Protocol::Dns4(domain) | Protocol::Dns6(domain),
Some(Protocol::Tcp(port)),
) => Some((domain.as_ref(), *port)),
(Protocol::Onion3(domain), _) => libp2p_onion_address_to_domain_and_port(domain),
(Protocol::Onion3(domain), _) => Some(libp2p_onion_address_to_domain_and_port(domain)),
_ => None,
}
}
Expand Down
94 changes: 58 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,28 @@
use arti_client::{TorClient, TorClientBuilder};
use futures::future::BoxFuture;
use futures::stream::BoxStream;
use libp2p::multiaddr::Protocol;
use libp2p::{
core::transport::{ListenerId, TransportEvent},
Multiaddr, Transport, TransportError,
};
use std::collections::HashMap;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::Arc;
use std::task::{Context, Poll};
use thiserror::Error;
use tor_hsservice::handle_rend_requests;
use tor_hsservice::status::OnionServiceStatus;
use tor_hsservice::StreamRequest;
use tor_rtcompat::tokio::TokioRustlsRuntime;

// We only need these imports if the `listen-onion-service` feature is enabled
#[cfg(feature = "listen-onion-service")]
use std::collections::HashMap;
#[cfg(feature = "listen-onion-service")]
use std::str::FromStr;
#[cfg(feature = "listen-onion-service")]
use tor_cell::relaycell::msg::{Connected, End, EndReason};
#[cfg(feature = "listen-onion-service")]
use tor_hsservice::{HsId, OnionServiceConfig, RunningOnionService};
use tor_hsservice::{
handle_rend_requests, status::OnionServiceStatus, HsId, OnionServiceConfig,
RunningOnionService, StreamRequest,
};
#[cfg(feature = "listen-onion-service")]
use tor_proto::stream::IncomingStreamRequest;

Expand All @@ -88,9 +88,9 @@ pub type TorError = arti_client::Error;

type PendingUpgrade = BoxFuture<'static, Result<TokioTorStream, TorTransportError>>;
#[cfg(feature = "listen-onion-service")]
type OnionServiceStream = BoxStream<'static, StreamRequest>;
type OnionServiceStream = futures::stream::BoxStream<'static, StreamRequest>;
#[cfg(feature = "listen-onion-service")]
type OnionServiceStatusStream = BoxStream<'static, OnionServiceStatus>;
type OnionServiceStatusStream = futures::stream::BoxStream<'static, OnionServiceStatus>;

/// Struct representing an onion address we are listening on for libp2p connections.
#[cfg(feature = "listen-onion-service")]
Expand Down Expand Up @@ -176,8 +176,8 @@ impl TorTransport {
conversion_mode: AddressConversion,
) -> Self {
Self {
client,
conversion_mode,
client,
#[cfg(feature = "listen-onion-service")]
listeners: HashMap::new(),
#[cfg(feature = "listen-onion-service")]
Expand Down Expand Up @@ -206,6 +206,9 @@ impl TorTransport {
/// # Returns
/// Returns the Multiaddr of the onion address that the transport can be instructed to listen on
/// To actually listen on the address, you need to call [`listen_on`] with the returned address
///
/// # Errors
/// Returns an error if we cannot get the onion address of the service
#[cfg(feature = "listen-onion-service")]
pub fn add_onion_service(
&mut self,
Expand All @@ -217,7 +220,7 @@ impl TorTransport {

let multiaddr = service
.onion_name()
.ok_or_else(|| anyhow::anyhow!("Onion service has no nickname"))?
.ok_or_else(|| anyhow::anyhow!("Onion service has no onion address"))?
.to_multiaddr(port);

self.services.push((service, request_stream));
Expand Down Expand Up @@ -251,35 +254,37 @@ trait HsIdExt {

#[cfg(feature = "listen-onion-service")]
impl HsIdExt for HsId {
/// Convert an HsId to a Multiaddr
/// Convert an `HsId` to a `Multiaddr`
fn to_multiaddr(&self, port: u16) -> Multiaddr {
let onion_domain = self.to_string();
let onion_without_dot_onion = onion_domain
.split(".")
.split('.')
.nth(0)
.expect("Display formatting of HsId to contain .onion suffix");
let multiaddress_string = format!("/onion3/{}:{}", onion_without_dot_onion, port);
let multiaddress_string = format!("/onion3/{onion_without_dot_onion}:{port}");

Multiaddr::from_str(&multiaddress_string)
.expect("A valid onion address to be convertible to a Multiaddr")
}
}

#[cfg(feature = "listen-onion-service")]
trait StatusExt {
fn is_reachable(&self) -> bool;
fn is_broken(&self) -> bool;
}

#[cfg(feature = "listen-onion-service")]
impl StatusExt for OnionServiceStatus {
/// Returns true if the onion service is reachable
/// Returns true if the onion service is probably reachable
fn is_reachable(&self) -> bool {
match self.state() {
tor_hsservice::status::State::Running => true,
tor_hsservice::status::State::DegradedReachable => true,
_ => false,
}
matches!(
self.state(),
tor_hsservice::status::State::Running | tor_hsservice::status::State::DegradedReachable
)
}

/// Returns true if the onion service is definitely broken
fn is_broken(&self) -> bool {
matches!(self.state(), tor_hsservice::status::State::Broken)
}
Expand All @@ -291,17 +296,25 @@ impl Transport for TorTransport {
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type ListenerUpgrade = PendingUpgrade;

#[cfg(not(feature = "listen-onion-service"))]
fn listen_on(
&mut self,
id: ListenerId,
_id: ListenerId,
onion_address: Multiaddr,
) -> Result<(), TransportError<Self::Error>> {
// If the `listen-onion-service` feature is not enabled, immediately return an error
#[cfg(not(feature = "listen-onion-service"))]
return Err(TransportError::MultiaddrNotSupported(onion_address.clone()));
// If the `listen-onion-service` feature is not enabled, we do not support listening
Err(TransportError::MultiaddrNotSupported(onion_address.clone()))
}

#[cfg(feature = "listen-onion-service")]
fn listen_on(
&mut self,
id: ListenerId,
onion_address: Multiaddr,
) -> Result<(), TransportError<Self::Error>> {
// If the address is not an onion3 address, return an error
let Some(Protocol::Onion3(address)) = onion_address.into_iter().nth(0) else {
let Some(libp2p::multiaddr::Protocol::Onion3(address)) = onion_address.into_iter().nth(0)
else {
return Err(TransportError::MultiaddrNotSupported(onion_address.clone()));
};

Expand Down Expand Up @@ -333,14 +346,17 @@ impl Transport for TorTransport {
},
);

return Ok(());
Ok(())
}

fn remove_listener(&mut self, id: ListenerId) -> bool {
// If the `listen-onion-service` feature is not enabled, we do not support listening
#[cfg(not(feature = "listen-onion-service"))]
return false;
// We do not support removing listeners if the `listen-onion-service` feature is not enabled
#[cfg(not(feature = "listen-onion-service"))]
fn remove_listener(&mut self, _id: ListenerId) -> bool {
false
}

#[cfg(feature = "listen-onion-service")]
fn remove_listener(&mut self, id: ListenerId) -> bool {
// Take the listener out of the map. This will stop listening on onion service for libp2p connections (we will not poll it anymore)
// However, we will not stop the onion service itself because we might want to reuse it later
// The onion service will be stopped when the transport is dropped
Expand Down Expand Up @@ -383,15 +399,21 @@ impl Transport for TorTransport {
None
}

#[cfg(not(feature = "listen-onion-service"))]
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
// If the `listen-onion-service` feature is not enabled, we do not support listening
#[cfg(not(feature = "listen-onion-service"))]
return Poll::Pending;
Poll::Pending
}

for (listener_id, listener) in self.listeners.iter_mut() {
#[cfg(feature = "listen-onion-service")]
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
for (listener_id, listener) in &mut self.listeners {
// Check if the service has any new statuses
if let Poll::Ready(Some(status)) = listener.status_stream.as_mut().poll_next(cx) {
tracing::debug!(
Expand Down

0 comments on commit 9ca6ffc

Please sign in to comment.