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
impl Endpoint
Sourcepub fn builder() -> Builder
pub fn builder() -> Builder
Returns the builder for an Endpoint, with a production configuration.
This uses the presets::N0 as the configuration.
Sourcepub fn empty_builder(relay_mode: RelayMode) -> Builder
pub fn empty_builder(relay_mode: RelayMode) -> Builder
Returns the builder for an Endpoint, with an empty configuration.
See Builder::empty for details.
Sourcepub async fn bind() -> Result<Self, BindError>
pub async fn bind() -> Result<Self, BindError>
Constructs a default Endpoint and binds it immediately.
Uses the presets::N0 as configuration.
Sourcepub fn set_alpns(&self, alpns: Vec<Vec<u8>>)
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.
Sourcepub async fn insert_relay(
&self,
relay: RelayUrl,
config: Arc<RelayConfig>,
) -> Option<Arc<RelayConfig>>
pub async fn insert_relay( &self, relay: RelayUrl, config: Arc<RelayConfig>, ) -> Option<Arc<RelayConfig>>
Sourcepub async fn remove_relay(&self, relay: &RelayUrl) -> Option<Arc<RelayConfig>>
pub async fn remove_relay(&self, relay: &RelayUrl) -> Option<Arc<RelayConfig>>
Sourcepub async fn connect(
&self,
endpoint_addr: impl Into<EndpointAddr>,
alpn: &[u8],
) -> Result<Connection, ConnectError>
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.
Sourcepub async fn connect_with_opts(
&self,
endpoint_addr: impl Into<EndpointAddr>,
alpn: &[u8],
options: ConnectOptions,
) -> Result<Connecting, ConnectWithOptsError>
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:
- The returned future resolves to a
Connecting, which can be further processed into aConnectionby awaiting, or alternatively allows connecting with 0-RTT viaConnecting::into_0rtt. Note: Please read the documentation forinto_0rttcarefully to assess security concerns. - The
TransportConfigfor the connection can be modified via the providedConnectOptions. 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.
Sourcepub fn accept(&self) -> Accept<'_> ⓘ
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.
Sourcepub fn secret_key(&self) -> &SecretKey
pub fn secret_key(&self) -> &SecretKey
Returns the secret_key of this endpoint.
Sourcepub fn id(&self) -> EndpointId
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.
Sourcepub fn addr(&self) -> EndpointAddr
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.
Sourcepub fn watch_addr(&self) -> impl Watcher<Value = EndpointAddr> + use<>
Available on non-wasm_browser only.
pub fn watch_addr(&self) -> impl Watcher<Value = EndpointAddr> + use<>
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
Sourcepub async fn online(&self)
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.
Sourcepub fn bound_sockets(&self) -> Vec<SocketAddr>
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.
Sourcepub async fn latency(&self, endpoint_id: EndpointId) -> Option<Duration>
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.
Sourcepub fn dns_resolver(&self) -> &DnsResolver
Available on non-wasm_browser only.
pub fn dns_resolver(&self) -> &DnsResolver
wasm_browser only.Returns the DNS resolver used in this Endpoint.
Sourcepub fn discovery(&self) -> &ConcurrentDiscovery
pub fn discovery(&self) -> &ConcurrentDiscovery
Returns the discovery mechanism, if configured.
See Builder::discovery.
Sourcepub fn metrics(&self) -> &EndpointMetrics
Available on crate feature metrics only.
pub fn metrics(&self) -> &EndpointMetrics
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"#));Sourcepub async fn network_change(&self)
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.
Sourcepub fn set_user_data_for_discovery(&self, user_data: Option<UserData>)
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.
Sourcepub async fn close(&self)
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.