diff --git a/iroh/examples/dht_discovery.rs b/iroh/examples/dht_discovery.rs index c514474d76..00df0d27dc 100644 --- a/iroh/examples/dht_discovery.rs +++ b/iroh/examples/dht_discovery.rs @@ -88,7 +88,7 @@ async fn chat_server(args: Args) -> anyhow::Result<()> { }; tokio::spawn(async move { let connection = connecting.await?; - let remote_node_id = connection.remote_node_id()?; + let remote_node_id = connection.remote_node_id(); println!("got connection from {}", remote_node_id); // just leave the tasks hanging. this is just an example. let (mut writer, mut reader) = connection.accept_bi().await?; diff --git a/iroh/examples/echo.rs b/iroh/examples/echo.rs index 89bd643a34..e26ce3b183 100644 --- a/iroh/examples/echo.rs +++ b/iroh/examples/echo.rs @@ -77,7 +77,7 @@ impl ProtocolHandler for Echo { // Wait for the connection to be fully established. let connection = connecting.await?; // We can get the remote's node id from the connection. - let node_id = connection.remote_node_id()?; + let node_id = connection.remote_node_id(); println!("accepted connection from {node_id}"); // Our protocol is a simple request-response protocol, so we expect the diff --git a/iroh/examples/listen-unreliable.rs b/iroh/examples/listen-unreliable.rs index 5028ca520a..1123daa43f 100644 --- a/iroh/examples/listen-unreliable.rs +++ b/iroh/examples/listen-unreliable.rs @@ -58,7 +58,7 @@ async fn main() -> anyhow::Result<()> { // accept incoming connections, returns a normal QUIC connection while let Some(incoming) = endpoint.accept().await { - let mut connecting = match incoming.accept() { + let connecting = match incoming.accept() { Ok(connecting) => connecting, Err(err) => { warn!("incoming connection failed: {err:#}"); @@ -67,9 +67,9 @@ async fn main() -> anyhow::Result<()> { continue; } }; - let alpn = connecting.alpn().await?; let conn = connecting.await?; - let node_id = conn.remote_node_id()?; + let alpn = conn.alpn(); + let node_id = conn.remote_node_id(); info!( "new (unreliable) connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(&alpn), diff --git a/iroh/examples/listen.rs b/iroh/examples/listen.rs index fb93e5342d..90f00be056 100644 --- a/iroh/examples/listen.rs +++ b/iroh/examples/listen.rs @@ -59,7 +59,7 @@ async fn main() -> anyhow::Result<()> { ); // accept incoming connections, returns a normal QUIC connection while let Some(incoming) = endpoint.accept().await { - let mut connecting = match incoming.accept() { + let connecting = match incoming.accept() { Ok(connecting) => connecting, Err(err) => { warn!("incoming connection failed: {err:#}"); @@ -68,9 +68,9 @@ async fn main() -> anyhow::Result<()> { continue; } }; - let alpn = connecting.alpn().await?; let conn = connecting.await?; - let node_id = conn.remote_node_id()?; + let alpn = conn.alpn(); + let node_id = conn.remote_node_id(); info!( "new connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(&alpn), diff --git a/iroh/examples/search.rs b/iroh/examples/search.rs index d60b629038..0d032465a2 100644 --- a/iroh/examples/search.rs +++ b/iroh/examples/search.rs @@ -134,7 +134,7 @@ impl ProtocolHandler for BlobSearch { // Wait for the connection to be fully established. let connection = connecting.await?; // We can get the remote's node id from the connection. - let node_id = connection.remote_node_id()?; + let node_id = connection.remote_node_id(); println!("accepted connection from {node_id}"); // Our protocol is a simple request-response protocol, so we expect the diff --git a/iroh/examples/transfer.rs b/iroh/examples/transfer.rs index 4c037ff30f..cdfccc48ff 100644 --- a/iroh/examples/transfer.rs +++ b/iroh/examples/transfer.rs @@ -179,7 +179,7 @@ async fn provide( } }; let conn = connecting.await?; - let node_id = conn.remote_node_id()?; + let node_id = conn.remote_node_id(); info!( "new connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(TRANSFER_ALPN), diff --git a/iroh/src/endpoint.rs b/iroh/src/endpoint.rs index 54605d174f..fa7b708272 100644 --- a/iroh/src/endpoint.rs +++ b/iroh/src/endpoint.rs @@ -12,7 +12,6 @@ //! [module docs]: crate use std::{ - any::Any, collections::BTreeSet, future::{Future, IntoFuture}, net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6}, @@ -1277,11 +1276,6 @@ impl Connecting { } } - /// Parameters negotiated during the handshake - pub async fn handshake_data(&mut self) -> Result, ConnectionError> { - self.inner.handshake_data().await - } - /// The local IP address which was used when the peer established the connection. pub fn local_ip(&self) -> Option { self.inner.local_ip() @@ -1295,15 +1289,12 @@ impl Connecting { /// Extracts the ALPN protocol from the peer's handshake data. // Note, we could totally provide this method to be on a Connection as well. But we'd // need to wrap Connection too. - pub async fn alpn(&mut self) -> Result> { - let data = self.handshake_data().await?; - match data.downcast::() { - Ok(data) => match data.protocol { - Some(protocol) => Ok(protocol), - None => bail!("no ALPN protocol available"), - }, - Err(_) => bail!("unknown handshake type"), - } + pub async fn alpn(&mut self) -> Result, ConnectionError> { + let data = self.inner.handshake_data().await?; + let data = data + .downcast::() + .expect("crypto setup for iroh"); + Ok(data.protocol.expect("ALPN required by iroh crypto setup")) } } @@ -1539,38 +1530,13 @@ impl Connection { self.inner.congestion_state() } - /// Parameters negotiated during the handshake. - /// - /// Guaranteed to return `Some` on fully established connections or after - /// [`Connecting::handshake_data()`] succeeds. See that method's documentations for - /// details on the returned value. - /// - /// [`Connection::handshake_data()`]: crate::Connecting::handshake_data - #[inline] - pub fn handshake_data(&self) -> Option> { - self.inner.handshake_data() - } - /// Extracts the ALPN protocol from the peer's handshake data. - pub fn alpn(&self) -> Option> { - let data = self.handshake_data()?; - match data.downcast::() { - Ok(data) => data.protocol, - Err(_) => None, - } - } - - /// Cryptographic identity of the peer. - /// - /// The dynamic type returned is determined by the configured [`Session`]. For the - /// default `rustls` session, the return value can be [`downcast`] to a - /// Vec<[rustls::pki_types::CertificateDer]> - /// - /// [`Session`]: quinn_proto::crypto::Session - /// [`downcast`]: Box::downcast - #[inline] - pub fn peer_identity(&self) -> Option> { - self.inner.peer_identity() + pub fn alpn(&self) -> Vec { + let data = self.inner.handshake_data().expect("iroh crypto setup"); + let data = data + .downcast::() + .expect("iroh crypto setup"); + data.protocol.expect("ALPN required by iroh crypto setup") } /// Returns the [`NodeId`] from the peer's TLS certificate. @@ -1581,25 +1547,17 @@ impl Connection { /// connection. /// /// [`PublicKey`]: iroh_base::PublicKey - // TODO: Would be nice if this could be infallible. - pub fn remote_node_id(&self) -> Result { - let data = self.peer_identity(); - match data { - None => bail!("no peer certificate found"), - Some(data) => match data.downcast::>() { - Ok(certs) => { - if certs.len() != 1 { - bail!( - "expected a single peer certificate, but {} found", - certs.len() - ); - } - let cert = tls::certificate::parse(&certs[0])?; - Ok(cert.peer_id()) - } - Err(_) => bail!("invalid peer certificate"), - }, - } + pub fn remote_node_id(&self) -> NodeId { + let data = self + .inner + .peer_identity() + .expect("required by iroh crypto setup"); + let certs = data + .downcast::>() + .expect("iroh crypto setup"); + debug_assert_eq!(certs.len(), 1); + let cert = tls::certificate::parse(&certs[0]).expect("TODO: is this guaranteed by now?"); + cert.peer_id() } /// A stable identifier for this connection. @@ -1660,10 +1618,7 @@ impl Connection { /// function. fn try_send_rtt_msg(conn: &Connection, magic_ep: &Endpoint) { // If we can't notify the rtt-actor that's not great but not critical. - let Ok(node_id) = conn.remote_node_id() else { - warn!(?conn, "failed to get remote node id"); - return; - }; + let node_id = conn.remote_node_id(); let Ok(conn_type_changes) = magic_ep.conn_type(node_id) else { warn!(?conn, "failed to create conn_type stream"); return; @@ -1989,7 +1944,7 @@ mod tests { info!("[server] round {i}"); let incoming = ep.accept().await.unwrap(); let conn = incoming.await.unwrap(); - let node_id = conn.remote_node_id().unwrap(); + let node_id = conn.remote_node_id(); info!(%i, peer = %node_id.fmt_short(), "accepted connection"); let (mut send, mut recv) = conn.accept_bi().await.unwrap(); let mut buf = vec![0u8; chunk_size]; @@ -2105,7 +2060,7 @@ mod tests { let mut iconn = incoming.accept().unwrap(); let alpn = iconn.alpn().await.unwrap(); let conn = iconn.await.unwrap(); - let node_id = conn.remote_node_id().unwrap(); + let node_id = conn.remote_node_id(); assert_eq!(node_id, src); assert_eq!(alpn, TEST_ALPN); let (mut send, mut recv) = conn.accept_bi().await.unwrap(); @@ -2195,7 +2150,7 @@ mod tests { async fn accept(ep: &Endpoint) -> NodeId { let incoming = ep.accept().await.unwrap(); let conn = incoming.await.unwrap(); - let node_id = conn.remote_node_id().unwrap(); + let node_id = conn.remote_node_id(); tracing::info!(node_id=%node_id.fmt_short(), "accepted connection"); node_id }