Endpoint

Struct Endpoint 

Source
pub struct Endpoint { /* private fields */ }
Expand description

Controls an iroh endpoint, establishing connections with other endpoints.

This is the main API interface to create connections to, and accept connections from other iroh endpoints. The connections are peer-to-peer and encrypted, a Relay server is used to make the connections reliable. See the [crate docs] for a more detailed overview of iroh.

It is recommended to only create a single instance per application. This ensures all the connections made share the same peer-to-peer connections to other iroh endpoints, while still remaining independent connections. This will result in more optimal network behaviour.

The endpoint is created using the Builder, which can be created using Endpoint::builder.

Once an endpoint exists, new connections are typically created using the Endpoint::connect and Endpoint::accept methods. Once established, the Connection gives access to most QUIC features. Individual streams to send data to the peer are created using the Connection::open_bi, Connection::accept_bi, Connection::open_uni and Connection::open_bi functions.

Note that due to the light-weight properties of streams a stream will only be accepted once the initiating peer has sent some data on it.

Implementations§

Source§

impl Endpoint

Source

pub fn builder() -> Builder

Returns the builder for an Endpoint, with a production configuration.

This uses the presets::N0 as the configuration.

Source

pub fn empty_builder(relay_mode: RelayMode) -> Builder

Returns the builder for an Endpoint, with an empty configuration.

See Builder::empty for details.

Source

pub async fn bind() -> Result<Self, BindError>

Constructs a default Endpoint and binds it immediately.

Uses the presets::N0 as configuration.

Source

pub fn set_alpns(&self, alpns: Vec<Vec<u8>>)

Sets the list of accepted ALPN protocols.

This will only affect new incoming connections. Note that this overrides the current list of ALPNs.

Source

pub async fn insert_relay( &self, relay: RelayUrl, config: Arc<RelayConfig>, ) -> Option<Arc<RelayConfig>>

Adds the provided configuration to the RelayMap.

Replacing and returning any existing configuration for RelayUrl.

Source

pub async fn remove_relay(&self, relay: &RelayUrl) -> Option<Arc<RelayConfig>>

Removes the configuration from the RelayMap for the provided RelayUrl.

Returns any existing configuration.

Source

pub async fn connect( &self, endpoint_addr: impl Into<EndpointAddr>, alpn: &[u8], ) -> Result<Connection, ConnectError>

Connects to a remote Endpoint.

A value that can be converted into an EndpointAddr is required. This can be either an EndpointAddr or an EndpointId.

The EndpointAddr must contain the EndpointId to dial and may also contain a RelayUrl and direct addresses. If direct addresses are provided, they will be used to try and establish a direct connection without involving a relay server.

If neither a RelayUrl or direct addresses are configured in the EndpointAddr it may still be possible a connection can be established. This depends on which, if any, crate::discovery::Discovery services were configured using Builder::discovery. The discovery service will also be used if the remote endpoint is not reachable on the provided direct addresses and there is no RelayUrl.

If addresses or relay servers are neither provided nor can be discovered, the connection attempt will fail with an error.

The alpn, or application-level protocol identifier, is also required. The remote endpoint must support this alpn, otherwise the connection attempt will fail with an error.

Source

pub async fn connect_with_opts( &self, endpoint_addr: impl Into<EndpointAddr>, alpn: &[u8], options: ConnectOptions, ) -> Result<Connecting, ConnectWithOptsError>

Starts a connection attempt with a remote Endpoint.

Like Endpoint::connect (see also its docs for general details), but allows for a more advanced connection setup with more customization in two aspects:

  1. The returned future resolves to a Connecting, which can be further processed into a Connection by awaiting, or alternatively allows connecting with 0-RTT via Connecting::into_0rtt. Note: Please read the documentation for into_0rtt carefully to assess security concerns.
  2. The TransportConfig for the connection can be modified via the provided ConnectOptions. Note: Please be aware that changing transport config settings may have adverse effects on establishing and maintaining direct connections. Carefully test settings you use and consider this currently as still rather experimental.
Source

pub fn accept(&self) -> Accept<'_>

Accepts an incoming connection on the endpoint.

Only connections with the ALPNs configured in Builder::alpns will be accepted. If multiple ALPNs have been configured the ALPN can be inspected before accepting the connection using Connecting::alpn.

The returned future will yield None if the endpoint is closed by calling Endpoint::close.

Source

pub fn secret_key(&self) -> &SecretKey

Returns the secret_key of this endpoint.

