iroh 0.98.0

p2p quic connections dialed by public key
Documentation
//! Peer-to-peer QUIC connections.
//!
//! iroh is a library to establish direct connectivity between peers.  It exposes an
//! interface to [QUIC] connections and streams to the user, while implementing direct
//! connectivity using [hole punching] complemented by relay servers under the hood.
//!
//! An iroh endpoint is created and controlled by the [`Endpoint`], e.g. connecting to
//! another endpoint:
//!
//! ```no_run
//! # #[cfg(with_crypto_provider)]
//! # {
//! # use iroh::{Endpoint, EndpointAddr, endpoint::presets};
//! # use n0_error::{StackResultExt, StdResultExt};
//! # async fn wrapper() -> n0_error::Result<()> {
//! let addr: EndpointAddr = todo!();
//! let ep = Endpoint::bind(presets::N0).await?;
//! let conn = ep.connect(addr, b"my-alpn").await?;
//! let mut send_stream = conn.open_uni().await.std_context("unable to open uni")?;
//! send_stream
//!     .write_all(b"msg")
//!     .await
//!     .std_context("unable to write all")?;
//! # Ok(())
//! # }
//! # }
//! ```
//!
//! The other endpoint can accept incoming connections using the [`Endpoint`] as well:
//!
//! ```no_run
//! # #[cfg(with_crypto_provider)]
//! # {
//! # use iroh::{Endpoint, EndpointAddr, endpoint::presets};
//! # use n0_error::{StackResultExt, StdResultExt};
//! # async fn wrapper() -> n0_error::Result<()> {
//! let ep = Endpoint::builder(presets::N0)
//!     .alpns(vec![b"my-alpn".to_vec()])
//!     .bind()
//!     .await?;
//! let conn = ep
//!     .accept()
//!     .await
//!     .context("accept error")?
//!     .await
//!     .std_context("connecting error")?;
//! let mut recv_stream = conn.accept_uni().await.std_context("unable to open uni")?;
//! let mut buf = [0u8; 3];
//! recv_stream
//!     .read_exact(&mut buf)
//!     .await
//!     .std_context("unable to read")?;
//! # Ok(())
//! # }
//! # }
//! ```
//!
//! Of course you can also use [bi-directional streams] or any other features from QUIC.
//!
//! For more elaborate examples, see [below](#examples) or the examples directory in
//! the source repository.
//!
//!
//! # Connection Establishment
//!
//! An iroh connection between two iroh endpoints is usually established with the help
//! of a Relay server.  When creating the [`Endpoint`] it connects to the closest Relay
//! server and designates this as the *home relay*.  When other endpoints want to connect they
//! first establish connection via this home relay.  As soon as connection between the two
//! endpoints is established they will attempt to create a direct connection, using [hole
//! punching] if needed.  Once the direct connection is established the relay server is no
//! longer involved in the connection.
//!
//! If one of the iroh endpoints can be reached directly, connectivity can also be
//! established without involving a Relay server.  This is done by using the endpoint's
//! listening addresses in the connection establishement instead of the [`RelayUrl`] which
//! is used to identify a Relay server.  Of course it is also possible to use both a
//! [`RelayUrl`] and direct addresses at the same time to connect.
//!
//!
//! # Encryption
//!
//! The connection is encrypted using TLS, like standard QUIC connections.  Unlike standard
//! QUIC there is no client, server or server TLS key and certificate chain.  Instead each iroh endpoint has a
//! unique [`SecretKey`] used to authenticate and encrypt the connection.  When an iroh
//! endpoint connects, it uses the corresponding [`PublicKey`] to ensure the connection is only
//! established with the intended peer.
//!
//! Since the [`PublicKey`] is also used to identify the iroh endpoint it is also known as
//! the [`EndpointId`].  As encryption is an integral part of TLS as used in QUIC this
//! [`EndpointId`] is always a required parameter to establish a connection.
//!
//! When accepting connections the peer's [`EndpointId`] is authenticated.  However it is up to
//! the application to decide if a particular peer is allowed to connect or not.
//!
//!
//! # Relay Servers
//!
//! Relay servers exist to ensure all iroh endpoints are always reachable.  They accept
//! **encrypted** traffic for iroh endpoints which are connected to them, forwarding it to
//! the correct destination based on the [`EndpointId`] only.  Since endpoints only send encrypted
//! traffic, the Relay servers can not decode any traffic for other iroh endpoints and only
//! forward it.
//!
//! The connections to the Relay server are initiated as normal HTTP 1.1 connections using
//! TLS.  Once connected the transport is upgraded to a plain TCP connection using a custom
//! protocol.  All further data is then sent using this custom relaying protocol.  Usually
//! soon after the connection is established via the Relay it will migrate to a direct
//! connection.  However if this is not possible the connection will keep flowing over the
//! relay server as a fallback.
//!
//! Additionally to providing reliable connectivity between iroh endpoints, Relay servers
//! provide some functions to assist in [hole punching].  They have various services to help
//! endpoints understand their own network situation.  This includes offering a [QAD] server,
//! but also a few HTTP extra endpoints as well as responding to ICMP echo requests.
//!
//! By default the [number 0] relay servers are used, see [`RelayMode::Default`].
//!
//!
//! # Connections and Streams
//!
//! An iroh endpoint is managed using the [`Endpoint`] and this is used to create or accept
//! connections to other endpoints.  To establish a connection to an iroh endpoint you need to
//! know three pieces of information:
//!
//! - The [`EndpointId`] of the peer to connect to.
//! - Some addressing information:
//!   - Usually the [`RelayUrl`] identifying the Relay server.
//!   - Sometimes, or usually additionally, any direct addresses which might be known.
//! - The QUIC/TLS Application-Layer Protocol Negotiation, or [ALPN], name to use.
//!
//! The ALPN is used by both sides to agree on which application-specific protocol will be
//! used over the resulting QUIC connection.  These can be protocols like `h3` used for
//! [HTTP/3][HTTP3], but more commonly will be a custom identifier for the application.
//!
//! Once connected the API exposes QUIC streams.  These are very cheap to create so can be
//! created at any time and can be used to create very many short-lived stream as well as
//! long-lived streams.  There are two stream types to choose from:
//!
//! - **Uni-directional** which only allows the peer which initiated the stream to send
//!   data.
//!
//! - **Bi-directional** which allows both peers to send and receive data.  However, the
//!   initiator of this stream has to send data before the peer will be aware of this
//!   stream.
//!
//! Additionally to being extremely light-weight, streams can be interleaved and will not
//! block each other.  Allowing many streams to co-exist, regardless of how long they last.
//!
//! <div class="warning">
//!
//! To keep streams cheap, they are lazily created on the network: only once a sender starts
//! sending data on the stream will the receiver become aware of a stream.  This means only
//! calling [`Connection::open_bi`] is not sufficient for the corresponding call to
//! [`Connection::accept_bi`] to return.  The sender **must** send data on the stream before
//! the receiver's [`Connection::accept_bi`] call will return.
//!
//! </div>
//!
//! ## Address Lookup
//!
//! The need to know the [`RelayUrl`] *or* some direct addresses in addition to the
//! [`EndpointId`] to connect to an iroh endpoint can be an obstacle.  To address this, the
//! [`endpoint::Builder`] allows you to configure an [`address_lookup`] service.
//!
//! The [`address_lookup::DnsAddressLookup`] service is an address lookup service which will publish the [`RelayUrl`]
//! and direct addresses to a service publishing those as DNS records.  To connect it looks
//! up the [`EndpointId`] in the DNS system to find the addressing details.  This enables
//! connecting using only the [`EndpointId`] which is often more convenient and resilient.
//!
//! See [the Address Lookup module] for more details.
//!
//!
//! # Examples
//!
//! The central struct is the [`Endpoint`], which allows you to connect to other endpoints:
//!
//! ```no_run
//! # #[cfg(with_crypto_provider)]
//! # {
//! use iroh::{Endpoint, EndpointAddr, endpoint::presets};
//! use n0_error::{Result, StackResultExt, StdResultExt};
//!
//! async fn connect(addr: EndpointAddr) -> Result<()> {
//!     // The Endpoint is the central object that manages an iroh node.
//!     let ep = Endpoint::bind(presets::N0).await?;
//!
//!     // Establish a QUIC connection, open a bi-directional stream, exchange messages.
//!     let conn = ep.connect(addr, b"hello-world").await?;
//!     let (mut send_stream, mut recv_stream) = conn.open_bi().await.std_context("open bi")?;
//!     send_stream.write_all(b"hello").await.std_context("write")?;
//!     send_stream.finish().std_context("finish")?;
//!     let _msg = recv_stream.read_to_end(10).await.std_context("read")?;
//!
//!     // Gracefully close the connection and endpoint.
//!     conn.close(1u8.into(), b"done");
//!     ep.close().await;
//!     println!("Client closed");
//!     Ok(())
//! }
//! # }
//! ```
//!
//! Every [`Endpoint`] can also accept connections:
//!
//! ```no_run
//! # #[cfg(with_crypto_provider)]
//! # {
//! use iroh::{Endpoint, EndpointAddr, endpoint::presets};
//! use n0_error::{Result, StackResultExt, StdResultExt};
//! use n0_future::StreamExt;
//!
//! async fn accept() -> Result<()> {
//!     // To accept connections at least one ALPN must be configured.
//!     let ep = Endpoint::builder(presets::N0)
//!         .alpns(vec![b"hello-world".to_vec()])
//!         .bind()
//!         .await?;
//!
//!     // Accept a QUIC connection, accept a bi-directional stream, exchange messages.
//!     let conn = ep
//!         .accept()
//!         .await
//!         .context("no incoming connection")?
//!         .await
//!         .context("accept conn")?;
//!     let (mut send_stream, mut recv_stream) =
//!         conn.accept_bi().await.std_context("accept stream")?;
//!     let _msg = recv_stream.read_to_end(10).await.std_context("read")?;
//!     send_stream.write_all(b"world").await.std_context("write")?;
//!     send_stream.finish().std_context("finish")?;
//!
//!     // Wait for the client to close the connection and gracefully close the endpoint.
//!     conn.closed().await;
//!     ep.close().await;
//!     Ok(())
//! }
//! # }
//! ```
//!
//! Please see the examples directory for more nuanced examples.
//!
//!
//! [QUIC]: https://quicwg.org
//! [bi-directional streams]: crate::endpoint::Connection::open_bi
//! [hole punching]: https://en.wikipedia.org/wiki/Hole_punching_(networking)
//! [socket addresses]: https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html
//! [QAD]: https://www.ietf.org/archive/id/draft-ietf-quic-address-discovery-00.html
//! [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
//! [HTTP3]: https://en.wikipedia.org/wiki/HTTP/3
//! [`SecretKey`]: crate::SecretKey
//! [`PublicKey`]: crate::PublicKey
//! [`RelayUrl`]: crate::RelayUrl
//! [`address_lookup`]: crate::endpoint::Builder::address_lookup
//! [`address_lookup::DnsAddressLookup`]: crate::address_lookup::DnsAddressLookup
//! [number 0]: https://n0.computer
//! [`RelayMode::Default`]: crate::RelayMode::Default
//! [the Address Lookup module]: crate::address_lookup
//! [`Connection::open_bi`]: crate::endpoint::Connection::open_bi
//! [`Connection::accept_bi`]: crate::endpoint::Connection::accept_bi

#![recursion_limit = "256"]
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
#![cfg_attr(wasm_browser, allow(unused))]
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
#![cfg_attr(iroh_docsrs, feature(doc_cfg))]

mod socket;
pub mod tls;

pub(crate) mod portmapper;
pub(crate) mod runtime;
pub(crate) mod util;

pub mod address_lookup;
pub mod defaults;
pub mod endpoint;
pub mod metrics;
mod net_report;
pub mod protocol;

pub use endpoint::{Endpoint, RelayMode};
pub use iroh_base::{
    EndpointAddr, EndpointId, KeyParsingError, PublicKey, RelayUrl, RelayUrlParseError, SecretKey,
    Signature, SignatureError, TransportAddr,
};
#[cfg(not(wasm_browser))]
pub use iroh_relay::dns;
pub use iroh_relay::{RelayConfig, RelayMap, endpoint_info};
pub use n0_watcher::Watcher;
pub use net_report::{Report as NetReport, TIMEOUT as NET_REPORT_TIMEOUT};

#[cfg(any(test, feature = "test-utils"))]
pub mod test_utils;