From 995d7ba3d8d1ba02e520dbe746f0b5d4f7343642 Mon Sep 17 00:00:00 2001 From: "Franz Heinzmann (Frando)" Date: Thu, 29 Jun 2023 11:10:12 +0200 Subject: [PATCH] change(net): cleanups and renames * move dial_peer onto MagicEndpoint * some renames for clarity * remove iroh_net::client module --- iroh-bytes/src/get.rs | 12 +-- iroh-net/examples/magic.rs | 3 +- iroh-net/src/client.rs | 58 ------------- iroh-net/src/hp/magicsock/conn.rs | 2 +- iroh-net/src/lib.rs | 5 +- .../src/{endpoint.rs => magic_endpoint.rs} | 82 ++++++++++++------- iroh/src/commands.rs | 21 ++++- iroh/src/commands/doctor.rs | 2 +- iroh/src/node.rs | 2 +- iroh/tests/provide.rs | 6 +- 10 files changed, 88 insertions(+), 105 deletions(-) delete mode 100644 iroh-net/src/client.rs rename iroh-net/src/{endpoint.rs => magic_endpoint.rs} (88%) diff --git a/iroh-bytes/src/get.rs b/iroh-bytes/src/get.rs index 7e7099299b4..afd8f37a632 100644 --- a/iroh-bytes/src/get.rs +++ b/iroh-bytes/src/get.rs @@ -69,12 +69,12 @@ pub async fn run_ticket( keylog: bool, derp_map: Option, ) -> Result { - let connection = iroh_net::client::dial_peer( - ticket.addrs(), + let connection = iroh_net::MagicEndpoint::dial_peer( ticket.peer(), &crate::P2P_ALPN, - keylog, + ticket.addrs(), derp_map, + keylog, ) .await?; @@ -624,12 +624,12 @@ pub async fn run( request: AnyGetRequest, opts: Options, ) -> anyhow::Result { - let connection = iroh_net::client::dial_peer( - &opts.addrs, + let connection = iroh_net::MagicEndpoint::dial_peer( opts.peer_id, &crate::P2P_ALPN, - opts.keylog, + &opts.addrs, opts.derp_map, + opts.keylog, ) .await?; Ok(run_connection(connection, request)) diff --git a/iroh-net/examples/magic.rs b/iroh-net/examples/magic.rs index ed6a32d2742..ebd81279658 100644 --- a/iroh-net/examples/magic.rs +++ b/iroh-net/examples/magic.rs @@ -4,9 +4,10 @@ use clap::Parser; use ed25519_dalek::SigningKey as SecretKey; use iroh_net::{ defaults::default_derp_map, - endpoint::{accept_conn, MagicEndpoint}, hp::derp::{DerpMap, UseIpv4, UseIpv6}, + magic_endpoint::accept_conn, tls::{Keypair, PeerId}, + MagicEndpoint, }; use tracing::{debug, info}; use url::Url; diff --git a/iroh-net/src/client.rs b/iroh-net/src/client.rs deleted file mode 100644 index 11beeaa841b..00000000000 --- a/iroh-net/src/client.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::{ - net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, - sync::Arc, - time::Duration, -}; - -use anyhow::{Context, Result}; - -use crate::{ - endpoint::MagicEndpoint, - hp::derp::DerpMap, - tls::{self, Keypair, PeerId}, -}; - -/// Connect to a remote endpoint, creating an endpoint on the fly. -/// -/// The PeerId and the ALPN protocol are required. If you happen to know dialable addresses of -/// the remote endpoint, they can be specified and will be added to the endpoint's peer map. -/// If no addresses are specified, the endpoint will try to dial the peer through the -/// configured DERP servers. -pub async fn dial_peer( - known_addrs: &[SocketAddr], - peer_id: PeerId, - alpn_protocol: &[u8], - keylog: bool, - derp_map: Option, -) -> Result { - let bind_addr = if known_addrs.iter().any(|addr| addr.ip().is_ipv6()) { - SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).into() - } else { - SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into() - }; - let endpoint = - MagicEndpoint::bind(Keypair::generate(), bind_addr, None, derp_map, None, keylog).await?; - endpoint - .connect(peer_id, alpn_protocol, known_addrs) - .await - .context("failed to connect to provider") -} - -pub fn create_quinn_client( - bind_addr: SocketAddr, - peer_id: Option, - alpn_protocols: Vec>, - keylog: bool, -) -> Result { - let keypair = Keypair::generate(); - - let tls_client_config = tls::make_client_config(&keypair, peer_id, alpn_protocols, keylog)?; - let mut client_config = quinn::ClientConfig::new(Arc::new(tls_client_config)); - let mut endpoint = quinn::Endpoint::client(bind_addr)?; - let mut transport_config = quinn::TransportConfig::default(); - transport_config.keep_alive_interval(Some(Duration::from_secs(1))); - client_config.transport_config(Arc::new(transport_config)); - - endpoint.set_default_client_config(client_config); - Ok(endpoint) -} diff --git a/iroh-net/src/hp/magicsock/conn.rs b/iroh-net/src/hp/magicsock/conn.rs index 9c0446b267c..3001529260d 100644 --- a/iroh-net/src/hp/magicsock/conn.rs +++ b/iroh-net/src/hp/magicsock/conn.rs @@ -2503,7 +2503,7 @@ pub(crate) mod tests { use super::*; use crate::{ - endpoint::MagicEndpoint, + MagicEndpoint, hp::{ derp::{DerpNode, DerpRegion, UseIpv4, UseIpv6}, stun, diff --git a/iroh-net/src/lib.rs b/iroh-net/src/lib.rs index 0bc23f00936..80b407a561a 100644 --- a/iroh-net/src/lib.rs +++ b/iroh-net/src/lib.rs @@ -1,9 +1,10 @@ #![recursion_limit = "256"] -pub mod client; pub mod defaults; -pub mod endpoint; +pub mod magic_endpoint; pub mod hp; pub mod net; pub mod tls; pub mod util; + +pub use magic_endpoint::MagicEndpoint; diff --git a/iroh-net/src/endpoint.rs b/iroh-net/src/magic_endpoint.rs similarity index 88% rename from iroh-net/src/endpoint.rs rename to iroh-net/src/magic_endpoint.rs index f762b55ff00..9f034c87e67 100644 --- a/iroh-net/src/endpoint.rs +++ b/iroh-net/src/magic_endpoint.rs @@ -1,5 +1,5 @@ use std::{ - net::SocketAddr, + net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, sync::{Arc, Mutex}, time::Duration, }; @@ -73,7 +73,7 @@ impl MagicEndpointBuilder { self } - /// Optionally provides a func to be called when endpoints change. + /// Optionally set a callback function to be called when endpoints change. #[allow(clippy::type_complexity)] pub fn on_endpoints( mut self, @@ -83,13 +83,13 @@ impl MagicEndpointBuilder { self } - /// Optionally provides a func to be called when a connection is made to a DERP server. + /// Optionally set a callback funcion to be called when a connection is made to a DERP server. pub fn on_derp_active(mut self, on_derp_active: Box) -> Self { self.callbacks.on_derp_active = Some(on_derp_active); self } - /// A callback that provides a `cfg::NetInfo` when discovered network conditions change. + /// Optionally set a callback function that provides a [cfg::NetInfo] when discovered network conditions change. pub fn on_net_info( mut self, on_net_info: Box, @@ -99,6 +99,11 @@ impl MagicEndpointBuilder { } /// Bind the magic endpoint on the specified socket address. + /// + /// The *bind_addr* is the address that should be bound locally. Even though this is an + /// outgoing connection a socket must be bound and this is explicit. The main choice to + /// make here is the address family: IPv4 or IPv6. Otherwise you normally bind to the + /// `UNSPECIFIED` address on port `0` thus allowing the kernel to do the right thing. pub async fn bind(self, bind_addr: SocketAddr) -> anyhow::Result { let keypair = self.keypair.unwrap_or_else(Keypair::generate); let mut server_config = make_server_config( @@ -149,26 +154,38 @@ impl MagicEndpoint { MagicEndpointBuilder::default() } - /// Create a quinn endpoint backed by a magicsock. - /// - /// The *bind_addr* is the address that should be bound locally. Even though this is an - /// outgoing connection a socket must be bound and this is explicit. The main choice to - /// make here is the address family: IPv4 or IPv6. Otherwise you normally bind to the - /// `UNSPECIFIED` address on port `0` thus allowing the kernel to do the right thing. - /// - /// If *peer_id* is present it will verify during the TLS connection setup that the remote - /// connected to has the required [`PeerId`], otherwise this will connect to any peer. + /// Connect to a remote endpoint, creating an endpoint on the fly. /// - /// The *alpn_protocols* are the list of Application-Layer Protocol Neotiation identifiers - /// you are happy to accept. - /// - /// If *keylog* is `true` and the KEYLOGFILE environment variable is present it will be - /// considered a filename to which the TLS pre-master keys are logged. This can be useful - /// to be able to decrypt captured traffic for debugging purposes. + /// The PeerId and the ALPN protocol are required. If you happen to know dialable addresses of + /// the remote endpoint, they can be specified and will be added to the endpoint's peer map. + /// If no addresses are specified, the endpoint will try to dial the peer through the + /// configured DERP servers. + pub async fn dial_peer( + peer_id: PeerId, + alpn_protocol: &[u8], + known_addrs: &[SocketAddr], + derp_map: Option, + keylog: bool, + ) -> anyhow::Result { + let bind_addr = if known_addrs.iter().any(|addr| addr.ip().is_ipv6()) { + SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).into() + } else { + SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into() + }; + let endpoint = + MagicEndpoint::bind(Keypair::generate(), bind_addr, None, derp_map, None, keylog) + .await?; + endpoint + .connect(peer_id, alpn_protocol, known_addrs) + .await + .context("failed to connect to provider") + } + + /// Create a quinn endpoint backed by a magicsock. /// - /// Finally the *derp_map* specifies the DERP servers that can be used to establish this - /// connection. - pub(crate) async fn bind( + /// This is for internal use, the public interface is the [MagicEndpointBuilder] obtained from + /// [Self::builder]. See the methods on the builder for documentation of the parameters. + async fn bind( keypair: Keypair, bind_addr: SocketAddr, server_config: Option, @@ -217,6 +234,11 @@ impl MagicEndpoint { self.keypair.public().into() } + /// Get the keypair of this endpoint. + pub fn keypair(&self) -> &Keypair { + &self.keypair + } + /// Get the local addresses on which the underlying magic socket is bound. /// /// Returns a tuple of the IPv4 and the optional IPv6 address. @@ -244,7 +266,9 @@ impl MagicEndpoint { alpn: &[u8], known_addrs: &[SocketAddr], ) -> anyhow::Result { - self.add_known_addrs(peer_id, known_addrs).await?; + if !known_addrs.is_empty() { + self.add_known_addrs(peer_id, known_addrs).await?; + } let node_key: hp::key::node::PublicKey = peer_id.into(); let addr = self @@ -268,13 +292,13 @@ impl MagicEndpoint { "connecting to {}: (via {} - {:?})", peer_id, addr, known_addrs ); + + // TODO: We'd eventually want to replace "localhost" with something that makes more sense. let connect = self .endpoint .connect_with(client_config, addr, "localhost")?; - let connection = connect.await.context("failed connecting to provider")?; - - Ok(connection) + connect.await.context("failed connecting to provider") } /// Inform the magic socket about addresses of the peer. @@ -392,10 +416,8 @@ mod test { use futures::future::BoxFuture; - use crate::{ - endpoint::{accept_conn, MagicEndpoint}, - hp::magicsock::conn_tests::{run_derp_and_stun, setup_logging}, - }; + use super::{accept_conn, MagicEndpoint}; + use crate::hp::magicsock::conn_tests::{run_derp_and_stun, setup_logging}; const TEST_ALPN: &[u8] = b"n0/iroh/test"; diff --git a/iroh/src/commands.rs b/iroh/src/commands.rs index 4fd2592c4d5..3da3a0107d9 100644 --- a/iroh/src/commands.rs +++ b/iroh/src/commands.rs @@ -1,11 +1,12 @@ use std::net::{Ipv4Addr, SocketAddrV4}; +use std::sync::Arc; use std::time::Duration; use std::{net::SocketAddr, path::PathBuf}; use anyhow::{Context, Result}; use clap::{Parser, Subcommand}; use iroh_bytes::{cid::Blake3Cid, protocol::RequestToken, provider::Ticket, runtime}; -use iroh_net::{client::create_quinn_client, tls::PeerId}; +use iroh_net::tls::PeerId; use quic_rpc::transport::quinn::QuinnConnection; use quic_rpc::RpcClient; @@ -235,7 +236,7 @@ async fn make_rpc_client( ) -> anyhow::Result>> { let bind_addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into(); - let endpoint = create_quinn_client(bind_addr, None, vec![RPC_ALPN.to_vec()], false)?; + let endpoint = create_quinn_client(bind_addr, vec![RPC_ALPN.to_vec()], false)?; let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), rpc_port); let server_name = "localhost".to_string(); let connection = QuinnConnection::new(endpoint, addr, server_name); @@ -247,6 +248,22 @@ async fn make_rpc_client( Ok(client) } +pub fn create_quinn_client( + bind_addr: SocketAddr, + alpn_protocols: Vec>, + keylog: bool, +) -> Result { + let keypair = iroh_net::tls::Keypair::generate(); + let tls_client_config = iroh_net::tls::make_client_config(&keypair, None, alpn_protocols, keylog)?; + let mut client_config = quinn::ClientConfig::new(Arc::new(tls_client_config)); + let mut endpoint = quinn::Endpoint::client(bind_addr)?; + let mut transport_config = quinn::TransportConfig::default(); + transport_config.keep_alive_interval(Some(Duration::from_secs(1))); + client_config.transport_config(Arc::new(transport_config)); + endpoint.set_default_client_config(client_config); + Ok(endpoint) +} + #[cfg(feature = "metrics")] pub fn init_metrics_collection( metrics_addr: Option, diff --git a/iroh/src/commands/doctor.rs b/iroh/src/commands/doctor.rs index d9adb7cb58a..71211fa1808 100644 --- a/iroh/src/commands/doctor.rs +++ b/iroh/src/commands/doctor.rs @@ -12,7 +12,7 @@ use clap::Subcommand; use indicatif::{HumanBytes, MultiProgress, ProgressBar}; use iroh_bytes::tokio_util::ProgressWriter; use iroh_net::{ - endpoint::MagicEndpoint, + MagicEndpoint, hp::{ self, derp::{DerpMap, UseIpv4, UseIpv6}, diff --git a/iroh/src/node.rs b/iroh/src/node.rs index f2cca0931d7..ca1ceb17a45 100644 --- a/iroh/src/node.rs +++ b/iroh/src/node.rs @@ -25,8 +25,8 @@ use iroh_bytes::{ runtime, util::{Hash, Progress}, }; -use iroh_net::endpoint::MagicEndpoint; use iroh_net::{ + MagicEndpoint, hp::{cfg::Endpoint, derp::DerpMap}, tls::{self, Keypair, PeerId}, }; diff --git a/iroh/tests/provide.rs b/iroh/tests/provide.rs index 3a7781b1a17..05d0e63c5a1 100644 --- a/iroh/tests/provide.rs +++ b/iroh/tests/provide.rs @@ -9,7 +9,7 @@ use anyhow::{anyhow, bail, Context, Result}; use bytes::Bytes; use futures::{future::BoxFuture, FutureExt}; use iroh::node::{Event, Node}; -use iroh_net::client::dial_peer; +use iroh_net::MagicEndpoint; use rand::RngCore; use testdir::testdir; use tokio::{fs, io::AsyncWriteExt, sync::broadcast}; @@ -583,7 +583,7 @@ async fn test_run_fsm() { let addrs = node.local_endpoint_addresses().await.unwrap(); let peer_id = node.peer_id(); tokio::time::timeout(Duration::from_secs(10), async move { - let connection = dial_peer(&addrs, peer_id, &iroh_bytes::P2P_ALPN, true, None).await?; + let connection = MagicEndpoint::dial_peer(peer_id, &iroh_bytes::P2P_ALPN, &addrs, None, true).await?; let request = GetRequest::all(hash).into(); let stream = get::run_connection(connection, request); let (collection, children, _) = aggregate_get_response(stream).await?; @@ -788,7 +788,7 @@ async fn test_token_passthrough() -> Result<()> { let addrs = provider.local_endpoint_addresses().await?; let peer_id = provider.peer_id(); tokio::time::timeout(Duration::from_secs(10), async move { - dial_peer(&addrs, peer_id, &iroh_bytes::P2P_ALPN, true, None).await?; + MagicEndpoint::dial_peer(peer_id, &iroh_bytes::P2P_ALPN, &addrs, None, true).await?; let request = GetRequest::all(hash).with_token(token).into(); let response = get::run( request,