Source

pub fn id(&self) -> EndpointId

Returns the endpoint id of this endpoint.

This ID is the unique addressing information of this endpoint and other peers must know it to be able to connect to this endpoint.

Source

pub fn addr(&self) -> EndpointAddr

Returns the current EndpointAddr. As long as the endpoint was able to bind to a network interface, some local addresses will be available.

The state of other fields depends on the state of networking and connectivity. Use the Endpoint::online method to ensure that the endpoint is considered “online” (has contacted a relay server) before calling this method, if you want to ensure that the EndpointAddr will contain enough information to allow this endpoint to be dialable by a remote endpoint over the internet.

You can use the Endpoint::watch_addr method to get updates when the EndpointAddr changes.

Source

pub fn watch_addr(&self) -> impl Watcher<Value = EndpointAddr> + use<>

Available on non-wasm_browser only.

Returns a Watcher for the current EndpointAddr for this endpoint.

The observed EndpointAddr will have the current RelayUrl and direct addresses.

use iroh::{Endpoint, Watcher};

let endpoint = Endpoint::builder()
    .alpns(vec![b"my-alpn".to_vec()])
    .bind()
    .await?;
let endpoint_addr = endpoint.watch_addr().get();

The Endpoint::online method can be used as a convenience method to understand if the endpoint has ever been considered “online”. But after that initial call to Endpoint::online, to understand if your endpoint is no longer able to be connected to by endpoints outside of the private or local network, watch for changes in it’s EndpointAddr. If there are no addrsin the EndpointAddr, you may not be dialable by other endpoints on the internet.

The EndpointAddr will change as:

  • network conditions change
  • the endpoint connects to a relay server
  • the endpoint changes its preferred relay server
  • more addresses are discovered for this endpoint
Source

pub async fn online(&self)

A convenience method that waits for the endpoint to be considered “online”.

This currently means at least one relay server was connected, and at least one local IP address is available. Event if no relays are configured, this will still wait for a relay connection.

Once this has been resolved once, this will always immediately resolve.

This has no timeout, so if that is needed, you need to wrap it in a timeout. We recommend using a timeout close to crate::net_report::TIMEOUT, so you can be sure that at least one crate::net_report::Report has been attempted.

To understand if the endpoint has gone back “offline”, you must use the Endpoint::watch_addr method, to get information on the current relay and direct address information.

Source

pub fn bound_sockets(&self) -> Vec<SocketAddr>

Returns the local socket addresses on which the underlying sockets are bound.

The Endpoint always binds on an IPv4 address and also tries to bind on an IPv6 address if available.

Source

pub async fn latency(&self, endpoint_id: EndpointId) -> Option<Duration>

Returns the currently lowest latency for this endpoint.

Will return None if we do not have any address information for the given endpoint_id.

Source

pub fn dns_resolver(&self) -> &DnsResolver

Available on non-wasm_browser only.

Returns the DNS resolver used in this Endpoint.

See Builder::dns_resolver.

Source

pub fn discovery(&self) -> &ConcurrentDiscovery

Returns the discovery mechanism, if configured.

See Builder::discovery.

Source

pub fn metrics(&self) -> &EndpointMetrics

Available on crate feature metrics only.

Returns metrics collected for this endpoint.

The endpoint internally collects various metrics about its operation. The returned EndpointMetrics struct contains all of these metrics.

You can access individual metrics directly by using the public fields:

let endpoint = Endpoint::bind().await?;
assert_eq!(endpoint.metrics().magicsock.recv_datagrams.get(), 0);

EndpointMetrics implements MetricsGroupSet, and each field implements MetricsGroup. These traits provide methods to iterate over the groups in the set, and over the individual metrics in each group, without having to access each field manually. With these methods, it is straightforward to collect all metrics into a map or push their values to a metrics collector.

For example, the following snippet collects all metrics into a map:

let endpoint = Endpoint::bind().await?;
let metrics: BTreeMap<String, MetricValue> = endpoint
    .metrics()
    .iter()
    .map(|(group, metric)| {
        let name = [group, metric.name()].join(":");
        (name, metric.value())
    })
    .collect();

assert_eq!(metrics["magicsock:recv_datagrams"], MetricValue::Counter(0));

The metrics can also be encoded into the OpenMetrics text format, as used by Prometheus. To do so, use the [iroh_metrics::Registry], add the endpoint metrics to the registry with Registry::register_all, and encode the metrics to a string with encode_openmetrics_to_string:

