pub struct Endpoint { /* private fields */ }
Expand description
Controls an iroh node, establishing connections with other nodes.
This is the main API interface to create connections to, and accept connections from other iroh nodes. 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 nodes, 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.
Sourcepub fn set_alpns(&self, alpns: Vec<Vec<u8>>) -> Result<()>
pub fn set_alpns(&self, alpns: Vec<Vec<u8>>) -> Result<()>
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 connect(
&self,
node_addr: impl Into<NodeAddr>,
alpn: &[u8],
) -> Result<Connection>
pub async fn connect( &self, node_addr: impl Into<NodeAddr>, alpn: &[u8], ) -> Result<Connection>
Connects to a remote Endpoint
.
A value that can be converted into a NodeAddr
is required. This can be either a
NodeAddr
, a NodeId
or a iroh_base::ticket::NodeTicket
.
The NodeAddr
must contain the NodeId
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 NodeAddr
it
may still be possible a connection can be established. This depends on other calls
to Endpoint::add_node_addr
which may provide contact information, or via the
Discovery
service configured using Builder::discovery
. The discovery
service will also be used if the remote node 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,
node_addr: impl Into<NodeAddr>,
alpn: &[u8],
options: ConnectOptions,
) -> Result<Connecting>
pub async fn connect_with_opts( &self, node_addr: impl Into<NodeAddr>, alpn: &[u8], options: ConnectOptions, ) -> Result<Connecting>
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 aConnection
by awaiting, or alternatively allows connecting with 0RTT viaConnecting::into_0rtt
. Note: Please read the documentation forinto_0rtt
carefully to assess security concerns. - The
TransportConfig
for 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 add_node_addr(&self, node_addr: NodeAddr) -> Result<()>
pub fn add_node_addr(&self, node_addr: NodeAddr) -> Result<()>
Informs this Endpoint
about addresses of the iroh node.
This updates the local state for the remote node. If the provided NodeAddr
contains a RelayUrl
this will be used as the new relay server for this node. If
it contains any new IP endpoints they will also be stored and tried when next
connecting to this node. Any address that matches this node’s direct addresses will be
silently ignored.
See also Endpoint::add_node_addr_with_source
.
§Using node discovery instead
It is strongly advised to use node discovery using the StaticProvider
instead.
This provides more flexibility and future proofing.
§Errors
Will return an error if we attempt to add our own NodeId
to the node map or
if the direct addresses are a subset of ours.
Sourcepub fn add_node_addr_with_source(
&self,
node_addr: NodeAddr,
source: &'static str,
) -> Result<()>
pub fn add_node_addr_with_source( &self, node_addr: NodeAddr, source: &'static str, ) -> Result<()>
Informs this Endpoint
about addresses of the iroh node, noting the source.
This updates the local state for the remote node. If the provided NodeAddr
contains a
RelayUrl
this will be used as the new relay server for this node. If it contains any
new IP endpoints they will also be stored and tried when next connecting to this node. Any
address that matches this node’s direct addresses will be silently ignored. The source is
used for logging exclusively and will not be stored.
§Using node discovery instead
It is strongly advised to use node discovery using the StaticProvider
instead.
This provides more flexibility and future proofing.
§Errors
Will return an error if we attempt to add our own NodeId
to the node map or
if the direct addresses are a subset of ours.
Sourcepub fn secret_key(&self) -> &SecretKey
pub fn secret_key(&self) -> &SecretKey
Returns the secret_key of this endpoint.
Sourcepub fn node_id(&self) -> NodeId
pub fn node_id(&self) -> NodeId
Returns the node id of this endpoint.
This ID is the unique addressing information of this node and other peers must know it to be able to connect to this node.
Sourcepub async fn node_addr(&self) -> Result<NodeAddr>
pub async fn node_addr(&self) -> Result<NodeAddr>
Returns the current NodeAddr
for this endpoint.
The returned NodeAddr
will have the current RelayUrl
and direct addresses
as they would be returned by Endpoint::home_relay
and
Endpoint::direct_addresses
.
In browsers, because direct addresses are unavailable, this will only wait for the home relay to be available before returning.
Sourcepub fn home_relay(&self) -> Watcher<Option<RelayUrl>>
pub fn home_relay(&self) -> Watcher<Option<RelayUrl>>
Returns a Watcher
for the RelayUrl
of the Relay server used as home relay.
Every endpoint has a home Relay server which it chooses as the server with the
lowest latency out of the configured servers provided by Builder::relay_mode
.
This is the server other iroh nodes can use to reliably establish a connection
to this node.
The watcher stores None
if we are not connected to any Relay server.
Note that this will store None
right after the Endpoint
is created since it takes
some time to connect to find and connect to the home relay server.
§Examples
To wait for a home relay connection to be established, use Watcher::initialized
:
use futures_lite::StreamExt;
use iroh::Endpoint;
let mep = Endpoint::builder().bind().await.unwrap();
let _relay_url = mep.home_relay().initialized().await.unwrap();
Sourcepub fn direct_addresses(&self) -> Watcher<Option<BTreeSet<DirectAddr>>>
pub fn direct_addresses(&self) -> Watcher<Option<BTreeSet<DirectAddr>>>
Returns a Watcher
for the direct addresses of this Endpoint
.
The direct addresses of the Endpoint
are those that could be used by other
iroh nodes to establish direct connectivity, depending on the network
situation. The yielded lists of direct addresses contain both the locally-bound
addresses and the Endpoint
’s publicly reachable addresses discovered through
mechanisms such as STUN and port mapping. Hence usually only a subset of these
will be applicable to a certain remote iroh node.
The Endpoint
continuously monitors the direct addresses for changes as its own
location in the network might change. Whenever changes are detected this stream
will yield a new list of direct addresses.
When issuing the first call to this method the first direct address discovery might
still be underway, in this case the Watcher
might not be initialized with Some
value yet. Once the first set of local direct addresses are discovered the Watcher
will always return Some
set of direct addresses immediately, which are the most
recently discovered direct addresses.
§Examples
To get the first set of direct addresses use Watcher::initialized
:
use futures_lite::StreamExt;
use iroh::Endpoint;
let mep = Endpoint::builder().bind().await.unwrap();
let _addrs = mep.direct_addresses().initialized().await.unwrap();
Sourcepub fn bound_sockets(&self) -> (SocketAddr, Option<SocketAddr>)
Available on non-wasm_browser
only.
pub fn bound_sockets(&self) -> (SocketAddr, Option<SocketAddr>)
wasm_browser
only.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 fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo>
pub fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo>
Returns information about the remote node identified by a NodeId
.
The Endpoint
keeps some information about remote iroh nodes, which it uses to find
the best path to a node. Having information on a remote node, however, does not mean we have
ever connected to it to or even whether a connection is even possible. The information about a
remote node will change over time, as the Endpoint
learns more about the node. Future
calls may return different information. Furthermore, node information may even be
completely evicted as it becomes stale.
See also Endpoint::remote_info_iter
which returns information on all nodes known
by this Endpoint
.
Sourcepub fn remote_info_iter(&self) -> impl Iterator<Item = RemoteInfo>
pub fn remote_info_iter(&self) -> impl Iterator<Item = RemoteInfo>
Returns information about all the remote nodes this Endpoint
knows about.
This returns the same information as Endpoint::remote_info
for each node known to this
Endpoint
.
The Endpoint
keeps some information about remote iroh nodes, which it uses to find
the best path to a node. This returns all the nodes it knows about, regardless of whether a
connection was ever made or is even possible.
See also Endpoint::remote_info
to only retrieve information about a single node.
Sourcepub fn discovery_stream(
&self,
) -> impl Stream<Item = Result<DiscoveryItem, Lagged>>
pub fn discovery_stream( &self, ) -> impl Stream<Item = Result<DiscoveryItem, Lagged>>
Returns a stream of all remote nodes discovered through the endpoint’s discovery services.
Whenever a node is discovered via the endpoint’s discovery service, the corresponding
DiscoveryItem
is yielded from this stream. This includes nodes discovered actively
through Discovery::resolve
, which is invoked automatically when calling
Endpoint::connect
for a NodeId
unknown to the endpoint. It also includes
nodes that the endpoint discovers passively from discovery services that implement
Discovery::subscribe
, which e.g. MdnsDiscovery
does.
The stream does not yield information about nodes that are added manually to the endpoint’s
addressbook by calling Endpoint::add_node_addr
or by supplying a full NodeAddr
to
Endpoint::connect
. It also does not yield information about nodes that we only
know about because they connected to us. When using the StaticProvider
discovery,
discovery info is only emitted once connecting to a node added to the static provider, not
at the time of adding it to the static provider.
The stream should be processed in a loop. If the stream is not processed fast enough,
Lagged
may be yielded, indicating that items were missed.
See also Endpoint::remote_info_iter
, which returns an iterator over all remotes
the endpoint knows about at a specific point in time.
Sourcepub fn conn_type(&self, node_id: NodeId) -> Result<Watcher<ConnectionType>>
pub fn conn_type(&self, node_id: NodeId) -> Result<Watcher<ConnectionType>>
Returns a Watcher
that reports the current connection type and any changes for
given remote node.
This watcher allows observing a stream of ConnectionType
items by calling
Watcher::stream()
. If the underlying connection to a remote node changes, it will
yield a new item. These connection changes are when the connection switches between
using the Relay server and a direct connection.
Note that this does not guarantee each connection change is yielded in the stream. If the connection type changes several times before this stream is polled, only the last recorded state is returned. This can be observed e.g. right at the start of a connection when the switch from a relayed to a direct connection can be so fast that the relayed state is never exposed.
If there is currently a connection with the remote node, then using Watcher::get
will immediately return either ConnectionType::Relay
, ConnectionType::Direct
or ConnectionType::Mixed
.
It is possible for the connection type to be ConnectionType::None
if you’ve
recently connected to this node id but previous methods of reaching the node have
become inaccessible.
§Errors
Will error if we do not have any address information for the given node_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) -> Option<&dyn Discovery>
pub fn discovery(&self) -> Option<&dyn Discovery>
Returns the discovery mechanism, if configured.
See Builder::discovery
.
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 node.
If the user-defined data passed to this function is different to the previous one, the endpoint will republish its node 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 Connection
s 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.