let endpoint = Endpoint::bind().await?;
let mut registry = Registry::default();
registry.register_all(endpoint.metrics());
let s = registry.encode_openmetrics_to_string()?;
assert!(s.contains(r#"TYPE magicsock_recv_datagrams counter"#));
assert!(s.contains(r#"magicsock_recv_datagrams_total 0"#));

Through a registry, you can also add labels or prefixes to metrics with Registry::sub_registry_with_label or Registry::sub_registry_with_prefix. Furthermore, [iroh_metrics::service] provides functions to easily start services to serve the metrics with a HTTP server, dump them to a file, or push them to a Prometheus gateway.

For example, the following snippet launches an HTTP server that serves the metrics in the OpenMetrics text format:

// Create a registry, wrapped in a read-write lock so that we can register and serve
// the metrics independently.
let registry = Arc::new(RwLock::new(Registry::default()));
// Spawn a task to serve the metrics on an OpenMetrics HTTP endpoint.
let metrics_task = tokio::task::spawn({
    let registry = registry.clone();
    async move {
        let addr = "0.0.0.0:9100".parse().unwrap();
        iroh_metrics::service::start_metrics_server(addr, registry).await
    }
});

// Spawn an endpoint and add the metrics to the registry.
let endpoint = Endpoint::bind().await?;
registry.write().unwrap().register_all(endpoint.metrics());

// Wait for the metrics server to bind, then fetch the metrics via HTTP.
tokio::time::sleep(Duration::from_millis(500));
let res = reqwest::get("http://localhost:9100/metrics")
    .await
    .std_context("get")?
    .text()
    .await
    .std_context("text")?;

assert!(res.contains(r#"TYPE magicsock_recv_datagrams counter"#));
assert!(res.contains(r#"magicsock_recv_datagrams_total 0"#));
Source

pub async fn network_change(&self)

Notifies the system of potential network changes.

On many systems iroh is able to detect network changes by itself, however some systems like android do not expose this functionality to native code. Android does however provide this functionality to Java code. This function allows for notifying iroh of any potential network changes like this.

Even when the network did not change, or iroh was already able to detect the network change itself, there is no harm in calling this function.

Source

pub fn set_user_data_for_discovery(&self, user_data: Option<UserData>)

Sets the initial user-defined data to be published in discovery services for this endpoint.

If the user-defined data passed to this function is different to the previous one, the endpoint will republish its endpoint info to the configured discovery services.

See also Builder::user_data_for_discovery for setting an initial value when building the endpoint.

Source

pub async fn close(&self)

Closes the QUIC endpoint and the magic socket.

This will close any remaining open Connections with an error code of 0 and an empty reason. Though it is best practice to close those explicitly before with a custom error code and reason.

It will then make a best effort to wait for all close notifications to be acknowledged by the peers, re-transmitting them if needed. This ensures the peers are aware of the closed connections instead of having to wait for a timeout on the connection. Once all connections are closed or timed out, the future finishes.

The maximum time-out that this future will wait for depends on QUIC transport configurations of non-drained connections at the time of calling, and their current estimates of round trip time. With default parameters and a conservative estimate of round trip time, this call’s future should take 3 seconds to resolve in cases of bad connectivity or failed connections. In the usual case, this call’s future should return much more quickly.

It is highly recommended you do wait for this close call to finish, if possible. Not doing so will make connections that were still open while closing the endpoint time out on the remote end. Thus remote ends will assume connections to have failed even if all application data was transmitted successfully.

Note: Someone used to closing TCP sockets might wonder why it is necessary to wait for timeouts when closing QUIC endpoints, while they don’t have to do this for TCP sockets. This is due to QUIC and its acknowledgments being implemented in user-land, while TCP sockets usually get closed and drained by the operating system in the kernel during the “Time-Wait” period of the TCP socket.

Be aware however that the underlying UDP sockets are only closed once all clones of the the respective Endpoint are dropped.

Source

pub fn is_closed(&self) -> bool

Check if this endpoint is still alive, or already closed.

Trait Implementations§

Source§

impl Clone for Endpoint

Source§

fn clone(&self) -> Endpoint

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Endpoint

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> CompatExt for T

§

fn compat(self) -> Compat<T>

Applies the [Compat] adapter by value. Read more
§

fn compat_ref(&self) -> Compat<&T>

Applies the [Compat] adapter by shared reference. Read more
§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the [Compat] adapter by mutable reference. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more