diff --git a/pr/2992/docs/.lock b/pr/2992/docs/.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pr/2992/docs/bulk/all.html b/pr/2992/docs/bulk/all.html new file mode 100644 index 0000000000..6e2ab838d9 --- /dev/null +++ b/pr/2992/docs/bulk/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Functions

\ No newline at end of file diff --git a/pr/2992/docs/bulk/fn.collect_and_print.html b/pr/2992/docs/bulk/fn.collect_and_print.html new file mode 100644 index 0000000000..650d7b3fc6 --- /dev/null +++ b/pr/2992/docs/bulk/fn.collect_and_print.html @@ -0,0 +1,4 @@ +collect_and_print in bulk - Rust

Function bulk::collect_and_print

source ·
pub(crate) fn collect_and_print(
+    category: &'static str,
+    metrics: Option<&impl Iterable>
+)
\ No newline at end of file diff --git a/pr/2992/docs/bulk/fn.main.html b/pr/2992/docs/bulk/fn.main.html new file mode 100644 index 0000000000..a99f5b2137 --- /dev/null +++ b/pr/2992/docs/bulk/fn.main.html @@ -0,0 +1 @@ +main in bulk - Rust

Function bulk::main

source ·
pub(crate) fn main()
\ No newline at end of file diff --git a/pr/2992/docs/bulk/fn.run_iroh.html b/pr/2992/docs/bulk/fn.run_iroh.html new file mode 100644 index 0000000000..446649a602 --- /dev/null +++ b/pr/2992/docs/bulk/fn.run_iroh.html @@ -0,0 +1 @@ +run_iroh in bulk - Rust

Function bulk::run_iroh

source ·
pub fn run_iroh(opt: Opt) -> Result<()>
\ No newline at end of file diff --git a/pr/2992/docs/bulk/fn.run_quinn.html b/pr/2992/docs/bulk/fn.run_quinn.html new file mode 100644 index 0000000000..3ebe0718f9 --- /dev/null +++ b/pr/2992/docs/bulk/fn.run_quinn.html @@ -0,0 +1 @@ +run_quinn in bulk - Rust

Function bulk::run_quinn

source ·
pub fn run_quinn(opt: Opt) -> Result<()>
\ No newline at end of file diff --git a/pr/2992/docs/bulk/fn.run_s2n.html b/pr/2992/docs/bulk/fn.run_s2n.html new file mode 100644 index 0000000000..9b89bd65c2 --- /dev/null +++ b/pr/2992/docs/bulk/fn.run_s2n.html @@ -0,0 +1 @@ +run_s2n in bulk - Rust

Function bulk::run_s2n

source ·
pub fn run_s2n(_opt: Opt) -> Result<()>
\ No newline at end of file diff --git a/pr/2992/docs/bulk/index.html b/pr/2992/docs/bulk/index.html new file mode 100644 index 0000000000..f6592081df --- /dev/null +++ b/pr/2992/docs/bulk/index.html @@ -0,0 +1 @@ +bulk - Rust

Crate bulk

source ·

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/bulk/sidebar-items.js b/pr/2992/docs/bulk/sidebar-items.js new file mode 100644 index 0000000000..463fb65621 --- /dev/null +++ b/pr/2992/docs/bulk/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["collect_and_print","main","run_iroh","run_quinn","run_s2n"]}; \ No newline at end of file diff --git a/pr/2992/docs/crates.js b/pr/2992/docs/crates.js new file mode 100644 index 0000000000..5519b233db --- /dev/null +++ b/pr/2992/docs/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["bulk","iroh","iroh_base","iroh_dns_server","iroh_net_bench","iroh_net_report","iroh_node_util","iroh_relay","iroh_test"]; \ No newline at end of file diff --git a/pr/2992/docs/help.html b/pr/2992/docs/help.html new file mode 100644 index 0000000000..675e019f65 --- /dev/null +++ b/pr/2992/docs/help.html @@ -0,0 +1 @@ +Help

Rustdoc help

Back
\ No newline at end of file diff --git a/pr/2992/docs/iroh/all.html b/pr/2992/docs/iroh/all.html new file mode 100644 index 0000000000..f1f08390e1 --- /dev/null +++ b/pr/2992/docs/iroh/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Traits

Functions

Type Aliases

Constants

\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTPS_PORT.html b/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTPS_PORT.html new file mode 100644 index 0000000000..bdd1af9ba7 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTPS_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_HTTPS_PORT in iroh::defaults - Rust

Constant iroh::defaults::DEFAULT_HTTPS_PORT

source ·
pub const DEFAULT_HTTPS_PORT: u16 = 443;
Expand description

The default HTTPS port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTP_PORT.html b/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTP_PORT.html new file mode 100644 index 0000000000..4feb98dabd --- /dev/null +++ b/pr/2992/docs/iroh/defaults/constant.DEFAULT_HTTP_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_HTTP_PORT in iroh::defaults - Rust

Constant iroh::defaults::DEFAULT_HTTP_PORT

source ·
pub const DEFAULT_HTTP_PORT: u16 = 80;
Expand description

The default HTTP port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/constant.DEFAULT_METRICS_PORT.html b/pr/2992/docs/iroh/defaults/constant.DEFAULT_METRICS_PORT.html new file mode 100644 index 0000000000..75e9a0d8ec --- /dev/null +++ b/pr/2992/docs/iroh/defaults/constant.DEFAULT_METRICS_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_METRICS_PORT in iroh::defaults - Rust

Constant iroh::defaults::DEFAULT_METRICS_PORT

source ·
pub const DEFAULT_METRICS_PORT: u16 = 9090;
Expand description

The default metrics port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html b/pr/2992/docs/iroh/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html new file mode 100644 index 0000000000..9ae90293bd --- /dev/null +++ b/pr/2992/docs/iroh/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html @@ -0,0 +1,7 @@ +DEFAULT_RELAY_QUIC_PORT in iroh::defaults - Rust

Constant iroh::defaults::DEFAULT_RELAY_QUIC_PORT

source ·
pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842; // 7_842u16
Expand description

The default QUIC port used by the Relay server to accept QUIC connections +for QUIC address discovery

+

The port is “QUIC” typed on a phone keypad. +The default QUIC port used by the Relay server to accept QUIC connections +for QUIC address discovery

+

The port is “QUIC” typed on a phone keypad.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/constant.DEFAULT_STUN_PORT.html b/pr/2992/docs/iroh/defaults/constant.DEFAULT_STUN_PORT.html new file mode 100644 index 0000000000..891d62a91f --- /dev/null +++ b/pr/2992/docs/iroh/defaults/constant.DEFAULT_STUN_PORT.html @@ -0,0 +1,6 @@ +DEFAULT_STUN_PORT in iroh::defaults - Rust

Constant iroh::defaults::DEFAULT_STUN_PORT

source ·
pub const DEFAULT_STUN_PORT: u16 = 3478; // 3_478u16
Expand description

The default STUN port used by the Relay server.

+

The STUN port as defined by RFC +8489 +The default STUN port used by the Relay server.

+

The STUN port as defined by RFC 8489

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/index.html b/pr/2992/docs/iroh/defaults/index.html new file mode 100644 index 0000000000..7ed33f0669 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/index.html @@ -0,0 +1,3 @@ +iroh::defaults - Rust

Module iroh::defaults

source ·
Expand description

Default values used in iroh

+

Modules§

  • Production configuration.
  • Staging configuration.

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/constant.AP_RELAY_HOSTNAME.html b/pr/2992/docs/iroh/defaults/prod/constant.AP_RELAY_HOSTNAME.html new file mode 100644 index 0000000000..e497321742 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/constant.AP_RELAY_HOSTNAME.html @@ -0,0 +1,2 @@ +AP_RELAY_HOSTNAME in iroh::defaults::prod - Rust

Constant iroh::defaults::prod::AP_RELAY_HOSTNAME

source ·
pub const AP_RELAY_HOSTNAME: &str = "aps1-1.relay.iroh.network.";
Expand description

Hostname of the default Asia-Pacific relay.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/constant.EU_RELAY_HOSTNAME.html b/pr/2992/docs/iroh/defaults/prod/constant.EU_RELAY_HOSTNAME.html new file mode 100644 index 0000000000..d17cda35ad --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/constant.EU_RELAY_HOSTNAME.html @@ -0,0 +1,2 @@ +EU_RELAY_HOSTNAME in iroh::defaults::prod - Rust

Constant iroh::defaults::prod::EU_RELAY_HOSTNAME

source ·
pub const EU_RELAY_HOSTNAME: &str = "euw1-1.relay.iroh.network.";
Expand description

Hostname of the default EU relay.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/constant.NA_RELAY_HOSTNAME.html b/pr/2992/docs/iroh/defaults/prod/constant.NA_RELAY_HOSTNAME.html new file mode 100644 index 0000000000..52da98eca5 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/constant.NA_RELAY_HOSTNAME.html @@ -0,0 +1,2 @@ +NA_RELAY_HOSTNAME in iroh::defaults::prod - Rust

Constant iroh::defaults::prod::NA_RELAY_HOSTNAME

source ·
pub const NA_RELAY_HOSTNAME: &str = "use1-1.relay.iroh.network.";
Expand description

Hostname of the default NA relay.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/fn.default_ap_relay_node.html b/pr/2992/docs/iroh/defaults/prod/fn.default_ap_relay_node.html new file mode 100644 index 0000000000..a61e95416e --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/fn.default_ap_relay_node.html @@ -0,0 +1,2 @@ +default_ap_relay_node in iroh::defaults::prod - Rust

Function iroh::defaults::prod::default_ap_relay_node

source ·
pub fn default_ap_relay_node() -> RelayNode
Expand description

Get the default RelayNode for Asia-Pacific

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/fn.default_eu_relay_node.html b/pr/2992/docs/iroh/defaults/prod/fn.default_eu_relay_node.html new file mode 100644 index 0000000000..a3065e21c5 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/fn.default_eu_relay_node.html @@ -0,0 +1,2 @@ +default_eu_relay_node in iroh::defaults::prod - Rust

Function iroh::defaults::prod::default_eu_relay_node

source ·
pub fn default_eu_relay_node() -> RelayNode
Expand description

Get the default RelayNode for EU.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/fn.default_na_relay_node.html b/pr/2992/docs/iroh/defaults/prod/fn.default_na_relay_node.html new file mode 100644 index 0000000000..5cadbf6d02 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/fn.default_na_relay_node.html @@ -0,0 +1,2 @@ +default_na_relay_node in iroh::defaults::prod - Rust

Function iroh::defaults::prod::default_na_relay_node

source ·
pub fn default_na_relay_node() -> RelayNode
Expand description

Get the default RelayNode for NA.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/fn.default_relay_map.html b/pr/2992/docs/iroh/defaults/prod/fn.default_relay_map.html new file mode 100644 index 0000000000..8de32c8ad3 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/fn.default_relay_map.html @@ -0,0 +1,2 @@ +default_relay_map in iroh::defaults::prod - Rust

Function iroh::defaults::prod::default_relay_map

source ·
pub fn default_relay_map() -> RelayMap
Expand description

Get the default RelayMap.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/index.html b/pr/2992/docs/iroh/defaults/prod/index.html new file mode 100644 index 0000000000..cddd4974ac --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/index.html @@ -0,0 +1,2 @@ +iroh::defaults::prod - Rust

Module iroh::defaults::prod

source ·
Expand description

Production configuration.

+

Constants§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/prod/sidebar-items.js b/pr/2992/docs/iroh/defaults/prod/sidebar-items.js new file mode 100644 index 0000000000..c1dfdf5f8c --- /dev/null +++ b/pr/2992/docs/iroh/defaults/prod/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["AP_RELAY_HOSTNAME","EU_RELAY_HOSTNAME","NA_RELAY_HOSTNAME"],"fn":["default_ap_relay_node","default_eu_relay_node","default_na_relay_node","default_relay_map"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/sidebar-items.js b/pr/2992/docs/iroh/defaults/sidebar-items.js new file mode 100644 index 0000000000..51b5306f93 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["DEFAULT_HTTPS_PORT","DEFAULT_HTTP_PORT","DEFAULT_METRICS_PORT","DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT"],"mod":["prod","staging"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/constant.EU_RELAY_HOSTNAME.html b/pr/2992/docs/iroh/defaults/staging/constant.EU_RELAY_HOSTNAME.html new file mode 100644 index 0000000000..645e856dc1 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/constant.EU_RELAY_HOSTNAME.html @@ -0,0 +1,2 @@ +EU_RELAY_HOSTNAME in iroh::defaults::staging - Rust

Constant iroh::defaults::staging::EU_RELAY_HOSTNAME

source ·
pub const EU_RELAY_HOSTNAME: &str = "staging-euw1-1.relay.iroh.network.";
Expand description

Hostname of the default EU relay.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/constant.NA_RELAY_HOSTNAME.html b/pr/2992/docs/iroh/defaults/staging/constant.NA_RELAY_HOSTNAME.html new file mode 100644 index 0000000000..b6e560634e --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/constant.NA_RELAY_HOSTNAME.html @@ -0,0 +1,2 @@ +NA_RELAY_HOSTNAME in iroh::defaults::staging - Rust

Constant iroh::defaults::staging::NA_RELAY_HOSTNAME

source ·
pub const NA_RELAY_HOSTNAME: &str = "staging-use1-1.relay.iroh.network.";
Expand description

Hostname of the default NA relay.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/fn.default_eu_relay_node.html b/pr/2992/docs/iroh/defaults/staging/fn.default_eu_relay_node.html new file mode 100644 index 0000000000..9a0485b6f1 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/fn.default_eu_relay_node.html @@ -0,0 +1,2 @@ +default_eu_relay_node in iroh::defaults::staging - Rust

Function iroh::defaults::staging::default_eu_relay_node

source ·
pub fn default_eu_relay_node() -> RelayNode
Expand description

Get the default RelayNode for EU.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/fn.default_na_relay_node.html b/pr/2992/docs/iroh/defaults/staging/fn.default_na_relay_node.html new file mode 100644 index 0000000000..939bc15dd2 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/fn.default_na_relay_node.html @@ -0,0 +1,2 @@ +default_na_relay_node in iroh::defaults::staging - Rust

Function iroh::defaults::staging::default_na_relay_node

source ·
pub fn default_na_relay_node() -> RelayNode
Expand description

Get the default RelayNode for NA.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/fn.default_relay_map.html b/pr/2992/docs/iroh/defaults/staging/fn.default_relay_map.html new file mode 100644 index 0000000000..ef1d44d43b --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/fn.default_relay_map.html @@ -0,0 +1,2 @@ +default_relay_map in iroh::defaults::staging - Rust

Function iroh::defaults::staging::default_relay_map

source ·
pub fn default_relay_map() -> RelayMap
Expand description

Get the default RelayMap.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/index.html b/pr/2992/docs/iroh/defaults/staging/index.html new file mode 100644 index 0000000000..9e14f54b28 --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/index.html @@ -0,0 +1,4 @@ +iroh::defaults::staging - Rust

Module iroh::defaults::staging

source ·
Expand description

Staging configuration.

+

Used by tests and might have incompatible changes deployed

+

Note: we have staging servers in EU and NA, but no corresponding staging server for AP at this time.

+

Constants§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/defaults/staging/sidebar-items.js b/pr/2992/docs/iroh/defaults/staging/sidebar-items.js new file mode 100644 index 0000000000..a18a58b6ce --- /dev/null +++ b/pr/2992/docs/iroh/defaults/staging/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["EU_RELAY_HOSTNAME","NA_RELAY_HOSTNAME"],"fn":["default_eu_relay_node","default_na_relay_node","default_relay_map"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/dialer/index.html b/pr/2992/docs/iroh/dialer/index.html new file mode 100644 index 0000000000..02c05ce163 --- /dev/null +++ b/pr/2992/docs/iroh/dialer/index.html @@ -0,0 +1,2 @@ +iroh::dialer - Rust

Module iroh::dialer

source ·
Expand description

A dialer to conveniently dial many nodes.

+

Structs§

  • Dials nodes and maintains a queue of pending dials.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dialer/sidebar-items.js b/pr/2992/docs/iroh/dialer/sidebar-items.js new file mode 100644 index 0000000000..9a33cb51da --- /dev/null +++ b/pr/2992/docs/iroh/dialer/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["Dialer"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/dialer/struct.Dialer.html b/pr/2992/docs/iroh/dialer/struct.Dialer.html new file mode 100644 index 0000000000..4f2ece7a39 --- /dev/null +++ b/pr/2992/docs/iroh/dialer/struct.Dialer.html @@ -0,0 +1,437 @@ +Dialer in iroh::dialer - Rust

Struct iroh::dialer::Dialer

source ·
pub struct Dialer { /* private fields */ }
Expand description

Dials nodes and maintains a queue of pending dials.

+

The Dialer wraps an Endpoint, connects to nodes through the endpoint, stores the +pending connect futures and emits finished connect results.

+

The Dialer also implements [Stream] to retrieve the dialled connections.

+

Implementations§

source§

impl Dialer

source

pub fn new(endpoint: Endpoint) -> Self

Create a new dialer for a Endpoint

+
source

pub fn queue_dial(&mut self, node_id: NodeId, alpn: &'static [u8])

Starts to dial a node by NodeId.

+

Since this dials by NodeId the Endpoint must know how to contact the node by +NodeId only. This relies on addressing information being provided by either the +discovery service or manually by calling Endpoint::add_node_addr.

+
source

pub fn abort_dial(&mut self, node_id: NodeId)

Aborts a pending dial.

+
source

pub fn is_pending(&self, node: NodeId) -> bool

Checks if a node is currently being dialed.

+
source

pub async fn next_conn(&mut self) -> (NodeId, Result<Connection>)

Waits for the next dial operation to complete.

+
source

pub fn pending_count(&self) -> usize

Number of pending connections to be opened.

+
source

pub fn endpoint(&self) -> &Endpoint

Returns a reference to the endpoint used in this dialer.

+

Trait Implementations§

source§

impl Debug for Dialer

source§

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

Formats the value using the given formatter. Read more
source§

impl Stream for Dialer

§

type Item = (PublicKey, Result<Connection, Error>)

Values yielded by the stream.
source§

fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_> +) -> Poll<Option<Self::Item>>

Attempt to pull out the next value of this stream, registering the +current task for wakeup if the value is not yet available, and returning +None if the stream is exhausted. Read more
§

fn size_hint(&self) -> (usize, Option<usize>)

Returns the bounds on the remaining length of the stream. Read more

Auto Trait Implementations§

§

impl Freeze for Dialer

§

impl !RefUnwindSafe for Dialer

§

impl Send for Dialer

§

impl Sync for Dialer

§

impl Unpin for Dialer

§

impl !UnwindSafe for Dialer

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
§

impl<T> BufferedStreamExt for T
where + T: Stream + ?Sized,

§

fn buffered_ordered(self, n: usize) -> BufferedOrdered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffered_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: usize, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<S> IntoStream for S
where + S: Stream,

§

type Item = <S as Stream>::Item

The type of the elements being iterated over.
§

type IntoStream = S

Which kind of stream are we turning this into?
§

fn into_stream(self) -> S

Creates a stream from a value.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn drain(&mut self) -> Drain<'_, Self>

Yields all immediately available values from a stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S1> StreamExt for S1
where + S1: Stream,

§

fn merge<T, S2>( + self, + other: S2 +) -> Merge2<T, S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Combines two streams into a single stream of all their outputs.
§

fn chain<T, S2>(self, other: S2) -> Chain2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Takes two streams and creates a new stream over all in sequence
§

fn zip<T, S2>(self, other: S2) -> Zip2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

‘Zips up’ multiple streams into a single stream of pairs.
§

fn co(self) -> FromStream<Self>
where + Self: Sized,

Convert into a concurrent stream.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay the yielding of items from the stream until the given deadline. Read more
§

impl<St> StreamExt for St
where + St: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Consumes and returns the next value in the stream or None if the +stream is finished. Read more
§

fn try_next<T, E>(&mut self) -> TryNext<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Consumes and returns the next item in the stream. If an error is +encountered before the next item, the error is returned instead. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn map_while<T, F>(self, f: F) -> MapWhile<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Map this stream’s items to a different type for as long as determined by +the provided closure. A stream of the target type will be returned, +which will yield elements until the closure returns None. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Maps this stream’s items asynchronously to a different type, returning a +new stream of the resulting type. Read more
§

fn merge<U>(self, other: U) -> Merge<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by interleaving the output of both as it +is produced. Read more
§

fn filter<F>(self, f: F) -> Filter<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Filters the values produced by this stream according to the provided +predicate. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Creates a stream which ends after the first None. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn take_while<F>(self, f: F) -> TakeWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Take elements from this stream while the provided predicate +resolves to true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream that will skip the n first items of the +underlying stream. Read more
§

fn skip_while<F>(self, f: F) -> SkipWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Skip elements from the underlying stream while the provided predicate +resolves to true. Read more
§

fn all<F>(&mut self, f: F) -> AllFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if every element of the stream matches a predicate. Read more
§

fn any<F>(&mut self, f: F) -> AnyFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if any element of the stream matches a predicate. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by first returning all values from the +first stream then all values from the second stream. Read more
§

fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
where + Self: Sized, + F: FnMut(B, Self::Item) -> B,

A combinator that applies a function to every element in a stream +producing a single, final value. Read more
§

fn collect<T>(self) -> Collect<Self, T>
where + T: FromStream<Self::Item>, + Self: Sized,

Drain stream pushing all emitted values into a collection. Read more
§

fn timeout(self, duration: Duration) -> Timeout<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn timeout_repeating(self, interval: Interval) -> TimeoutRepeating<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn throttle(self, duration: Duration) -> Throttle<Self>
where + Self: Sized,

Slows down a stream by enforcing a delay between items. Read more
§

fn chunks_timeout( + self, + max_size: usize, + duration: Duration +) -> ChunksTimeout<Self>
where + Self: Sized,

Batches the items in the given stream using a maximum duration and size for each batch. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Turns the stream into a peekable stream, whose next element can be peeked at without being +consumed. Read more
§

impl<T> StreamExt for T
where + T: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Creates a future that resolves to the next item in the stream. Read more
§

fn into_future(self) -> StreamFuture<Self>
where + Self: Sized + Unpin,

Converts this stream into a future of (next_item, tail_of_stream). +If the stream terminates, then the next item is None. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Creates a stream which gives the current iteration count as well as +the next value. Read more
§

fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Filters the values produced by this stream according to the provided +asynchronous predicate. Read more
§

fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = Option<T>>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided asynchronous closure. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Computes from this stream’s items new items of a different type using +an asynchronous closure. Read more
§

fn collect<C>(self) -> Collect<Self, C>
where + C: Default + Extend<Self::Item>, + Self: Sized,

Transforms a stream into a collection, returning a +future representing the result of that computation. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> Unzip<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Converts a stream of pairs into a future, which +resolves to pair of containers. Read more
§

fn concat(self) -> Concat<Self>
where + Self: Sized, + Self::Item: Extend<<Self::Item as IntoIterator>::Item> + IntoIterator + Default,

Concatenate all items of a stream into a single extendable +destination, returning a future representing the end result. Read more
§

fn count(self) -> Count<Self>
where + Self: Sized,

Drives the stream to completion, counting the number of items. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats a stream endlessly. Read more
§

fn fold<T, Fut, F>(self, init: T, f: F) -> Fold<Self, Fut, T, F>
where + F: FnMut(T, Self::Item) -> Fut, + Fut: Future<Output = T>, + Self: Sized,

Execute an accumulating asynchronous computation over a stream, +collecting all the values into one final result. Read more
§

fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if any element in stream satisfied a predicate. Read more
§

fn all<Fut, F>(self, f: F) -> All<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if all element in stream satisfied a predicate. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Item: Stream, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Read more
§

fn flatten_unordered( + self, + limit: impl Into<Option<usize>> +) -> FlattenUnorderedWithFlowController<Self, ()>
where + Self::Item: Stream + Unpin, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Polls +inner streams produced by the base stream concurrently. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + F: FnMut(Self::Item) -> U, + U: Stream, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams. Read more
§

fn flat_map_unordered<U, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> FlatMapUnordered<Self, U, F>
where + U: Stream + Unpin, + F: FnMut(Self::Item) -> U, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams +and polls them concurrently, yielding items in any order, as they made +available. Read more
§

fn scan<S, B, Fut, F>(self, initial_state: S, f: F) -> Scan<Self, S, Fut, F>
where + F: FnMut(&mut S, Self::Item) -> Fut, + Fut: Future<Output = Option<B>>, + Self: Sized,

Combinator similar to [StreamExt::fold] that holds internal state +and produces a new stream. Read more
§

fn skip_while<Fut, F>(self, f: F) -> SkipWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Skip elements on this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_while<Fut, F>(self, f: F) -> TakeWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Take elements from this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_until<Fut>(self, fut: Fut) -> TakeUntil<Self, Fut>
where + Fut: Future, + Self: Sized,

Take elements from this stream until the provided future resolves. Read more
§

fn for_each<Fut, F>(self, f: F) -> ForEach<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream. Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream which skips n items of the underlying stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a stream such that poll_next will never +again be called once it has finished. This method can be used to turn +any Stream into a FusedStream. Read more
§

fn by_ref(&mut self) -> &mut Self

Borrows a stream, rather than consuming it. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn buffered(self, n: usize) -> Buffered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn zip<St>(self, other: St) -> Zip<Self, St>
where + St: Stream, + Self: Sized,

An adapter for zipping two streams together. Read more
§

fn chain<St>(self, other: St) -> Chain<Self, St>
where + St: Stream<Item = Self::Item>, + Self: Sized,

Adapter for chaining two streams. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Creates a new stream which exposes a peek method. Read more
§

fn chunks(self, capacity: usize) -> Chunks<Self>
where + Self: Sized,

An adaptor for chunking up items of the stream inside a vector. Read more
§

fn ready_chunks(self, capacity: usize) -> ReadyChunks<Self>
where + Self: Sized,

An adaptor for chunking up ready items of the stream inside a vector. Read more
§

fn forward<S>(self, sink: S) -> Forward<Self, S>
where + S: Sink<Self::Ok, Error = Self::Error>, + Self: Sized + TryStream,

A future that completes after the given stream has been fully processed +into the sink and the sink has been flushed and closed. Read more
§

fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>)
where + Self: Sized + Sink<Item>,

Splits this Stream + Sink object into separate Sink and Stream +objects. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnMut(&Self::Item), + Self: Sized,

Do something with each item of this stream, afterwards passing it on. Read more
§

fn left_stream<B>(self) -> Either<Self, B>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the left-hand variant +of that Either. Read more
§

fn right_stream<B>(self) -> Either<B, Self>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the right-hand variant +of that Either. Read more
§

fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience method for calling [Stream::poll_next] on Unpin +stream types.
§

fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
where + Self: Unpin + FusedStream,

Returns a Future that resolves when the next item in this stream is +ready. Read more
§

impl<'a, S> StreamRateLimitExt<'a> for S
where + S: Stream,

§

fn ratelimit_stream<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW> +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items. Read more
§

fn ratelimit_stream_with_jitter<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW>, + jitter: Jitter +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items, with a randomized wait period. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_PROD.html b/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_PROD.html new file mode 100644 index 0000000000..a1f910e7c3 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_PROD.html @@ -0,0 +1,2 @@ +N0_DNS_NODE_ORIGIN_PROD in iroh::discovery::dns - Rust

Constant iroh::discovery::dns::N0_DNS_NODE_ORIGIN_PROD

source ·
pub const N0_DNS_NODE_ORIGIN_PROD: &str = "dns.iroh.link";
Expand description

The n0 testing DNS node origin, for production.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_STAGING.html b/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_STAGING.html new file mode 100644 index 0000000000..f479dd6d4d --- /dev/null +++ b/pr/2992/docs/iroh/discovery/dns/constant.N0_DNS_NODE_ORIGIN_STAGING.html @@ -0,0 +1,2 @@ +N0_DNS_NODE_ORIGIN_STAGING in iroh::discovery::dns - Rust

Constant iroh::discovery::dns::N0_DNS_NODE_ORIGIN_STAGING

source ·
pub const N0_DNS_NODE_ORIGIN_STAGING: &str = "staging-dns.iroh.link";
Expand description

The n0 testing DNS node origin, for testing.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/dns/index.html b/pr/2992/docs/iroh/discovery/dns/index.html new file mode 100644 index 0000000000..328fcbe460 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/dns/index.html @@ -0,0 +1,2 @@ +iroh::discovery::dns - Rust

Module iroh::discovery::dns

source ·
Expand description

DNS node discovery for iroh

+

Structs§

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/dns/sidebar-items.js b/pr/2992/docs/iroh/discovery/dns/sidebar-items.js new file mode 100644 index 0000000000..b6ba4b4956 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/dns/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["N0_DNS_NODE_ORIGIN_PROD","N0_DNS_NODE_ORIGIN_STAGING"],"struct":["DnsDiscovery"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/dns/struct.DnsDiscovery.html b/pr/2992/docs/iroh/discovery/dns/struct.DnsDiscovery.html new file mode 100644 index 0000000000..b5eeb05364 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/dns/struct.DnsDiscovery.html @@ -0,0 +1,54 @@ +DnsDiscovery in iroh::discovery::dns - Rust

Struct iroh::discovery::dns::DnsDiscovery

source ·
pub struct DnsDiscovery { /* private fields */ }
Expand description

DNS node discovery

+

When asked to resolve a NodeId, this service performs a lookup in the Domain Name System (DNS).

+

It uses the Endpoint’s DNS resolver to query for TXT records under the domain +_iroh.<z32-node-id>.<origin-domain>:

+
    +
  • _iroh: is the record name
  • +
  • <z32-node-id> is the NodeId encoded in [z-base-32] format
  • +
  • <origin-domain> is the node origin domain as set in DnsDiscovery::new.
  • +
+

Each TXT record returned from the query is expected to contain a string in the format <name>=<value>. +If a TXT record contains multiple character strings, they are concatenated first. +The supported attributes are:

+
    +
  • relay=<url>: The URL of the home relay server of the node
  • +
+

The DNS resolver defaults to using the nameservers configured on the host system, but can be changed +with crate::endpoint::Builder::dns_resolver.

+

Implementations§

source§

impl DnsDiscovery

source

pub fn new(origin_domain: String) -> Self

Creates a new DNS discovery.

+
source

pub fn n0_dns() -> Self

Creates a new DNS discovery using the iroh.link domain.

+

This uses the N0_DNS_NODE_ORIGIN_PROD domain.

+
§Usage during tests
+

For testing it is possible to use the N0_DNS_NODE_ORIGIN_STAGING domain +with DnsDiscovery::new. This would then use a hosted staging discovery +service for testing purposes.

+

Trait Implementations§

source§

impl Debug for DnsDiscovery

source§

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

Formats the value using the given formatter. Read more
source§

impl Discovery for DnsDiscovery

source§

fn resolve( + &self, + ep: Endpoint, + node_id: NodeId +) -> Option<BoxStream<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn publish(&self, _info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/index.html b/pr/2992/docs/iroh/discovery/index.html new file mode 100644 index 0000000000..a4815887b3 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/index.html @@ -0,0 +1,70 @@ +iroh::discovery - Rust

Module iroh::discovery

source ·
Expand description

Node address discovery.

+

To connect to an iroh node a NodeAddr is needed, which may contain a +RelayUrl or one or more direct addresses in addition to the NodeId.

+

Since there is a conversion from NodeId to NodeAddr, you can also use +connect directly with a NodeId.

+

For this to work however, the endpoint has to get the addressing information by +other means. This can be done by manually calling Endpoint::add_node_addr, +but that still requires knowing the other addressing information.

+

Node discovery is an automated system for an Endpoint to retrieve this addressing +information. Each iroh node will automatically publish their own addressing +information. Usually this means publishing which RelayUrl to use for their +NodeId, but they could also publish their direct addresses.

+

The Discovery trait is used to define node discovery. This allows multiple +implementations to co-exist because there are many possible ways to implement this. +Each Endpoint can use the discovery mechanisms most suitable to the application. +The Builder::discovery method is used to add a discovery mechanism to an +Endpoint.

+

Some generally useful discovery implementations are provided:

+
    +
  • +

    The DnsDiscovery which performs lookups via the standard DNS systems. To publish +to this DNS server a PkarrPublisher is needed. Number 0 runs a public instance +of a PkarrPublisher with attached DNS server which is globally available and a +reliable default choice.

    +
  • +
  • +

    The PkarrResolver which can perform lookups from designated pkarr relay servers +using HTTP.

    +
  • +
  • +
           very similar to mDNS.
    +
  • +
  • +

    The DhtDiscovery also uses the pkarr system but can also publish and lookup +records to/from the Mainline DHT.

    +
  • +
+

To use multiple discovery systems simultaneously use ConcurrentDiscovery which will +perform lookups to all discovery systems at the same time.

+

§Examples

+

A very common setup is to enable DNS discovery, which needs to be done in two parts as a +PkarrPublisher and DnsDiscovery:

+ +
use iroh::{
+    discovery::{dns::DnsDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery},
+    key::SecretKey,
+    Endpoint,
+};
+
+let secret_key = SecretKey::generate();
+let discovery = ConcurrentDiscovery::from_services(vec![
+    Box::new(PkarrPublisher::n0_dns(secret_key.clone())),
+    Box::new(DnsDiscovery::n0_dns()),
+]);
+let ep = Endpoint::builder()
+    .secret_key(secret_key)
+    .discovery(Box::new(discovery))
+    .bind()
+    .await?;
+

To also enable +LocalSwarmDiscovery +it can be added as another service in the +ConcurrentDiscovery:

+ +
let discovery = ConcurrentDiscovery::from_services(vec![
+    Box::new(PkarrPublisher::n0_dns(secret_key.clone())),
+    Box::new(DnsDiscovery::n0_dns()),
+    Box::new(LocalSwarmDiscovery::new(secret_key.public())?),
+]);
+

Modules§

  • DNS node discovery for iroh
  • local_swarm_discoverydiscovery-local-network
    A discovery service that uses an mdns-like service to discover local nodes.
  • A discovery service which publishes and resolves node information using a pkarr relay.
  • A static discovery implementation that allows adding info for nodes manually.

Structs§

Traits§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/local_swarm_discovery/constant.NAME.html b/pr/2992/docs/iroh/discovery/local_swarm_discovery/constant.NAME.html new file mode 100644 index 0000000000..a32ac0d907 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/local_swarm_discovery/constant.NAME.html @@ -0,0 +1,4 @@ +NAME in iroh::discovery::local_swarm_discovery - Rust

Constant iroh::discovery::local_swarm_discovery::NAME

source ·
pub const NAME: &str = "local.swarm.discovery";
Available on crate feature discovery-local-network only.
Expand description

Name of this discovery service.

+

Used as the provenance field in DiscoveryItems.

+

Used in the crate::endpoint::Source::Discovery enum variant as the name.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/local_swarm_discovery/index.html b/pr/2992/docs/iroh/discovery/local_swarm_discovery/index.html new file mode 100644 index 0000000000..cc0d06bfe2 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/local_swarm_discovery/index.html @@ -0,0 +1,29 @@ +iroh::discovery::local_swarm_discovery - Rust

Module iroh::discovery::local_swarm_discovery

source ·
Available on crate feature discovery-local-network only.
Expand description

A discovery service that uses an mdns-like service to discover local nodes.

+

This allows you to use an mdns-like swarm discovery service to find address information about nodes that are on your local network, no relay or outside internet needed. +See the swarm-discovery crate for more details.

+

When LocalSwarmDiscovery is enabled, it’s possible to get a list of the locally discovered nodes by filtering a list of RemoteInfos.

+ +
use std::time::Duration;
+
+use iroh::endpoint::{Endpoint, Source};
+
+#[tokio::main]
+async fn main() {
+    let recent = Duration::from_secs(600); // 10 minutes in seconds
+
+    let endpoint = Endpoint::builder().bind().await.unwrap();
+    let remotes = endpoint.remote_info_iter();
+    let locally_discovered: Vec<_> = remotes
+        .filter(|remote| {
+            remote.sources().iter().any(|(source, duration)| {
+                if let Source::Discovery { name } = source {
+                    name == iroh::discovery::local_swarm_discovery::NAME && *duration <= recent
+                } else {
+                    false
+                }
+            })
+        })
+        .collect();
+    println!("locally discovered nodes: {locally_discovered:?}");
+}
+

Structs§

Constants§

  • Name of this discovery service.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/local_swarm_discovery/sidebar-items.js b/pr/2992/docs/iroh/discovery/local_swarm_discovery/sidebar-items.js new file mode 100644 index 0000000000..719b972ad5 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/local_swarm_discovery/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["NAME"],"struct":["LocalSwarmDiscovery"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/local_swarm_discovery/struct.LocalSwarmDiscovery.html b/pr/2992/docs/iroh/discovery/local_swarm_discovery/struct.LocalSwarmDiscovery.html new file mode 100644 index 0000000000..a12f07261c --- /dev/null +++ b/pr/2992/docs/iroh/discovery/local_swarm_discovery/struct.LocalSwarmDiscovery.html @@ -0,0 +1,37 @@ +LocalSwarmDiscovery in iroh::discovery::local_swarm_discovery - Rust
pub struct LocalSwarmDiscovery { /* private fields */ }
Available on crate feature discovery-local-network only.
Expand description

Discovery using swarm-discovery, a variation on mdns

+

Implementations§

source§

impl LocalSwarmDiscovery

source

pub fn new(node_id: NodeId) -> Result<Self>

Create a new LocalSwarmDiscovery Service.

+

This starts a [Discoverer] that broadcasts your addresses and receives addresses from other nodes in your local network.

+
§Errors
+

Returns an error if the network does not allow ipv4 OR ipv6.

+
§Panics
+

This relies on [tokio::runtime::Handle::current] and will panic if called outside of the context of a tokio runtime.

+

Trait Implementations§

source§

impl Debug for LocalSwarmDiscovery

source§

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

Formats the value using the given formatter. Read more
source§

impl Discovery for LocalSwarmDiscovery

source§

fn resolve( + &self, + _ep: Endpoint, + node_id: NodeId +) -> Option<BoxStream<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn publish(&self, info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_PKARR_TTL.html b/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_PKARR_TTL.html new file mode 100644 index 0000000000..4cf6feb227 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_PKARR_TTL.html @@ -0,0 +1,6 @@ +DEFAULT_PKARR_TTL in iroh::discovery::pkarr - Rust

Constant iroh::discovery::pkarr::DEFAULT_PKARR_TTL

source ·
pub const DEFAULT_PKARR_TTL: u32 = 30;
Expand description

Default TTL for the records in the pkarr signed packet.

+

The Time To Live (TTL) tells DNS caches how long to store a record. It is ignored by the +iroh-dns-server, e.g. as running on N0_DNS_PKARR_RELAY_PROD, as the home server +keeps the records for the domain. When using the pkarr relay no DNS is involved and the +setting is ignored.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_REPUBLISH_INTERVAL.html b/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_REPUBLISH_INTERVAL.html new file mode 100644 index 0000000000..f989a0e7cb --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/constant.DEFAULT_REPUBLISH_INTERVAL.html @@ -0,0 +1,2 @@ +DEFAULT_REPUBLISH_INTERVAL in iroh::discovery::pkarr - Rust

Constant iroh::discovery::pkarr::DEFAULT_REPUBLISH_INTERVAL

source ·
pub const DEFAULT_REPUBLISH_INTERVAL: Duration;
Expand description

Interval in which to republish the node info even if unchanged: 5 minutes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_PROD.html b/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_PROD.html new file mode 100644 index 0000000000..5513f6eb2a --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_PROD.html @@ -0,0 +1,5 @@ +N0_DNS_PKARR_RELAY_PROD in iroh::discovery::pkarr - Rust

Constant iroh::discovery::pkarr::N0_DNS_PKARR_RELAY_PROD

source ·
pub const N0_DNS_PKARR_RELAY_PROD: &str = "https://dns.iroh.link/pkarr";
Expand description

The production pkarr relay run by number 0.

+

This server is both a pkarr relay server as well as a DNS resolver, see the module +documentation. However it does not interact with the Mainline DHT, so is a more +central service. It is a reliable service to use for node discovery.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_STAGING.html b/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_STAGING.html new file mode 100644 index 0000000000..99cfd8a740 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/constant.N0_DNS_PKARR_RELAY_STAGING.html @@ -0,0 +1,4 @@ +N0_DNS_PKARR_RELAY_STAGING in iroh::discovery::pkarr - Rust

Constant iroh::discovery::pkarr::N0_DNS_PKARR_RELAY_STAGING

source ·
pub const N0_DNS_PKARR_RELAY_STAGING: &str = "https://staging-dns.iroh.link/pkarr";
Expand description

The testing pkarr relay run by number 0.

+

This server operates similarly to N0_DNS_PKARR_RELAY_PROD but is not as reliable. +It is meant for more experimental use and testing purposes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/dht/index.html b/pr/2992/docs/iroh/discovery/pkarr/dht/index.html new file mode 100644 index 0000000000..02bdaaf5b0 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/dht/index.html @@ -0,0 +1,5 @@ +iroh::discovery::pkarr::dht - Rust

Module iroh::discovery::pkarr::dht

source ·
Available on crate feature discovery-pkarr-dht only.
Expand description

Pkarr based node discovery for iroh, supporting both relay servers and the DHT.

+

This module contains pkarr-based node discovery for iroh which can use both pkarr +relay servers as well as the Mainline DHT directly. See the pkarr module for an +overview of pkarr.

+

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/dht/sidebar-items.js b/pr/2992/docs/iroh/discovery/pkarr/dht/sidebar-items.js new file mode 100644 index 0000000000..e5f05b450c --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/dht/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["Builder","DhtDiscovery"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/dht/struct.Builder.html b/pr/2992/docs/iroh/discovery/pkarr/dht/struct.Builder.html new file mode 100644 index 0000000000..356ef54865 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/dht/struct.Builder.html @@ -0,0 +1,39 @@ +Builder in iroh::discovery::pkarr::dht - Rust

Struct iroh::discovery::pkarr::dht::Builder

source ·
pub struct Builder { /* private fields */ }
Available on crate feature discovery-pkarr-dht only.
Expand description

Builder for DhtDiscovery.

+

By default, publishing to the DHT is enabled, and relay publishing is disabled.

+

Implementations§

source§

impl Builder

source

pub fn client(self, client: PkarrClient) -> Self

Explicitly sets the pkarr client to use.

+
source

pub fn secret_key(self, secret_key: SecretKey) -> Self

Sets the secret key to use for signing the DNS packets.

+

Without a secret key, the node will not publish its address to the DHT.

+
source

pub fn ttl(self, ttl: u32) -> Self

Sets the time-to-live value for the DNS packets.

+
source

pub fn pkarr_relay(self, pkarr_relay: Url) -> Self

Sets the pkarr relay URL to use.

+
source

pub fn n0_dns_pkarr_relay(self) -> Self

Uses the default number 0 pkarr relay URL.

+
source

pub fn dht(self, dht: bool) -> Self

Sets whether to publish to the Mainline DHT.

+
source

pub fn include_direct_addresses(self, include_direct_addresses: bool) -> Self

Sets whether to include the direct addresses in the DNS packet.

+
source

pub fn initial_publish_delay(self, initial_publish_delay: Duration) -> Self

Sets the initial delay before the first publish.

+
source

pub fn republish_delay(self, republish_delay: Duration) -> Self

Sets the republish delay for the DHT.

+
source

pub fn build(self) -> Result<DhtDiscovery>

Builds the discovery mechanism.

+

Trait Implementations§

source§

impl Debug for Builder

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Builder

source§

fn default() -> Self

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/dht/struct.DhtDiscovery.html b/pr/2992/docs/iroh/discovery/pkarr/dht/struct.DhtDiscovery.html new file mode 100644 index 0000000000..e16f63c37b --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/dht/struct.DhtDiscovery.html @@ -0,0 +1,40 @@ +DhtDiscovery in iroh::discovery::pkarr::dht - Rust

Struct iroh::discovery::pkarr::dht::DhtDiscovery

source ·
pub struct DhtDiscovery(/* private fields */);
Available on crate feature discovery-pkarr-dht only.
Expand description

Pkarr Mainline DHT and relay server node discovery.

+

It stores node addresses in DNS records, signed by the node’s private key, and publishes +them to the BitTorrent Mainline DHT. See the pkarr module for more details.

+

This implements the Discovery trait to be used as a node discovery service which can +be used as both a publisher and resolver. Calling DhtDiscovery::publish will start +a background task that periodically publishes the node address.

+

Implementations§

source§

impl DhtDiscovery

source

pub fn builder() -> Builder

Creates a new builder for DhtDiscovery.

+

Trait Implementations§

source§

impl Clone for DhtDiscovery

source§

fn clone(&self) -> DhtDiscovery

Returns a copy 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 DhtDiscovery

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for DhtDiscovery

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Discovery for DhtDiscovery

source§

fn publish(&self, info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn resolve( + &self, + _endpoint: Endpoint, + node_id: NodeId +) -> Option<Boxed<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/index.html b/pr/2992/docs/iroh/discovery/pkarr/index.html new file mode 100644 index 0000000000..317879bab1 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/index.html @@ -0,0 +1,43 @@ +iroh::discovery::pkarr - Rust

Module iroh::discovery::pkarr

source ·
Expand description

A discovery service which publishes and resolves node information using a pkarr relay.

+

Public-Key Addressable Resource Records, pkarr, is a system which allows publishing +DNS Resource Records owned by a particular SecretKey under a name derived from its +corresponding PublicKey, also known as the NodeId. Additionally this pkarr +Resource Record is signed using the same SecretKey, ensuring authenticity of the +record.

+

Pkarr normally stores these records on the Mainline DHT, but also provides two bridges +that do not require clients to directly interact with the DHT:

+
    +
  • +

    Resolvers are servers which expose the pkarr Resource Record under a domain name, +e.g. o3dks..6uyy.dns.iroh.link. This allows looking up the pkarr Resource Records +using normal DNS clients. These resolvers would normally perform lookups on the +Mainline DHT augmented with a local cache to improve performance.

    +
  • +
  • +

    Relays are servers which allow both publishing and looking up of the pkarr Resource +Records using HTTP PUT and GET requests. They will usually perform the publishing to +the Mainline DHT on behalf on the client as well as cache lookups performed on the DHT +to improve performance.

    +
  • +
+

For node discovery in iroh the pkarr Resource Records contain the AddrInfo +information, providing nodes which retrieve the pkarr Resource Record with enough detail +to contact the iroh node.

+

There are several node discovery services built on top of pkarr, which can be composed +to the application’s needs:

+
    +
  • +

    PkarrPublisher, which publishes to a pkarr relay server using HTTP.

    +
  • +
  • +

    PkarrResolver, which resolves from a pkarr relay server using HTTP.

    +
  • +
  • +

    DnsDiscovery, which resolves from a DNS server.

    +
  • +
  • +

    DhtDiscovery, which resolves and publishes from both pkarr relay servers and well +as the Mainline DHT.

    +
  • +
+

Modules§

  • dhtdiscovery-pkarr-dht
    Pkarr based node discovery for iroh, supporting both relay servers and the DHT.

Structs§

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/sidebar-items.js b/pr/2992/docs/iroh/discovery/pkarr/sidebar-items.js new file mode 100644 index 0000000000..aed164cef7 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["DEFAULT_PKARR_TTL","DEFAULT_REPUBLISH_INTERVAL","N0_DNS_PKARR_RELAY_PROD","N0_DNS_PKARR_RELAY_STAGING"],"mod":["dht"],"struct":["PkarrPublisher","PkarrRelayClient","PkarrResolver"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrPublisher.html b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrPublisher.html new file mode 100644 index 0000000000..173882fa7a --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrPublisher.html @@ -0,0 +1,63 @@ +PkarrPublisher in iroh::discovery::pkarr - Rust

Struct iroh::discovery::pkarr::PkarrPublisher

source ·
pub struct PkarrPublisher { /* private fields */ }
Expand description

Publisher of node discovery information to a pkarr relay.

+

This publisher uses HTTP to publish node discovery information to a pkarr relay +server, see the module docs for details.

+

This implements the Discovery trait to be used as a node discovery service. Note +that it only publishes node discovery information, for the corresponding resolver use +the PkarrResolver together with ConcurrentDiscovery.

+

This publisher will only publish the RelayUrl if the AddrInfo contains a +RelayUrl. If the AddrInfo does not contain a RelayUrl the direct +addresses are published instead.

+

Implementations§

source§

impl PkarrPublisher

source

pub fn new(secret_key: SecretKey, pkarr_relay: Url) -> Self

Creates a new publisher for the SecretKey.

+

This publisher will be able to publish pkarr records for SecretKey. It will +use DEFAULT_PKARR_TTL as the time-to-live value for the published packets. Will +republish discovery information every DEFAULT_REPUBLISH_INTERVAL, even if the +information is unchanged.

+
source

pub fn with_options( + secret_key: SecretKey, + pkarr_relay: Url, + ttl: u32, + republish_interval: Duration +) -> Self

Creates a new PkarrPublisher with a custom TTL and republish intervals.

+

This allows creating the publisher with custom time-to-live values of the +[pkarr::SignedPacket]s and well as a custom republish interval.

+
source

pub fn n0_dns(secret_key: SecretKey) -> Self

Creates a pkarr publisher which uses the number 0 pkarr relay server.

+

This uses the pkarr relay server operated by number 0, at +N0_DNS_PKARR_RELAY_PROD.

+

When running with the environment variable +IROH_FORCE_STAGING_RELAYS set to any non empty value N0_DNS_PKARR_RELAY_STAGING +server is used instead.

+
source

pub fn update_addr_info(&self, info: &AddrInfo)

Publishes AddrInfo about this node to a pkarr relay.

+

This is a nonblocking function, the actual update is performed in the background.

+

Trait Implementations§

source§

impl Clone for PkarrPublisher

source§

fn clone(&self) -> PkarrPublisher

Returns a copy 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 PkarrPublisher

source§

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

Formats the value using the given formatter. Read more
source§

impl Discovery for PkarrPublisher

source§

fn publish(&self, info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn resolve( + &self, + _endpoint: Endpoint, + _node_id: NodeId +) -> Option<BoxStream<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. Read more
source§

impl Drop for PkarrPublisher

source§

fn drop(&mut self)

Executes the destructor for this type. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrRelayClient.html b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrRelayClient.html new file mode 100644 index 0000000000..19a7e29774 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrRelayClient.html @@ -0,0 +1,33 @@ +PkarrRelayClient in iroh::discovery::pkarr - Rust

Struct iroh::discovery::pkarr::PkarrRelayClient

source ·
pub struct PkarrRelayClient { /* private fields */ }
Expand description

A pkarr client to publish [pkarr::SignedPacket]s to a pkarr relay.

+

Implementations§

source§

impl PkarrRelayClient

source

pub fn new(pkarr_relay_url: Url) -> Self

Creates a new client.

+
source

pub async fn resolve(&self, node_id: NodeId) -> Result<SignedPacket>

Resolves a [SignedPacket] for the given NodeId.

+
source

pub async fn publish(&self, signed_packet: &SignedPacket) -> Result<()>

Publishes a [SignedPacket].

+

Trait Implementations§

source§

impl Clone for PkarrRelayClient

source§

fn clone(&self) -> PkarrRelayClient

Returns a copy 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 PkarrRelayClient

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrResolver.html b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrResolver.html new file mode 100644 index 0000000000..dcf6d2b9bb --- /dev/null +++ b/pr/2992/docs/iroh/discovery/pkarr/struct.PkarrResolver.html @@ -0,0 +1,46 @@ +PkarrResolver in iroh::discovery::pkarr - Rust

Struct iroh::discovery::pkarr::PkarrResolver

source ·
pub struct PkarrResolver { /* private fields */ }
Expand description

Resolver of node discovery information from a pkarr relay.

+

The resolver uses HTTP to query node discovery information from a pkarr relay server, +see the module docs for details.

+

This implements the Discovery trait to be used as a node discovery service. Note +that it only resolves node discovery information, for the corresponding publisher use +the PkarrPublisher together with ConcurrentDiscovery.

+

Implementations§

source§

impl PkarrResolver

source

pub fn new(pkarr_relay: Url) -> Self

Creates a new publisher using the pkarr relay server at the URL.

+
source

pub fn n0_dns() -> Self

Creates a pkarr resolver which uses the number 0 pkarr relay server.

+

This uses the pkarr relay server operated by number 0 at +N0_DNS_PKARR_RELAY_PROD.

+

When running with the environment variable IROH_FORCE_STAGING_RELAYS +set to any non empty value N0_DNS_PKARR_RELAY_STAGING +server is used instead.

+

Trait Implementations§

source§

impl Clone for PkarrResolver

source§

fn clone(&self) -> PkarrResolver

Returns a copy 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 PkarrResolver

source§

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

Formats the value using the given formatter. Read more
source§

impl Discovery for PkarrResolver

source§

fn resolve( + &self, + _ep: Endpoint, + node_id: NodeId +) -> Option<BoxStream<'static, Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn publish(&self, _info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/sidebar-items.js b/pr/2992/docs/iroh/discovery/sidebar-items.js new file mode 100644 index 0000000000..3c086f4eb5 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["dns","local_swarm_discovery","pkarr","static_provider"],"struct":["ConcurrentDiscovery","DiscoveryItem"],"trait":["Discovery"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/static_provider/index.html b/pr/2992/docs/iroh/discovery/static_provider/index.html new file mode 100644 index 0000000000..9c12863a51 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/static_provider/index.html @@ -0,0 +1,2 @@ +iroh::discovery::static_provider - Rust

Module iroh::discovery::static_provider

source ·
Expand description

A static discovery implementation that allows adding info for nodes manually.

+

Structs§

  • A static discovery implementation that allows providing info for nodes manually.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/static_provider/sidebar-items.js b/pr/2992/docs/iroh/discovery/static_provider/sidebar-items.js new file mode 100644 index 0000000000..5a08b73378 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/static_provider/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["StaticProvider"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/static_provider/struct.StaticProvider.html b/pr/2992/docs/iroh/discovery/static_provider/struct.StaticProvider.html new file mode 100644 index 0000000000..2534236ae0 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/static_provider/struct.StaticProvider.html @@ -0,0 +1,57 @@ +StaticProvider in iroh::discovery::static_provider - Rust

Struct iroh::discovery::static_provider::StaticProvider

source ·
pub struct StaticProvider { /* private fields */ }
Expand description

A static discovery implementation that allows providing info for nodes manually.

+

Implementations§

source§

impl StaticProvider

source

pub const PROVENANCE: &'static str = "static_discovery"

The provenance string for this discovery implementation.

+
source

pub fn new() -> Self

Create a new static discovery instance.

+
source

pub fn from_node_addrs( + infos: impl IntoIterator<Item = impl Into<NodeAddr>> +) -> Self

Creates a static discovery instance from something that can be converted into node addresses.

+

Example:

+ +
use std::str::FromStr;
+
+use iroh_base::ticket::NodeTicket;
+use iroh::{Endpoint, discovery::static_provider::StaticProvider};
+
+// get tickets from command line args
+let tickets: Vec<NodeTicket> = args.tickets;
+// create a StaticProvider from the tickets. Ticket info will be combined if multiple tickets refer to the same node.
+let discovery = StaticProvider::from_node_addrs(tickets);
+// create an endpoint with the discovery
+let endpoint = Endpoint::builder()
+    .add_discovery(|_| Some(discovery))
+    .bind().await?;
+
source

pub fn set_node_addr(&self, info: impl Into<NodeAddr>) -> Option<NodeAddr>

Add node info for the given node id.

+

This will completely overwrite any existing info for the node.

+
source

pub fn add_node_addr(&self, info: impl Into<NodeAddr>)

Add node info for the given node id, combining it with any existing info.

+

This will add any new direct addresses and overwrite the relay url.

+
source

pub fn get_node_addr(&self, node_id: NodeId) -> Option<NodeAddr>

Get node info for the given node id.

+
source

pub fn remove_node_addr(&self, node_id: NodeId) -> Option<NodeAddr>

Remove node info for the given node id.

+

Trait Implementations§

source§

impl Debug for StaticProvider

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for StaticProvider

source§

fn default() -> StaticProvider

Returns the “default value” for a type. Read more
source§

impl Discovery for StaticProvider

source§

fn publish(&self, _info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn resolve( + &self, + _endpoint: Endpoint, + node_id: NodeId +) -> Option<Boxed<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/struct.ConcurrentDiscovery.html b/pr/2992/docs/iroh/discovery/struct.ConcurrentDiscovery.html new file mode 100644 index 0000000000..381acb1df0 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/struct.ConcurrentDiscovery.html @@ -0,0 +1,36 @@ +ConcurrentDiscovery in iroh::discovery - Rust

Struct iroh::discovery::ConcurrentDiscovery

source ·
pub struct ConcurrentDiscovery { /* private fields */ }
Expand description

A discovery service that combines multiple discovery sources.

+

The discovery services will resolve concurrently.

+

Implementations§

source§

impl ConcurrentDiscovery

source

pub fn empty() -> Self

Creates an empty ConcurrentDiscovery.

+
source

pub fn from_services(services: Vec<Box<dyn Discovery>>) -> Self

Creates a new ConcurrentDiscovery.

+
source

pub fn add(&mut self, service: impl Discovery + 'static)

Adds a Discovery service.

+

Trait Implementations§

source§

impl Debug for ConcurrentDiscovery

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for ConcurrentDiscovery

source§

fn default() -> ConcurrentDiscovery

Returns the “default value” for a type. Read more
source§

impl Discovery for ConcurrentDiscovery

source§

fn publish(&self, info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism. Read more
source§

fn resolve( + &self, + endpoint: Endpoint, + node_id: NodeId +) -> Option<BoxStream<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId. Read more
source§

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered. Read more
source§

impl<T> From<T> for ConcurrentDiscovery
where + T: IntoIterator<Item = Box<dyn Discovery>>,

source§

fn from(iter: T) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/struct.DiscoveryItem.html b/pr/2992/docs/iroh/discovery/struct.DiscoveryItem.html new file mode 100644 index 0000000000..d92584473e --- /dev/null +++ b/pr/2992/docs/iroh/discovery/struct.DiscoveryItem.html @@ -0,0 +1,41 @@ +DiscoveryItem in iroh::discovery - Rust

Struct iroh::discovery::DiscoveryItem

source ·
pub struct DiscoveryItem {
+    pub node_id: NodeId,
+    pub provenance: &'static str,
+    pub last_updated: Option<u64>,
+    pub addr_info: AddrInfo,
+}
Expand description

The results returned from Discovery::resolve.

+

Fields§

§node_id: NodeId

The NodeId whose address we have discovered

+
§provenance: &'static str

A static string to identify the discovery source.

+

Should be uniform per discovery service.

+
§last_updated: Option<u64>

Optional timestamp when this node address info was last updated.

+

Must be microseconds since the unix epoch.

+
§addr_info: AddrInfo

The address info for the node being resolved.

+

Trait Implementations§

source§

impl Clone for DiscoveryItem

source§

fn clone(&self) -> DiscoveryItem

Returns a copy 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 DiscoveryItem

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/discovery/trait.Discovery.html b/pr/2992/docs/iroh/discovery/trait.Discovery.html new file mode 100644 index 0000000000..679907ced8 --- /dev/null +++ b/pr/2992/docs/iroh/discovery/trait.Discovery.html @@ -0,0 +1,50 @@ +Discovery in iroh::discovery - Rust

Trait iroh::discovery::Discovery

source ·
pub trait Discovery: Debug + Send + Sync {
+    // Provided methods
+    fn publish(&self, _info: &AddrInfo) { ... }
+    fn resolve(
+        &self,
+        _endpoint: Endpoint,
+        _node_id: NodeId
+    ) -> Option<BoxStream<Result<DiscoveryItem>>> { ... }
+    fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>> { ... }
+}
Expand description

Node discovery for super::Endpoint.

+

This trait defines publishing and resolving addressing information for a NodeId. +This enables connecting to other nodes with only knowing the NodeId, by using this +Discovery system to look up the actual addressing information. It is common for +implementations to require each node to publish their own information before it can be +looked up by other nodes.

+

The published addressing information can include both a RelayUrl and/or direct +addresses.

+

To allow for discovery, the super::Endpoint will call publish whenever +discovery information changes. If a discovery mechanism requires a periodic +refresh, it should start its own task.

+

Provided Methods§

source

fn publish(&self, _info: &AddrInfo)

Publishes the given AddrInfo to the discovery mechanism.

+

This is fire and forget, since the Endpoint can not wait for successful +publishing. If publishing is async, the implementation should start it’s own task.

+

This will be called from a tokio task, so it is safe to spawn new tasks. +These tasks will be run on the runtime of the super::Endpoint.

+
source

fn resolve( + &self, + _endpoint: Endpoint, + _node_id: NodeId +) -> Option<BoxStream<Result<DiscoveryItem>>>

Resolves the AddrInfo for the given NodeId.

+

Once the returned [BoxStream] is dropped, the service should stop any pending +work.

+
source

fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>>

Subscribe to all addresses that get passively discovered.

+

An implementation may choose to defer emitting passively discovered nodes +until the stream is actually polled. To avoid missing discovered nodes, +poll the stream as soon as possible.

+

If you do not regularly poll the stream, you may miss discovered nodes.

+

Any discovery systems that only discover when explicitly resolving a +specific NodeId do not need to implement this method. Any nodes or +addresses that are discovered by calling resolve should NOT be added +to the subscribe stream.

+

Discovery systems that are capable of receiving information about NodeIds +and their AddrInfos without explicitly calling resolve, i.e., +systems that do “passive” discovery, should implement this method. If +subscribe is called multiple times, the passively discovered addresses +should be sent on all streams.

+

The crate::endpoint::Endpoint will subscribe to the discovery system +and add the discovered addresses to the internal address book as they arrive +on this stream.

+

Implementors§

source§

impl Discovery for DnsDiscovery

source§

impl Discovery for LocalSwarmDiscovery

Available on crate feature discovery-local-network only.
source§

impl Discovery for DhtDiscovery

Available on crate feature discovery-pkarr-dht only.
source§

impl Discovery for PkarrPublisher

source§

impl Discovery for PkarrResolver

source§

impl Discovery for StaticProvider

source§

impl Discovery for ConcurrentDiscovery

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/fn.default_resolver.html b/pr/2992/docs/iroh/dns/fn.default_resolver.html new file mode 100644 index 0000000000..21098ab462 --- /dev/null +++ b/pr/2992/docs/iroh/dns/fn.default_resolver.html @@ -0,0 +1,4 @@ +default_resolver in iroh::dns - Rust

Function iroh::dns::default_resolver

source ·
pub fn default_resolver() -> &'static DnsResolver
Expand description

Get a reference to the default DNS resolver.

+

The default resolver can be cheaply cloned and is shared throughout the running process. +It is configured to use the system’s DNS configuration.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/fn.resolver.html b/pr/2992/docs/iroh/dns/fn.resolver.html new file mode 100644 index 0000000000..1e4acbf2eb --- /dev/null +++ b/pr/2992/docs/iroh/dns/fn.resolver.html @@ -0,0 +1,2 @@ +resolver in iroh::dns - Rust

Function iroh::dns::resolver

source ·
pub fn resolver() -> &'static TokioAsyncResolver
Expand description

Get the DNS resolver used within iroh.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/index.html b/pr/2992/docs/iroh/dns/index.html new file mode 100644 index 0000000000..bb7e1020a6 --- /dev/null +++ b/pr/2992/docs/iroh/dns/index.html @@ -0,0 +1,6 @@ +iroh::dns - Rust

Module iroh::dns

source ·
Expand description

This module exports a DNS resolver, which is also the default resolver used in the +crate::Endpoint if no custom resolver is configured.

+

It also exports ResolverExt: A extension trait over DnsResolver to perform DNS queries +by ipv4, ipv6, name and node_id. See the node_info module documentation for details on how +iroh node records are structured.

+

Modules§

Traits§

Functions§

Type Aliases§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/constant.IROH_TXT_NAME.html b/pr/2992/docs/iroh/dns/node_info/constant.IROH_TXT_NAME.html new file mode 100644 index 0000000000..a8023972cf --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/constant.IROH_TXT_NAME.html @@ -0,0 +1,2 @@ +IROH_TXT_NAME in iroh::dns::node_info - Rust

Constant iroh::dns::node_info::IROH_TXT_NAME

source ·
pub const IROH_TXT_NAME: &str = "_iroh";
Expand description

The DNS name for the iroh TXT record.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/enum.IrohAttr.html b/pr/2992/docs/iroh/dns/node_info/enum.IrohAttr.html new file mode 100644 index 0000000000..dfe0271ed1 --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/enum.IrohAttr.html @@ -0,0 +1,49 @@ +IrohAttr in iroh::dns::node_info - Rust

Enum iroh::dns::node_info::IrohAttr

source ·
pub enum IrohAttr {
+    Relay,
+    Addr,
+}
Expand description

The attributes supported by iroh for IROH_TXT_NAME DNS resource records.

+

The resource record uses the lower-case names.

+

Variants§

§

Relay

URL of home relay.

+
§

Addr

Direct address.

+

Trait Implementations§

source§

impl AsRef<str> for IrohAttr

source§

fn as_ref(&self) -> &str

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Debug for IrohAttr

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for IrohAttr

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for IrohAttr

§

type Err = ParseError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<IrohAttr, <Self as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for IrohAttr

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for IrohAttr

source§

fn cmp(&self, other: &IrohAttr) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for IrohAttr

source§

fn eq(&self, other: &IrohAttr) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for IrohAttr

source§

fn partial_cmp(&self, other: &IrohAttr) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl TryFrom<&str> for IrohAttr

§

type Error = ParseError

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

fn try_from(s: &str) -> Result<IrohAttr, <Self as TryFrom<&str>>::Error>

Performs the conversion.
source§

impl Eq for IrohAttr

source§

impl StructuralPartialEq for IrohAttr

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/fn.from_z32.html b/pr/2992/docs/iroh/dns/node_info/fn.from_z32.html new file mode 100644 index 0000000000..1405fae0cd --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/fn.from_z32.html @@ -0,0 +1,2 @@ +from_z32 in iroh::dns::node_info - Rust

Function iroh::dns::node_info::from_z32

source ·
pub fn from_z32(s: &str) -> Result<NodeId>
Expand description

Parses a NodeId from [z-base-32] encoding.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/fn.to_z32.html b/pr/2992/docs/iroh/dns/node_info/fn.to_z32.html new file mode 100644 index 0000000000..0434366951 --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/fn.to_z32.html @@ -0,0 +1,2 @@ +to_z32 in iroh::dns::node_info - Rust

Function iroh::dns::node_info::to_z32

source ·
pub fn to_z32(node_id: &NodeId) -> String
Expand description

Encodes a NodeId in [z-base-32] encoding.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/index.html b/pr/2992/docs/iroh/dns/node_info/index.html new file mode 100644 index 0000000000..921d657762 --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/index.html @@ -0,0 +1,33 @@ +iroh::dns::node_info - Rust

Module iroh::dns::node_info

source ·
Expand description

Support for handling DNS resource records for dialing by NodeId.

+

Dialing by NodeId is supported by iroh nodes publishing Pkarr records to DNS +servers or the Mainline DHT. This module supports creating and parsing these records.

+

DNS records are published under the following names:

+

_iroh.<z32-node-id>.<origin-domain> TXT

+ +

The returned TXT records must contain a string value of the form key=value as defined +in RFC1464. The following attributes are defined:

+
    +
  • +

    relay=<url>: The home RelayUrl of this node.

    +
  • +
  • +

    addr=<addr> <addr>: A space-separated list of sockets addresses for this iroh node. +Each address is an IPv4 or IPv6 address with a port.

    +
  • +
+

Structs§

Enums§

Constants§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/sidebar-items.js b/pr/2992/docs/iroh/dns/node_info/sidebar-items.js new file mode 100644 index 0000000000..94bdeea4ac --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["IROH_TXT_NAME"],"enum":["IrohAttr"],"fn":["from_z32","to_z32"],"struct":["NodeInfo","TxtAttrs"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/struct.NodeInfo.html b/pr/2992/docs/iroh/dns/node_info/struct.NodeInfo.html new file mode 100644 index 0000000000..bd0113ec90 --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/struct.NodeInfo.html @@ -0,0 +1,61 @@ +NodeInfo in iroh::dns::node_info - Rust

Struct iroh::dns::node_info::NodeInfo

source ·
pub struct NodeInfo {
+    pub node_id: NodeId,
+    pub relay_url: Option<Url>,
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
Expand description

Information about the iroh node contained in an IROH_TXT_NAME TXT resource record.

+

Fields§

§node_id: NodeId

The NodeId.

+
§relay_url: Option<Url>

The advertised home relay server.

+
§direct_addresses: BTreeSet<SocketAddr>

Any direct addresses.

+

Implementations§

source§

impl NodeInfo

source

pub fn new( + node_id: NodeId, + relay_url: Option<Url>, + direct_addresses: BTreeSet<SocketAddr> +) -> Self

Creates a new NodeInfo from its parts.

+
source

pub fn from_hickory_records(records: &[Record]) -> Result<Self>

Parses a NodeInfo from a set of DNS records.

+
source

pub fn from_pkarr_signed_packet(packet: &SignedPacket) -> Result<Self>

Parses a NodeInfo from a [pkarr::SignedPacket].

+
source

pub fn to_pkarr_signed_packet( + &self, + secret_key: &SecretKey, + ttl: u32 +) -> Result<SignedPacket>

Creates a [pkarr::SignedPacket].

+

This constructs a DNS packet and signs it with a SecretKey.

+
source

pub fn to_hickory_records( + &self, + origin: &str, + ttl: u32 +) -> Result<impl Iterator<Item = Record> + 'static>

Converts into a [hickory_proto::rr::Record] DNS record.

+

Trait Implementations§

source§

impl Clone for NodeInfo

source§

fn clone(&self) -> NodeInfo

Returns a copy 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 NodeInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl From<&NodeInfo> for TxtAttrs<IrohAttr>

source§

fn from(info: &NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<&TxtAttrs<IrohAttr>> for NodeInfo

source§

fn from(attrs: &TxtAttrs<IrohAttr>) -> Self

Converts to this type from the input type.
source§

impl From<NodeInfo> for AddrInfo

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<NodeInfo> for NodeAddr

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<TxtAttrs<IrohAttr>> for NodeInfo

source§

fn from(attrs: TxtAttrs<IrohAttr>) -> Self

Converts to this type from the input type.
source§

impl PartialEq for NodeInfo

source§

fn eq(&self, other: &NodeInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for NodeInfo

source§

impl StructuralPartialEq for NodeInfo

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/node_info/struct.TxtAttrs.html b/pr/2992/docs/iroh/dns/node_info/struct.TxtAttrs.html new file mode 100644 index 0000000000..04b2767fe7 --- /dev/null +++ b/pr/2992/docs/iroh/dns/node_info/struct.TxtAttrs.html @@ -0,0 +1,66 @@ +TxtAttrs in iroh::dns::node_info - Rust

Struct iroh::dns::node_info::TxtAttrs

source ·
pub struct TxtAttrs<T> { /* private fields */ }
Expand description

Attributes parsed from IROH_TXT_NAME TXT records.

+

This struct is generic over the key type. When using with String, this will parse +all attributes. Can also be used with an enum, if it implements FromStr and +Display.

+

Implementations§

source§

impl<T: FromStr + Display + Hash + Ord> TxtAttrs<T>

source

pub fn from_parts( + node_id: NodeId, + pairs: impl Iterator<Item = (T, String)> +) -> Self

Creates TxtAttrs from a node id and an iterator of key-value pairs.

+
source

pub fn from_strings( + node_id: NodeId, + strings: impl Iterator<Item = String> +) -> Result<Self>

Creates TxtAttrs from a node id and an iterator of “{key}={value}” strings.

+
source

pub async fn lookup_by_id( + resolver: &TokioAsyncResolver, + node_id: &NodeId, + origin: &str +) -> Result<Self>

Looks up attributes by NodeId and origin domain.

+
source

pub async fn lookup_by_name( + resolver: &TokioAsyncResolver, + name: &str +) -> Result<Self>

Looks up attributes by DNS name.

+
source

pub fn attrs(&self) -> &BTreeMap<T, Vec<String>>

Returns the parsed attributes.

+
source

pub fn node_id(&self) -> NodeId

Returns the node id.

+
source

pub fn from_pkarr_signed_packet(packet: &SignedPacket) -> Result<Self>

Parses a [pkarr::SignedPacket].

+
source

pub fn from_hickory_records(records: &[Record]) -> Result<Self>

Parses a set of DNS resource records.

+
source

pub fn to_hickory_records( + &self, + origin: &str, + ttl: u32 +) -> Result<impl Iterator<Item = Record> + '_>

Converts to a list of [hickory_proto::rr::Record] resource records.

+
source

pub fn to_pkarr_signed_packet( + &self, + secret_key: &SecretKey, + ttl: u32 +) -> Result<SignedPacket>

Creates a [pkarr::SignedPacket]

+

This constructs a DNS packet and signs it with a SecretKey.

+

Trait Implementations§

source§

impl<T: Debug> Debug for TxtAttrs<T>

source§

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

Formats the value using the given formatter. Read more
source§

impl From<&NodeInfo> for TxtAttrs<IrohAttr>

source§

fn from(info: &NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<&TxtAttrs<IrohAttr>> for NodeInfo

source§

fn from(attrs: &TxtAttrs<IrohAttr>) -> Self

Converts to this type from the input type.
source§

impl From<TxtAttrs<IrohAttr>> for NodeInfo

source§

fn from(attrs: TxtAttrs<IrohAttr>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> Freeze for TxtAttrs<T>

§

impl<T> RefUnwindSafe for TxtAttrs<T>
where + T: RefUnwindSafe,

§

impl<T> Send for TxtAttrs<T>
where + T: Send,

§

impl<T> Sync for TxtAttrs<T>
where + T: Sync,

§

impl<T> Unpin for TxtAttrs<T>

§

impl<T> UnwindSafe for TxtAttrs<T>
where + T: RefUnwindSafe,

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/sidebar-items.js b/pr/2992/docs/iroh/dns/sidebar-items.js new file mode 100644 index 0000000000..46815808f2 --- /dev/null +++ b/pr/2992/docs/iroh/dns/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["default_resolver","resolver"],"mod":["node_info"],"trait":["ResolverExt"],"type":["DnsResolver"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/trait.ResolverExt.html b/pr/2992/docs/iroh/dns/trait.ResolverExt.html new file mode 100644 index 0000000000..46fe0c83f7 --- /dev/null +++ b/pr/2992/docs/iroh/dns/trait.ResolverExt.html @@ -0,0 +1,128 @@ +ResolverExt in iroh::dns - Rust

Trait iroh::dns::ResolverExt

source ·
pub trait ResolverExt {
+    // Required methods
+    fn lookup_ipv4<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_ipv6<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_ipv4_ipv6<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_by_name(
+        &self,
+        name: &str
+    ) -> impl Future<Output = Result<NodeAddr>>;
+    fn lookup_by_id(
+        &self,
+        node_id: &NodeId,
+        origin: &str
+    ) -> impl Future<Output = Result<NodeAddr>>;
+    fn lookup_ipv4_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64]
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64]
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64]
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+    fn lookup_by_name_staggered(
+        &self,
+        name: &str,
+        delays_ms: &[u64]
+    ) -> impl Future<Output = Result<NodeAddr>>;
+    fn lookup_by_id_staggered(
+        &self,
+        node_id: &NodeId,
+        origin: &str,
+        delays_ms: &[u64]
+    ) -> impl Future<Output = Result<NodeAddr>>;
+}
Expand description

Extension trait to DnsResolver.

+

Required Methods§

source

fn lookup_ipv4<N: IntoName>( + &self, + host: N, + timeout: Duration +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Perform an ipv4 lookup with a timeout.

+
source

fn lookup_ipv6<N: IntoName>( + &self, + host: N, + timeout: Duration +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Perform an ipv6 lookup with a timeout.

+
source

fn lookup_ipv4_ipv6<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Race an ipv4 and ipv6 lookup with a timeout.

+
source

fn lookup_by_name(&self, name: &str) -> impl Future<Output = Result<NodeAddr>>

Looks up node info by DNS name.

+
source

fn lookup_by_id( + &self, + node_id: &NodeId, + origin: &str +) -> impl Future<Output = Result<NodeAddr>>

Looks up node info by NodeId and origin domain name.

+
source

fn lookup_ipv4_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Perform an ipv4 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied to each call individually. The +result of the first successful call is returned, or a summary of all errors otherwise.

+
source

fn lookup_ipv6_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Perform an ipv6 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied to each call individually. The +result of the first successful call is returned, or a summary of all errors otherwise.

+
source

fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>

Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied as stated in +Self::lookup_ipv4_ipv6. The result of the first successful call is returned, or a +summary of all errors otherwise.

+
source

fn lookup_by_name_staggered( + &self, + name: &str, + delays_ms: &[u64] +) -> impl Future<Output = Result<NodeAddr>>

Looks up node info by DNS name in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a +summary of all errors otherwise.

+
source

fn lookup_by_id_staggered( + &self, + node_id: &NodeId, + origin: &str, + delays_ms: &[u64] +) -> impl Future<Output = Result<NodeAddr>>

Looks up node info by NodeId and origin domain name.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a +summary of all errors otherwise.

+

Object Safety§

This trait is not object safe.

Implementors§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/dns/type.DnsResolver.html b/pr/2992/docs/iroh/dns/type.DnsResolver.html new file mode 100644 index 0000000000..461868a268 --- /dev/null +++ b/pr/2992/docs/iroh/dns/type.DnsResolver.html @@ -0,0 +1,72 @@ +DnsResolver in iroh::dns - Rust

Type Alias iroh::dns::DnsResolver

source ·
pub type DnsResolver = TokioAsyncResolver;
Expand description

The DNS resolver type used throughout iroh.

+

Aliased Type§

struct DnsResolver { /* private fields */ }

Trait Implementations§

source§

impl ResolverExt for DnsResolver

source§

async fn lookup_ipv4_ipv6<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration +) -> Result<impl Iterator<Item = IpAddr>>

Resolve IPv4 and IPv6 in parallel.

+

LookupIpStrategy::Ipv4AndIpv6 will wait for ipv6 resolution timeout, even if it is +not usable on the stack, so we manually query both lookups concurrently and time them out +individually.

+
source§

async fn lookup_by_name(&self, name: &str) -> Result<NodeAddr>

Looks up node info by DNS name.

+

The resource records returned for name must either contain an node_info::IROH_TXT_NAME TXT +record or be a CNAME record that leads to an node_info::IROH_TXT_NAME TXT record.

+
source§

async fn lookup_by_id(&self, node_id: &NodeId, origin: &str) -> Result<NodeAddr>

Looks up node info by NodeId and origin domain name.

+
source§

async fn lookup_ipv4_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> Result<impl Iterator<Item = IpAddr>>

Perform an ipv4 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied to each call individually. The +result of the first successful call is returned, or a summary of all errors otherwise.

+
source§

async fn lookup_ipv6_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> Result<impl Iterator<Item = IpAddr>>

Perform an ipv6 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied to each call individually. The +result of the first successful call is returned, or a summary of all errors otherwise.

+
source§

async fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>( + &self, + host: N, + timeout: Duration, + delays_ms: &[u64] +) -> Result<impl Iterator<Item = IpAddr>>

Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The timeout is applied as stated in +[Self::lookup_ipv4_ipv6]. The result of the first successful call is returned, or a +summary of all errors otherwise.

+
source§

async fn lookup_by_name_staggered( + &self, + name: &str, + delays_ms: &[u64] +) -> Result<NodeAddr>

Looks up node info by DNS name in a staggered fashion.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a +summary of all errors otherwise.

+
source§

async fn lookup_by_id_staggered( + &self, + node_id: &NodeId, + origin: &str, + delays_ms: &[u64] +) -> Result<NodeAddr>

Looks up node info by NodeId and origin domain name.

+

From the moment this function is called, each lookup is scheduled after the delays in +delays_ms with the first call being done immediately. [200ms, 300ms] results in calls +at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a +summary of all errors otherwise.

+
source§

async fn lookup_ipv4<N: IntoName>( + &self, + host: N, + timeout: Duration +) -> Result<impl Iterator<Item = IpAddr>>

Perform an ipv4 lookup with a timeout.
source§

async fn lookup_ipv6<N: IntoName>( + &self, + host: N, + timeout: Duration +) -> Result<impl Iterator<Item = IpAddr>>

Perform an ipv6 lookup with a timeout.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/constant.ENV_FORCE_STAGING_RELAYS.html b/pr/2992/docs/iroh/endpoint/constant.ENV_FORCE_STAGING_RELAYS.html new file mode 100644 index 0000000000..a9ad41e62c --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/constant.ENV_FORCE_STAGING_RELAYS.html @@ -0,0 +1,2 @@ +ENV_FORCE_STAGING_RELAYS in iroh::endpoint - Rust

Constant iroh::endpoint::ENV_FORCE_STAGING_RELAYS

source ·
pub const ENV_FORCE_STAGING_RELAYS: &str = "IROH_FORCE_STAGING_RELAYS";
Available on non-test only.
Expand description

Environment variable to force the use of staging relays.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.AddrInfoOptions.html b/pr/2992/docs/iroh/endpoint/enum.AddrInfoOptions.html new file mode 100644 index 0000000000..6b39677a2a --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.AddrInfoOptions.html @@ -0,0 +1,57 @@ +AddrInfoOptions in iroh::endpoint - Rust

Enum iroh::endpoint::AddrInfoOptions

source ·
pub enum AddrInfoOptions {
+    Id,
+    RelayAndAddresses,
+    Relay,
+    Addresses,
+}
Expand description

Options to configure what is included in a NodeAddr and AddrInfo.

+

Variants§

§

Id

Only the Node ID is added.

+

This usually means that iroh-dns discovery is used to find address information.

+
§

RelayAndAddresses

Includes the Node ID and both the relay URL, and the direct addresses.

+
§

Relay

Includes the Node ID and the relay URL.

+
§

Addresses

Includes the Node ID and the direct addresses.

+

Trait Implementations§

source§

impl Clone for AddrInfoOptions

source§

fn clone(&self) -> AddrInfoOptions

Returns a copy 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 AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfoOptions

source§

fn default() -> AddrInfoOptions

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfoOptions

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<AddrInfoOptions, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for AddrInfoOptions

§

type Err = FromStrError

The associated error which can be returned from parsing.
source§

fn from_str( + src: &str +) -> Result<AddrInfoOptions, <AddrInfoOptions as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for AddrInfoOptions

source§

fn eq(&self, other: &AddrInfoOptions) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for AddrInfoOptions

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for AddrInfoOptions

source§

impl Eq for AddrInfoOptions

source§

impl StructuralPartialEq for AddrInfoOptions

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ConnectionError.html b/pr/2992/docs/iroh/endpoint/enum.ConnectionError.html new file mode 100644 index 0000000000..3f1f5872df --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ConnectionError.html @@ -0,0 +1,58 @@ +ConnectionError in iroh::endpoint - Rust

Enum iroh::endpoint::ConnectionError

pub enum ConnectionError {
+    VersionMismatch,
+    TransportError(Error),
+    ConnectionClosed(ConnectionClose),
+    ApplicationClosed(ApplicationClose),
+    Reset,
+    TimedOut,
+    LocallyClosed,
+    CidsExhausted,
+}
Expand description

Reasons why a connection might be lost

+

Variants§

§

VersionMismatch

The peer doesn’t implement any supported version

+
§

TransportError(Error)

The peer violated the QUIC specification as understood by this implementation

+
§

ConnectionClosed(ConnectionClose)

The peer’s QUIC stack aborted the connection automatically

+
§

ApplicationClosed(ApplicationClose)

The peer closed the connection

+
§

Reset

The peer is unable to continue processing this connection, usually due to having restarted

+
§

TimedOut

Communication with the peer has lapsed for longer than the negotiated idle timeout

+

If neither side is sending keep-alives, a connection will time out after a long enough idle +period even if the peer is still reachable. See also TransportConfig::max_idle_timeout() +and TransportConfig::keep_alive_interval().

+
§

LocallyClosed

The local application closed the connection

+
§

CidsExhausted

The connection could not be created because not enough of the CID space is available

+

Try using longer connection IDs.

+

Trait Implementations§

§

impl Clone for ConnectionError

§

fn clone(&self) -> ConnectionError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ConnectionError

§

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

Formats the value using the given formatter. Read more
§

impl Display for ConnectionError

§

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

Formats the value using the given formatter. Read more
§

impl Error for ConnectionError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<Close> for ConnectionError

§

fn from(x: Close) -> ConnectionError

Converts to this type from the input type.
§

impl From<ConnectionError> for ReadError

§

fn from(source: ConnectionError) -> ReadError

Converts to this type from the input type.
§

impl From<ConnectionError> for ResetError

§

fn from(source: ConnectionError) -> ResetError

Converts to this type from the input type.
§

impl From<ConnectionError> for SendDatagramError

§

fn from(source: ConnectionError) -> SendDatagramError

Converts to this type from the input type.
§

impl From<ConnectionError> for StoppedError

§

fn from(source: ConnectionError) -> StoppedError

Converts to this type from the input type.
§

impl From<ConnectionError> for WriteError

§

fn from(source: ConnectionError) -> WriteError

Converts to this type from the input type.
§

impl From<Error> for ConnectionError

§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
§

impl PartialEq for ConnectionError

§

fn eq(&self, other: &ConnectionError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ConnectionError

§

impl StructuralPartialEq for ConnectionError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ConnectionType.html b/pr/2992/docs/iroh/endpoint/enum.ConnectionType.html new file mode 100644 index 0000000000..62fa6dc269 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ConnectionType.html @@ -0,0 +1,51 @@ +ConnectionType in iroh::endpoint - Rust

Enum iroh::endpoint::ConnectionType

source ·
pub enum ConnectionType {
+    Direct(SocketAddr),
+    Relay(RelayUrl),
+    Mixed(SocketAddr, RelayUrl),
+    None,
+}
Expand description

The type of connection we have to the endpoint.

+

Variants§

§

Direct(SocketAddr)

Direct UDP connection

+
§

Relay(RelayUrl)

Relay connection over relay

+
§

Mixed(SocketAddr, RelayUrl)

Both a UDP and a relay connection are used.

+

This is the case if we do have a UDP address, but are missing a recent confirmation that +the address works.

+
§

None

We have no verified connection to this PublicKey

+

Trait Implementations§

source§

impl Clone for ConnectionType

source§

fn clone(&self) -> ConnectionType

Returns a copy 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 ConnectionType

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for ConnectionType

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for ConnectionType

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for ConnectionType

source§

fn eq(&self, other: &ConnectionType) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for ConnectionType

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for ConnectionType

source§

impl StructuralPartialEq for ConnectionType

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ControlMsg.html b/pr/2992/docs/iroh/endpoint/enum.ControlMsg.html new file mode 100644 index 0000000000..a7dbfdfc5c --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ControlMsg.html @@ -0,0 +1,47 @@ +ControlMsg in iroh::endpoint - Rust

Enum iroh::endpoint::ControlMsg

source ·
pub enum ControlMsg {
+    Ping,
+    Pong,
+    CallMeMaybe,
+}
Expand description

The type of control message we have received.

+

Variants§

§

Ping

We received a Ping from the node.

+
§

Pong

We received a Pong from the node.

+
§

CallMeMaybe

We received a CallMeMaybe.

+

Trait Implementations§

source§

impl Clone for ControlMsg

source§

fn clone(&self) -> ControlMsg

Returns a copy 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 ControlMsg

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for ControlMsg

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for ControlMsg

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for ControlMsg

source§

fn eq(&self, other: &ControlMsg) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for ControlMsg

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for ControlMsg

source§

impl Eq for ControlMsg

source§

impl StructuralPartialEq for ControlMsg

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.DirectAddrType.html b/pr/2992/docs/iroh/endpoint/enum.DirectAddrType.html new file mode 100644 index 0000000000..bf749f148e --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.DirectAddrType.html @@ -0,0 +1,68 @@ +DirectAddrType in iroh::endpoint - Rust

Enum iroh::endpoint::DirectAddrType

source ·
pub enum DirectAddrType {
+    Unknown,
+    Local,
+    Stun,
+    Portmapped,
+    Stun4LocalPort,
+}
Expand description

The type of direct address.

+

These are the various sources or origins from which an iroh node might have found a +possible DirectAddr.

+

Variants§

§

Unknown

Not yet determined..

+
§

Local

A locally bound socket address.

+
§

Stun

Public internet address discovered via STUN.

+

When possible an iroh node will perform STUN to discover which is the address +from which it sends data on the public internet. This can be different from locally +bound addresses when the node is on a local network which performs NAT or similar.

+
§

Portmapped

An address assigned by the router using port mapping.

+

When possible an iroh node will request a port mapping from the local router to +get a publicly routable direct address.

+
§

Stun4LocalPort

Hard NAT: STUN’ed IPv4 address + local fixed port.

+

It is possible to configure iroh to bound to a specific port and independently +configure the router to forward this port to the iroh node. This indicates a +situation like this, which still uses STUN to discover the public address.

+

Trait Implementations§

source§

impl Clone for DirectAddrType

source§

fn clone(&self) -> DirectAddrType

Returns a copy 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 DirectAddrType

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for DirectAddrType

source§

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

Formats the value using the given formatter. Read more
source§

impl Hash for DirectAddrType

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for DirectAddrType

source§

fn cmp(&self, other: &DirectAddrType) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for DirectAddrType

source§

fn eq(&self, other: &DirectAddrType) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for DirectAddrType

source§

fn partial_cmp(&self, other: &DirectAddrType) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Copy for DirectAddrType

source§

impl Eq for DirectAddrType

source§

impl StructuralPartialEq for DirectAddrType

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ReadError.html b/pr/2992/docs/iroh/endpoint/enum.ReadError.html new file mode 100644 index 0000000000..c0002142ae --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ReadError.html @@ -0,0 +1,53 @@ +ReadError in iroh::endpoint - Rust

Enum iroh::endpoint::ReadError

pub enum ReadError {
+    Reset(VarInt),
+    ConnectionLost(ConnectionError),
+    ClosedStream,
+    IllegalOrderedRead,
+    ZeroRttRejected,
+}
Expand description

Errors that arise from reading from a stream.

+

Variants§

§

Reset(VarInt)

The peer abandoned transmitting data on this stream

+

Carries an application-defined error code.

+
§

ConnectionLost(ConnectionError)

The connection was lost

+
§

ClosedStream

The stream has already been stopped, finished, or reset

+
§

IllegalOrderedRead

Attempted an ordered read following an unordered read

+

Performing an unordered read allows discontinuities to arise in the receive buffer of a +stream which cannot be recovered, making further ordered reads impossible.

+
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

+

Can only occur on clients for 0-RTT streams, which can be opened using +Connecting::into_0rtt().

+

Trait Implementations§

§

impl Clone for ReadError

§

fn clone(&self) -> ReadError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ReadError

§

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

Formats the value using the given formatter. Read more
§

impl Display for ReadError

§

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

Formats the value using the given formatter. Read more
§

impl Error for ReadError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ConnectionError> for ReadError

§

fn from(source: ConnectionError) -> ReadError

Converts to this type from the input type.
§

impl From<ReadError> for ReadExactError

§

fn from(source: ReadError) -> ReadExactError

Converts to this type from the input type.
§

impl From<ReadError> for ReadToEndError

§

fn from(source: ReadError) -> ReadToEndError

Converts to this type from the input type.
§

impl From<ReadableError> for ReadError

§

fn from(e: ReadableError) -> ReadError

Converts to this type from the input type.
§

impl From<ResetError> for ReadError

§

fn from(e: ResetError) -> ReadError

Converts to this type from the input type.
§

impl PartialEq for ReadError

§

fn eq(&self, other: &ReadError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ReadError

§

impl StructuralPartialEq for ReadError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ReadExactError.html b/pr/2992/docs/iroh/endpoint/enum.ReadExactError.html new file mode 100644 index 0000000000..84dc959669 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ReadExactError.html @@ -0,0 +1,42 @@ +ReadExactError in iroh::endpoint - Rust

Enum iroh::endpoint::ReadExactError

pub enum ReadExactError {
+    FinishedEarly(usize),
+    ReadError(ReadError),
+}
Expand description

Errors that arise from reading from a stream.

+

Variants§

§

FinishedEarly(usize)

The stream finished before all bytes were read

+
§

ReadError(ReadError)

A read error occurred

+

Trait Implementations§

§

impl Clone for ReadExactError

§

fn clone(&self) -> ReadExactError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ReadExactError

§

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

Formats the value using the given formatter. Read more
§

impl Display for ReadExactError

§

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

Formats the value using the given formatter. Read more
§

impl Error for ReadExactError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ReadError> for ReadExactError

§

fn from(source: ReadError) -> ReadExactError

Converts to this type from the input type.
§

impl PartialEq for ReadExactError

§

fn eq(&self, other: &ReadExactError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ReadExactError

§

impl StructuralPartialEq for ReadExactError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ReadToEndError.html b/pr/2992/docs/iroh/endpoint/enum.ReadToEndError.html new file mode 100644 index 0000000000..ae1cca8c38 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ReadToEndError.html @@ -0,0 +1,42 @@ +ReadToEndError in iroh::endpoint - Rust

Enum iroh::endpoint::ReadToEndError

pub enum ReadToEndError {
+    Read(ReadError),
+    TooLong,
+}
Expand description

Variants§

§

Read(ReadError)

An error occurred during reading

+
§

TooLong

The stream is larger than the user-supplied limit

+

Trait Implementations§

§

impl Clone for ReadToEndError

§

fn clone(&self) -> ReadToEndError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ReadToEndError

§

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

Formats the value using the given formatter. Read more
§

impl Display for ReadToEndError

§

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

Formats the value using the given formatter. Read more
§

impl Error for ReadToEndError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ReadError> for ReadToEndError

§

fn from(source: ReadError) -> ReadToEndError

Converts to this type from the input type.
§

impl PartialEq for ReadToEndError

§

fn eq(&self, other: &ReadToEndError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ReadToEndError

§

impl StructuralPartialEq for ReadToEndError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.RelayMode.html b/pr/2992/docs/iroh/endpoint/enum.RelayMode.html new file mode 100644 index 0000000000..4023c69a76 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.RelayMode.html @@ -0,0 +1,47 @@ +RelayMode in iroh::endpoint - Rust

Enum iroh::endpoint::RelayMode

source ·
pub enum RelayMode {
+    Disabled,
+    Default,
+    Staging,
+    Custom(RelayMap),
+}
Expand description

Configuration of the relay servers for an Endpoint.

+

Variants§

§

Disabled

Disable relay servers completely.

+
§

Default

Use the default relay map, with production relay servers from n0.

+

See crate::defaults::prod for the severs used.

+
§

Staging

Use the staging relay servers from n0.

+
§

Custom(RelayMap)

Use a custom relay map.

+

Implementations§

source§

impl RelayMode

source

pub fn relay_map(&self) -> RelayMap

Returns the relay map for this mode.

+

Trait Implementations§

source§

impl Clone for RelayMode

source§

fn clone(&self) -> RelayMode

Returns a copy 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 RelayMode

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for RelayMode

source§

fn eq(&self, other: &RelayMode) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RelayMode

source§

impl StructuralPartialEq for RelayMode

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.ResetError.html b/pr/2992/docs/iroh/endpoint/enum.ResetError.html new file mode 100644 index 0000000000..d0d61168c2 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.ResetError.html @@ -0,0 +1,44 @@ +ResetError in iroh::endpoint - Rust

Enum iroh::endpoint::ResetError

pub enum ResetError {
+    ConnectionLost(ConnectionError),
+    ZeroRttRejected,
+}
Expand description

Errors that arise while waiting for a stream to be reset

+

Variants§

§

ConnectionLost(ConnectionError)

The connection was lost

+
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

+

Can only occur on clients for 0-RTT streams, which can be opened using +Connecting::into_0rtt().

+

Trait Implementations§

§

impl Clone for ResetError

§

fn clone(&self) -> ResetError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ResetError

§

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

Formats the value using the given formatter. Read more
§

impl Display for ResetError

§

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

Formats the value using the given formatter. Read more
§

impl Error for ResetError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ConnectionError> for ResetError

§

fn from(source: ConnectionError) -> ResetError

Converts to this type from the input type.
§

impl From<ResetError> for ReadError

§

fn from(e: ResetError) -> ReadError

Converts to this type from the input type.
§

impl PartialEq for ResetError

§

fn eq(&self, other: &ResetError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ResetError

§

impl StructuralPartialEq for ResetError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.SendDatagramError.html b/pr/2992/docs/iroh/endpoint/enum.SendDatagramError.html new file mode 100644 index 0000000000..9caf659588 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.SendDatagramError.html @@ -0,0 +1,48 @@ +SendDatagramError in iroh::endpoint - Rust

Enum iroh::endpoint::SendDatagramError

pub enum SendDatagramError {
+    UnsupportedByPeer,
+    Disabled,
+    TooLarge,
+    ConnectionLost(ConnectionError),
+}
Expand description

Errors that can arise when sending a datagram

+

Variants§

§

UnsupportedByPeer

The peer does not support receiving datagram frames

+
§

Disabled

Datagram support is disabled locally

+
§

TooLarge

The datagram is larger than the connection can currently accommodate

+

Indicates that the path MTU minus overhead or the limit advertised by the peer has been +exceeded.

+
§

ConnectionLost(ConnectionError)

The connection was lost

+

Trait Implementations§

§

impl Clone for SendDatagramError

§

fn clone(&self) -> SendDatagramError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for SendDatagramError

§

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

Formats the value using the given formatter. Read more
§

impl Display for SendDatagramError

§

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

Formats the value using the given formatter. Read more
§

impl Error for SendDatagramError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ConnectionError> for SendDatagramError

§

fn from(source: ConnectionError) -> SendDatagramError

Converts to this type from the input type.
§

impl PartialEq for SendDatagramError

§

fn eq(&self, other: &SendDatagramError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for SendDatagramError

§

impl StructuralPartialEq for SendDatagramError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.Source.html b/pr/2992/docs/iroh/endpoint/enum.Source.html new file mode 100644 index 0000000000..7410857bc5 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.Source.html @@ -0,0 +1,73 @@ +Source in iroh::endpoint - Rust

Enum iroh::endpoint::Source

source ·
pub enum Source {
+    Saved,
+    Udp,
+    Relay,
+    App,
+    Discovery {
+        name: String,
+    },
+    NamedApp {
+        name: String,
+    },
+}
Expand description

The origin or source through which an address associated with a remote node +was discovered.

+

An aggregate of the Sources of all the addresses of a node describe the +Sources of the node itself.

+

A Source helps track how and where an address was learned. Multiple +sources can be associated with a single address, if we have discovered this +address through multiple means.

+

Each time a NodeAddr is added to the node map, usually through +crate::endpoint::Endpoint::add_node_addr_with_source, a Source must be supplied to indicate +how the address was obtained.

+

A Source can describe a variety of places that an address or node was +discovered, such as a configured discovery service, the network itself +(if another node has reached out to us), or as a user supplied NodeAddr.

+

Variants§

§

Saved

Address was loaded from the fs.

+
§

Udp

A node communicated with us first via UDP.

+
§

Relay

A node communicated with us first via relay.

+
§

App

Application layer added the address directly.

+
§

Discovery

The address was discovered by a discovery service.

+

Fields

§name: String

The name of the discovery service that discovered the address.

+
§

NamedApp

Application layer with a specific name added the node directly.

+

Fields

§name: String

The name of the application that added the node

+

Trait Implementations§

source§

impl Clone for Source

source§

fn clone(&self) -> Source

Returns a copy 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 Source

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Source

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Source

source§

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

Formats the value using the given formatter. Read more
source§

impl Hash for Source

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq for Source

source§

fn eq(&self, other: &Source) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for Source

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for Source

source§

impl StructuralPartialEq for Source

Auto Trait Implementations§

§

impl Freeze for Source

§

impl RefUnwindSafe for Source

§

impl Send for Source

§

impl Sync for Source

§

impl Unpin for Source

§

impl UnwindSafe for Source

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.StoppedError.html b/pr/2992/docs/iroh/endpoint/enum.StoppedError.html new file mode 100644 index 0000000000..73431861a8 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.StoppedError.html @@ -0,0 +1,44 @@ +StoppedError in iroh::endpoint - Rust

Enum iroh::endpoint::StoppedError

pub enum StoppedError {
+    ConnectionLost(ConnectionError),
+    ZeroRttRejected,
+}
Expand description

Errors that arise while monitoring for a send stream stop from the peer

+

Variants§

§

ConnectionLost(ConnectionError)

The connection was lost

+
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

+

Can only occur on clients for 0-RTT streams, which can be opened using +Connecting::into_0rtt().

+

Trait Implementations§

§

impl Clone for StoppedError

§

fn clone(&self) -> StoppedError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for StoppedError

§

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

Formats the value using the given formatter. Read more
§

impl Display for StoppedError

§

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

Formats the value using the given formatter. Read more
§

impl Error for StoppedError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ConnectionError> for StoppedError

§

fn from(source: ConnectionError) -> StoppedError

Converts to this type from the input type.
§

impl From<StoppedError> for WriteError

§

fn from(x: StoppedError) -> WriteError

Converts to this type from the input type.
§

impl PartialEq for StoppedError

§

fn eq(&self, other: &StoppedError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for StoppedError

§

impl StructuralPartialEq for StoppedError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/enum.WriteError.html b/pr/2992/docs/iroh/endpoint/enum.WriteError.html new file mode 100644 index 0000000000..dbd21f9210 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/enum.WriteError.html @@ -0,0 +1,49 @@ +WriteError in iroh::endpoint - Rust

Enum iroh::endpoint::WriteError

pub enum WriteError {
+    Stopped(VarInt),
+    ConnectionLost(ConnectionError),
+    ClosedStream,
+    ZeroRttRejected,
+}
Expand description

Errors that arise from writing to a stream

+

Variants§

§

Stopped(VarInt)

The peer is no longer accepting data on this stream

+

Carries an application-defined error code.

+
§

ConnectionLost(ConnectionError)

The connection was lost

+
§

ClosedStream

The stream has already been finished or reset

+
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

+

Can only occur on clients for 0-RTT streams, which can be opened using +Connecting::into_0rtt().

+

Trait Implementations§

§

impl Clone for WriteError

§

fn clone(&self) -> WriteError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for WriteError

§

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

Formats the value using the given formatter. Read more
§

impl Display for WriteError

§

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

Formats the value using the given formatter. Read more
§

impl Error for WriteError

§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ClosedStream> for WriteError

§

fn from(_: ClosedStream) -> WriteError

Converts to this type from the input type.
§

impl From<ConnectionError> for WriteError

§

fn from(source: ConnectionError) -> WriteError

Converts to this type from the input type.
§

impl From<StoppedError> for WriteError

§

fn from(x: StoppedError) -> WriteError

Converts to this type from the input type.
§

impl PartialEq for WriteError

§

fn eq(&self, other: &WriteError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for WriteError

§

impl StructuralPartialEq for WriteError

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/fn.default_relay_mode.html b/pr/2992/docs/iroh/endpoint/fn.default_relay_mode.html new file mode 100644 index 0000000000..e340ce8242 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/fn.default_relay_mode.html @@ -0,0 +1,4 @@ +default_relay_mode in iroh::endpoint - Rust

Function iroh::endpoint::default_relay_mode

source ·
pub fn default_relay_mode() -> RelayMode
Expand description

Returns the default relay mode.

+

If the IROH_FORCE_STAGING_RELAYS environment variable is non empty, it will return RelayMode::Staging. +Otherwise, it will return RelayMode::Default.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/fn.force_staging_infra.html b/pr/2992/docs/iroh/endpoint/fn.force_staging_infra.html new file mode 100644 index 0000000000..56edf4eed2 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/fn.force_staging_infra.html @@ -0,0 +1,2 @@ +force_staging_infra in iroh::endpoint - Rust

Function iroh::endpoint::force_staging_infra

source ·
pub fn force_staging_infra() -> bool
Expand description

Returns true if the use of staging relays is forced.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/fn.get_remote_node_id.html b/pr/2992/docs/iroh/endpoint/fn.get_remote_node_id.html new file mode 100644 index 0000000000..f202499719 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/fn.get_remote_node_id.html @@ -0,0 +1,2 @@ +get_remote_node_id in iroh::endpoint - Rust

Function iroh::endpoint::get_remote_node_id

source ·
pub fn get_remote_node_id(connection: &Connection) -> Result<PublicKey>
Expand description

Extract the PublicKey from the peer’s TLS certificate.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/fn.make_server_config.html b/pr/2992/docs/iroh/endpoint/fn.make_server_config.html new file mode 100644 index 0000000000..a568a7d782 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/fn.make_server_config.html @@ -0,0 +1,7 @@ +make_server_config in iroh::endpoint - Rust

Function iroh::endpoint::make_server_config

source ·
pub fn make_server_config(
+    secret_key: &SecretKey,
+    alpn_protocols: Vec<Vec<u8>>,
+    transport_config: Arc<TransportConfig>,
+    keylog: bool
+) -> Result<ServerConfig>
Expand description

Creates a ServerConfig with the given secret key and limits.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/index.html b/pr/2992/docs/iroh/endpoint/index.html new file mode 100644 index 0000000000..ab04f4bcb6 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/index.html @@ -0,0 +1,13 @@ +iroh::endpoint - Rust

Module iroh::endpoint

source ·
Expand description

The Endpoint allows establishing connections to other iroh nodes.

+

The Endpoint is the main API interface to manage a local iroh node. It allows +connecting to and accepting connections from other nodes. See the module docs for +more details on how iroh connections work.

+

The main items in this module are:

+ +

Structs§

Enums§

Constants§

Traits§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/sidebar-items.js b/pr/2992/docs/iroh/endpoint/sidebar-items.js new file mode 100644 index 0000000000..b3b67d538d --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["ENV_FORCE_STAGING_RELAYS"],"enum":["AddrInfoOptions","ConnectionError","ConnectionType","ControlMsg","DirectAddrType","ReadError","ReadExactError","ReadToEndError","RelayMode","ResetError","SendDatagramError","Source","StoppedError","WriteError"],"fn":["default_relay_mode","force_staging_infra","get_remote_node_id","make_server_config"],"struct":["Accept","AcceptBi","AcceptUni","AckFrequencyConfig","AddrInfo","ApplicationClose","Builder","Bytes","Chunk","ClosedStream","Connecting","Connection","ConnectionClose","ConnectionStats","ConnectionTypeStream","CryptoError","DirectAddr","DirectAddrInfo","DirectAddrsStream","Endpoint","ExportKeyingMaterialError","FrameStats","Incoming","IncomingFuture","MtuDiscoveryConfig","NodeAddr","OpenBi","OpenUni","PathStats","ReadDatagram","RecvStream","RemoteInfo","RetryError","SendStream","ServerConfig","StreamId","TransportConfig","TransportError","TransportErrorCode","UdpStats","UnsupportedVersion","VarInt","WeakConnectionHandle","Written","ZeroRttAccepted"],"trait":["AeadKey","Controller","ControllerFactory","CryptoServerConfig","HandshakeTokenKey"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Accept.html b/pr/2992/docs/iroh/endpoint/struct.Accept.html new file mode 100644 index 0000000000..11813dbf54 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Accept.html @@ -0,0 +1,102 @@ +Accept in iroh::endpoint - Rust

Struct iroh::endpoint::Accept

source ·
pub struct Accept<'a> { /* private fields */ }
Expand description

Future produced by Endpoint::accept.

+

Trait Implementations§

source§

impl<'a> Debug for Accept<'a>

source§

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

Formats the value using the given formatter. Read more
source§

impl Future for Accept<'_>

§

type Output = Option<Incoming>

The type of value produced on completion.
source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
source§

impl<'pin, 'a> Unpin for Accept<'a>
where + PinnedFieldsOf<__Accept<'pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for Accept<'a>

§

impl<'a> !RefUnwindSafe for Accept<'a>

§

impl<'a> Send for Accept<'a>

§

impl<'a> Sync for Accept<'a>

§

impl<'a> !UnwindSafe for Accept<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.AcceptBi.html b/pr/2992/docs/iroh/endpoint/struct.AcceptBi.html new file mode 100644 index 0000000000..18b062c61f --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.AcceptBi.html @@ -0,0 +1,156 @@ +AcceptBi in iroh::endpoint - Rust

Struct iroh::endpoint::AcceptBi

pub struct AcceptBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_bi

+

Trait Implementations§

§

impl Future for AcceptBi<'_>

§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
§

fn poll( + self: Pin<&mut AcceptBi<'_>>, + ctx: &mut Context<'_> +) -> Poll<<AcceptBi<'_> as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
§

impl<'__pin, 'a> Unpin for AcceptBi<'a>
where + <PinnedFieldsOfHelperStruct<__Origin<'__pin, 'a>> as PinnedFieldsOfHelperTrait>::Actual: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for AcceptBi<'a>

§

impl<'a> !RefUnwindSafe for AcceptBi<'a>

§

impl<'a> Send for AcceptBi<'a>

§

impl<'a> Sync for AcceptBi<'a>

§

impl<'a> !UnwindSafe for AcceptBi<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.AcceptUni.html b/pr/2992/docs/iroh/endpoint/struct.AcceptUni.html new file mode 100644 index 0000000000..feb5b34fdc --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.AcceptUni.html @@ -0,0 +1,156 @@ +AcceptUni in iroh::endpoint - Rust

Struct iroh::endpoint::AcceptUni

pub struct AcceptUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_uni

+

Trait Implementations§

§

impl Future for AcceptUni<'_>

§

type Output = Result<RecvStream, ConnectionError>

The type of value produced on completion.
§

fn poll( + self: Pin<&mut AcceptUni<'_>>, + ctx: &mut Context<'_> +) -> Poll<<AcceptUni<'_> as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
§

impl<'__pin, 'a> Unpin for AcceptUni<'a>
where + <PinnedFieldsOfHelperStruct<__Origin<'__pin, 'a>> as PinnedFieldsOfHelperTrait>::Actual: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for AcceptUni<'a>

§

impl<'a> !RefUnwindSafe for AcceptUni<'a>

§

impl<'a> Send for AcceptUni<'a>

§

impl<'a> Sync for AcceptUni<'a>

§

impl<'a> !UnwindSafe for AcceptUni<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.AckFrequencyConfig.html b/pr/2992/docs/iroh/endpoint/struct.AckFrequencyConfig.html new file mode 100644 index 0000000000..6c5e3d94f5 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.AckFrequencyConfig.html @@ -0,0 +1,68 @@ +AckFrequencyConfig in iroh::endpoint - Rust

Struct iroh::endpoint::AckFrequencyConfig

pub struct AckFrequencyConfig { /* private fields */ }
Expand description

Parameters for controlling the peer’s acknowledgement frequency

+

The parameters provided in this config will be sent to the peer at the beginning of the +connection, so it can take them into account when sending acknowledgements (see each parameter’s +description for details on how it influences acknowledgement frequency).

+

Quinn’s implementation follows the fourth draft of the +QUIC Acknowledgement Frequency extension. +The defaults produce behavior slightly different than the behavior without this extension, +because they change the way reordered packets are handled (see +AckFrequencyConfig::reordering_threshold for details).

+

Implementations§

§

impl AckFrequencyConfig

pub fn ack_eliciting_threshold( + &mut self, + value: VarInt +) -> &mut AckFrequencyConfig

The ack-eliciting threshold we will request the peer to use

+

This threshold represents the number of ack-eliciting packets an endpoint may receive +without immediately sending an ACK.

+

The remote peer should send at least one ACK frame when more than this number of +ack-eliciting packets have been received. A value of 0 results in a receiver immediately +acknowledging every ack-eliciting packet.

+

Defaults to 1, which sends ACK frames for every other ack-eliciting packet.

+

pub fn max_ack_delay( + &mut self, + value: Option<Duration> +) -> &mut AckFrequencyConfig

The max_ack_delay we will request the peer to use

+

This parameter represents the maximum amount of time that an endpoint waits before sending +an ACK when the ack-eliciting threshold hasn’t been reached.

+

The effective max_ack_delay will be clamped to be at least the peer’s min_ack_delay +transport parameter, and at most the greater of the current path RTT or 25ms.

+

Defaults to None, in which case the peer’s original max_ack_delay will be used, as +obtained from its transport parameters.

+

pub fn reordering_threshold(&mut self, value: VarInt) -> &mut AckFrequencyConfig

The reordering threshold we will request the peer to use

+

This threshold represents the amount of out-of-order packets that will trigger an endpoint +to send an ACK, without waiting for ack_eliciting_threshold to be exceeded or for +max_ack_delay to be elapsed.

+

A value of 0 indicates out-of-order packets do not elicit an immediate ACK. A value of 1 +immediately acknowledges any packets that are received out of order (this is also the +behavior when the extension is disabled).

+

It is recommended to set this value to TransportConfig::packet_threshold minus one. +Since the default value for TransportConfig::packet_threshold is 3, this value defaults +to 2.

+

Trait Implementations§

§

impl Clone for AckFrequencyConfig

§

fn clone(&self) -> AckFrequencyConfig

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for AckFrequencyConfig

§

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

Formats the value using the given formatter. Read more
§

impl Default for AckFrequencyConfig

§

fn default() -> AckFrequencyConfig

Returns the “default value” for a type. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.AddrInfo.html b/pr/2992/docs/iroh/endpoint/struct.AddrInfo.html new file mode 100644 index 0000000000..f830ea56de --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.AddrInfo.html @@ -0,0 +1,64 @@ +AddrInfo in iroh::endpoint - Rust

Struct iroh::endpoint::AddrInfo

source ·
pub struct AddrInfo {
+    pub relay_url: Option<RelayUrl>,
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
Expand description

Network paths to contact an iroh node.

+

This contains zero or more network paths to establish a connection to an iroh node. +Unless a [discovery service] is used at least one path is required to connect to an +other node, see NodeAddr for details.

+

Fields§

§relay_url: Option<RelayUrl>

The node’s home relay url.

+
§direct_addresses: BTreeSet<SocketAddr>

Socket addresses where the peer might be reached directly.

+

Implementations§

source§

impl AddrInfo

source

pub fn is_empty(&self) -> bool

Returns whether this addressing information is empty.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in ab AddrInfo +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+

Trait Implementations§

source§

impl Clone for AddrInfo

source§

fn clone(&self) -> AddrInfo

Returns a copy 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 AddrInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfo

source§

fn default() -> AddrInfo

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfo

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<AddrInfo, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<NodeInfo> for AddrInfo

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl Ord for AddrInfo

source§

fn cmp(&self, other: &AddrInfo) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for AddrInfo

source§

fn eq(&self, other: &AddrInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for AddrInfo

source§

fn partial_cmp(&self, other: &AddrInfo) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for AddrInfo

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for AddrInfo

source§

impl StructuralPartialEq for AddrInfo

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ApplicationClose.html b/pr/2992/docs/iroh/endpoint/struct.ApplicationClose.html new file mode 100644 index 0000000000..9af9e1ba61 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ApplicationClose.html @@ -0,0 +1,42 @@ +ApplicationClose in iroh::endpoint - Rust

Struct iroh::endpoint::ApplicationClose

pub struct ApplicationClose {
+    pub error_code: VarInt,
+    pub reason: Bytes,
+}
Expand description

Reason given by an application for closing the connection

+

Fields§

§error_code: VarInt

Application-specific reason code

+
§reason: Bytes

Human-readable reason for the close

+

Trait Implementations§

§

impl Clone for ApplicationClose

§

fn clone(&self) -> ApplicationClose

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ApplicationClose

§

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

Formats the value using the given formatter. Read more
§

impl Display for ApplicationClose

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for ApplicationClose

§

fn eq(&self, other: &ApplicationClose) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ApplicationClose

§

impl StructuralPartialEq for ApplicationClose

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Builder.html b/pr/2992/docs/iroh/endpoint/struct.Builder.html new file mode 100644 index 0000000000..f388bbc534 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Builder.html @@ -0,0 +1,122 @@ +Builder in iroh::endpoint - Rust

Struct iroh::endpoint::Builder

source ·
pub struct Builder { /* private fields */ }
Expand description

Builder for Endpoint.

+

By default the endpoint will generate a new random SecretKey, which will result in a +new NodeId.

+

To create the Endpoint call Builder::bind.

+

Implementations§

source§

impl Builder

source

pub async fn bind(self) -> Result<Endpoint>

Binds the magic endpoint.

+
source

pub fn bind_addr_v4(self, addr: SocketAddrV4) -> Self

Sets the IPv4 bind address.

+

Setting the port to 0 will use a random port. +If the port specified is already in use, it will fallback to choosing a random port.

+

By default will use 0.0.0.0:0 to bind to.

+
source

pub fn bind_addr_v6(self, addr: SocketAddrV6) -> Self

Sets the IPv6 bind address.

+

Setting the port to 0 will use a random port. +If the port specified is already in use, it will fallback to choosing a random port.

+

By default will use [::]:0 to bind to.

+
source

pub fn secret_key(self, secret_key: SecretKey) -> Self

Sets a secret key to authenticate with other peers.

+

This secret key’s public key will be the PublicKey of this endpoint and thus +also its NodeId

+

If not set, a new secret key will be generated.

+
source

pub fn alpns(self, alpn_protocols: Vec<Vec<u8>>) -> Self

Sets the ALPN protocols that this endpoint will accept on incoming connections.

+

Not setting this will still allow creating connections, but to accept incoming +connections the ALPN must be set.

+
source

pub fn relay_mode(self, relay_mode: RelayMode) -> Self

Sets the relay servers to assist in establishing connectivity.

+

Relay servers are used to establish initial connection with another iroh node. +They also perform various functions related to hole punching, see the crate docs +for more details.

+

By default the number 0 relay servers are used, see RelayMode::Default.

+

When using RelayMode::Custom, the provided relay_map must contain at least one +configured relay node. If an invalid RelayMap is provided bind +will result in an error.

+
source

pub fn clear_discovery(self) -> Self

Removes all discovery services from the builder.

+
source

pub fn discovery(self, discovery: Box<dyn Discovery>) -> Self

Optionally sets a discovery mechanism for this endpoint.

+

If you want to combine multiple discovery services, you can use +Builder::add_discovery instead. This will internally create a +crate::discovery::ConcurrentDiscovery.

+

If no discovery service is set, connecting to a node without providing its +direct addresses or relay URLs will fail.

+

See the documentation of the Discovery trait for details.

+
source

pub fn add_discovery<F, D>(self, discovery: F) -> Self
where + F: FnOnce(&SecretKey) -> Option<D> + Send + Sync + 'static, + D: Discovery + 'static,

Adds a discovery mechanism for this endpoint.

+

The function discovery +will be called on endpoint creation with the configured secret key of +the endpoint. Discovery services that need to publish information need +to use this secret key to sign the information.

+

If you add multiple discovery services, they will be combined using a +crate::discovery::ConcurrentDiscovery.

+

If no discovery service is set, connecting to a node without providing its +direct addresses or relay URLs will fail.

+

To clear all discovery services, use Builder::clear_discovery.

+

See the documentation of the Discovery trait for details.

+
source

pub fn discovery_n0(self) -> Self

Configures the endpoint to use the default n0 DNS discovery service.

+

The default discovery service publishes to and resolves from the +n0.computer dns server iroh.link.

+

This is equivalent to adding both a crate::discovery::pkarr::PkarrPublisher +and a crate::discovery::dns::DnsDiscovery, both configured to use the +n0.computer dns server.

+

This will by default use N0_DNS_PKARR_RELAY_PROD. +When in tests, or when the test-utils feature is enabled, this will use the +N0_DNS_PKARR_RELAY_STAGING.

+
source

pub fn discovery_dht(self) -> Self

Configures the endpoint to also use the mainline DHT with default settings.

+

This is equivalent to adding a crate::discovery::pkarr::dht::DhtDiscovery +with default settings. Note that DhtDiscovery has various more advanced +configuration options. If you need any of those, you should manually +create a DhtDiscovery and add it with Builder::add_discovery.

+
source

pub fn discovery_local_network(self) -> Self

Configures the endpoint to also use local network discovery.

+

This is equivalent to adding a crate::discovery::local_swarm_discovery::LocalSwarmDiscovery +with default settings. Note that LocalSwarmDiscovery has various more advanced +configuration options. If you need any of those, you should manually +create a LocalSwarmDiscovery and add it with Builder::add_discovery.

+
source

pub fn known_nodes(self, nodes: Vec<NodeAddr>) -> Self

Optionally set a list of known nodes.

+
source

pub fn transport_config(self, transport_config: TransportConfig) -> Self

Sets a custom quinn::TransportConfig for this endpoint.

+

The transport config contains parameters governing the QUIC state machine.

+

If unset, the default config is used. Default values should be suitable for most +internet applications. Applications protocols which forbid remotely-initiated +streams should set max_concurrent_bidi_streams and max_concurrent_uni_streams to +zero.

+
source

pub fn dns_resolver(self, dns_resolver: DnsResolver) -> Self

Optionally sets a custom DNS resolver to use for this endpoint.

+

The DNS resolver is used to resolve relay hostnames, and node addresses if +crate::discovery::dns::DnsDiscovery is configured.

+

By default, all endpoints share a DNS resolver, which is configured to use the +host system’s DNS configuration. You can pass a custom instance of DnsResolver +here to use a differently configured DNS resolver for this endpoint.

+
source

pub fn proxy_url(self, url: Url) -> Self

Sets an explicit proxy url to proxy all HTTP(S) traffic through.

+
source

pub fn proxy_from_env(self) -> Self

Sets the proxy url from the environment, in this order:

+
    +
  • HTTP_PROXY
  • +
  • http_proxy
  • +
  • HTTPS_PROXY
  • +
  • https_proxy
  • +
+
source

pub fn keylog(self, keylog: bool) -> Self

Enables saving the TLS pre-master key for connections.

+

This key should normally remain secret but can be useful to debug networking issues +by decrypting captured traffic.

+

If keylog is true then setting the SSLKEYLOGFILE environment variable to a +filename will result in this file being used to log the TLS pre-master keys.

+
source

pub fn insecure_skip_relay_cert_verify(self, skip_verify: bool) -> Self

Available on test or crate feature test-utils only.

Skip verification of SSL certificates from relay servers

+

May only be used in tests.

+

Trait Implementations§

source§

impl Debug for Builder

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Builder

source§

fn default() -> Self

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Bytes.html b/pr/2992/docs/iroh/endpoint/struct.Bytes.html new file mode 100644 index 0000000000..0adbf637e5 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Bytes.html @@ -0,0 +1,1453 @@ +Bytes in iroh::endpoint - Rust

Struct iroh::endpoint::Bytes

pub struct Bytes { /* private fields */ }
Expand description

A cheaply cloneable and sliceable chunk of contiguous memory.

+

Bytes is an efficient container for storing and operating on contiguous +slices of memory. It is intended for use primarily in networking code, but +could have applications elsewhere as well.

+

Bytes values facilitate zero-copy network programming by allowing multiple +Bytes objects to point to the same underlying memory.

+

Bytes does not have a single implementation. It is an interface, whose +exact behavior is implemented through dynamic dispatch in several underlying +implementations of Bytes.

+

All Bytes implementations must fulfill the following requirements:

+
    +
  • They are cheaply cloneable and thereby shareable between an unlimited amount +of components, for example by modifying a reference count.
  • +
  • Instances can be sliced to refer to a subset of the original buffer.
  • +
+ +
use bytes::Bytes;
+
+let mut mem = Bytes::from("Hello world");
+let a = mem.slice(0..5);
+
+assert_eq!(a, "Hello");
+
+let b = mem.split_to(6);
+
+assert_eq!(mem, "world");
+assert_eq!(b, "Hello ");
+

§Memory layout

+

The Bytes struct itself is fairly small, limited to 4 usize fields used +to track information about which segment of the underlying memory the +Bytes handle has access to.

+

Bytes keeps both a pointer to the shared state containing the full memory +slice and a pointer to the start of the region visible by the handle. +Bytes also tracks the length of its view into the memory.

+

§Sharing

+

Bytes contains a vtable, which allows implementations of Bytes to define +how sharing/cloning is implemented in detail. +When Bytes::clone() is called, Bytes will call the vtable function for +cloning the backing storage in order to share it behind multiple Bytes +instances.

+

For Bytes implementations which refer to constant memory (e.g. created +via Bytes::from_static()) the cloning implementation will be a no-op.

+

For Bytes implementations which point to a reference counted shared storage +(e.g. an Arc<[u8]>), sharing will be implemented by increasing the +reference count.

+

Due to this mechanism, multiple Bytes instances may point to the same +shared memory region. +Each Bytes instance can point to different sections within that +memory region, and Bytes instances may or may not have overlapping views +into the memory.

+

The following diagram visualizes a scenario where 2 Bytes instances make +use of an Arc-based backing storage, and provide access to different views:

+

+   Arc ptrs                   ┌─────────┐
+   ________________________ / │ Bytes 2 │
+  /                           └─────────┘
+ /          ┌───────────┐     |         |
+|_________/ │  Bytes 1  │     |         |
+|           └───────────┘     |         |
+|           |           | ___/ data     | tail
+|      data |      tail |/              |
+v           v           v               v
+┌─────┬─────┬───────────┬───────────────┬─────┐
+│ Arc │     │           │               │     │
+└─────┴─────┴───────────┴───────────────┴─────┘
+

Implementations§

§

impl Bytes

pub const fn new() -> Bytes

Creates a new empty Bytes.

+

This will not allocate and the returned Bytes handle will be empty.

+
§Examples
+
use bytes::Bytes;
+
+let b = Bytes::new();
+assert_eq!(&b[..], b"");
+

pub const fn from_static(bytes: &'static [u8]) -> Bytes

Creates a new Bytes from a static slice.

+

The returned Bytes will point directly to the static slice. There is +no allocating or copying.

+
§Examples
+
use bytes::Bytes;
+
+let b = Bytes::from_static(b"hello");
+assert_eq!(&b[..], b"hello");
+

pub fn from_owner<T>(owner: T) -> Bytes
where + T: AsRef<[u8]> + Send + 'static,

Create Bytes with a buffer whose lifetime is controlled +via an explicit owner.

+

A common use case is to zero-copy construct from mapped memory.

+ +
use bytes::Bytes;
+use memmap2::Mmap;
+
+let file = File::open("upload_bundle.tar.gz")?;
+let mmap = unsafe { Mmap::map(&file) }?;
+let b = Bytes::from_owner(mmap);
+

The owner will be transferred to the constructed Bytes object, which +will ensure it is dropped once all remaining clones of the constructed +object are dropped. The owner will then be responsible for dropping the +specified region of memory as part of its Drop implementation.

+

Note that converting Bytes constructed from an owner into a [BytesMut] +will always create a deep copy of the buffer into newly allocated memory.

+

pub const fn len(&self) -> usize

Returns the number of bytes contained in this Bytes.

+
§Examples
+
use bytes::Bytes;
+
+let b = Bytes::from(&b"hello"[..]);
+assert_eq!(b.len(), 5);
+

pub const fn is_empty(&self) -> bool

Returns true if the Bytes has a length of 0.

+
§Examples
+
use bytes::Bytes;
+
+let b = Bytes::new();
+assert!(b.is_empty());
+

pub fn is_unique(&self) -> bool

Returns true if this is the only reference to the data and +Into<BytesMut> would avoid cloning the underlying buffer.

+

Always returns false if the data is backed by a static slice, +or an owner.

+

The result of this method may be invalidated immediately if another +thread clones this value while this is being called. Ensure you have +unique access to this value (&mut Bytes) first if you need to be +certain the result is valid (i.e. for safety reasons).

+
§Examples
+
use bytes::Bytes;
+
+let a = Bytes::from(vec![1, 2, 3]);
+assert!(a.is_unique());
+let b = a.clone();
+assert!(!a.is_unique());
+

pub fn copy_from_slice(data: &[u8]) -> Bytes

Creates Bytes instance from slice, by copying it.

+

pub fn slice(&self, range: impl RangeBounds<usize>) -> Bytes

Returns a slice of self for the provided range.

+

This will increment the reference count for the underlying memory and +return a new Bytes handle set to the slice.

+

This operation is O(1).

+
§Examples
+
use bytes::Bytes;
+
+let a = Bytes::from(&b"hello world"[..]);
+let b = a.slice(2..5);
+
+assert_eq!(&b[..], b"llo");
+
§Panics
+

Requires that begin <= end and end <= self.len(), otherwise slicing +will panic.

+

pub fn slice_ref(&self, subset: &[u8]) -> Bytes

Returns a slice of self that is equivalent to the given subset.

+

When processing a Bytes buffer with other tools, one often gets a +&[u8] which is in fact a slice of the Bytes, i.e. a subset of it. +This function turns that &[u8] into another Bytes, as if one had +called self.slice() with the offsets that correspond to subset.

+

This operation is O(1).

+
§Examples
+
use bytes::Bytes;
+
+let bytes = Bytes::from(&b"012345678"[..]);
+let as_slice = bytes.as_ref();
+let subset = &as_slice[2..6];
+let subslice = bytes.slice_ref(&subset);
+assert_eq!(&subslice[..], b"2345");
+
§Panics
+

Requires that the given sub slice is in fact contained within the +Bytes buffer; otherwise this function will panic.

+

pub fn split_off(&mut self, at: usize) -> Bytes

Splits the bytes into two at the given index.

+

Afterwards self contains elements [0, at), and the returned Bytes +contains elements [at, len). It’s guaranteed that the memory does not +move, that is, the address of self does not change, and the address of +the returned slice is at bytes after that.

+

This is an O(1) operation that just increases the reference count and +sets a few indices.

+
§Examples
+
use bytes::Bytes;
+
+let mut a = Bytes::from(&b"hello world"[..]);
+let b = a.split_off(5);
+
+assert_eq!(&a[..], b"hello");
+assert_eq!(&b[..], b" world");
+
§Panics
+

Panics if at > len.

+

pub fn split_to(&mut self, at: usize) -> Bytes

Splits the bytes into two at the given index.

+

Afterwards self contains elements [at, len), and the returned +Bytes contains elements [0, at).

+

This is an O(1) operation that just increases the reference count and +sets a few indices.

+
§Examples
+
use bytes::Bytes;
+
+let mut a = Bytes::from(&b"hello world"[..]);
+let b = a.split_to(5);
+
+assert_eq!(&a[..], b" world");
+assert_eq!(&b[..], b"hello");
+
§Panics
+

Panics if at > len.

+

pub fn truncate(&mut self, len: usize)

Shortens the buffer, keeping the first len bytes and dropping the +rest.

+

If len is greater than the buffer’s current length, this has no +effect.

+

The split_off method can emulate truncate, but this causes the +excess bytes to be returned instead of dropped.

+
§Examples
+
use bytes::Bytes;
+
+let mut buf = Bytes::from(&b"hello world"[..]);
+buf.truncate(5);
+assert_eq!(buf, b"hello"[..]);
+

pub fn clear(&mut self)

Clears the buffer, removing all data.

+
§Examples
+
use bytes::Bytes;
+
+let mut buf = Bytes::from(&b"hello world"[..]);
+buf.clear();
+assert!(buf.is_empty());
+

pub fn try_into_mut(self) -> Result<BytesMut, Bytes>

Try to convert self into BytesMut.

+

If self is unique for the entire original buffer, this will succeed +and return a BytesMut with the contents of self without copying. +If self is not unique for the entire original buffer, this will fail +and return self.

+

This will also always fail if the buffer was constructed via either +from_owner or from_static.

+
§Examples
+
use bytes::{Bytes, BytesMut};
+
+let bytes = Bytes::from(b"hello".to_vec());
+assert_eq!(bytes.try_into_mut(), Ok(BytesMut::from(&b"hello"[..])));
+

Methods from Deref<Target = [u8]>§

source

pub fn as_str(&self) -> &str

🔬This is a nightly-only experimental API. (ascii_char)

Views this slice of ASCII characters as a UTF-8 str.

+
source

pub fn as_bytes(&self) -> &[u8]

🔬This is a nightly-only experimental API. (ascii_char)

Views this slice of ASCII characters as a slice of u8 bytes.

+
1.0.0 · source

pub fn len(&self) -> usize

Returns the number of elements in the slice.

+
§Examples
+
let a = [1, 2, 3];
+assert_eq!(a.len(), 3);
+
1.0.0 · source

pub fn is_empty(&self) -> bool

Returns true if the slice has a length of 0.

+
§Examples
+
let a = [1, 2, 3];
+assert!(!a.is_empty());
+
+let b: &[i32] = &[];
+assert!(b.is_empty());
+
1.0.0 · source

pub fn first(&self) -> Option<&T>

Returns the first element of the slice, or None if it is empty.

+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&10), v.first());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.first());
+
1.5.0 · source

pub fn split_first(&self) -> Option<(&T, &[T])>

Returns the first and all the rest of the elements of the slice, or None if it is empty.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((first, elements)) = x.split_first() {
+    assert_eq!(first, &0);
+    assert_eq!(elements, &[1, 2]);
+}
+
1.5.0 · source

pub fn split_last(&self) -> Option<(&T, &[T])>

Returns the last and all the rest of the elements of the slice, or None if it is empty.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((last, elements)) = x.split_last() {
+    assert_eq!(last, &2);
+    assert_eq!(elements, &[0, 1]);
+}
+
1.0.0 · source

pub fn last(&self) -> Option<&T>

Returns the last element of the slice, or None if it is empty.

+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&30), v.last());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.last());
+
1.77.0 · source

pub fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>

Return an array reference to the first N items in the slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let u = [10, 40, 30];
+assert_eq!(Some(&[10, 40]), u.first_chunk::<2>());
+
+let v: &[i32] = &[10];
+assert_eq!(None, v.first_chunk::<2>());
+
+let w: &[i32] = &[];
+assert_eq!(Some(&[]), w.first_chunk::<0>());
+
1.77.0 · source

pub fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>

Return an array reference to the first N items in the slice and the remaining slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((first, elements)) = x.split_first_chunk::<2>() {
+    assert_eq!(first, &[0, 1]);
+    assert_eq!(elements, &[2]);
+}
+
+assert_eq!(None, x.split_first_chunk::<4>());
+
1.77.0 · source

pub fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>

Return an array reference to the last N items in the slice and the remaining slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((elements, last)) = x.split_last_chunk::<2>() {
+    assert_eq!(elements, &[0]);
+    assert_eq!(last, &[1, 2]);
+}
+
+assert_eq!(None, x.split_last_chunk::<4>());
+
1.77.0 · source

pub fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>

Return an array reference to the last N items in the slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let u = [10, 40, 30];
+assert_eq!(Some(&[40, 30]), u.last_chunk::<2>());
+
+let v: &[i32] = &[10];
+assert_eq!(None, v.last_chunk::<2>());
+
+let w: &[i32] = &[];
+assert_eq!(Some(&[]), w.last_chunk::<0>());
+
1.0.0 · source

pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
where + I: SliceIndex<[T]>,

Returns a reference to an element or subslice depending on the type of +index.

+
    +
  • If given a position, returns a reference to the element at that +position or None if out of bounds.
  • +
  • If given a range, returns the subslice corresponding to that range, +or None if out of bounds.
  • +
+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&40), v.get(1));
+assert_eq!(Some(&[10, 40][..]), v.get(0..2));
+assert_eq!(None, v.get(3));
+assert_eq!(None, v.get(0..4));
+
1.0.0 · source

pub unsafe fn get_unchecked<I>( + &self, + index: I +) -> &<I as SliceIndex<[T]>>::Output
where + I: SliceIndex<[T]>,

Returns a reference to an element or subslice, without doing bounds +checking.

+

For a safe alternative see get.

+
§Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used.

+

You can think of this like .get(index).unwrap_unchecked(). It’s UB +to call .get_unchecked(len), even if you immediately convert to a +pointer. And it’s UB to call .get_unchecked(..len + 1), +.get_unchecked(..=len), or similar.

+
§Examples
+
let x = &[1, 2, 4];
+
+unsafe {
+    assert_eq!(x.get_unchecked(1), &2);
+}
+
1.0.0 · source

pub fn as_ptr(&self) -> *const T

Returns a raw pointer to the slice’s buffer.

+

The caller must ensure that the slice outlives the pointer this +function returns, or else it will end up pointing to garbage.

+

The caller must also ensure that the memory the pointer (non-transitively) points to +is never written to (except inside an UnsafeCell) using this pointer or any pointer +derived from it. If you need to mutate the contents of the slice, use as_mut_ptr.

+

Modifying the container referenced by this slice may cause its buffer +to be reallocated, which would also make any pointers to it invalid.

+
§Examples
+
let x = &[1, 2, 4];
+let x_ptr = x.as_ptr();
+
+unsafe {
+    for i in 0..x.len() {
+        assert_eq!(x.get_unchecked(i), &*x_ptr.add(i));
+    }
+}
+
1.48.0 · source

pub fn as_ptr_range(&self) -> Range<*const T>

Returns the two raw pointers spanning the slice.

+

The returned range is half-open, which means that the end pointer +points one past the last element of the slice. This way, an empty +slice is represented by two equal pointers, and the difference between +the two pointers represents the size of the slice.

+

See as_ptr for warnings on using these pointers. The end pointer +requires extra caution, as it does not point to a valid element in the +slice.

+

This function is useful for interacting with foreign interfaces which +use two pointers to refer to a range of elements in memory, as is +common in C++.

+

It can also be useful to check if a pointer to an element refers to an +element of this slice:

+ +
let a = [1, 2, 3];
+let x = &a[1] as *const _;
+let y = &5 as *const _;
+
+assert!(a.as_ptr_range().contains(&x));
+assert!(!a.as_ptr_range().contains(&y));
+
1.0.0 · source

pub fn iter(&self) -> Iter<'_, T>

Returns an iterator over the slice.

+

The iterator yields all items from start to end.

+
§Examples
+
let x = &[1, 2, 4];
+let mut iterator = x.iter();
+
+assert_eq!(iterator.next(), Some(&1));
+assert_eq!(iterator.next(), Some(&2));
+assert_eq!(iterator.next(), Some(&4));
+assert_eq!(iterator.next(), None);
+
1.0.0 · source

pub fn windows(&self, size: usize) -> Windows<'_, T>

Returns an iterator over all contiguous windows of length +size. The windows overlap. If the slice is shorter than +size, the iterator returns no values.

+
§Panics
+

Panics if size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.windows(3);
+assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']);
+assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']);
+assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']);
+assert!(iter.next().is_none());
+

If the slice is shorter than size:

+ +
let slice = ['f', 'o', 'o'];
+let mut iter = slice.windows(4);
+assert!(iter.next().is_none());
+

There’s no windows_mut, as that existing would let safe code violate the +“only one &mut at a time to the same thing” rule. However, you can sometimes +use Cell::as_slice_of_cells in +conjunction with windows to accomplish something similar:

+ +
use std::cell::Cell;
+
+let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5'];
+let slice = &mut array[..];
+let slice_of_cells: &[Cell<char>] = Cell::from_mut(slice).as_slice_of_cells();
+for w in slice_of_cells.windows(3) {
+    Cell::swap(&w[0], &w[2]);
+}
+assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']);
+
1.0.0 · source

pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See chunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and rchunks for the same iterator but starting at the end of the +slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert_eq!(iter.next().unwrap(), &['m']);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of chunks.

+

See chunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and rchunks_exact for the same iterator but starting at the end of the slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+
source

pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]]

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +assuming that there’s no remainder.

+
§Safety
+

This may only be called when

+
    +
  • The slice splits exactly into N-element chunks (aka self.len() % N == 0).
  • +
  • N != 0.
  • +
+
§Examples
+
#![feature(slice_as_chunks)]
+let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
+let chunks: &[[char; 1]] =
+    // SAFETY: 1-element chunks never have remainder
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+let chunks: &[[char; 3]] =
+    // SAFETY: The slice length (6) is a multiple of 3
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
+
+// These would be unsound:
+// let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
+// let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
+
source

pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T])

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the beginning of the slice, +and a remainder slice with length strictly less than N.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (chunks, remainder) = slice.as_chunks();
+assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
+assert_eq!(remainder, &['m']);
+

If you expect the slice to be an exact multiple, you can combine +let-else with an empty slice pattern:

+ +
#![feature(slice_as_chunks)]
+let slice = ['R', 'u', 's', 't'];
+let (chunks, []) = slice.as_chunks::<2>() else {
+    panic!("slice didn't have even length")
+};
+assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
+
source

pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]])

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the end of the slice, +and a remainder slice with length strictly less than N.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (remainder, chunks) = slice.as_rchunks();
+assert_eq!(remainder, &['l']);
+assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
+
source

pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N>

🔬This is a nightly-only experimental API. (array_chunks)

Returns an iterator over N elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are array references and do not overlap. If N does not divide the +length of the slice, then the last up to N-1 elements will be omitted and can be +retrieved from the remainder function of the iterator.

+

This method is the const generic equivalent of chunks_exact.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(array_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.array_chunks();
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+
source

pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N>

🔬This is a nightly-only experimental API. (array_windows)

Returns an iterator over overlapping windows of N elements of a slice, +starting at the beginning of the slice.

+

This is the const generic equivalent of windows.

+

If N is greater than the size of the slice, it will return no windows.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(array_windows)]
+let slice = [0, 1, 2, 3];
+let mut iter = slice.array_windows();
+assert_eq!(iter.next().unwrap(), &[0, 1]);
+assert_eq!(iter.next().unwrap(), &[1, 2]);
+assert_eq!(iter.next().unwrap(), &[2, 3]);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the end +of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See rchunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and chunks for the same iterator but starting at the beginning +of the slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert_eq!(iter.next().unwrap(), &['l']);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +end of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of rchunks.

+

See rchunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and chunks_exact for the same iterator but starting at the beginning of the +slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['l']);
+
1.77.0 · source

pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F>
where + F: FnMut(&T, &T) -> bool,

Returns an iterator over the slice producing non-overlapping runs +of elements using the predicate to separate them.

+

The predicate is called for every pair of consecutive elements, +meaning that it is called on slice[0] and slice[1], +followed by slice[1] and slice[2], and so on.

+
§Examples
+
let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
+
+let mut iter = slice.chunk_by(|a, b| a == b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+assert_eq!(iter.next(), Some(&[3, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+assert_eq!(iter.next(), None);
+

This method can be used to extract the sorted subslices:

+ +
let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4];
+
+let mut iter = slice.chunk_by(|a, b| a <= b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3, 4][..]));
+assert_eq!(iter.next(), None);
+
1.0.0 · source

pub fn split_at(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+
§Panics
+

Panics if mid > len. For a non-panicking alternative see +split_at_checked.

+
§Examples
+
let v = [1, 2, 3, 4, 5, 6];
+
+{
+   let (left, right) = v.split_at(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
1.80.0 · source

pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index, without doing bounds checking.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+

For a safe alternative see split_at.

+
§Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used. The caller has to ensure that +0 <= mid <= self.len().

+
§Examples
+
let v = [1, 2, 3, 4, 5, 6];
+
+unsafe {
+   let (left, right) = v.split_at_unchecked(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
source

pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])>

🔬This is a nightly-only experimental API. (split_at_checked)

Divides one slice into two at an index, returning None if the slice is +too short.

+

If mid ≤ len returns a pair of slices where the first will contain all +indices from [0, mid) (excluding the index mid itself) and the +second will contain all indices from [mid, len) (excluding the index +len itself).

+

Otherwise, if mid > len, returns None.

+
§Examples
+
#![feature(split_at_checked)]
+
+let v = [1, -2, 3, -4, 5, -6];
+
+{
+   let (left, right) = v.split_at_checked(0).unwrap();
+   assert_eq!(left, []);
+   assert_eq!(right, [1, -2, 3, -4, 5, -6]);
+}
+
+{
+    let (left, right) = v.split_at_checked(2).unwrap();
+    assert_eq!(left, [1, -2]);
+    assert_eq!(right, [3, -4, 5, -6]);
+}
+
+{
+    let (left, right) = v.split_at_checked(6).unwrap();
+    assert_eq!(left, [1, -2, 3, -4, 5, -6]);
+    assert_eq!(right, []);
+}
+
+assert_eq!(None, v.split_at_checked(7));
+
1.0.0 · source

pub fn split<F>(&self, pred: F) -> Split<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred. The matched element is not contained in the subslices.

+
§Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the first element is matched, an empty slice will be the first item +returned by the iterator. Similarly, if the last element in the slice +is matched, an empty slice will be the last item returned by the +iterator:

+ +
let slice = [10, 40, 33];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert!(iter.next().is_none());
+

If two matched elements are directly adjacent, an empty slice will be +present between them:

+ +
let slice = [10, 6, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+
1.51.0 · source

pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred. The matched element is contained in the end of the previous +subslice as a terminator.

+
§Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the last element of the slice is matched, +that element will be considered the terminator of the preceding slice. +That slice will be the last item returned by the iterator.

+ +
let slice = [3, 10, 40, 33];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[3]);
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert!(iter.next().is_none());
+
1.27.0 · source

pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred, starting at the end of the slice and working backwards. +The matched element is not contained in the subslices.

+
§Examples
+
let slice = [11, 22, 33, 0, 44, 55];
+let mut iter = slice.rsplit(|num| *num == 0);
+
+assert_eq!(iter.next().unwrap(), &[44, 55]);
+assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+assert_eq!(iter.next(), None);
+

As with split(), if the first or last element is matched, an empty +slice will be the first (or last) item returned by the iterator.

+ +
let v = &[0, 1, 1, 2, 3, 5, 8];
+let mut it = v.rsplit(|n| *n % 2 == 0);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next().unwrap(), &[3, 5]);
+assert_eq!(it.next().unwrap(), &[1, 1]);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next(), None);
+
1.0.0 · source

pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred, limited to returning at most n items. The matched element is +not contained in the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
§Examples
+

Print the slice split once by numbers divisible by 3 (i.e., [10, 40], +[20, 60, 50]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.splitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+
1.0.0 · source

pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred limited to returning at most n items. This starts at the end of +the slice and works backwards. The matched element is not contained in +the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
§Examples
+

Print the slice split once, starting from the end, by numbers divisible +by 3 (i.e., [50], [10, 40, 30, 20]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.rsplitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+
source

pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where + F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the first element that matches the specified +predicate.

+

If any matching elements are present in the slice, returns the prefix +before the match and suffix after. The matching element itself is not +included. If no elements match, returns None.

+
§Examples
+
#![feature(slice_split_once)]
+let s = [1, 2, 3, 2, 4];
+assert_eq!(s.split_once(|&x| x == 2), Some((
+    &[1][..],
+    &[3, 2, 4][..]
+)));
+assert_eq!(s.split_once(|&x| x == 0), None);
+
source

pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where + F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the last element that matches the specified +predicate.

+

If any matching elements are present in the slice, returns the prefix +before the match and suffix after. The matching element itself is not +included. If no elements match, returns None.

+
§Examples
+
#![feature(slice_split_once)]
+let s = [1, 2, 3, 2, 4];
+assert_eq!(s.rsplit_once(|&x| x == 2), Some((
+    &[1, 2, 3][..],
+    &[4][..]
+)));
+assert_eq!(s.rsplit_once(|&x| x == 0), None);
+
1.0.0 · source

pub fn contains(&self, x: &T) -> bool
where + T: PartialEq,

Returns true if the slice contains an element with the given value.

+

This operation is O(n).

+

Note that if you have a sorted slice, binary_search may be faster.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.contains(&30));
+assert!(!v.contains(&50));
+

If you do not have a &T, but some other value that you can compare +with one (for example, String implements PartialEq<str>), you can +use iter().any:

+ +
let v = [String::from("hello"), String::from("world")]; // slice of `String`
+assert!(v.iter().any(|e| e == "hello")); // search with `&str`
+assert!(!v.iter().any(|e| e == "hi"));
+
1.0.0 · source

pub fn starts_with(&self, needle: &[T]) -> bool
where + T: PartialEq,

Returns true if needle is a prefix of the slice or equal to the slice.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.starts_with(&[10]));
+assert!(v.starts_with(&[10, 40]));
+assert!(v.starts_with(&v));
+assert!(!v.starts_with(&[50]));
+assert!(!v.starts_with(&[10, 50]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.starts_with(&[]));
+let v: &[u8] = &[];
+assert!(v.starts_with(&[]));
+
1.0.0 · source

pub fn ends_with(&self, needle: &[T]) -> bool
where + T: PartialEq,

Returns true if needle is a suffix of the slice or equal to the slice.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.ends_with(&[30]));
+assert!(v.ends_with(&[40, 30]));
+assert!(v.ends_with(&v));
+assert!(!v.ends_with(&[50]));
+assert!(!v.ends_with(&[50, 30]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.ends_with(&[]));
+let v: &[u8] = &[];
+assert!(v.ends_with(&[]));
+
1.51.0 · source

pub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]>
where + P: SlicePattern<Item = T> + ?Sized, + T: PartialEq,

Returns a subslice with the prefix removed.

+

If the slice starts with prefix, returns the subslice after the prefix, wrapped in Some. +If prefix is empty, simply returns the original slice. If prefix is equal to the +original slice, returns an empty slice.

+

If the slice does not start with prefix, returns None.

+
§Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
+assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
+assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
+assert_eq!(v.strip_prefix(&[50]), None);
+assert_eq!(v.strip_prefix(&[10, 50]), None);
+
+let prefix : &str = "he";
+assert_eq!(b"hello".strip_prefix(prefix.as_bytes()),
+           Some(b"llo".as_ref()));
+
1.51.0 · source

pub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]>
where + P: SlicePattern<Item = T> + ?Sized, + T: PartialEq,

Returns a subslice with the suffix removed.

+

If the slice ends with suffix, returns the subslice before the suffix, wrapped in Some. +If suffix is empty, simply returns the original slice. If suffix is equal to the +original slice, returns an empty slice.

+

If the slice does not end with suffix, returns None.

+
§Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
+assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
+assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..]));
+assert_eq!(v.strip_suffix(&[50]), None);
+assert_eq!(v.strip_suffix(&[50, 30]), None);
+

Binary searches this slice for a given element. +If the slice is not sorted, the returned result is unspecified and +meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search_by, binary_search_by_key, and partition_point.

+
§Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+assert_eq!(s.binary_search(&13),  Ok(9));
+assert_eq!(s.binary_search(&4),   Err(7));
+assert_eq!(s.binary_search(&100), Err(13));
+let r = s.binary_search(&1);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+

If you want to find that whole range of matching items, rather than +an arbitrary matching one, that can be done using partition_point:

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let low = s.partition_point(|x| x < &1);
+assert_eq!(low, 1);
+let high = s.partition_point(|x| x <= &1);
+assert_eq!(high, 5);
+let r = s.binary_search(&1);
+assert!((low..high).contains(&r.unwrap()));
+
+assert!(s[..low].iter().all(|&x| x < 1));
+assert!(s[low..high].iter().all(|&x| x == 1));
+assert!(s[high..].iter().all(|&x| x > 1));
+
+// For something not found, the "range" of equal items is empty
+assert_eq!(s.partition_point(|x| x < &11), 9);
+assert_eq!(s.partition_point(|x| x <= &11), 9);
+assert_eq!(s.binary_search(&11), Err(9));
+

If you want to insert an item to a sorted vector, while maintaining +sort order, consider using partition_point:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x <= num);
+// If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+// `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert`
+// to shift less elements.
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+
1.0.0 · source

pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
where + F: FnMut(&'a T) -> Ordering,

Binary searches this slice with a comparator function.

+

The comparator function should return an order code that indicates +whether its argument is Less, Equal or Greater the desired +target. +If the slice is not sorted or if the comparator function does not +implement an order consistent with the sort order of the underlying +slice, the returned result is unspecified and meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by_key, and partition_point.

+
§Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let seek = 13;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+let seek = 4;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+let seek = 100;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+let seek = 1;
+let r = s.binary_search_by(|probe| probe.cmp(&seek));
+assert!(match r { Ok(1..=4) => true, _ => false, });
+
1.10.0 · source

pub fn binary_search_by_key<'a, B, F>( + &'a self, + b: &B, + f: F +) -> Result<usize, usize>
where + F: FnMut(&'a T) -> B, + B: Ord,

Binary searches this slice with a key extraction function.

+

Assumes that the slice is sorted by the key, for instance with +sort_by_key using the same key extraction function. +If the slice is not sorted by the key, the returned result is +unspecified and meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by, and partition_point.

+
§Examples
+

Looks up a series of four elements in a slice of pairs sorted by +their second elements. The first is found, with a uniquely +determined position; the second and third are not found; the +fourth could match any position in [1, 4].

+ +
let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
+         (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+         (1, 21), (2, 34), (4, 55)];
+
+assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b),  Ok(9));
+assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b),   Err(7));
+assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
+let r = s.binary_search_by_key(&1, |&(a, b)| b);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+
1.30.0 · source

pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])

Transmute the slice to a slice of another type, ensuring alignment of the types is +maintained.

+

This method splits the slice into three distinct slices: prefix, correctly aligned middle +slice of a new type, and the suffix slice. The middle part will be as big as possible under +the given alignment constraint and element size.

+

This method has no purpose when either input element T or output element U are +zero-sized and will return the original slice without splitting anything.

+
§Safety
+

This method is essentially a transmute with respect to the elements in the returned +middle slice, so all the usual caveats pertaining to transmute::<T, U> also apply here.

+
§Examples
+

Basic usage:

+ +
unsafe {
+    let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, shorts, suffix) = bytes.align_to::<u16>();
+    // less_efficient_algorithm_for_bytes(prefix);
+    // more_efficient_algorithm_for_aligned_shorts(shorts);
+    // less_efficient_algorithm_for_bytes(suffix);
+}
+
source

pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
where + Simd<T, LANES>: AsRef<[T; LANES]>, + T: SimdElement, + LaneCount<LANES>: SupportedLaneCount,

🔬This is a nightly-only experimental API. (portable_simd)

Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.

+

This is a safe wrapper around slice::align_to, so has the same weak +postconditions as that method. You’re only assured that +self.len() == prefix.len() + middle.len() * LANES + suffix.len().

+

Notably, all of the following are possible:

+
    +
  • prefix.len() >= LANES.
  • +
  • middle.is_empty() despite self.len() >= 3 * LANES.
  • +
  • suffix.len() >= LANES.
  • +
+

That said, this is a safe method, so if you’re only writing safe code, +then this can at most cause incorrect logic, not unsoundness.

+
§Panics
+

This will panic if the size of the SIMD type is different from +LANES times that of the scalar.

+

At the time of writing, the trait restrictions on Simd<T, LANES> keeps +that from ever happening, as only power-of-two numbers of lanes are +supported. It’s possible that, in the future, those restrictions might +be lifted in a way that would make it possible to see panics from this +method for something like LANES == 3.

+
§Examples
+
#![feature(portable_simd)]
+use core::simd::prelude::*;
+
+let short = &[1, 2, 3];
+let (prefix, middle, suffix) = short.as_simd::<4>();
+assert_eq!(middle, []); // Not enough elements for anything in the middle
+
+// They might be split in any possible way between prefix and suffix
+let it = prefix.iter().chain(suffix).copied();
+assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
+
+fn basic_simd_sum(x: &[f32]) -> f32 {
+    use std::ops::Add;
+    let (prefix, middle, suffix) = x.as_simd();
+    let sums = f32x4::from_array([
+        prefix.iter().copied().sum(),
+        0.0,
+        0.0,
+        suffix.iter().copied().sum(),
+    ]);
+    let sums = middle.iter().copied().fold(sums, f32x4::add);
+    sums.reduce_sum()
+}
+
+let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
+assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
+
source

pub fn is_sorted(&self) -> bool
where + T: PartialOrd,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted.

+

That is, for each element a and its following element b, a <= b must hold. If the +slice yields exactly zero or one element, true is returned.

+

Note that if Self::Item is only PartialOrd, but not Ord, the above definition +implies that this function returns false if any two consecutive items are not +comparable.

+
§Examples
+
#![feature(is_sorted)]
+let empty: [i32; 0] = [];
+
+assert!([1, 2, 2, 9].is_sorted());
+assert!(![1, 3, 2, 4].is_sorted());
+assert!([0].is_sorted());
+assert!(empty.is_sorted());
+assert!(![0.0, 1.0, f32::NAN].is_sorted());
+
source

pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool
where + F: FnMut(&'a T, &'a T) -> bool,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given comparator function.

+

Instead of using PartialOrd::partial_cmp, this function uses the given compare +function to determine whether two elements are to be considered in sorted order.

+
§Examples
+
#![feature(is_sorted)]
+
+assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b));
+assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b));
+
+assert!([0].is_sorted_by(|a, b| true));
+assert!([0].is_sorted_by(|a, b| false));
+
+let empty: [i32; 0] = [];
+assert!(empty.is_sorted_by(|a, b| false));
+assert!(empty.is_sorted_by(|a, b| true));
+
source

pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
where + F: FnMut(&'a T) -> K, + K: PartialOrd,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given key extraction function.

+

Instead of comparing the slice’s elements directly, this function compares the keys of the +elements, as determined by f. Apart from that, it’s equivalent to is_sorted; see its +documentation for more information.

+
§Examples
+
#![feature(is_sorted)]
+
+assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+
1.52.0 · source

pub fn partition_point<P>(&self, pred: P) -> usize
where + P: FnMut(&T) -> bool,

Returns the index of the partition point according to the given predicate +(the index of the first element of the second partition).

+

The slice is assumed to be partitioned according to the given predicate. +This means that all elements for which the predicate returns true are at the start of the slice +and all elements for which the predicate returns false are at the end. +For example, [7, 15, 3, 5, 4, 12, 6] is partitioned under the predicate x % 2 != 0 +(all odd numbers are at the start, all even at the end).

+

If this slice is not partitioned, the returned result is unspecified and meaningless, +as this method performs a kind of binary search.

+

See also binary_search, binary_search_by, and binary_search_by_key.

+
§Examples
+
let v = [1, 2, 3, 3, 5, 6, 7];
+let i = v.partition_point(|&x| x < 5);
+
+assert_eq!(i, 4);
+assert!(v[..i].iter().all(|&x| x < 5));
+assert!(v[i..].iter().all(|&x| !(x < 5)));
+

If all elements of the slice match the predicate, including if the slice +is empty, then the length of the slice will be returned:

+ +
let a = [2, 4, 8];
+assert_eq!(a.partition_point(|x| x < &100), a.len());
+let a: [i32; 0] = [];
+assert_eq!(a.partition_point(|x| x < &100), 0);
+

If you want to insert an item to a sorted vector, while maintaining +sort order:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x <= num);
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+
source

pub fn flatten(&self) -> &[T]

🔬This is a nightly-only experimental API. (slice_flatten)

Takes a &[[T; N]], and flattens it to a &[T].

+
§Panics
+

This panics if the length of the resulting slice would overflow a usize.

+

This is only possible when flattening a slice of arrays of zero-sized +types, and thus tends to be irrelevant in practice. If +size_of::<T>() > 0, this will never panic.

+
§Examples
+
#![feature(slice_flatten)]
+
+assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
+
+assert_eq!(
+    [[1, 2, 3], [4, 5, 6]].flatten(),
+    [[1, 2], [3, 4], [5, 6]].flatten(),
+);
+
+let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
+assert!(slice_of_empty_arrays.flatten().is_empty());
+
+let empty_slice_of_arrays: &[[u32; 10]] = &[];
+assert!(empty_slice_of_arrays.flatten().is_empty());
+
1.23.0 · source

pub fn is_ascii(&self) -> bool

Checks if all bytes in this slice are within the ASCII range.

+
source

pub fn as_ascii(&self) -> Option<&[AsciiChar]>

🔬This is a nightly-only experimental API. (ascii_char)

If this slice is_ascii, returns it as a slice of +ASCII characters, otherwise returns None.

+
source

pub unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar]

🔬This is a nightly-only experimental API. (ascii_char)

Converts this slice of bytes into a slice of ASCII characters, +without checking whether they’re valid.

+
§Safety
+

Every byte in the slice must be in 0..=127, or else this is UB.

+
1.23.0 · source

pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool

Checks that two slices are an ASCII case-insensitive match.

+

Same as to_ascii_lowercase(a) == to_ascii_lowercase(b), +but without allocating and copying temporaries.

+
1.60.0 · source

pub fn escape_ascii(&self) -> EscapeAscii<'_>

Returns an iterator that produces an escaped version of this slice, +treating it as an ASCII string.

+
§Examples
+

+let s = b"0\t\r\n'\"\\\x9d";
+let escaped = s.escape_ascii().to_string();
+assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
+
source

pub fn trim_ascii_start(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
+assert_eq!(b"  ".trim_ascii_start(), b"");
+assert_eq!(b"".trim_ascii_start(), b"");
+
source

pub fn trim_ascii_end(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with trailing ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
+assert_eq!(b"  ".trim_ascii_end(), b"");
+assert_eq!(b"".trim_ascii_end(), b"");
+
source

pub fn trim_ascii(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading and trailing ASCII whitespace bytes +removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
+assert_eq!(b"  ".trim_ascii(), b"");
+assert_eq!(b"".trim_ascii(), b"");
+
1.80.0 · source

pub fn utf8_chunks(&self) -> Utf8Chunks<'_>

Creates an iterator over the contiguous valid UTF-8 ranges of this +slice, and the non-UTF-8 fragments in between.

+
§Examples
+

This function formats arbitrary but mostly-UTF-8 bytes into Rust source +code in the form of a C-string literal (c"...").

+ +
use std::fmt::Write as _;
+
+pub fn cstr_literal(bytes: &[u8]) -> String {
+    let mut repr = String::new();
+    repr.push_str("c\"");
+    for chunk in bytes.utf8_chunks() {
+        for ch in chunk.valid().chars() {
+            // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for non-printable characters.
+            write!(repr, "{}", ch.escape_debug()).unwrap();
+        }
+        for byte in chunk.invalid() {
+            write!(repr, "\\x{:02X}", byte).unwrap();
+        }
+    }
+    repr.push('"');
+    repr
+}
+
+fn main() {
+    let lit = cstr_literal(b"\xferris the \xf0\x9f\xa6\x80\x07");
+    let expected = stringify!(c"\xFErris the 🦀\u{7}");
+    assert_eq!(lit, expected);
+}
+
1.23.0 · source

pub fn to_ascii_uppercase(&self) -> Vec<u8>

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII upper case equivalent.

+

ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, +but non-ASCII letters are unchanged.

+

To uppercase the value in-place, use make_ascii_uppercase.

+
1.23.0 · source

pub fn to_ascii_lowercase(&self) -> Vec<u8>

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII lower case equivalent.

+

ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, +but non-ASCII letters are unchanged.

+

To lowercase the value in-place, use make_ascii_lowercase.

+
1.0.0 · source

pub fn to_vec(&self) -> Vec<T>
where + T: Clone,

Copies self into a new Vec.

+
§Examples
+
let s = [10, 40, 30];
+let x = s.to_vec();
+// Here, `s` and `x` can be modified independently.
+
source

pub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A>
where + A: Allocator, + T: Clone,

🔬This is a nightly-only experimental API. (allocator_api)

Copies self into a new Vec with an allocator.

+
§Examples
+
#![feature(allocator_api)]
+
+use std::alloc::System;
+
+let s = [10, 40, 30];
+let x = s.to_vec_in(System);
+// Here, `s` and `x` can be modified independently.
+
1.40.0 · source

pub fn repeat(&self, n: usize) -> Vec<T>
where + T: Copy,

Creates a vector by copying a slice n times.

+
§Panics
+

This function will panic if the capacity would overflow.

+
§Examples
+

Basic usage:

+ +
assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
+

A panic upon overflow:

+ +
// this will panic at runtime
+b"0123456789abcdef".repeat(usize::MAX);
+
1.0.0 · source

pub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output
where + [T]: Concat<Item>, + Item: ?Sized,

Flattens a slice of T into a single value Self::Output.

+
§Examples
+
assert_eq!(["hello", "world"].concat(), "helloworld");
+assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
+
1.3.0 · source

pub fn join<Separator>( + &self, + sep: Separator +) -> <[T] as Join<Separator>>::Output
where + [T]: Join<Separator>,

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
§Examples
+
assert_eq!(["hello", "world"].join(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
+assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
+
1.0.0 · source

pub fn connect<Separator>( + &self, + sep: Separator +) -> <[T] as Join<Separator>>::Output
where + [T]: Join<Separator>,

👎Deprecated since 1.3.0: renamed to join

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
§Examples
+
assert_eq!(["hello", "world"].connect(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
+

Trait Implementations§

§

impl AsRef<[u8]> for Bytes

§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
§

impl Borrow<[u8]> for Bytes

§

fn borrow(&self) -> &[u8]

Immutably borrows from an owned value. Read more
§

impl Buf for Bytes

§

fn remaining(&self) -> usize

Returns the number of bytes between the current position and the end of +the buffer. Read more
§

fn chunk(&self) -> &[u8]

Returns a slice starting at the current position and of length between 0 +and Buf::remaining(). Note that this can return a shorter slice (this +allows non-continuous internal representation). Read more
§

fn advance(&mut self, cnt: usize)

Advance the internal cursor of the Buf Read more
§

fn copy_to_bytes(&mut self, len: usize) -> Bytes

Consumes len bytes inside self and returns new instance of Bytes +with this data. Read more
§

fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize

Fills dst with potentially multiple slices starting at self’s +current position. Read more
§

fn has_remaining(&self) -> bool

Returns true if there are any more bytes to consume Read more
§

fn copy_to_slice(&mut self, dst: &mut [u8])

Copies bytes from self into dst. Read more
§

fn get_u8(&mut self) -> u8

Gets an unsigned 8 bit integer from self. Read more
§

fn get_i8(&mut self) -> i8

Gets a signed 8 bit integer from self. Read more
§

fn get_u16(&mut self) -> u16

Gets an unsigned 16 bit integer from self in big-endian byte order. Read more
§

fn get_u16_le(&mut self) -> u16

Gets an unsigned 16 bit integer from self in little-endian byte order. Read more
§

fn get_u16_ne(&mut self) -> u16

Gets an unsigned 16 bit integer from self in native-endian byte order. Read more
§

fn get_i16(&mut self) -> i16

Gets a signed 16 bit integer from self in big-endian byte order. Read more
§

fn get_i16_le(&mut self) -> i16

Gets a signed 16 bit integer from self in little-endian byte order. Read more
§

fn get_i16_ne(&mut self) -> i16

Gets a signed 16 bit integer from self in native-endian byte order. Read more
§

fn get_u32(&mut self) -> u32

Gets an unsigned 32 bit integer from self in the big-endian byte order. Read more
§

fn get_u32_le(&mut self) -> u32

Gets an unsigned 32 bit integer from self in the little-endian byte order. Read more
§

fn get_u32_ne(&mut self) -> u32

Gets an unsigned 32 bit integer from self in native-endian byte order. Read more
§

fn get_i32(&mut self) -> i32

Gets a signed 32 bit integer from self in big-endian byte order. Read more
§

fn get_i32_le(&mut self) -> i32

Gets a signed 32 bit integer from self in little-endian byte order. Read more
§

fn get_i32_ne(&mut self) -> i32

Gets a signed 32 bit integer from self in native-endian byte order. Read more
§

fn get_u64(&mut self) -> u64

Gets an unsigned 64 bit integer from self in big-endian byte order. Read more
§

fn get_u64_le(&mut self) -> u64

Gets an unsigned 64 bit integer from self in little-endian byte order. Read more
§

fn get_u64_ne(&mut self) -> u64

Gets an unsigned 64 bit integer from self in native-endian byte order. Read more
§

fn get_i64(&mut self) -> i64

Gets a signed 64 bit integer from self in big-endian byte order. Read more
§

fn get_i64_le(&mut self) -> i64

Gets a signed 64 bit integer from self in little-endian byte order. Read more
§

fn get_i64_ne(&mut self) -> i64

Gets a signed 64 bit integer from self in native-endian byte order. Read more
§

fn get_u128(&mut self) -> u128

Gets an unsigned 128 bit integer from self in big-endian byte order. Read more
§

fn get_u128_le(&mut self) -> u128

Gets an unsigned 128 bit integer from self in little-endian byte order. Read more
§

fn get_u128_ne(&mut self) -> u128

Gets an unsigned 128 bit integer from self in native-endian byte order. Read more
§

fn get_i128(&mut self) -> i128

Gets a signed 128 bit integer from self in big-endian byte order. Read more
§

fn get_i128_le(&mut self) -> i128

Gets a signed 128 bit integer from self in little-endian byte order. Read more
§

fn get_i128_ne(&mut self) -> i128

Gets a signed 128 bit integer from self in native-endian byte order. Read more
§

fn get_uint(&mut self, nbytes: usize) -> u64

Gets an unsigned n-byte integer from self in big-endian byte order. Read more
§

fn get_uint_le(&mut self, nbytes: usize) -> u64

Gets an unsigned n-byte integer from self in little-endian byte order. Read more
§

fn get_uint_ne(&mut self, nbytes: usize) -> u64

Gets an unsigned n-byte integer from self in native-endian byte order. Read more
§

fn get_int(&mut self, nbytes: usize) -> i64

Gets a signed n-byte integer from self in big-endian byte order. Read more
§

fn get_int_le(&mut self, nbytes: usize) -> i64

Gets a signed n-byte integer from self in little-endian byte order. Read more
§

fn get_int_ne(&mut self, nbytes: usize) -> i64

Gets a signed n-byte integer from self in native-endian byte order. Read more
§

fn get_f32(&mut self) -> f32

Gets an IEEE754 single-precision (4 bytes) floating point number from +self in big-endian byte order. Read more
§

fn get_f32_le(&mut self) -> f32

Gets an IEEE754 single-precision (4 bytes) floating point number from +self in little-endian byte order. Read more
§

fn get_f32_ne(&mut self) -> f32

Gets an IEEE754 single-precision (4 bytes) floating point number from +self in native-endian byte order. Read more
§

fn get_f64(&mut self) -> f64

Gets an IEEE754 double-precision (8 bytes) floating point number from +self in big-endian byte order. Read more
§

fn get_f64_le(&mut self) -> f64

Gets an IEEE754 double-precision (8 bytes) floating point number from +self in little-endian byte order. Read more
§

fn get_f64_ne(&mut self) -> f64

Gets an IEEE754 double-precision (8 bytes) floating point number from +self in native-endian byte order. Read more
§

fn take(self, limit: usize) -> Take<Self>
where + Self: Sized,

Creates an adaptor which will read at most limit bytes from self. Read more
§

fn chain<U>(self, next: U) -> Chain<Self, U>
where + U: Buf, + Self: Sized,

Creates an adaptor which will chain this buffer with another. Read more
§

fn reader(self) -> Reader<Self>
where + Self: Sized,

Creates an adaptor which implements the Read trait for self. Read more
§

impl Clone for Bytes

§

fn clone(&self) -> Bytes

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Bytes

§

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

Formats the value using the given formatter. Read more
§

impl Default for Bytes

§

fn default() -> Bytes

Returns the “default value” for a type. Read more
§

impl Deref for Bytes

§

type Target = [u8]

The resulting type after dereferencing.
§

fn deref(&self) -> &[u8]

Dereferences the value.
§

impl Drop for Bytes

§

fn drop(&mut self)

Executes the destructor for this type. Read more
§

impl From<&'static [u8]> for Bytes

§

fn from(slice: &'static [u8]) -> Bytes

Converts to this type from the input type.
§

impl From<&'static str> for Bytes

§

fn from(slice: &'static str) -> Bytes

Converts to this type from the input type.
§

impl From<Box<[u8]>> for Bytes

§

fn from(slice: Box<[u8]>) -> Bytes

Converts to this type from the input type.
§

impl From<ByteStr> for Bytes

§

fn from(src: ByteStr) -> Bytes

Converts to this type from the input type.
source§

impl From<ByteStr> for Bytes

source§

fn from(src: ByteStr) -> Bytes

Converts to this type from the input type.
§

impl From<Bytes> for Vec<u8>

§

fn from(bytes: Bytes) -> Vec<u8>

Converts to this type from the input type.
§

impl From<BytesMut> for Bytes

§

fn from(src: BytesMut) -> Bytes

Converts to this type from the input type.
§

impl From<Custom> for Bytes

§

fn from(_: Custom) -> Bytes

Converts to this type from the input type.
source§

impl From<Custom> for Bytes

source§

fn from(_: Custom) -> Bytes

Converts to this type from the input type.
§

impl From<ReasonPhrase> for Bytes

§

fn from(reason: ReasonPhrase) -> Bytes

Converts to this type from the input type.
§

impl From<String> for Bytes

§

fn from(s: String) -> Bytes

Converts to this type from the input type.
§

impl From<Vec<u8>> for Bytes

§

fn from(vec: Vec<u8>) -> Bytes

Converts to this type from the input type.
§

impl FromIterator<u8> for Bytes

§

fn from_iter<T>(into_iter: T) -> Bytes
where + T: IntoIterator<Item = u8>,

Creates a value from an iterator. Read more
§

impl<S> FromRequest<S> for Bytes
where + S: Send + Sync,

§

type Rejection = BytesRejection

If the extractor fails it’ll use this “rejection” type. A rejection is +a kind of error that can be converted into a response.
§

fn from_request<'life0, 'async_trait>( + req: Request<Body>, + _: &'life0 S +) -> Pin<Box<dyn Future<Output = Result<Bytes, <Bytes as FromRequest<S>>::Rejection>> + Send + 'async_trait>>
where + 'life0: 'async_trait, + Bytes: 'async_trait,

Perform the extraction.
§

impl Hash for Bytes

§

fn hash<H>(&self, state: &mut H)
where + H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
§

impl<'a> IntoIterator for &'a Bytes

§

type Item = &'a u8

The type of the elements being iterated over.
§

type IntoIter = Iter<'a, u8>

Which kind of iterator are we turning this into?
§

fn into_iter(self) -> <&'a Bytes as IntoIterator>::IntoIter

Creates an iterator from a value. Read more
§

impl IntoIterator for Bytes

§

type Item = u8

The type of the elements being iterated over.
§

type IntoIter = IntoIter<Bytes>

Which kind of iterator are we turning this into?
§

fn into_iter(self) -> <Bytes as IntoIterator>::IntoIter

Creates an iterator from a value. Read more
§

impl IntoResponse for Bytes

§

fn into_response(self) -> Response<Body>

Create a response.
§

impl LowerHex for Bytes

§

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

Formats the value using the given formatter.
§

impl Ord for Bytes

§

fn cmp(&self, other: &Bytes) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
§

impl<'a, T> PartialEq<&'a T> for Bytes
where + Bytes: PartialEq<T>, + T: ?Sized,

§

fn eq(&self, other: &&'a T) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<[u8]> for Bytes

§

fn eq(&self, other: &[u8]) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Bytes> for &[u8]

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Bytes> for &str

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Bytes> for [u8]

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Bytes> for Vec<u8>

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Bytes> for str

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<BytesMut> for Bytes

§

fn eq(&self, other: &BytesMut) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<String> for Bytes

§

fn eq(&self, other: &String) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<Vec<u8>> for Bytes

§

fn eq(&self, other: &Vec<u8>) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq<str> for Bytes

§

fn eq(&self, other: &str) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialEq for Bytes

§

fn eq(&self, other: &Bytes) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl<'a, T> PartialOrd<&'a T> for Bytes
where + Bytes: PartialOrd<T>, + T: ?Sized,

§

fn partial_cmp(&self, other: &&'a T) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<[u8]> for Bytes

§

fn partial_cmp(&self, other: &[u8]) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Bytes> for &[u8]

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Bytes> for &str

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Bytes> for [u8]

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Bytes> for Vec<u8>

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Bytes> for str

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<String> for Bytes

§

fn partial_cmp(&self, other: &String) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<Vec<u8>> for Bytes

§

fn partial_cmp(&self, other: &Vec<u8>) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd<str> for Bytes

§

fn partial_cmp(&self, other: &str) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl PartialOrd for Bytes

§

fn partial_cmp(&self, other: &Bytes) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl UpperHex for Bytes

§

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

Formats the value using the given formatter.
§

impl Eq for Bytes

§

impl Send for Bytes

§

impl Sync for Bytes

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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, S> Handler<IntoResponseHandler, S> for T
where + T: IntoResponse + Clone + Send + 'static,

§

type Future = Ready<Response<Body>>

The type of future calling this handler returns.
§

fn call( + self, + _req: Request<Body>, + _state: S +) -> <T as Handler<IntoResponseHandler, S>>::Future

Call the handler with the given request.
§

fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>
where + L: Layer<HandlerService<Self, T, S>> + Clone, + <L as Layer<HandlerService<Self, T, S>>>::Service: Service<Request<Body>>,

Apply a [tower::Layer] to the handler. Read more
§

fn with_state(self, state: S) -> HandlerService<Self, T, S>

Convert the handler into a [Service] by providing the state
§

impl<H, T> HandlerWithoutStateExt<T> for H
where + H: Handler<T, ()>,

§

fn into_service(self) -> HandlerService<H, T, ()>

Convert the handler into a [Service] and no state.
§

fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, ()>>

Convert the handler into a MakeService and no state. Read more
§

fn into_make_service_with_connect_info<C>( + self +) -> IntoMakeServiceWithConnectInfo<HandlerService<H, T, ()>, C>

Convert the handler into a MakeService which stores information +about the incoming connection and has no state. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Chunk.html b/pr/2992/docs/iroh/endpoint/struct.Chunk.html new file mode 100644 index 0000000000..e2145753c4 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Chunk.html @@ -0,0 +1,38 @@ +Chunk in iroh::endpoint - Rust

Struct iroh::endpoint::Chunk

pub struct Chunk {
+    pub offset: u64,
+    pub bytes: Bytes,
+}
Expand description

A chunk of data from the receive stream

+

Fields§

§offset: u64

The offset in the stream

+
§bytes: Bytes

The contents of the chunk

+

Trait Implementations§

§

impl Debug for Chunk

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for Chunk

§

fn eq(&self, other: &Chunk) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for Chunk

§

impl StructuralPartialEq for Chunk

Auto Trait Implementations§

§

impl !Freeze for Chunk

§

impl RefUnwindSafe for Chunk

§

impl Send for Chunk

§

impl Sync for Chunk

§

impl Unpin for Chunk

§

impl UnwindSafe for Chunk

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ClosedStream.html b/pr/2992/docs/iroh/endpoint/struct.ClosedStream.html new file mode 100644 index 0000000000..e6f88066f8 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ClosedStream.html @@ -0,0 +1,37 @@ +ClosedStream in iroh::endpoint - Rust

Struct iroh::endpoint::ClosedStream

pub struct ClosedStream { /* private fields */ }
Expand description

Error indicating that a stream has not been opened or has already been finished or reset

+

Trait Implementations§

§

impl Clone for ClosedStream

§

fn clone(&self) -> ClosedStream

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ClosedStream

§

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

Formats the value using the given formatter. Read more
§

impl Display for ClosedStream

§

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

Formats the value using the given formatter. Read more
§

impl Error for ClosedStream

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<ClosedStream> for WriteError

§

fn from(_: ClosedStream) -> WriteError

Converts to this type from the input type.
§

impl PartialEq for ClosedStream

§

fn eq(&self, other: &ClosedStream) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ClosedStream

§

impl StructuralPartialEq for ClosedStream

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Connecting.html b/pr/2992/docs/iroh/endpoint/struct.Connecting.html new file mode 100644 index 0000000000..ec22aa89e1 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Connecting.html @@ -0,0 +1,158 @@ +Connecting in iroh::endpoint - Rust

Struct iroh::endpoint::Connecting

source ·
pub struct Connecting { /* private fields */ }
Expand description

In-progress connection attempt future

+

Implementations§

source§

impl Connecting

source

pub fn into_0rtt(self) -> Result<(Connection, ZeroRttAccepted), Self>

Convert into a 0-RTT or 0.5-RTT connection at the cost of weakened security.

+
source

pub async fn handshake_data(&mut self) -> Result<Box<dyn Any>, ConnectionError>

Parameters negotiated during the handshake

+
source

pub fn local_ip(&self) -> Option<IpAddr>

The local IP address which was used when the peer established the connection.

+
source

pub fn remote_address(&self) -> SocketAddr

The peer’s UDP address.

+
source

pub async fn alpn(&mut self) -> Result<Vec<u8>>

Extracts the ALPN protocol from the peer’s handshake data.

+

Trait Implementations§

source§

impl Debug for Connecting

source§

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

Formats the value using the given formatter. Read more
source§

impl Future for Connecting

§

type Output = Result<Connection, ConnectionError>

The type of value produced on completion.
source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
source§

impl<'pin> Unpin for Connecting
where + PinnedFieldsOf<__Connecting<'pin>>: Unpin,

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Connection.html b/pr/2992/docs/iroh/endpoint/struct.Connection.html new file mode 100644 index 0000000000..6ca37193f2 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Connection.html @@ -0,0 +1,142 @@ +Connection in iroh::endpoint - Rust

Struct iroh::endpoint::Connection

pub struct Connection(/* private fields */);
Expand description

A QUIC connection.

+

If all references to a connection (including every clone of the Connection handle, streams of +incoming streams, and the various stream types) have been dropped, then the connection will be +automatically closed with an error_code of 0 and an empty reason. You can also close the +connection explicitly by calling Connection::close().

+

Closing the connection immediately abandons efforts to deliver data to the peer. Upon +receiving CONNECTION_CLOSE the peer may drop any stream data not yet delivered to the +application. Connection::close() describes in more detail how to gracefully close a +connection without losing application data.

+

May be cloned to obtain another handle to the same connection.

+

Implementations§

§

impl Connection

pub fn weak_handle(&self) -> WeakConnectionHandle

Returns a weak reference to the inner connection struct.

+

pub fn open_uni(&self) -> OpenUni<'_>

Initiate a new outgoing unidirectional stream.

+

Streams are cheap and instantaneous to open unless blocked by flow control. As a +consequence, the peer won’t be notified that a stream has been opened until the stream is +actually used.

+

pub fn open_bi(&self) -> OpenBi<'_>

Initiate a new outgoing bidirectional stream.

+

Streams are cheap and instantaneous to open unless blocked by flow control. As a +consequence, the peer won’t be notified that a stream has been opened until the stream is +actually used. Calling open_bi() then waiting on the RecvStream without writing +anything to SendStream will never succeed.

+

pub fn accept_uni(&self) -> AcceptUni<'_>

Accept the next incoming uni-directional stream

+

pub fn accept_bi(&self) -> AcceptBi<'_>

Accept the next incoming bidirectional stream

+

Important Note: The Connection that calls open_bi() must write to its SendStream +before the other Connection is able to accept_bi(). Calling open_bi() then +waiting on the RecvStream without writing anything to SendStream will never succeed.

+

pub fn read_datagram(&self) -> ReadDatagram<'_>

Receive an application datagram

+

pub async fn closed(&self) -> ConnectionError

Wait for the connection to be closed for any reason

+

Despite the return type’s name, closed connections are often not an error condition at the +application layer. Cases that might be routine include ConnectionError::LocallyClosed +and ConnectionError::ApplicationClosed.

+

pub fn close_reason(&self) -> Option<ConnectionError>

If the connection is closed, the reason why.

+

Returns None if the connection is still open.

+

pub fn close(&self, error_code: VarInt, reason: &[u8])

Close the connection immediately.

+

Pending operations will fail immediately with ConnectionError::LocallyClosed. No +more data is sent to the peer and the peer may drop buffered data upon receiving +the CONNECTION_CLOSE frame.

+

error_code and reason are not interpreted, and are provided directly to the peer.

+

reason will be truncated to fit in a single packet with overhead; to improve odds that it +is preserved in full, it should be kept under 1KiB.

+
§Gracefully closing a connection
+

Only the peer last receiving application data can be certain that all data is +delivered. The only reliable action it can then take is to close the connection, +potentially with a custom error code. The delivery of the final CONNECTION_CLOSE +frame is very likely if both endpoints stay online long enough, and +Endpoint::wait_idle() can be used to provide sufficient time. Otherwise, the +remote peer will time out the connection, provided that the idle timeout is not +disabled.

+

The sending side can not guarantee all stream data is delivered to the remote +application. It only knows the data is delivered to the QUIC stack of the remote +endpoint. Once the local side sends a CONNECTION_CLOSE frame in response to calling +close() the remote endpoint may drop any data it received but is as yet +undelivered to the application, including data that was acknowledged as received to +the local endpoint.

+

pub fn send_datagram(&self, data: Bytes) -> Result<(), SendDatagramError>

Transmit data as an unreliable, unordered application datagram

+

Application datagrams are a low-level primitive. They may be lost or delivered out of order, +and data must both fit inside a single QUIC packet and be smaller than the maximum +dictated by the peer.

+

pub fn send_datagram_wait(&self, data: Bytes) -> SendDatagram<'_>

Transmit data as an unreliable, unordered application datagram

+

Unlike send_datagram(), this method will wait for buffer space during congestion +conditions, which effectively prioritizes old datagrams over new datagrams.

+

See send_datagram() for details.

+

pub fn max_datagram_size(&self) -> Option<usize>

Compute the maximum size of datagrams that may be passed to send_datagram().

+

Returns None if datagrams are unsupported by the peer or disabled locally.

+

This may change over the lifetime of a connection according to variation in the path MTU +estimate. The peer can also enforce an arbitrarily small fixed limit, but if the peer’s +limit is large this is guaranteed to be a little over a kilobyte at minimum.

+

Not necessarily the maximum size of received datagrams.

+

pub fn datagram_send_buffer_space(&self) -> usize

Bytes available in the outgoing datagram buffer

+

When greater than zero, calling send_datagram() with a datagram of +at most this size is guaranteed not to cause older datagrams to be dropped.

+

pub fn remote_address(&self) -> SocketAddr

The peer’s UDP address

+

If ServerConfig::migration is true, clients may change addresses at will, e.g. when +switching to a cellular internet connection.

+

pub fn local_ip(&self) -> Option<IpAddr>

The local IP address which was used when the peer established +the connection

+

This can be different from the address the endpoint is bound to, in case +the endpoint is bound to a wildcard address like 0.0.0.0 or ::.

+

This will return None for clients, or when the platform does not expose this +information. See quinn_udp::RecvMeta::dst_ip for a list of +supported platforms when using quinn_udp for I/O, which is the default.

+

pub fn rtt(&self) -> Duration

Current best estimate of this connection’s latency (round-trip-time)

+

pub fn stats(&self) -> ConnectionStats

Returns connection statistics

+

pub fn congestion_state(&self) -> Box<dyn Controller>

Current state of the congestion control algorithm, for debugging purposes

+

pub fn handshake_data(&self) -> Option<Box<dyn Any>>

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.

+

pub fn peer_identity(&self) -> Option<Box<dyn Any>>

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]>

+

pub fn stable_id(&self) -> usize

A stable identifier for this connection

+

Peer addresses and connection IDs can change, but this value will remain +fixed for the lifetime of the connection.

+

pub fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: &[u8] +) -> Result<(), ExportKeyingMaterialError>

Derive keying material from this connection’s TLS session secrets.

+

When both peers call this method with the same label and context +arguments and output buffers of equal length, they will get the +same sequence of bytes in output. These bytes are cryptographically +strong and pseudorandom, and are suitable for use as keying material.

+

See RFC5705 for more information.

+

pub fn set_max_concurrent_uni_streams(&self, count: VarInt)

Modify the number of remotely initiated unidirectional streams that may be concurrently open

+

No streams may be opened by the peer unless fewer than count are already open. Large +counts increase both minimum and worst-case memory consumption.

+

pub fn set_receive_window(&self, receive_window: VarInt)

pub fn set_max_concurrent_bi_streams(&self, count: VarInt)

Modify the number of remotely initiated bidirectional streams that may be concurrently open

+

No streams may be opened by the peer unless fewer than count are already open. Large +counts increase both minimum and worst-case memory consumption.

+

pub fn observed_external_addr(&self) -> Receiver<Option<SocketAddr>>

Track changed on our external address as reported by the peer.

+

Trait Implementations§

§

impl Clone for Connection

§

fn clone(&self) -> Connection

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Connection

§

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

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ConnectionClose.html b/pr/2992/docs/iroh/endpoint/struct.ConnectionClose.html new file mode 100644 index 0000000000..77901d8b56 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ConnectionClose.html @@ -0,0 +1,44 @@ +ConnectionClose in iroh::endpoint - Rust

Struct iroh::endpoint::ConnectionClose

pub struct ConnectionClose {
+    pub error_code: Code,
+    pub frame_type: Option<Type>,
+    pub reason: Bytes,
+}
Expand description

Reason given by the transport for closing the connection

+

Fields§

§error_code: Code

Class of error as encoded in the specification

+
§frame_type: Option<Type>

Type of frame that caused the close

+
§reason: Bytes

Human-readable reason for the close

+

Trait Implementations§

§

impl Clone for ConnectionClose

§

fn clone(&self) -> ConnectionClose

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ConnectionClose

§

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

Formats the value using the given formatter. Read more
§

impl Display for ConnectionClose

§

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

Formats the value using the given formatter. Read more
§

impl From<Error> for ConnectionClose

§

fn from(x: Error) -> ConnectionClose

Converts to this type from the input type.
§

impl PartialEq for ConnectionClose

§

fn eq(&self, other: &ConnectionClose) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ConnectionClose

§

impl StructuralPartialEq for ConnectionClose

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ConnectionStats.html b/pr/2992/docs/iroh/endpoint/struct.ConnectionStats.html new file mode 100644 index 0000000000..ca5015db47 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ConnectionStats.html @@ -0,0 +1,41 @@ +ConnectionStats in iroh::endpoint - Rust

Struct iroh::endpoint::ConnectionStats

#[non_exhaustive]
pub struct ConnectionStats { + pub udp_tx: UdpStats, + pub udp_rx: UdpStats, + pub frame_tx: FrameStats, + pub frame_rx: FrameStats, + pub path: PathStats, +}
Expand description

Connection statistics

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§udp_tx: UdpStats

Statistics about UDP datagrams transmitted on a connection

+
§udp_rx: UdpStats

Statistics about UDP datagrams received on a connection

+
§frame_tx: FrameStats

Statistics about frames transmitted on a connection

+
§frame_rx: FrameStats

Statistics about frames received on a connection

+
§path: PathStats

Statistics related to the current transmission path

+

Trait Implementations§

§

impl Clone for ConnectionStats

§

fn clone(&self) -> ConnectionStats

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ConnectionStats

§

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

Formats the value using the given formatter. Read more
§

impl Default for ConnectionStats

§

fn default() -> ConnectionStats

Returns the “default value” for a type. Read more
§

impl Copy for ConnectionStats

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ConnectionTypeStream.html b/pr/2992/docs/iroh/endpoint/struct.ConnectionTypeStream.html new file mode 100644 index 0000000000..98b8c5e789 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ConnectionTypeStream.html @@ -0,0 +1,424 @@ +ConnectionTypeStream in iroh::endpoint - Rust

Struct iroh::endpoint::ConnectionTypeStream

source ·
pub struct ConnectionTypeStream { /* private fields */ }
Expand description

Stream returning ConnectionTypes

+

Trait Implementations§

source§

impl Debug for ConnectionTypeStream

source§

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

Formats the value using the given formatter. Read more
source§

impl Stream for ConnectionTypeStream

§

type Item = ConnectionType

Values yielded by the stream.
source§

fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_> +) -> Poll<Option<Self::Item>>

Attempt to pull out the next value of this stream, registering the +current task for wakeup if the value is not yet available, and returning +None if the stream is exhausted. Read more
§

fn size_hint(&self) -> (usize, Option<usize>)

Returns the bounds on the remaining length of the stream. 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
§

impl<T> BufferedStreamExt for T
where + T: Stream + ?Sized,

§

fn buffered_ordered(self, n: usize) -> BufferedOrdered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffered_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: usize, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<S> IntoStream for S
where + S: Stream,

§

type Item = <S as Stream>::Item

The type of the elements being iterated over.
§

type IntoStream = S

Which kind of stream are we turning this into?
§

fn into_stream(self) -> S

Creates a stream from a value.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn drain(&mut self) -> Drain<'_, Self>

Yields all immediately available values from a stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S1> StreamExt for S1
where + S1: Stream,

§

fn merge<T, S2>( + self, + other: S2 +) -> Merge2<T, S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Combines two streams into a single stream of all their outputs.
§

fn chain<T, S2>(self, other: S2) -> Chain2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Takes two streams and creates a new stream over all in sequence
§

fn zip<T, S2>(self, other: S2) -> Zip2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

‘Zips up’ multiple streams into a single stream of pairs.
§

fn co(self) -> FromStream<Self>
where + Self: Sized,

Convert into a concurrent stream.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay the yielding of items from the stream until the given deadline. Read more
§

impl<St> StreamExt for St
where + St: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Consumes and returns the next value in the stream or None if the +stream is finished. Read more
§

fn try_next<T, E>(&mut self) -> TryNext<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Consumes and returns the next item in the stream. If an error is +encountered before the next item, the error is returned instead. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn map_while<T, F>(self, f: F) -> MapWhile<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Map this stream’s items to a different type for as long as determined by +the provided closure. A stream of the target type will be returned, +which will yield elements until the closure returns None. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Maps this stream’s items asynchronously to a different type, returning a +new stream of the resulting type. Read more
§

fn merge<U>(self, other: U) -> Merge<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by interleaving the output of both as it +is produced. Read more
§

fn filter<F>(self, f: F) -> Filter<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Filters the values produced by this stream according to the provided +predicate. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Creates a stream which ends after the first None. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn take_while<F>(self, f: F) -> TakeWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Take elements from this stream while the provided predicate +resolves to true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream that will skip the n first items of the +underlying stream. Read more
§

fn skip_while<F>(self, f: F) -> SkipWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Skip elements from the underlying stream while the provided predicate +resolves to true. Read more
§

fn all<F>(&mut self, f: F) -> AllFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if every element of the stream matches a predicate. Read more
§

fn any<F>(&mut self, f: F) -> AnyFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if any element of the stream matches a predicate. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by first returning all values from the +first stream then all values from the second stream. Read more
§

fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
where + Self: Sized, + F: FnMut(B, Self::Item) -> B,

A combinator that applies a function to every element in a stream +producing a single, final value. Read more
§

fn collect<T>(self) -> Collect<Self, T>
where + T: FromStream<Self::Item>, + Self: Sized,

Drain stream pushing all emitted values into a collection. Read more
§

fn timeout(self, duration: Duration) -> Timeout<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn timeout_repeating(self, interval: Interval) -> TimeoutRepeating<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn throttle(self, duration: Duration) -> Throttle<Self>
where + Self: Sized,

Slows down a stream by enforcing a delay between items. Read more
§

fn chunks_timeout( + self, + max_size: usize, + duration: Duration +) -> ChunksTimeout<Self>
where + Self: Sized,

Batches the items in the given stream using a maximum duration and size for each batch. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Turns the stream into a peekable stream, whose next element can be peeked at without being +consumed. Read more
§

impl<T> StreamExt for T
where + T: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Creates a future that resolves to the next item in the stream. Read more
§

fn into_future(self) -> StreamFuture<Self>
where + Self: Sized + Unpin,

Converts this stream into a future of (next_item, tail_of_stream). +If the stream terminates, then the next item is None. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Creates a stream which gives the current iteration count as well as +the next value. Read more
§

fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Filters the values produced by this stream according to the provided +asynchronous predicate. Read more
§

fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = Option<T>>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided asynchronous closure. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Computes from this stream’s items new items of a different type using +an asynchronous closure. Read more
§

fn collect<C>(self) -> Collect<Self, C>
where + C: Default + Extend<Self::Item>, + Self: Sized,

Transforms a stream into a collection, returning a +future representing the result of that computation. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> Unzip<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Converts a stream of pairs into a future, which +resolves to pair of containers. Read more
§

fn concat(self) -> Concat<Self>
where + Self: Sized, + Self::Item: Extend<<Self::Item as IntoIterator>::Item> + IntoIterator + Default,

Concatenate all items of a stream into a single extendable +destination, returning a future representing the end result. Read more
§

fn count(self) -> Count<Self>
where + Self: Sized,

Drives the stream to completion, counting the number of items. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats a stream endlessly. Read more
§

fn fold<T, Fut, F>(self, init: T, f: F) -> Fold<Self, Fut, T, F>
where + F: FnMut(T, Self::Item) -> Fut, + Fut: Future<Output = T>, + Self: Sized,

Execute an accumulating asynchronous computation over a stream, +collecting all the values into one final result. Read more
§

fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if any element in stream satisfied a predicate. Read more
§

fn all<Fut, F>(self, f: F) -> All<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if all element in stream satisfied a predicate. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Item: Stream, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Read more
§

fn flatten_unordered( + self, + limit: impl Into<Option<usize>> +) -> FlattenUnorderedWithFlowController<Self, ()>
where + Self::Item: Stream + Unpin, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Polls +inner streams produced by the base stream concurrently. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + F: FnMut(Self::Item) -> U, + U: Stream, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams. Read more
§

fn flat_map_unordered<U, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> FlatMapUnordered<Self, U, F>
where + U: Stream + Unpin, + F: FnMut(Self::Item) -> U, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams +and polls them concurrently, yielding items in any order, as they made +available. Read more
§

fn scan<S, B, Fut, F>(self, initial_state: S, f: F) -> Scan<Self, S, Fut, F>
where + F: FnMut(&mut S, Self::Item) -> Fut, + Fut: Future<Output = Option<B>>, + Self: Sized,

Combinator similar to [StreamExt::fold] that holds internal state +and produces a new stream. Read more
§

fn skip_while<Fut, F>(self, f: F) -> SkipWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Skip elements on this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_while<Fut, F>(self, f: F) -> TakeWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Take elements from this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_until<Fut>(self, fut: Fut) -> TakeUntil<Self, Fut>
where + Fut: Future, + Self: Sized,

Take elements from this stream until the provided future resolves. Read more
§

fn for_each<Fut, F>(self, f: F) -> ForEach<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream. Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream which skips n items of the underlying stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a stream such that poll_next will never +again be called once it has finished. This method can be used to turn +any Stream into a FusedStream. Read more
§

fn by_ref(&mut self) -> &mut Self

Borrows a stream, rather than consuming it. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn buffered(self, n: usize) -> Buffered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn zip<St>(self, other: St) -> Zip<Self, St>
where + St: Stream, + Self: Sized,

An adapter for zipping two streams together. Read more
§

fn chain<St>(self, other: St) -> Chain<Self, St>
where + St: Stream<Item = Self::Item>, + Self: Sized,

Adapter for chaining two streams. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Creates a new stream which exposes a peek method. Read more
§

fn chunks(self, capacity: usize) -> Chunks<Self>
where + Self: Sized,

An adaptor for chunking up items of the stream inside a vector. Read more
§

fn ready_chunks(self, capacity: usize) -> ReadyChunks<Self>
where + Self: Sized,

An adaptor for chunking up ready items of the stream inside a vector. Read more
§

fn forward<S>(self, sink: S) -> Forward<Self, S>
where + S: Sink<Self::Ok, Error = Self::Error>, + Self: Sized + TryStream,

A future that completes after the given stream has been fully processed +into the sink and the sink has been flushed and closed. Read more
§

fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>)
where + Self: Sized + Sink<Item>,

Splits this Stream + Sink object into separate Sink and Stream +objects. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnMut(&Self::Item), + Self: Sized,

Do something with each item of this stream, afterwards passing it on. Read more
§

fn left_stream<B>(self) -> Either<Self, B>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the left-hand variant +of that Either. Read more
§

fn right_stream<B>(self) -> Either<B, Self>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the right-hand variant +of that Either. Read more
§

fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience method for calling [Stream::poll_next] on Unpin +stream types.
§

fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
where + Self: Unpin + FusedStream,

Returns a Future that resolves when the next item in this stream is +ready. Read more
§

impl<'a, S> StreamRateLimitExt<'a> for S
where + S: Stream,

§

fn ratelimit_stream<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW> +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items. Read more
§

fn ratelimit_stream_with_jitter<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW>, + jitter: Jitter +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items, with a randomized wait period. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.CryptoError.html b/pr/2992/docs/iroh/endpoint/struct.CryptoError.html new file mode 100644 index 0000000000..634132cb4b --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.CryptoError.html @@ -0,0 +1,27 @@ +CryptoError in iroh::endpoint - Rust

Struct iroh::endpoint::CryptoError

pub struct CryptoError;
Expand description

Generic crypto errors

+

Trait Implementations§

§

impl Debug for CryptoError

§

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

Formats the value using the given formatter. Read more
§

impl From<Unspecified> for CryptoError

§

fn from(_: Unspecified) -> CryptoError

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.DirectAddr.html b/pr/2992/docs/iroh/endpoint/struct.DirectAddr.html new file mode 100644 index 0000000000..961a5c2fca --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.DirectAddr.html @@ -0,0 +1,53 @@ +DirectAddr in iroh::endpoint - Rust

Struct iroh::endpoint::DirectAddr

source ·
pub struct DirectAddr {
+    pub addr: SocketAddr,
+    pub typ: DirectAddrType,
+}
Expand description

A direct address on which an iroh-node might be contactable.

+

Direct addresses are UDP socket addresses on which an iroh node could potentially be +contacted. These can come from various sources depending on the network topology of the +iroh node, see DirectAddrType for the several kinds of sources.

+

Fields§

§addr: SocketAddr

The address.

+
§typ: DirectAddrType

The origin of this direct address.

+

Trait Implementations§

source§

impl Clone for DirectAddr

source§

fn clone(&self) -> DirectAddr

Returns a copy 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 DirectAddr

source§

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

Formats the value using the given formatter. Read more
source§

impl Hash for DirectAddr

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for DirectAddr

source§

fn cmp(&self, other: &DirectAddr) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for DirectAddr

source§

fn eq(&self, other: &DirectAddr) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for DirectAddr

source§

fn partial_cmp(&self, other: &DirectAddr) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Eq for DirectAddr

source§

impl StructuralPartialEq for DirectAddr

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.DirectAddrInfo.html b/pr/2992/docs/iroh/endpoint/struct.DirectAddrInfo.html new file mode 100644 index 0000000000..6b9e182a38 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.DirectAddrInfo.html @@ -0,0 +1,76 @@ +DirectAddrInfo in iroh::endpoint - Rust

Struct iroh::endpoint::DirectAddrInfo

source ·
pub struct DirectAddrInfo {
+    pub addr: SocketAddr,
+    pub latency: Option<Duration>,
+    pub last_control: Option<(Duration, ControlMsg)>,
+    pub last_payload: Option<Duration>,
+    pub last_alive: Option<Duration>,
+    pub sources: HashMap<Source, Duration>,
+}
Expand description

Information about a direct address.

+

The direct addresses of an iroh node are those that could be used by other nodes to +establish direct connectivity, depending on the network situation. Due to NAT configurations, +for example, not all direct addresses of a node are usable by all peers.

+

Fields§

§addr: SocketAddr

The UDP address reported by the remote node.

+
§latency: Option<Duration>

The latency to the remote node over this network path.

+

If there has never been any connectivity via this address no latency will be known.

+
§last_control: Option<(Duration, ControlMsg)>

Last control message received by this node about this address.

+

This contains the elapsed duration since the control message was received and the +kind of control message received at that time. Only the most recent control message +is returned.

+

Note that ControlMsg::CallMeMaybe is received via a relay path, while +ControlMsg::Ping and ControlMsg::Pong are received on the path to +DirectAddrInfo::addr itself and thus convey very different information.

+
§last_payload: Option<Duration>

Elapsed time since the last payload message was received on this network path.

+

This indicates how long ago a QUIC datagram was received from the remote node sent +from this DirectAddrInfo::addr. It indicates the network path was in use to +transport payload data.

+
§last_alive: Option<Duration>

Elapsed time since this network path was known to exist.

+

A network path is considered to exist only because the remote node advertised it. +It may not mean the path is usable. However, if there was any communication with +the remote node over this network path it also means the path exists.

+

The elapsed time since any confirmation of the path’s existence was received is +returned. If the remote node moved networks and no longer has this path, this could +be a long duration. If the path was added via Endpoint::add_node_addr or some +node discovery the path may never have been known to exist.

+
§sources: HashMap<Source, Duration>

A HashMap of Sources to Durations.

+

The Duration indicates the elapsed time since this source last +recorded this address.

+

The Duration will always indicate the most recent time the source +recorded this address.

+

Trait Implementations§

source§

impl Clone for DirectAddrInfo

source§

fn clone(&self) -> DirectAddrInfo

Returns a copy 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 DirectAddrInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for DirectAddrInfo

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl PartialEq for DirectAddrInfo

source§

fn eq(&self, other: &DirectAddrInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for DirectAddrInfo

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for DirectAddrInfo

source§

impl StructuralPartialEq for DirectAddrInfo

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.DirectAddrsStream.html b/pr/2992/docs/iroh/endpoint/struct.DirectAddrsStream.html new file mode 100644 index 0000000000..68ed67b6c3 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.DirectAddrsStream.html @@ -0,0 +1,424 @@ +DirectAddrsStream in iroh::endpoint - Rust

Struct iroh::endpoint::DirectAddrsStream

source ·
pub struct DirectAddrsStream { /* private fields */ }
Expand description

Stream returning local endpoints as they change.

+

Trait Implementations§

source§

impl Debug for DirectAddrsStream

source§

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

Formats the value using the given formatter. Read more
source§

impl Stream for DirectAddrsStream

§

type Item = BTreeSet<DirectAddr>

Values yielded by the stream.
source§

fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_> +) -> Poll<Option<Self::Item>>

Attempt to pull out the next value of this stream, registering the +current task for wakeup if the value is not yet available, and returning +None if the stream is exhausted. Read more
§

fn size_hint(&self) -> (usize, Option<usize>)

Returns the bounds on the remaining length of the stream. 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
§

impl<T> BufferedStreamExt for T
where + T: Stream + ?Sized,

§

fn buffered_ordered(self, n: usize) -> BufferedOrdered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffered_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: usize, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<S> IntoStream for S
where + S: Stream,

§

type Item = <S as Stream>::Item

The type of the elements being iterated over.
§

type IntoStream = S

Which kind of stream are we turning this into?
§

fn into_stream(self) -> S

Creates a stream from a value.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn drain(&mut self) -> Drain<'_, Self>

Yields all immediately available values from a stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S> StreamExt for S
where + S: Stream + ?Sized,

§

fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience for calling [Stream::poll_next()] on !Unpin types.
§

fn next(&mut self) -> NextFuture<'_, Self>
where + Self: Unpin,

Retrieves the next item in the stream. Read more
§

fn try_next<T, E>(&mut self) -> TryNextFuture<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Retrieves the next item in the stream. Read more
§

fn count(self) -> CountFuture<Self>
where + Self: Sized,

Counts the number of items in the stream. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> T,

Maps items of the stream to new values using a closure. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + Self: Sized, + U: Stream, + F: FnMut(Self::Item) -> U,

Maps items to streams and then concatenates them. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self: Sized, + Self::Item: Stream,

Concatenates inner streams. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, F, Fut>
where + Self: Sized, + F: FnMut(Self::Item) -> Fut, + Fut: Future,

Maps items of the stream to new values using an async closure. Read more
§

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Keeps items of the stream for which predicate returns true. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + Self: Sized, + F: FnMut(Self::Item) -> Option<T>,

Filters and maps items of the stream using a closure. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Takes only the first n items of the stream. Read more
§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Takes items while predicate returns true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Skips the first n items of the stream. Read more
§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Skips items while predicate returns true. Read more
§

fn step_by(self, step: usize) -> StepBy<Self>
where + Self: Sized,

Yields every stepth item. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + Self: Sized, + U: Stream<Item = Self::Item>,

Appends another stream to the end of this one. Read more
§

fn cloned<'a, T>(self) -> Cloned<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Clone + 'a,

Clones all items. Read more
§

fn copied<'a, T>(self) -> Copied<Self>
where + Self: Sized + Stream<Item = &'a T>, + T: Copy + 'a,

Copies all items. Read more
§

fn collect<C>(self) -> CollectFuture<Self, C>
where + Self: Sized, + C: Default + Extend<Self::Item>,

Collects all items in the stream into a collection. Read more
§

fn try_collect<T, E, C>(self) -> TryCollectFuture<Self, C>
where + Self: Sized + Stream<Item = Result<T, E>>, + C: Default + Extend<T>,

Collects all items in the fallible stream into a collection. Read more
§

fn partition<B, P>(self, predicate: P) -> PartitionFuture<Self, P, B>
where + Self: Sized, + B: Default + Extend<Self::Item>, + P: FnMut(&Self::Item) -> bool,

Partitions items into those for which predicate is true and those for which it is +false, and then collects them into two collections. Read more
§

fn fold<T, F>(self, init: T, f: F) -> FoldFuture<Self, F, T>
where + Self: Sized, + F: FnMut(T, Self::Item) -> T,

Accumulates a computation over the stream. Read more
§

fn try_fold<T, E, F, B>( + &mut self, + init: B, + f: F +) -> TryFoldFuture<'_, Self, F, B>
where + Self: Sized + Stream<Item = Result<T, E>> + Unpin, + F: FnMut(B, T) -> Result<B, E>,

Accumulates a fallible computation over the stream. Read more
§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

Maps items of the stream to new values using a state value and a closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuses the stream so that it stops yielding items after the first None. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats the stream from beginning to end, forever. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Enumerates items, mapping them to (index, item). Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + Self: Sized, + F: FnMut(&Self::Item),

Calls a closure on each item and passes it on. Read more
§

fn nth(&mut self, n: usize) -> NthFuture<'_, Self>
where + Self: Unpin,

Gets the nth item of the stream. Read more
§

fn last(self) -> LastFuture<Self>
where + Self: Sized,

Returns the last item in the stream. Read more
§

fn find<P>(&mut self, predicate: P) -> FindFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(&Self::Item) -> bool,

Finds the first item of the stream for which predicate returns true. Read more
§

fn find_map<F, B>(&mut self, f: F) -> FindMapFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Option<B>,

Applies a closure to items in the stream and returns the first Some result. Read more
§

fn position<P>(&mut self, predicate: P) -> PositionFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Finds the index of the first item of the stream for which predicate returns true. Read more
§

fn all<P>(&mut self, predicate: P) -> AllFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for all items in the stream. Read more
§

fn any<P>(&mut self, predicate: P) -> AnyFuture<'_, Self, P>
where + Self: Unpin, + P: FnMut(Self::Item) -> bool,

Tests if predicate returns true for any item in the stream. Read more
§

fn for_each<F>(self, f: F) -> ForEachFuture<Self, F>
where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each item of the stream. Read more
§

fn try_for_each<F, E>(&mut self, f: F) -> TryForEachFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> Result<(), E>,

Calls a fallible closure on each item of the stream, stopping on first error. Read more
§

fn zip<U>(self, other: U) -> Zip<Self, U>
where + Self: Sized, + U: Stream,

Zips up two streams into a single stream of pairs. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> UnzipFuture<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Collects a stream of pairs into a pair of collections. Read more
§

fn or<S>(self, other: S) -> Or<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, preferring items from self whenever both streams are ready. Read more
§

fn race<S>(self, other: S) -> Race<Self, S>
where + Self: Sized, + S: Stream<Item = Self::Item>,

Merges with other stream, with no preference for either stream when both are ready. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the stream and changes its type to dyn Stream + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Boxes the stream and changes its type to dyn Stream + 'a. Read more
§

impl<S1> StreamExt for S1
where + S1: Stream,

§

fn merge<T, S2>( + self, + other: S2 +) -> Merge2<T, S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Combines two streams into a single stream of all their outputs.
§

fn chain<T, S2>(self, other: S2) -> Chain2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

Takes two streams and creates a new stream over all in sequence
§

fn zip<T, S2>(self, other: S2) -> Zip2<S1, <S2 as IntoStream>::IntoStream>
where + S1: Stream<Item = T>, + S2: IntoStream<Item = T>,

‘Zips up’ multiple streams into a single stream of pairs.
§

fn co(self) -> FromStream<Self>
where + Self: Sized,

Convert into a concurrent stream.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay the yielding of items from the stream until the given deadline. Read more
§

impl<St> StreamExt for St
where + St: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Consumes and returns the next value in the stream or None if the +stream is finished. Read more
§

fn try_next<T, E>(&mut self) -> TryNext<'_, Self>
where + Self: Stream<Item = Result<T, E>> + Unpin,

Consumes and returns the next item in the stream. If an error is +encountered before the next item, the error is returned instead. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn map_while<T, F>(self, f: F) -> MapWhile<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Map this stream’s items to a different type for as long as determined by +the provided closure. A stream of the target type will be returned, +which will yield elements until the closure returns None. Read more
§

fn then<F, Fut>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Maps this stream’s items asynchronously to a different type, returning a +new stream of the resulting type. Read more
§

fn merge<U>(self, other: U) -> Merge<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by interleaving the output of both as it +is produced. Read more
§

fn filter<F>(self, f: F) -> Filter<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Filters the values produced by this stream according to the provided +predicate. Read more
§

fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
where + F: FnMut(Self::Item) -> Option<T>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided closure. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Creates a stream which ends after the first None. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn take_while<F>(self, f: F) -> TakeWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Take elements from this stream while the provided predicate +resolves to true. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream that will skip the n first items of the +underlying stream. Read more
§

fn skip_while<F>(self, f: F) -> SkipWhile<Self, F>
where + F: FnMut(&Self::Item) -> bool, + Self: Sized,

Skip elements from the underlying stream while the provided predicate +resolves to true. Read more
§

fn all<F>(&mut self, f: F) -> AllFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if every element of the stream matches a predicate. Read more
§

fn any<F>(&mut self, f: F) -> AnyFuture<'_, Self, F>
where + Self: Unpin, + F: FnMut(Self::Item) -> bool,

Tests if any element of the stream matches a predicate. Read more
§

fn chain<U>(self, other: U) -> Chain<Self, U>
where + U: Stream<Item = Self::Item>, + Self: Sized,

Combine two streams into one by first returning all values from the +first stream then all values from the second stream. Read more
§

fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
where + Self: Sized, + F: FnMut(B, Self::Item) -> B,

A combinator that applies a function to every element in a stream +producing a single, final value. Read more
§

fn collect<T>(self) -> Collect<Self, T>
where + T: FromStream<Self::Item>, + Self: Sized,

Drain stream pushing all emitted values into a collection. Read more
§

fn timeout(self, duration: Duration) -> Timeout<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn timeout_repeating(self, interval: Interval) -> TimeoutRepeating<Self>
where + Self: Sized,

Applies a per-item timeout to the passed stream. Read more
§

fn throttle(self, duration: Duration) -> Throttle<Self>
where + Self: Sized,

Slows down a stream by enforcing a delay between items. Read more
§

fn chunks_timeout( + self, + max_size: usize, + duration: Duration +) -> ChunksTimeout<Self>
where + Self: Sized,

Batches the items in the given stream using a maximum duration and size for each batch. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Turns the stream into a peekable stream, whose next element can be peeked at without being +consumed. Read more
§

impl<T> StreamExt for T
where + T: Stream + ?Sized,

§

fn next(&mut self) -> Next<'_, Self>
where + Self: Unpin,

Creates a future that resolves to the next item in the stream. Read more
§

fn into_future(self) -> StreamFuture<Self>
where + Self: Sized + Unpin,

Converts this stream into a future of (next_item, tail_of_stream). +If the stream terminates, then the next item is None. Read more
§

fn map<T, F>(self, f: F) -> Map<Self, F>
where + F: FnMut(Self::Item) -> T, + Self: Sized,

Maps this stream’s items to a different type, returning a new stream of +the resulting type. Read more
§

fn enumerate(self) -> Enumerate<Self>
where + Self: Sized,

Creates a stream which gives the current iteration count as well as +the next value. Read more
§

fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Filters the values produced by this stream according to the provided +asynchronous predicate. Read more
§

fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = Option<T>>, + Self: Sized,

Filters the values produced by this stream while simultaneously mapping +them to a different type according to the provided asynchronous closure. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future, + Self: Sized,

Computes from this stream’s items new items of a different type using +an asynchronous closure. Read more
§

fn collect<C>(self) -> Collect<Self, C>
where + C: Default + Extend<Self::Item>, + Self: Sized,

Transforms a stream into a collection, returning a +future representing the result of that computation. Read more
§

fn unzip<A, B, FromA, FromB>(self) -> Unzip<Self, FromA, FromB>
where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Stream<Item = (A, B)>,

Converts a stream of pairs into a future, which +resolves to pair of containers. Read more
§

fn concat(self) -> Concat<Self>
where + Self: Sized, + Self::Item: Extend<<Self::Item as IntoIterator>::Item> + IntoIterator + Default,

Concatenate all items of a stream into a single extendable +destination, returning a future representing the end result. Read more
§

fn count(self) -> Count<Self>
where + Self: Sized,

Drives the stream to completion, counting the number of items. Read more
§

fn cycle(self) -> Cycle<Self>
where + Self: Sized + Clone,

Repeats a stream endlessly. Read more
§

fn fold<T, Fut, F>(self, init: T, f: F) -> Fold<Self, Fut, T, F>
where + F: FnMut(T, Self::Item) -> Fut, + Fut: Future<Output = T>, + Self: Sized,

Execute an accumulating asynchronous computation over a stream, +collecting all the values into one final result. Read more
§

fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if any element in stream satisfied a predicate. Read more
§

fn all<Fut, F>(self, f: F) -> All<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Execute predicate over asynchronous stream, and return true if all element in stream satisfied a predicate. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Item: Stream, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Read more
§

fn flatten_unordered( + self, + limit: impl Into<Option<usize>> +) -> FlattenUnorderedWithFlowController<Self, ()>
where + Self::Item: Stream + Unpin, + Self: Sized,

Flattens a stream of streams into just one continuous stream. Polls +inner streams produced by the base stream concurrently. Read more
§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where + F: FnMut(Self::Item) -> U, + U: Stream, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams. Read more
§

fn flat_map_unordered<U, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> FlatMapUnordered<Self, U, F>
where + U: Stream + Unpin, + F: FnMut(Self::Item) -> U, + Self: Sized,

Maps a stream like [StreamExt::map] but flattens nested Streams +and polls them concurrently, yielding items in any order, as they made +available. Read more
§

fn scan<S, B, Fut, F>(self, initial_state: S, f: F) -> Scan<Self, S, Fut, F>
where + F: FnMut(&mut S, Self::Item) -> Fut, + Fut: Future<Output = Option<B>>, + Self: Sized,

Combinator similar to [StreamExt::fold] that holds internal state +and produces a new stream. Read more
§

fn skip_while<Fut, F>(self, f: F) -> SkipWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Skip elements on this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_while<Fut, F>(self, f: F) -> TakeWhile<Self, Fut, F>
where + F: FnMut(&Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized,

Take elements from this stream while the provided asynchronous predicate +resolves to true. Read more
§

fn take_until<Fut>(self, fut: Fut) -> TakeUntil<Self, Fut>
where + Fut: Future, + Self: Sized,

Take elements from this stream until the provided future resolves. Read more
§

fn for_each<Fut, F>(self, f: F) -> ForEach<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream. Read more
§

fn for_each_concurrent<Fut, F>( + self, + limit: impl Into<Option<usize>>, + f: F +) -> ForEachConcurrent<Self, Fut, F>
where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = ()>, + Self: Sized,

Runs this stream to completion, executing the provided asynchronous +closure for each element on the stream concurrently as elements become +available. Read more
§

fn take(self, n: usize) -> Take<Self>
where + Self: Sized,

Creates a new stream of at most n items of the underlying stream. Read more
§

fn skip(self, n: usize) -> Skip<Self>
where + Self: Sized,

Creates a new stream which skips n items of the underlying stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a stream such that poll_next will never +again be called once it has finished. This method can be used to turn +any Stream into a FusedStream. Read more
§

fn by_ref(&mut self) -> &mut Self

Borrows a stream, rather than consuming it. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the stream. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>
where + Self: Sized + 'a,

Wrap the stream in a Box, pinning it. Read more
§

fn buffered(self, n: usize) -> Buffered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures. Read more
§

fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
where + Self::Item: Future, + Self: Sized,

An adaptor for creating a buffered list of pending futures (unordered). Read more
§

fn zip<St>(self, other: St) -> Zip<Self, St>
where + St: Stream, + Self: Sized,

An adapter for zipping two streams together. Read more
§

fn chain<St>(self, other: St) -> Chain<Self, St>
where + St: Stream<Item = Self::Item>, + Self: Sized,

Adapter for chaining two streams. Read more
§

fn peekable(self) -> Peekable<Self>
where + Self: Sized,

Creates a new stream which exposes a peek method. Read more
§

fn chunks(self, capacity: usize) -> Chunks<Self>
where + Self: Sized,

An adaptor for chunking up items of the stream inside a vector. Read more
§

fn ready_chunks(self, capacity: usize) -> ReadyChunks<Self>
where + Self: Sized,

An adaptor for chunking up ready items of the stream inside a vector. Read more
§

fn forward<S>(self, sink: S) -> Forward<Self, S>
where + S: Sink<Self::Ok, Error = Self::Error>, + Self: Sized + TryStream,

A future that completes after the given stream has been fully processed +into the sink and the sink has been flushed and closed. Read more
§

fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>)
where + Self: Sized + Sink<Item>,

Splits this Stream + Sink object into separate Sink and Stream +objects. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnMut(&Self::Item), + Self: Sized,

Do something with each item of this stream, afterwards passing it on. Read more
§

fn left_stream<B>(self) -> Either<Self, B>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the left-hand variant +of that Either. Read more
§

fn right_stream<B>(self) -> Either<B, Self>
where + B: Stream<Item = Self::Item>, + Self: Sized,

Wrap this stream in an Either stream, making it the right-hand variant +of that Either. Read more
§

fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
where + Self: Unpin,

A convenience method for calling [Stream::poll_next] on Unpin +stream types.
§

fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
where + Self: Unpin + FusedStream,

Returns a Future that resolves when the next item in this stream is +ready. Read more
§

impl<'a, S> StreamRateLimitExt<'a> for S
where + S: Stream,

§

fn ratelimit_stream<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW> +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items. Read more
§

fn ratelimit_stream_with_jitter<D, C, MW>( + self, + limiter: &'a RateLimiter<NotKeyed, D, C, MW>, + jitter: Jitter +) -> RatelimitedStream<'a, S, D, C, MW>
where + D: DirectStateStore, + C: ReasonablyRealtime, + MW: RateLimitingMiddleware<<C as Clock>::Instant>,

Limits the rate at which the stream produces items, with a randomized wait period. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Endpoint.html b/pr/2992/docs/iroh/endpoint/struct.Endpoint.html new file mode 100644 index 0000000000..23f7caa6d4 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Endpoint.html @@ -0,0 +1,213 @@ +Endpoint in iroh::endpoint - Rust

Struct iroh::endpoint::Endpoint

source ·
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.

+

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.

+
source

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.

+
source

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.

+
source

pub async fn connect_by_node_id( + &self, + node_id: NodeId, + alpn: &[u8] +) -> Result<Connection>

👎Deprecated since 0.27.0: Please use connect directly with a NodeId. This fn will be removed in 0.28.0.

Connects to a remote endpoint, using just the nodes’s NodeId.

+

This is a convenience function for Endpoint::connect. It relies on addressing +information being provided by either the discovery service or using +Endpoint::add_node_addr. See Endpoint::connect for the details of how it +uses the discovery service to establish a connection to a remote node.

+
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 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.

+
§Errors
+

Will return an error if we attempt to add our own PublicKey to the node map or if the +direct addresses are a subset of ours.

+
source

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.

+
§Errors
+

Will return an error if we attempt to add our own PublicKey to the node map or if the +direct addresses are a subset of ours.

+
source

pub fn secret_key(&self) -> &SecretKey

Returns the secret_key of this endpoint.

+
source

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.

+
source

pub async fn node_addr(&self) -> Result<NodeAddr>

Returns the current NodeAddr for this endpoint.

+

The returned NodeAddr will have the current RelayUrl and local IP endpoints +as they would be returned by Endpoint::home_relay and +Endpoint::direct_addresses.

+
source

pub fn home_relay(&self) -> Option<RelayUrl>

Returns 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.

+

Returns None if we are not connected to any Relay server.

+

Note that this will be None right after the Endpoint is created since it takes +some time to connect to find and connect to the home relay server. Use +Endpoint::watch_home_relay to wait until the home relay server is available.

+
source

pub fn watch_home_relay(&self) -> impl Stream<Item = RelayUrl>

Watches for changes to the home relay.

+

If there is currently a home relay it will be yielded immediately as the first item +in the stream. This makes it possible to use this function to wait for the initial +home relay to be known.

+

Note that it is not guaranteed that a home relay will ever become available. If no +servers are configured with Builder::relay_mode this stream will never yield an +item.

+
source

pub fn direct_addresses(&self) -> DirectAddrsStream

Returns 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 first item of the returned stream will not be +immediately available. Once this first set of local IP endpoints are discovered the +stream will always return the first set of IP endpoints immediately, which are the +most recently discovered IP endpoints.

+
§Examples
+

To get the current endpoints, drop the stream after the first item was received:

+ +
use futures_lite::StreamExt;
+use iroh::Endpoint;
+
+let mep = Endpoint::builder().bind().await.unwrap();
+let _addrs = mep.direct_addresses().next().await;
+
source

pub fn bound_sockets(&self) -> (SocketAddr, Option<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 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.

+
source

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.

+
source

pub fn conn_type_stream(&self, node_id: NodeId) -> Result<ConnectionTypeStream>

Returns a stream that reports connection type changes for the remote node.

+

This returns a stream of ConnectionType items, each time the underlying +connection to a remote node changes it yields an item. These connection changes are +when the connection switches between using the Relay server and a direct connection.

+

If there is currently a connection with the remote node the first item in the stream +will yield immediately returning the current connection type.

+

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.

+
§Errors
+

Will error if we do not have any address information for the given node_id.

+
source

pub fn dns_resolver(&self) -> &DnsResolver

Returns the DNS resolver used in this Endpoint.

+

See Builder::discovery.

+
source

pub fn discovery(&self) -> Option<&dyn Discovery>

Returns the discovery mechanism, if configured.

+

See Builder::dns_resolver.

+
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 async fn close(&self) -> Result<()>

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 magic socket is closed.

+

Be aware however that the underlying UDP sockets are only closed +on Drop, bearing in mind the Endpoint is only dropped once all the clones +are dropped.

+

Returns an error if closing the magic socket failed. +TODO: Document error cases.

+
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 copy 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, __derive_more_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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ExportKeyingMaterialError.html b/pr/2992/docs/iroh/endpoint/struct.ExportKeyingMaterialError.html new file mode 100644 index 0000000000..10c33b85dc --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ExportKeyingMaterialError.html @@ -0,0 +1,34 @@ +ExportKeyingMaterialError in iroh::endpoint - Rust

Struct iroh::endpoint::ExportKeyingMaterialError

pub struct ExportKeyingMaterialError;
Expand description

Error returned by [Session::export_keying_material].

+

This error occurs if the requested output length is too large.

+

Trait Implementations§

§

impl Debug for ExportKeyingMaterialError

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for ExportKeyingMaterialError

§

fn eq(&self, other: &ExportKeyingMaterialError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for ExportKeyingMaterialError

§

impl StructuralPartialEq for ExportKeyingMaterialError

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.FrameStats.html b/pr/2992/docs/iroh/endpoint/struct.FrameStats.html new file mode 100644 index 0000000000..821e186ab8 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.FrameStats.html @@ -0,0 +1,56 @@ +FrameStats in iroh::endpoint - Rust

Struct iroh::endpoint::FrameStats

#[non_exhaustive]
pub struct FrameStats {
Show 25 fields + pub acks: u64, + pub ack_frequency: u64, + pub crypto: u64, + pub connection_close: u64, + pub data_blocked: u64, + pub datagram: u64, + pub handshake_done: u8, + pub immediate_ack: u64, + pub max_data: u64, + pub max_stream_data: u64, + pub max_streams_bidi: u64, + pub max_streams_uni: u64, + pub new_connection_id: u64, + pub new_token: u64, + pub path_challenge: u64, + pub path_response: u64, + pub ping: u64, + pub reset_stream: u64, + pub retire_connection_id: u64, + pub stream_data_blocked: u64, + pub streams_blocked_bidi: u64, + pub streams_blocked_uni: u64, + pub stop_sending: u64, + pub stream: u64, + pub observed_addr: u64, +
}
Expand description

Number of frames transmitted of each frame type

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§acks: u64§ack_frequency: u64§crypto: u64§connection_close: u64§data_blocked: u64§datagram: u64§handshake_done: u8§immediate_ack: u64§max_data: u64§max_stream_data: u64§max_streams_bidi: u64§max_streams_uni: u64§new_connection_id: u64§new_token: u64§path_challenge: u64§path_response: u64§ping: u64§reset_stream: u64§retire_connection_id: u64§stream_data_blocked: u64§streams_blocked_bidi: u64§streams_blocked_uni: u64§stop_sending: u64§stream: u64§observed_addr: u64

Trait Implementations§

§

impl Clone for FrameStats

§

fn clone(&self) -> FrameStats

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for FrameStats

§

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

Formats the value using the given formatter. Read more
§

impl Default for FrameStats

§

fn default() -> FrameStats

Returns the “default value” for a type. Read more
§

impl Copy for FrameStats

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Incoming.html b/pr/2992/docs/iroh/endpoint/struct.Incoming.html new file mode 100644 index 0000000000..13b65281bd --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Incoming.html @@ -0,0 +1,51 @@ +Incoming in iroh::endpoint - Rust

Struct iroh::endpoint::Incoming

source ·
pub struct Incoming { /* private fields */ }
Expand description

An incoming connection for which the server has not yet begun its parts of the +handshake.

+

Implementations§

source§

impl Incoming

source

pub fn accept(self) -> Result<Connecting, ConnectionError>

Attempts to accept this incoming connection (an error may still occur).

+

Errors occurring here are likely not caused by the application or remote. The QUIC +connection listens on a normal UDP socket and any reachable network endpoint can +send datagrams to it, solicited or not. Even if the first few bytes look like a +QUIC packet, it might not even be a QUIC packet that is being received.

+

Thus it is common to simply log the errors here and accept them as something which +can happen.

+
source

pub fn accept_with( + self, + server_config: Arc<ServerConfig> +) -> Result<Connecting, ConnectionError>

Accepts this incoming connection using a custom configuration.

+

See accept() for more details.

+
source

pub fn refuse(self)

Rejects this incoming connection attempt.

+
source

pub fn retry(self) -> Result<(), RetryError>

Responds with a retry packet.

+

This requires the client to retry with address validation.

+

Errors if remote_address_validated() is true.

+
source

pub fn ignore(self)

Ignores this incoming connection attempt, not sending any packet in response.

+
source

pub fn local_ip(&self) -> Option<IpAddr>

Returns the local IP address which was used when the peer established the +connection.

+
source

pub fn remote_address(&self) -> SocketAddr

Returns the peer’s UDP address.

+
source

pub fn remote_address_validated(&self) -> bool

Whether the socket address that is initiating this connection has been validated.

+

This means that the sender of the initial packet has proved that they can receive +traffic sent to self.remote_address().

+

Trait Implementations§

source§

impl Debug for Incoming

source§

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

Formats the value using the given formatter. Read more
source§

impl IntoFuture for Incoming

§

type Output = Result<Connection, ConnectionError>

The output that the future will produce on completion.
§

type IntoFuture = IncomingFuture

Which kind of future are we turning this into?
source§

fn into_future(self) -> Self::IntoFuture

Creates a future from a value. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.IncomingFuture.html b/pr/2992/docs/iroh/endpoint/struct.IncomingFuture.html new file mode 100644 index 0000000000..54b428afdb --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.IncomingFuture.html @@ -0,0 +1,153 @@ +IncomingFuture in iroh::endpoint - Rust

Struct iroh::endpoint::IncomingFuture

source ·
pub struct IncomingFuture { /* private fields */ }
Expand description

Adaptor to let Incoming be awaited like a Connecting.

+

Trait Implementations§

source§

impl Debug for IncomingFuture

source§

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

Formats the value using the given formatter. Read more
source§

impl Future for IncomingFuture

§

type Output = Result<Connection, ConnectionError>

The type of value produced on completion.
source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
source§

impl<'pin> Unpin for IncomingFuture
where + PinnedFieldsOf<__IncomingFuture<'pin>>: Unpin,

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.MtuDiscoveryConfig.html b/pr/2992/docs/iroh/endpoint/struct.MtuDiscoveryConfig.html new file mode 100644 index 0000000000..2e2f8ce33a --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.MtuDiscoveryConfig.html @@ -0,0 +1,91 @@ +MtuDiscoveryConfig in iroh::endpoint - Rust

Struct iroh::endpoint::MtuDiscoveryConfig

pub struct MtuDiscoveryConfig { /* private fields */ }
Expand description

Parameters governing MTU discovery.

+

§The why of MTU discovery

+

By design, QUIC ensures during the handshake that the network path between the client and the +server is able to transmit unfragmented UDP packets with a body of 1200 bytes. In other words, +once the connection is established, we know that the network path’s maximum transmission unit +(MTU) is of at least 1200 bytes (plus IP and UDP headers). Because of this, a QUIC endpoint can +split outgoing data in packets of 1200 bytes, with confidence that the network will be able to +deliver them (if the endpoint were to send bigger packets, they could prove too big and end up +being dropped).

+

There is, however, a significant overhead associated to sending a packet. If the same +information can be sent in fewer packets, that results in higher throughput. The amount of +packets that need to be sent is inversely proportional to the MTU: the higher the MTU, the +bigger the packets that can be sent, and the fewer packets that are needed to transmit a given +amount of bytes.

+

Most networks have an MTU higher than 1200. Through MTU discovery, endpoints can detect the +path’s MTU and, if it turns out to be higher, start sending bigger packets.

+

§MTU discovery internals

+

Quinn implements MTU discovery through DPLPMTUD (Datagram Packetization Layer Path MTU +Discovery), described in section 14.3 of RFC +9000. This method consists of sending +QUIC packets padded to a particular size (called PMTU probes), and waiting to see if the remote +peer responds with an ACK. If an ACK is received, that means the probe arrived at the remote +peer, which in turn means that the network path’s MTU is of at least the packet’s size. If the +probe is lost, it is sent another 2 times before concluding that the MTU is lower than the +packet’s size.

+

MTU discovery runs on a schedule (e.g. every 600 seconds) specified through +MtuDiscoveryConfig::interval. The first run happens right after the handshake, and +subsequent discoveries are scheduled to run when the interval has elapsed, starting from the +last time when MTU discovery completed.

+

Since the search space for MTUs is quite big (the smallest possible MTU is 1200, and the highest +is 65527), Quinn performs a binary search to keep the number of probes as low as possible. The +lower bound of the search is equal to TransportConfig::initial_mtu in the +initial MTU discovery run, and is equal to the currently discovered MTU in subsequent runs. The +upper bound is determined by the minimum of MtuDiscoveryConfig::upper_bound and the +max_udp_payload_size transport parameter received from the peer during the handshake.

+

§Black hole detection

+

If, at some point, the network path no longer accepts packets of the detected size, packet loss +will eventually trigger black hole detection and reset the detected MTU to 1200. In that case, +MTU discovery will be triggered after MtuDiscoveryConfig::black_hole_cooldown (ignoring the +timer that was set based on MtuDiscoveryConfig::interval).

+

§Interaction between peers

+

There is no guarantee that the MTU on the path between A and B is the same as the MTU of the +path between B and A. Therefore, each peer in the connection needs to run MTU discovery +independently in order to discover the path’s MTU.

+

Implementations§

§

impl MtuDiscoveryConfig

pub fn interval(&mut self, value: Duration) -> &mut MtuDiscoveryConfig

Specifies the time to wait after completing MTU discovery before starting a new MTU +discovery run.

+

Defaults to 600 seconds, as recommended by RFC +8899.

+

pub fn upper_bound(&mut self, value: u16) -> &mut MtuDiscoveryConfig

Specifies the upper bound to the max UDP payload size that MTU discovery will search for.

+

Defaults to 1452, to stay within Ethernet’s MTU when using IPv4 and IPv6. The highest +allowed value is 65527, which corresponds to the maximum permitted UDP payload on IPv6.

+

It is safe to use an arbitrarily high upper bound, regardless of the network path’s MTU. The +only drawback is that MTU discovery might take more time to finish.

+

pub fn black_hole_cooldown( + &mut self, + value: Duration +) -> &mut MtuDiscoveryConfig

Specifies the amount of time that MTU discovery should wait after a black hole was detected +before running again. Defaults to one minute.

+

Black hole detection can be spuriously triggered in case of congestion, so it makes sense to +try MTU discovery again after a short period of time.

+

pub fn minimum_change(&mut self, value: u16) -> &mut MtuDiscoveryConfig

Specifies the minimum MTU change to stop the MTU discovery phase. +Defaults to 20.

+

Trait Implementations§

§

impl Clone for MtuDiscoveryConfig

§

fn clone(&self) -> MtuDiscoveryConfig

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for MtuDiscoveryConfig

§

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

Formats the value using the given formatter. Read more
§

impl Default for MtuDiscoveryConfig

§

fn default() -> MtuDiscoveryConfig

Returns the “default value” for a type. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.NodeAddr.html b/pr/2992/docs/iroh/endpoint/struct.NodeAddr.html new file mode 100644 index 0000000000..4dbbd6b5fe --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.NodeAddr.html @@ -0,0 +1,96 @@ +NodeAddr in iroh::endpoint - Rust

Struct iroh::endpoint::NodeAddr

source ·
pub struct NodeAddr {
+    pub node_id: PublicKey,
+    pub info: AddrInfo,
+}
Expand description

Network-level addressing information for an iroh node.

+

This combines a node’s identifier with network-level addressing information of how to +contact the node.

+

To establish a network connection to a node both the NodeId and one or more network +paths are needed. The network paths can come from various sources:

+
    +
  • +

    A discovery service which can provide routing information for a given NodeId.

    +
  • +
  • +

    A RelayUrl of the node’s home relay, this allows establishing the connection via +the Relay server and is very reliable.

    +
  • +
  • +

    One or more direct addresses on which the node might be reachable. Depending on the +network location of both nodes it might not be possible to establish a direct +connection without the help of a Relay server.

    +
  • +
+

This structure will always contain the required NodeId and will contain an optional +number of network-level addressing information. It is a generic addressing type used +whenever a connection to other nodes needs to be established.

+

Fields§

§node_id: PublicKey

The node’s identifier.

+
§info: AddrInfo

Addressing information to connect to Self::node_id.

+

Implementations§

source§

impl NodeAddr

source

pub fn new(node_id: PublicKey) -> NodeAddr

Creates a new NodeAddr with empty AddrInfo.

+
source

pub fn with_relay_url(self, relay_url: RelayUrl) -> NodeAddr

Adds a relay url to the node’s AddrInfo.

+
source

pub fn with_direct_addresses( + self, + addresses: impl IntoIterator<Item = SocketAddr> +) -> NodeAddr

Adds the given direct addresses to the peer’s AddrInfo.

+
source

pub fn from_parts( + node_id: PublicKey, + relay_url: Option<RelayUrl>, + direct_addresses: impl IntoIterator<Item = SocketAddr> +) -> NodeAddr

Creates a new NodeAddr from its parts.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in a NodeAddr +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+
source

pub fn direct_addresses(&self) -> impl Iterator<Item = &SocketAddr>

Returns the direct addresses of this peer.

+
source

pub fn relay_url(&self) -> Option<&RelayUrl>

Returns the relay url of this peer.

+

Trait Implementations§

source§

impl Clone for NodeAddr

source§

fn clone(&self) -> NodeAddr

Returns a copy 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 NodeAddr

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeAddr

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<NodeAddr, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for NodeAddr

source§

fn from(value: (PublicKey, Option<RelayUrl>, &[SocketAddr])) -> NodeAddr

Converts to this type from the input type.
source§

impl From<NodeAddr> for NodeTicket

source§

fn from(addr: NodeAddr) -> NodeTicket

Creates a ticket from given addressing info.

+
source§

impl From<NodeInfo> for NodeAddr

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<NodeTicket> for NodeAddr

source§

fn from(ticket: NodeTicket) -> NodeAddr

Returns the addressing info from given ticket.

+
source§

impl From<PublicKey> for NodeAddr

source§

fn from(node_id: PublicKey) -> NodeAddr

Converts to this type from the input type.
source§

impl From<RemoteInfo> for NodeAddr

source§

fn from(info: RemoteInfo) -> Self

Converts to this type from the input type.
source§

impl Ord for NodeAddr

source§

fn cmp(&self, other: &NodeAddr) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for NodeAddr

source§

fn eq(&self, other: &NodeAddr) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for NodeAddr

source§

fn partial_cmp(&self, other: &NodeAddr) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for NodeAddr

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for NodeAddr

source§

impl StructuralPartialEq for NodeAddr

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.OpenBi.html b/pr/2992/docs/iroh/endpoint/struct.OpenBi.html new file mode 100644 index 0000000000..07401e8c48 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.OpenBi.html @@ -0,0 +1,156 @@ +OpenBi in iroh::endpoint - Rust

Struct iroh::endpoint::OpenBi

pub struct OpenBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_bi

+

Trait Implementations§

§

impl Future for OpenBi<'_>

§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
§

fn poll( + self: Pin<&mut OpenBi<'_>>, + ctx: &mut Context<'_> +) -> Poll<<OpenBi<'_> as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
§

impl<'__pin, 'a> Unpin for OpenBi<'a>
where + <PinnedFieldsOfHelperStruct<__Origin<'__pin, 'a>> as PinnedFieldsOfHelperTrait>::Actual: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for OpenBi<'a>

§

impl<'a> !RefUnwindSafe for OpenBi<'a>

§

impl<'a> Send for OpenBi<'a>

§

impl<'a> Sync for OpenBi<'a>

§

impl<'a> !UnwindSafe for OpenBi<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.OpenUni.html b/pr/2992/docs/iroh/endpoint/struct.OpenUni.html new file mode 100644 index 0000000000..b1b5b4aff7 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.OpenUni.html @@ -0,0 +1,156 @@ +OpenUni in iroh::endpoint - Rust

Struct iroh::endpoint::OpenUni

pub struct OpenUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_uni

+

Trait Implementations§

§

impl Future for OpenUni<'_>

§

type Output = Result<SendStream, ConnectionError>

The type of value produced on completion.
§

fn poll( + self: Pin<&mut OpenUni<'_>>, + ctx: &mut Context<'_> +) -> Poll<<OpenUni<'_> as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
§

impl<'__pin, 'a> Unpin for OpenUni<'a>
where + <PinnedFieldsOfHelperStruct<__Origin<'__pin, 'a>> as PinnedFieldsOfHelperTrait>::Actual: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for OpenUni<'a>

§

impl<'a> !RefUnwindSafe for OpenUni<'a>

§

impl<'a> Send for OpenUni<'a>

§

impl<'a> Sync for OpenUni<'a>

§

impl<'a> !UnwindSafe for OpenUni<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.PathStats.html b/pr/2992/docs/iroh/endpoint/struct.PathStats.html new file mode 100644 index 0000000000..8ca2687276 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.PathStats.html @@ -0,0 +1,52 @@ +PathStats in iroh::endpoint - Rust

Struct iroh::endpoint::PathStats

#[non_exhaustive]
pub struct PathStats { + pub rtt: Duration, + pub cwnd: u64, + pub congestion_events: u64, + pub lost_packets: u64, + pub lost_bytes: u64, + pub sent_packets: u64, + pub sent_plpmtud_probes: u64, + pub lost_plpmtud_probes: u64, + pub black_holes_detected: u64, + pub current_mtu: u16, +}
Expand description

Statistics related to a transmission path

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§rtt: Duration

Current best estimate of this connection’s latency (round-trip-time)

+
§cwnd: u64

Current congestion window of the connection

+
§congestion_events: u64

Congestion events on the connection

+
§lost_packets: u64

The amount of packets lost on this path

+
§lost_bytes: u64

The amount of bytes lost on this path

+
§sent_packets: u64

The amount of packets sent on this path

+
§sent_plpmtud_probes: u64

The amount of PLPMTUD probe packets sent on this path (also counted by sent_packets)

+
§lost_plpmtud_probes: u64

The amount of PLPMTUD probe packets lost on this path (ignored by lost_packets and +lost_bytes)

+
§black_holes_detected: u64

The number of times a black hole was detected in the path

+
§current_mtu: u16

Largest UDP payload size the path currently supports

+

Trait Implementations§

§

impl Clone for PathStats

§

fn clone(&self) -> PathStats

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for PathStats

§

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

Formats the value using the given formatter. Read more
§

impl Default for PathStats

§

fn default() -> PathStats

Returns the “default value” for a type. Read more
§

impl Copy for PathStats

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ReadDatagram.html b/pr/2992/docs/iroh/endpoint/struct.ReadDatagram.html new file mode 100644 index 0000000000..97c4bf7a04 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ReadDatagram.html @@ -0,0 +1,156 @@ +ReadDatagram in iroh::endpoint - Rust

Struct iroh::endpoint::ReadDatagram

pub struct ReadDatagram<'a> { /* private fields */ }
Expand description

Future produced by Connection::read_datagram

+

Trait Implementations§

§

impl Future for ReadDatagram<'_>

§

type Output = Result<Bytes, ConnectionError>

The type of value produced on completion.
§

fn poll( + self: Pin<&mut ReadDatagram<'_>>, + ctx: &mut Context<'_> +) -> Poll<<ReadDatagram<'_> as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
§

impl<'__pin, 'a> Unpin for ReadDatagram<'a>
where + <PinnedFieldsOfHelperStruct<__Origin<'__pin, 'a>> as PinnedFieldsOfHelperTrait>::Actual: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for ReadDatagram<'a>

§

impl<'a> !RefUnwindSafe for ReadDatagram<'a>

§

impl<'a> Send for ReadDatagram<'a>

§

impl<'a> Sync for ReadDatagram<'a>

§

impl<'a> !UnwindSafe for ReadDatagram<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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.
§

impl<F, T, E> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

The type of successful values yielded by this future
§

type Error = E

The type of failures yielded by this future
§

fn try_poll( + self: Pin<&mut F>, + cx: &mut Context<'_> +) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
§

impl<T, E, F> TryFuture for F
where + F: Future<Output = Result<T, E>> + ?Sized,

§

type Ok = T

§

type Err = E

§

impl<Fut> TryFutureExt for Fut
where + Fut: TryFuture + ?Sized,

§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where + Self::Ok: Sink<Item, Error = Self::Error>, + Self: Sized,

Flattens the execution of this future when the successful result of this +future is a [Sink]. Read more
§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
where + F: FnOnce(Self::Ok) -> T, + Self: Sized,

Maps this future’s success value to a different value. Read more
§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E>
where + F: FnOnce(Self::Ok) -> T, + E: FnOnce(Self::Error) -> T, + Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
where + F: FnOnce(Self::Error) -> E, + Self: Sized,

Maps this future’s error value to a different value. Read more
§

fn err_into<E>(self) -> ErrInto<Self, E>
where + Self: Sized, + Self::Error: Into<E>,

Maps this future’s Error to a new error type +using the Into trait. Read more
§

fn ok_into<U>(self) -> OkInto<Self, U>
where + Self: Sized, + Self::Ok: Into<U>,

Maps this future’s Ok to a new type +using the Into trait.
§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
where + F: FnOnce(Self::Ok) -> Fut, + Fut: TryFuture<Error = Self::Error>, + Self: Sized,

Executes another future after this one resolves successfully. The +success value is passed to a closure to create this subsequent future. Read more
§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
where + F: FnOnce(Self::Error) -> Fut, + Fut: TryFuture<Ok = Self::Ok>, + Self: Sized,

Executes another future if this one resolves to an error. The +error value is passed to a closure to create this subsequent future. Read more
§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
where + F: FnOnce(&Self::Ok), + Self: Sized,

Do something with the success value of a future before passing it on. Read more
§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where + F: FnOnce(&Self::Error), + Self: Sized,

Do something with the error value of a future before passing it on. Read more
§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok>
where + Self::Ok: TryFuture<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is another future. Read more
§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where + Self::Ok: TryStream<Error = Self::Error>, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F>
where + Self: Sized, + F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s +Ok type as its +Output type. Read more
§

fn into_future(self) -> IntoFuture<Self>
where + Self: Sized,

Wraps a [TryFuture] into a type that implements +Future. Read more
§

fn try_poll_unpin( + &mut self, + cx: &mut Context<'_> +) -> Poll<Result<Self::Ok, Self::Error>>
where + Self: Unpin,

A convenience method for calling [TryFuture::try_poll] on Unpin +future types.
source§

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

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.RecvStream.html b/pr/2992/docs/iroh/endpoint/struct.RecvStream.html new file mode 100644 index 0000000000..4c3b91e064 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.RecvStream.html @@ -0,0 +1,172 @@ +RecvStream in iroh::endpoint - Rust

Struct iroh::endpoint::RecvStream

pub struct RecvStream { /* private fields */ }
Expand description

A stream that can only be used to receive data

+

stop(0) is implicitly called on drop unless:

+
    +
  • A variant of ReadError has been yielded by a read call
  • +
  • stop() was called explicitly
  • +
+

§Cancellation

+

A read method is said to be cancel-safe when dropping its future before the future becomes +ready cannot lead to loss of stream data. This is true of methods which succeed immediately when +any progress is made, and is not true of methods which might need to perform multiple reads +internally before succeeding. Each read method documents whether it is cancel-safe.

+

§Common issues

§Data never received on a locally-opened stream

+

Peers are not notified of streams until they or a later-numbered stream are used to send +data. If a bidirectional stream is locally opened but never used to send, then the peer may +never see it. Application protocols should always arrange for the endpoint which will first +transmit on a stream to be the endpoint responsible for opening it.

+

§Data never received on a remotely-opened stream

+

Verify that the stream you are receiving is the same one that the server is sending on, e.g. by +logging the id of each. Streams are always accepted in the same order as they are created, +i.e. ascending order by StreamId. For example, even if a sender first transmits on +bidirectional stream 1, the first stream yielded by Connection::accept_bi on the receiver +will be bidirectional stream 0.

+

Implementations§

§

impl RecvStream

pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError>

Read data contiguously from the stream.

+

Yields the number of bytes read into buf on success, or None if the stream was finished.

+

This operation is cancel-safe.

+

pub async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError>

Read an exact number of bytes contiguously from the stream.

+

See read() for details. This operation is not cancel-safe.

+

pub fn poll_read( + &mut self, + cx: &mut Context<'_>, + buf: &mut [u8] +) -> Poll<Result<usize, ReadError>>

Attempts to read from the stream into buf.

+

On success, returns Poll::Ready(Ok(num_bytes_read)) and places data in +the buf. If no data was read, it implies that EOF has been reached.

+

If no data is available for reading, the method returns Poll::Pending +and arranges for the current task (via cx.waker()) to receive a notification +when the stream becomes readable or is closed.

+

pub async fn read_chunk( + &mut self, + max_length: usize, + ordered: bool +) -> Result<Option<Chunk>, ReadError>

Read the next segment of data

+

Yields None if the stream was finished. Otherwise, yields a segment of data and its +offset in the stream. If ordered is true, the chunk’s offset will be immediately after +the last data yielded by read() or read_chunk(). If ordered is false, segments may +be received in any order, and the Chunk’s offset field can be used to determine +ordering in the caller. Unordered reads are less prone to head-of-line blocking within a +stream, but require the application to manage reassembling the original data.

+

Slightly more efficient than read due to not copying. Chunk boundaries do not correspond +to peer writes, and hence cannot be used as framing.

+

This operation is cancel-safe.

+

pub async fn read_chunks( + &mut self, + bufs: &mut [Bytes] +) -> Result<Option<usize>, ReadError>

Read the next segments of data

+

Fills bufs with the segments of data beginning immediately after the +last data yielded by read or read_chunk, or None if the stream was +finished.

+

Slightly more efficient than read due to not copying. Chunk boundaries +do not correspond to peer writes, and hence cannot be used as framing.

+

This operation is cancel-safe.

+

pub async fn read_to_end( + &mut self, + size_limit: usize +) -> Result<Vec<u8>, ReadToEndError>

Convenience method to read all remaining data into a buffer

+

Fails with ReadToEndError::TooLong on reading more than size_limit bytes, discarding +all data read. Uses unordered reads to be more efficient than using AsyncRead would +allow. size_limit should be set to limit worst-case memory use.

+

If unordered reads have already been made, the resulting buffer may have gaps containing +arbitrary data.

+

This operation is not cancel-safe.

+

pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream>

Stop accepting data

+

Discards unread data and notifies the peer to stop transmitting. Once stopped, further +attempts to operate on a stream will yield ClosedStream errors.

+

pub fn is_0rtt(&self) -> bool

Check if this stream has been opened during 0-RTT.

+

In which case any non-idempotent request should be considered dangerous at the application +level. Because read data is subject to replay attacks.

+

pub fn id(&self) -> StreamId

Get the identity of this stream

+

pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError>

Completes when the stream has been reset by the peer or otherwise closed

+

Yields Some with the reset error code when the stream is reset by the peer. Yields None +when the stream was previously stop()ed, or when the stream was +finish()ed by the peer and all data has been received, after +which it is no longer meaningful for the stream to be reset.

+

This operation is cancel-safe.

+

Trait Implementations§

§

impl AsyncRead for RecvStream

§

fn poll_read( + self: Pin<&mut RecvStream>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_> +) -> Poll<Result<(), Error>>

Attempts to read from the AsyncRead into buf. Read more
§

impl Debug for RecvStream

§

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

Formats the value using the given formatter. Read more
§

impl Drop for RecvStream

§

fn drop(&mut self)

Executes the destructor for this type. 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>

§

impl<R> AsyncReadExt for R
where + R: AsyncRead + ?Sized,

§

fn chain<R>(self, next: R) -> Chain<Self, R>
where + Self: Sized, + R: AsyncRead,

Creates a new AsyncRead instance that chains this stream with +next. Read more
§

fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>
where + Self: Unpin,

Pulls some bytes from this source into the specified buffer, +returning how many bytes were read. Read more
§

fn read_buf<'a, B>(&'a mut self, buf: &'a mut B) -> ReadBuf<'a, Self, B>
where + Self: Unpin, + B: BufMut + ?Sized,

Pulls some bytes from this source into the specified buffer, +advancing the buffer’s internal cursor. Read more
§

fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>
where + Self: Unpin,

Reads the exact number of bytes required to fill buf. Read more
§

fn read_u8(&mut self) -> ReadU8<&mut Self>
where + Self: Unpin,

Reads an unsigned 8 bit integer from the underlying reader. Read more
§

fn read_i8(&mut self) -> ReadI8<&mut Self>
where + Self: Unpin,

Reads a signed 8 bit integer from the underlying reader. Read more
§

fn read_u16(&mut self) -> ReadU16<&mut Self>
where + Self: Unpin,

Reads an unsigned 16-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i16(&mut self) -> ReadI16<&mut Self>
where + Self: Unpin,

Reads a signed 16-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u32(&mut self) -> ReadU32<&mut Self>
where + Self: Unpin,

Reads an unsigned 32-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i32(&mut self) -> ReadI32<&mut Self>
where + Self: Unpin,

Reads a signed 32-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u64(&mut self) -> ReadU64<&mut Self>
where + Self: Unpin,

Reads an unsigned 64-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i64(&mut self) -> ReadI64<&mut Self>
where + Self: Unpin,

Reads an signed 64-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u128(&mut self) -> ReadU128<&mut Self>
where + Self: Unpin,

Reads an unsigned 128-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i128(&mut self) -> ReadI128<&mut Self>
where + Self: Unpin,

Reads an signed 128-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_f32(&mut self) -> ReadF32<&mut Self>
where + Self: Unpin,

Reads an 32-bit floating point type in big-endian order from the +underlying reader. Read more
§

fn read_f64(&mut self) -> ReadF64<&mut Self>
where + Self: Unpin,

Reads an 64-bit floating point type in big-endian order from the +underlying reader. Read more
§

fn read_u16_le(&mut self) -> ReadU16Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 16-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i16_le(&mut self) -> ReadI16Le<&mut Self>
where + Self: Unpin,

Reads a signed 16-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u32_le(&mut self) -> ReadU32Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 32-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i32_le(&mut self) -> ReadI32Le<&mut Self>
where + Self: Unpin,

Reads a signed 32-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u64_le(&mut self) -> ReadU64Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 64-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i64_le(&mut self) -> ReadI64Le<&mut Self>
where + Self: Unpin,

Reads an signed 64-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u128_le(&mut self) -> ReadU128Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 128-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i128_le(&mut self) -> ReadI128Le<&mut Self>
where + Self: Unpin,

Reads an signed 128-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_f32_le(&mut self) -> ReadF32Le<&mut Self>
where + Self: Unpin,

Reads an 32-bit floating point type in little-endian order from the +underlying reader. Read more
§

fn read_f64_le(&mut self) -> ReadF64Le<&mut Self>
where + Self: Unpin,

Reads an 64-bit floating point type in little-endian order from the +underlying reader. Read more
§

fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
where + Self: Unpin,

Reads all bytes until EOF in this source, placing them into buf. Read more
§

fn read_to_string<'a>( + &'a mut self, + dst: &'a mut String +) -> ReadToString<'a, Self>
where + Self: Unpin,

Reads all bytes until EOF in this source, appending them to buf. Read more
§

fn take(self, limit: u64) -> Take<Self>
where + Self: Sized,

Creates an adaptor which reads at most limit bytes from it. Read more
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.RemoteInfo.html b/pr/2992/docs/iroh/endpoint/struct.RemoteInfo.html new file mode 100644 index 0000000000..d885083373 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.RemoteInfo.html @@ -0,0 +1,71 @@ +RemoteInfo in iroh::endpoint - Rust

Struct iroh::endpoint::RemoteInfo

source ·
pub struct RemoteInfo {
+    pub node_id: NodeId,
+    pub relay_url: Option<RelayUrlInfo>,
+    pub addrs: Vec<DirectAddrInfo>,
+    pub conn_type: ConnectionType,
+    pub latency: Option<Duration>,
+    pub last_used: Option<Duration>,
+}
Expand description

Details about a remote iroh node which is known to this node.

+

Having details of a node does not mean it can be connected to, nor that it has ever been +connected to in the past. There are various reasons a node might be known: it could have +been manually added via Endpoint::add_node_addr, it could have been added by some +discovery mechanism, the node could have contacted this node, etc.

+

Fields§

§node_id: NodeId

The globally unique identifier for this node.

+
§relay_url: Option<RelayUrlInfo>

Relay server information, if available.

+
§addrs: Vec<DirectAddrInfo>

The addresses at which this node might be reachable.

+

Some of these addresses might only be valid for networks we are not part of, but the remote +node might be a part of.

+
§conn_type: ConnectionType

The type of connection we have to the node, either direct or over relay.

+
§latency: Option<Duration>

The latency of the current network path to the remote node.

+
§last_used: Option<Duration>

Time elapsed time since last we have sent to or received from the node.

+

This is the duration since any data (payload or control messages) was sent or receive +from the remote node. Note that sending to the remote node does not imply +the remote node received anything.

+

Implementations§

source§

impl RemoteInfo

source

pub fn last_received(&self) -> Option<Duration>

Get the duration since the last activity we received from this endpoint +on any of its direct addresses.

+
source

pub fn has_send_address(&self) -> bool

Whether there is a possible known network path to the remote node.

+

Note that this does not provide any guarantees of whether any network path is +usable.

+
source

pub fn sources(&self) -> Vec<(Source, Duration)>

Returns a deduplicated list of Sources merged from all address in the RemoteInfo.

+

Deduplication is on the (Source, Duration) tuple, so you will get multiple Sources +for each Source variant, if different addresses were discovered from the same Source +at different times.

+

The list is sorted from least to most recent Source.

+

Trait Implementations§

source§

impl Clone for RemoteInfo

source§

fn clone(&self) -> RemoteInfo

Returns a copy 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 RemoteInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RemoteInfo

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<RemoteInfo> for NodeAddr

source§

fn from(info: RemoteInfo) -> Self

Converts to this type from the input type.
source§

impl PartialEq for RemoteInfo

source§

fn eq(&self, other: &RemoteInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for RemoteInfo

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RemoteInfo

source§

impl StructuralPartialEq for RemoteInfo

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.RetryError.html b/pr/2992/docs/iroh/endpoint/struct.RetryError.html new file mode 100644 index 0000000000..87a548f9e6 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.RetryError.html @@ -0,0 +1,30 @@ +RetryError in iroh::endpoint - Rust

Struct iroh::endpoint::RetryError

pub struct RetryError(/* private fields */);
Expand description

Error for attempting to retry an [Incoming] which already bears an address +validation token from a previous retry

+

Implementations§

§

impl RetryError

pub fn into_incoming(self) -> Incoming

Get the [Incoming]

+

Trait Implementations§

§

impl Debug for RetryError

§

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

Formats the value using the given formatter. Read more
§

impl Display for RetryError

§

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

Formats the value using the given formatter. Read more
§

impl Error for RetryError

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.SendStream.html b/pr/2992/docs/iroh/endpoint/struct.SendStream.html new file mode 100644 index 0000000000..59728b56ea --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.SendStream.html @@ -0,0 +1,176 @@ +SendStream in iroh::endpoint - Rust

Struct iroh::endpoint::SendStream

pub struct SendStream { /* private fields */ }
Expand description

A stream that can only be used to send data

+

If dropped, streams that haven’t been explicitly reset() will be implicitly finish()ed, +continuing to (re)transmit previously written data until it has been fully acknowledged or the +connection is closed.

+

§Cancellation

+

A write method is said to be cancel-safe when dropping its future before the future becomes +ready will always result in no data being written to the stream. This is true of methods which +succeed immediately when any progress is made, and is not true of methods which might need to +perform multiple writes internally before succeeding. Each write method documents whether it is +cancel-safe.

+

Implementations§

§

impl SendStream

pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WriteError>

Write bytes to the stream

+

Yields the number of bytes written on success. Congestion and flow control may cause this to +be shorter than buf.len(), indicating that only a prefix of buf was written.

+

This operation is cancel-safe.

+

pub async fn write_all(&mut self, buf: &[u8]) -> Result<(), WriteError>

Convenience method to write an entire buffer to the stream

+

This operation is not cancel-safe.

+

pub async fn write_chunks( + &mut self, + bufs: &mut [Bytes] +) -> Result<Written, WriteError>

Write chunks to the stream

+

Yields the number of bytes and chunks written on success. +Congestion and flow control may cause this to be shorter than buf.len(), +indicating that only a prefix of bufs was written

+

This operation is cancel-safe.

+

pub async fn write_chunk(&mut self, buf: Bytes) -> Result<(), WriteError>

Convenience method to write a single chunk in its entirety to the stream

+

This operation is not cancel-safe.

+

pub async fn write_all_chunks( + &mut self, + bufs: &mut [Bytes] +) -> Result<(), WriteError>

Convenience method to write an entire list of chunks to the stream

+

This operation is not cancel-safe.

+

pub fn finish(&mut self) -> Result<(), ClosedStream>

Notify the peer that no more data will ever be written to this stream

+

It is an error to write to a SendStream after finish()ing it. reset() +may still be called after finish to abandon transmission of any stream data that might +still be buffered.

+

To wait for the peer to receive all buffered stream data, see stopped().

+

May fail if finish() or reset() was previously +called. This error is harmless and serves only to indicate that the caller may have +incorrect assumptions about the stream’s state.

+

pub fn reset(&mut self, error_code: VarInt) -> Result<(), ClosedStream>

Close the send stream immediately.

+

No new data can be written after calling this method. Locally buffered data is dropped, and +previously transmitted data will no longer be retransmitted if lost. If an attempt has +already been made to finish the stream, the peer may still receive all written data.

+

May fail if finish() or reset() was previously +called. This error is harmless and serves only to indicate that the caller may have +incorrect assumptions about the stream’s state.

+

pub fn set_priority(&self, priority: i32) -> Result<(), ClosedStream>

Set the priority of the send stream

+

Every send stream has an initial priority of 0. Locally buffered data from streams with +higher priority will be transmitted before data from streams with lower priority. Changing +the priority of a stream with pending data may only take effect after that data has been +transmitted. Using many different priority levels per connection may have a negative +impact on performance.

+

pub fn priority(&self) -> Result<i32, ClosedStream>

Get the priority of the send stream

+

pub async fn stopped(&mut self) -> Result<Option<VarInt>, StoppedError>

Completes when the peer stops the stream or reads the stream to completion

+

Yields Some with the stop error code if the peer stops the stream. Yields None if the +local side finish()es the stream and then the peer acknowledges receipt +of all stream data (although not necessarily the processing of it), after which the peer +closing the stream is no longer meaningful.

+

For a variety of reasons, the peer may not send acknowledgements immediately upon receiving +data. As such, relying on stopped to know when the peer has read a stream to completion +may introduce more latency than using an application-level response of some sort.

+

pub fn id(&self) -> StreamId

Get the identity of this stream

+

pub fn poll_write( + self: Pin<&mut SendStream>, + cx: &mut Context<'_>, + buf: &[u8] +) -> Poll<Result<usize, WriteError>>

Attempt to write bytes from buf into the stream.

+

On success, returns Poll::Ready(Ok(num_bytes_written)).

+

If the stream is not ready for writing, the method returns Poll::Pending and arranges +for the current task (via cx.waker().wake_by_ref()) to receive a notification when the +stream becomes writable or is closed.

+

Trait Implementations§

§

impl AsyncWrite for SendStream

§

fn poll_write( + self: Pin<&mut SendStream>, + cx: &mut Context<'_>, + buf: &[u8] +) -> Poll<Result<usize, Error>>

Attempt to write bytes from buf into the object. Read more
§

fn poll_flush( + self: Pin<&mut SendStream>, + _cx: &mut Context<'_> +) -> Poll<Result<(), Error>>

Attempts to flush the object, ensuring that any buffered data reach +their destination. Read more
§

fn poll_shutdown( + self: Pin<&mut SendStream>, + _cx: &mut Context<'_> +) -> Poll<Result<(), Error>>

Initiates or attempts to shut down this writer, returning success when +the I/O connection has completely shut down. Read more
§

fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>] +) -> Poll<Result<usize, Error>>

Like poll_write, except that it writes from a slice of buffers. Read more
§

fn is_write_vectored(&self) -> bool

Determines if this writer has an efficient poll_write_vectored +implementation. Read more
§

impl Debug for SendStream

§

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

Formats the value using the given formatter. Read more
§

impl Drop for SendStream

§

fn drop(&mut self)

Executes the destructor for this type. 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>

§

impl<W> AsyncWriteExt for W
where + W: AsyncWrite + ?Sized,

§

fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self>
where + Self: Unpin,

Writes a buffer into this writer, returning how many bytes were +written. Read more
§

fn write_vectored<'a, 'b>( + &'a mut self, + bufs: &'a [IoSlice<'b>] +) -> WriteVectored<'a, 'b, Self>
where + Self: Unpin,

Like write, except that it writes from a slice of buffers. Read more
§

fn write_buf<'a, B>(&'a mut self, src: &'a mut B) -> WriteBuf<'a, Self, B>
where + Self: Sized + Unpin, + B: Buf,

Writes a buffer into this writer, advancing the buffer’s internal +cursor. Read more
§

fn write_all_buf<'a, B>( + &'a mut self, + src: &'a mut B +) -> WriteAllBuf<'a, Self, B>
where + Self: Sized + Unpin, + B: Buf,

Attempts to write an entire buffer into this writer. Read more
§

fn write_all<'a>(&'a mut self, src: &'a [u8]) -> WriteAll<'a, Self>
where + Self: Unpin,

Attempts to write an entire buffer into this writer. Read more
§

fn write_u8(&mut self, n: u8) -> WriteU8<&mut Self>
where + Self: Unpin,

Writes an unsigned 8-bit integer to the underlying writer. Read more
§

fn write_i8(&mut self, n: i8) -> WriteI8<&mut Self>
where + Self: Unpin,

Writes a signed 8-bit integer to the underlying writer. Read more
§

fn write_u16(&mut self, n: u16) -> WriteU16<&mut Self>
where + Self: Unpin,

Writes an unsigned 16-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i16(&mut self, n: i16) -> WriteI16<&mut Self>
where + Self: Unpin,

Writes a signed 16-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u32(&mut self, n: u32) -> WriteU32<&mut Self>
where + Self: Unpin,

Writes an unsigned 32-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i32(&mut self, n: i32) -> WriteI32<&mut Self>
where + Self: Unpin,

Writes a signed 32-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u64(&mut self, n: u64) -> WriteU64<&mut Self>
where + Self: Unpin,

Writes an unsigned 64-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i64(&mut self, n: i64) -> WriteI64<&mut Self>
where + Self: Unpin,

Writes an signed 64-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u128(&mut self, n: u128) -> WriteU128<&mut Self>
where + Self: Unpin,

Writes an unsigned 128-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i128(&mut self, n: i128) -> WriteI128<&mut Self>
where + Self: Unpin,

Writes an signed 128-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_f32(&mut self, n: f32) -> WriteF32<&mut Self>
where + Self: Unpin,

Writes an 32-bit floating point type in big-endian order to the +underlying writer. Read more
§

fn write_f64(&mut self, n: f64) -> WriteF64<&mut Self>
where + Self: Unpin,

Writes an 64-bit floating point type in big-endian order to the +underlying writer. Read more
§

fn write_u16_le(&mut self, n: u16) -> WriteU16Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 16-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i16_le(&mut self, n: i16) -> WriteI16Le<&mut Self>
where + Self: Unpin,

Writes a signed 16-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u32_le(&mut self, n: u32) -> WriteU32Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 32-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i32_le(&mut self, n: i32) -> WriteI32Le<&mut Self>
where + Self: Unpin,

Writes a signed 32-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u64_le(&mut self, n: u64) -> WriteU64Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 64-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i64_le(&mut self, n: i64) -> WriteI64Le<&mut Self>
where + Self: Unpin,

Writes an signed 64-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u128_le(&mut self, n: u128) -> WriteU128Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 128-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i128_le(&mut self, n: i128) -> WriteI128Le<&mut Self>
where + Self: Unpin,

Writes an signed 128-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_f32_le(&mut self, n: f32) -> WriteF32Le<&mut Self>
where + Self: Unpin,

Writes an 32-bit floating point type in little-endian order to the +underlying writer. Read more
§

fn write_f64_le(&mut self, n: f64) -> WriteF64Le<&mut Self>
where + Self: Unpin,

Writes an 64-bit floating point type in little-endian order to the +underlying writer. Read more
§

fn flush(&mut self) -> Flush<'_, Self>
where + Self: Unpin,

Flushes this output stream, ensuring that all intermediately buffered +contents reach their destination. Read more
§

fn shutdown(&mut self) -> Shutdown<'_, Self>
where + Self: Unpin,

Shuts down the output stream, ensuring that the value can be dropped +cleanly. Read more
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ServerConfig.html b/pr/2992/docs/iroh/endpoint/struct.ServerConfig.html new file mode 100644 index 0000000000..43a25e6eec --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ServerConfig.html @@ -0,0 +1,104 @@ +ServerConfig in iroh::endpoint - Rust

Struct iroh::endpoint::ServerConfig

pub struct ServerConfig {
+    pub transport: Arc<TransportConfig>,
+    pub crypto: Arc<dyn ServerConfig>,
+    /* private fields */
+}
Expand description

Parameters governing incoming connections

+

Default values should be suitable for most internet applications.

+

Fields§

§transport: Arc<TransportConfig>

Transport configuration to use for incoming connections

+
§crypto: Arc<dyn ServerConfig>

TLS configuration used for incoming connections.

+

Must be set to use TLS 1.3 only.

+

Implementations§

§

impl ServerConfig

pub fn new( + crypto: Arc<dyn ServerConfig>, + token_key: Arc<dyn HandshakeTokenKey> +) -> ServerConfig

Create a default config with a particular handshake token key

+

pub fn transport_config( + &mut self, + transport: Arc<TransportConfig> +) -> &mut ServerConfig

Set a custom TransportConfig

+

pub fn token_key( + &mut self, + value: Arc<dyn HandshakeTokenKey> +) -> &mut ServerConfig

Private key used to authenticate data included in handshake tokens.

+

pub fn retry_token_lifetime(&mut self, value: Duration) -> &mut ServerConfig

Duration after a stateless retry token was issued for which it’s considered valid.

+

pub fn migration(&mut self, value: bool) -> &mut ServerConfig

Whether to allow clients to migrate to new addresses

+

Improves behavior for clients that move between different internet connections or suffer NAT +rebinding. Enabled by default.

+

pub fn preferred_address_v4( + &mut self, + address: Option<SocketAddrV4> +) -> &mut ServerConfig

The preferred IPv4 address that will be communicated to clients during handshaking. +If the client is able to reach this address, it will switch to it.

+

pub fn preferred_address_v6( + &mut self, + address: Option<SocketAddrV6> +) -> &mut ServerConfig

The preferred IPv6 address that will be communicated to clients during handshaking. +If the client is able to reach this address, it will switch to it.

+

pub fn max_incoming(&mut self, max_incoming: usize) -> &mut ServerConfig

Maximum number of [Incoming][crate::Incoming] to allow to exist at a time

+

An [Incoming][crate::Incoming] comes into existence when an incoming connection attempt +is received and stops existing when the application either accepts it or otherwise disposes +of it. While this limit is reached, new incoming connection attempts are immediately +refused. Larger values have greater worst-case memory consumption, but accommodate greater +application latency in handling incoming connection attempts.

+

The default value is set to 65536. With a typical Ethernet MTU of 1500 bytes, this limits +memory consumption from this to under 100 MiB–a generous amount that still prevents memory +exhaustion in most contexts.

+

pub fn incoming_buffer_size( + &mut self, + incoming_buffer_size: u64 +) -> &mut ServerConfig

Maximum number of received bytes to buffer for each [Incoming][crate::Incoming]

+

An [Incoming][crate::Incoming] comes into existence when an incoming connection attempt +is received and stops existing when the application either accepts it or otherwise disposes +of it. This limit governs only packets received within that period, and does not include +the first packet. Packets received in excess of this limit are dropped, which may cause +0-RTT or handshake data to have to be retransmitted.

+

The default value is set to 10 MiB–an amount such that in most situations a client would +not transmit that much 0-RTT data faster than the server handles the corresponding +[Incoming][crate::Incoming].

+

pub fn incoming_buffer_size_total( + &mut self, + incoming_buffer_size_total: u64 +) -> &mut ServerConfig

Maximum number of received bytes to buffer for all [Incoming][crate::Incoming] +collectively

+

An [Incoming][crate::Incoming] comes into existence when an incoming connection attempt +is received and stops existing when the application either accepts it or otherwise disposes +of it. This limit governs only packets received within that period, and does not include +the first packet. Packets received in excess of this limit are dropped, which may cause +0-RTT or handshake data to have to be retransmitted.

+

The default value is set to 100 MiB–a generous amount that still prevents memory +exhaustion in most contexts.

+
§

impl ServerConfig

pub fn with_single_cert( + cert_chain: Vec<CertificateDer<'static>>, + key: PrivateKeyDer<'static> +) -> Result<ServerConfig, Error>

Create a server config with the given certificate chain to be presented to clients

+

Uses a randomized handshake token key.

+
§

impl ServerConfig

pub fn with_crypto(crypto: Arc<dyn ServerConfig>) -> ServerConfig

Create a server config with the given crypto::ServerConfig

+

Uses a randomized handshake token key.

+

Trait Implementations§

§

impl Clone for ServerConfig

§

fn clone(&self) -> ServerConfig

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for ServerConfig

§

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

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.StreamId.html b/pr/2992/docs/iroh/endpoint/struct.StreamId.html new file mode 100644 index 0000000000..9619f60a0a --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.StreamId.html @@ -0,0 +1,52 @@ +StreamId in iroh::endpoint - Rust

Struct iroh::endpoint::StreamId

pub struct StreamId(/* private fields */);
Expand description

Identifier for a stream within a particular connection

+

Implementations§

§

impl StreamId

pub fn new(initiator: Side, dir: Dir, index: u64) -> StreamId

Create a new StreamId

+

pub fn initiator(self) -> Side

Which side of a connection initiated the stream

+

pub fn dir(self) -> Dir

Which directions data flows in

+

pub fn index(self) -> u64

Distinguishes streams of the same initiator and directionality

+

Trait Implementations§

§

impl Clone for StreamId

§

fn clone(&self) -> StreamId

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for StreamId

§

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

Formats the value using the given formatter. Read more
§

impl Display for StreamId

§

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

Formats the value using the given formatter. Read more
§

impl From<StreamId> for VarInt

§

fn from(x: StreamId) -> VarInt

Converts to this type from the input type.
§

impl From<VarInt> for StreamId

§

fn from(v: VarInt) -> StreamId

Converts to this type from the input type.
§

impl Hash for StreamId

§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
§

impl Ord for StreamId

§

fn cmp(&self, other: &StreamId) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
§

impl PartialEq for StreamId

§

fn eq(&self, other: &StreamId) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialOrd for StreamId

§

fn partial_cmp(&self, other: &StreamId) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl Copy for StreamId

§

impl Eq for StreamId

§

impl StructuralPartialEq for StreamId

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.TransportConfig.html b/pr/2992/docs/iroh/endpoint/struct.TransportConfig.html new file mode 100644 index 0000000000..1553fcd92d --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.TransportConfig.html @@ -0,0 +1,182 @@ +TransportConfig in iroh::endpoint - Rust

Struct iroh::endpoint::TransportConfig

pub struct TransportConfig { /* private fields */ }
Expand description

Parameters governing the core QUIC state machine

+

Default values should be suitable for most internet applications. Applications protocols which +forbid remotely-initiated streams should set max_concurrent_bidi_streams and +max_concurrent_uni_streams to zero.

+

In some cases, performance or resource requirements can be improved by tuning these values to +suit a particular application and/or network connection. In particular, data window sizes can be +tuned for a particular expected round trip time, link capacity, and memory availability. Tuning +for higher bandwidths and latencies increases worst-case memory consumption, but does not impair +performance at lower bandwidths and latencies. The default configuration is tuned for a 100Mbps +link with a 100ms round trip time.

+

Implementations§

§

impl TransportConfig

pub fn max_concurrent_bidi_streams( + &mut self, + value: VarInt +) -> &mut TransportConfig

Maximum number of incoming bidirectional streams that may be open concurrently

+

Must be nonzero for the peer to open any bidirectional streams.

+

Worst-case memory use is directly proportional to max_concurrent_bidi_streams * stream_receive_window, with an upper bound proportional to receive_window.

+

pub fn max_concurrent_uni_streams( + &mut self, + value: VarInt +) -> &mut TransportConfig

Variant of max_concurrent_bidi_streams affecting unidirectional streams

+

pub fn max_idle_timeout( + &mut self, + value: Option<IdleTimeout> +) -> &mut TransportConfig

Maximum duration of inactivity to accept before timing out the connection.

+

The true idle timeout is the minimum of this and the peer’s own max idle timeout. None +represents an infinite timeout. Defaults to 30 seconds.

+

WARNING: If a peer or its network path malfunctions or acts maliciously, an infinite +idle timeout can result in permanently hung futures!

+ +
let mut config = TransportConfig::default();
+
+// Set the idle timeout as `VarInt`-encoded milliseconds
+config.max_idle_timeout(Some(VarInt::from_u32(10_000).into()));
+
+// Set the idle timeout as a `Duration`
+config.max_idle_timeout(Some(Duration::from_secs(10).try_into()?));
+

pub fn stream_receive_window(&mut self, value: VarInt) -> &mut TransportConfig

Maximum number of bytes the peer may transmit without acknowledgement on any one stream +before becoming blocked.

+

This should be set to at least the expected connection latency multiplied by the maximum +desired throughput. Setting this smaller than receive_window helps ensure that a single +stream doesn’t monopolize receive buffers, which may otherwise occur if the application +chooses not to read from a large stream for a time while still requiring data on other +streams.

+

pub fn receive_window(&mut self, value: VarInt) -> &mut TransportConfig

Maximum number of bytes the peer may transmit across all streams of a connection before +becoming blocked.

+

This should be set to at least the expected connection latency multiplied by the maximum +desired throughput. Larger values can be useful to allow maximum throughput within a +stream while another is blocked.

+

pub fn send_window(&mut self, value: u64) -> &mut TransportConfig

Maximum number of bytes to transmit to a peer without acknowledgment

+

Provides an upper bound on memory when communicating with peers that issue large amounts of +flow control credit. Endpoints that wish to handle large numbers of connections robustly +should take care to set this low enough to guarantee memory exhaustion does not occur if +every connection uses the entire window.

+

pub fn packet_threshold(&mut self, value: u32) -> &mut TransportConfig

Maximum reordering in packet number space before FACK style loss detection considers a +packet lost. Should not be less than 3, per RFC5681.

+

pub fn time_threshold(&mut self, value: f32) -> &mut TransportConfig

Maximum reordering in time space before time based loss detection considers a packet lost, +as a factor of RTT

+

pub fn initial_rtt(&mut self, value: Duration) -> &mut TransportConfig

The RTT used before an RTT sample is taken

+

pub fn initial_mtu(&mut self, value: u16) -> &mut TransportConfig

The initial value to be used as the maximum UDP payload size before running MTU discovery +(see TransportConfig::mtu_discovery_config).

+

Must be at least 1200, which is the default, and known to be safe for typical internet +applications. Larger values are more efficient, but increase the risk of packet loss due to +exceeding the network path’s IP MTU. If the provided value is higher than what the network +path actually supports, packet loss will eventually trigger black hole detection and bring +it down to TransportConfig::min_mtu.

+

pub fn min_mtu(&mut self, value: u16) -> &mut TransportConfig

The maximum UDP payload size guaranteed to be supported by the network.

+

Must be at least 1200, which is the default, and lower than or equal to +TransportConfig::initial_mtu.

+

Real-world MTUs can vary according to ISP, VPN, and properties of intermediate network links +outside of either endpoint’s control. Extreme care should be used when raising this value +outside of private networks where these factors are fully controlled. If the provided value +is higher than what the network path actually supports, the result will be unpredictable and +catastrophic packet loss, without a possibility of repair. Prefer +TransportConfig::initial_mtu together with +TransportConfig::mtu_discovery_config to set a maximum UDP payload size that robustly +adapts to the network.

+

pub fn mtu_discovery_config( + &mut self, + value: Option<MtuDiscoveryConfig> +) -> &mut TransportConfig

Specifies the MTU discovery config (see MtuDiscoveryConfig for details).

+

Enabled by default.

+

pub fn ack_frequency_config( + &mut self, + value: Option<AckFrequencyConfig> +) -> &mut TransportConfig

Specifies the ACK frequency config (see AckFrequencyConfig for details)

+

The provided configuration will be ignored if the peer does not support the acknowledgement +frequency QUIC extension.

+

Defaults to None, which disables controlling the peer’s acknowledgement frequency. Even +if set to None, the local side still supports the acknowledgement frequency QUIC +extension and may use it in other ways.

+

pub fn persistent_congestion_threshold( + &mut self, + value: u32 +) -> &mut TransportConfig

Number of consecutive PTOs after which network is considered to be experiencing persistent congestion.

+

pub fn keep_alive_interval( + &mut self, + value: Option<Duration> +) -> &mut TransportConfig

Period of inactivity before sending a keep-alive packet

+

Keep-alive packets prevent an inactive but otherwise healthy connection from timing out.

+

None to disable, which is the default. Only one side of any given connection needs keep-alive +enabled for the connection to be preserved. Must be set lower than the idle_timeout of both +peers to be effective.

+

pub fn crypto_buffer_size(&mut self, value: usize) -> &mut TransportConfig

Maximum quantity of out-of-order crypto layer data to buffer

+

pub fn allow_spin(&mut self, value: bool) -> &mut TransportConfig

Whether the implementation is permitted to set the spin bit on this connection

+

This allows passive observers to easily judge the round trip time of a connection, which can +be useful for network administration but sacrifices a small amount of privacy.

+

pub fn datagram_receive_buffer_size( + &mut self, + value: Option<usize> +) -> &mut TransportConfig

Maximum number of incoming application datagram bytes to buffer, or None to disable +incoming datagrams

+

The peer is forbidden to send single datagrams larger than this size. If the aggregate size +of all datagrams that have been received from the peer but not consumed by the application +exceeds this value, old datagrams are dropped until it is no longer exceeded.

+

pub fn datagram_send_buffer_size( + &mut self, + value: usize +) -> &mut TransportConfig

Maximum number of outgoing application datagram bytes to buffer

+

While datagrams are sent ASAP, it is possible for an application to generate data faster +than the link, or even the underlying hardware, can transmit them. This limits the amount of +memory that may be consumed in that case. When the send buffer is full and a new datagram is +sent, older datagrams are dropped until sufficient space is available.

+

pub fn congestion_controller_factory( + &mut self, + factory: Arc<dyn ControllerFactory + Send + Sync> +) -> &mut TransportConfig

How to construct new congestion::Controllers

+

Typically the refcounted configuration of a congestion::Controller, +e.g. a congestion::NewRenoConfig.

+
§Example
+
let mut config = TransportConfig::default();
+config.congestion_controller_factory(Arc::new(congestion::NewRenoConfig::default()));
+

pub fn enable_segmentation_offload( + &mut self, + enabled: bool +) -> &mut TransportConfig

Whether to use “Generic Segmentation Offload” to accelerate transmits, when supported by the +environment

+

Defaults to true.

+

GSO dramatically reduces CPU consumption when sending large numbers of packets with the same +headers, such as when transmitting bulk data on a connection. However, it is not supported +by all network interface drivers or packet inspection tools. quinn-udp will attempt to +disable GSO automatically when unavailable, but this can lead to spurious packet loss at +startup, temporarily degrading performance.

+

pub fn send_observed_address_reports( + &mut self, + enabled: bool +) -> &mut TransportConfig

Whether to send observed address reports to peers.

+

This will aid peers in inferring their reachable address, which in most NATd networks +will not be easily available to them.

+

pub fn receive_observed_address_reports( + &mut self, + enabled: bool +) -> &mut TransportConfig

Whether to receive observed address reports from other peers.

+

Peers with the address discovery extension enabled that are willing to provide observed +address reports will do so if this transport parameter is set. In general, observed address +reports cannot be trusted. This, however, can aid the current endpoint in inferring its +reachable address, which in most NATd networks will not be easily available.

+

Trait Implementations§

§

impl Debug for TransportConfig

§

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

Formats the value using the given formatter. Read more
§

impl Default for TransportConfig

§

fn default() -> TransportConfig

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.TransportError.html b/pr/2992/docs/iroh/endpoint/struct.TransportError.html new file mode 100644 index 0000000000..9162723286 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.TransportError.html @@ -0,0 +1,44 @@ +TransportError in iroh::endpoint - Rust

Struct iroh::endpoint::TransportError

pub struct TransportError {
+    pub code: Code,
+    pub frame: Option<Type>,
+    pub reason: String,
+}
Expand description

Transport-level errors occur when a peer violates the protocol specification

+

Fields§

§code: Code

Type of error

+
§frame: Option<Type>

Frame type that triggered the error

+
§reason: String

Human-readable explanation of the reason

+

Trait Implementations§

§

impl Clone for Error

§

fn clone(&self) -> Error

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Error

§

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

Formats the value using the given formatter. Read more
§

impl Display for Error

§

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

Formats the value using the given formatter. Read more
§

impl Error for Error

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
§

impl From<Error> for Error

§

fn from(e: Error) -> Error

Converts to this type from the input type.
§

impl From<InvalidFrame> for Error

§

fn from(err: InvalidFrame) -> Error

Converts to this type from the input type.
§

impl From<Error> for ConnectionClose

§

fn from(x: Error) -> ConnectionClose

Converts to this type from the input type.
§

impl From<Error> for ConnectionError

§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
§

impl From<Code> for Error

§

fn from(x: Code) -> Error

Converts to this type from the input type.
§

impl PartialEq for Error

§

fn eq(&self, other: &Error) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Eq for Error

§

impl StructuralPartialEq for Error

Auto Trait Implementations§

§

impl Freeze for Error

§

impl RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnwindSafe for Error

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.TransportErrorCode.html b/pr/2992/docs/iroh/endpoint/struct.TransportErrorCode.html new file mode 100644 index 0000000000..a3c79dd447 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.TransportErrorCode.html @@ -0,0 +1,55 @@ +TransportErrorCode in iroh::endpoint - Rust

Struct iroh::endpoint::TransportErrorCode

pub struct TransportErrorCode(/* private fields */);
Expand description

Transport-level error code

+

Implementations§

§

impl Code

pub fn crypto(code: u8) -> Code

Create QUIC error code from TLS alert code

+
§

impl Code

pub const NO_ERROR: Code = _

the connection is being closed abruptly in the absence of any error

+

pub const INTERNAL_ERROR: Code = _

the endpoint encountered an internal error and cannot continue with the connection

+

pub const CONNECTION_REFUSED: Code = _

the server refused to accept a new connection

+

pub const FLOW_CONTROL_ERROR: Code = _

received more data than permitted in advertised data limits

+

pub const STREAM_LIMIT_ERROR: Code = _

received a frame for a stream identifier that exceeded advertised the stream limit for the corresponding stream type

+

pub const STREAM_STATE_ERROR: Code = _

received a frame for a stream that was not in a state that permitted that frame

+

pub const FINAL_SIZE_ERROR: Code = _

received a STREAM frame or a RESET_STREAM frame containing a different final size to the one already established

+

pub const FRAME_ENCODING_ERROR: Code = _

received a frame that was badly formatted

+

pub const TRANSPORT_PARAMETER_ERROR: Code = _

received transport parameters that were badly formatted, included an invalid value, was absent even though it is mandatory, was present though it is forbidden, or is otherwise in error

+

pub const CONNECTION_ID_LIMIT_ERROR: Code = _

the number of connection IDs provided by the peer exceeds the advertised active_connection_id_limit

+

pub const PROTOCOL_VIOLATION: Code = _

detected an error with protocol compliance that was not covered by more specific error codes

+

pub const INVALID_TOKEN: Code = _

received an invalid Retry Token in a client Initial

+

pub const APPLICATION_ERROR: Code = _

the application or application protocol caused the connection to be closed during the handshake

+

pub const CRYPTO_BUFFER_EXCEEDED: Code = _

received more data in CRYPTO frames than can be buffered

+

pub const KEY_UPDATE_ERROR: Code = _

key update error

+

pub const AEAD_LIMIT_REACHED: Code = _

the endpoint has reached the confidentiality or integrity limit for the AEAD algorithm

+

pub const NO_VIABLE_PATH: Code = _

no viable network path exists

+

Trait Implementations§

§

impl Clone for Code

§

fn clone(&self) -> Code

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Code

§

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

Formats the value using the given formatter. Read more
§

impl Display for Code

§

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

Formats the value using the given formatter. Read more
§

impl From<Code> for Error

§

fn from(x: Code) -> Error

Converts to this type from the input type.
§

impl PartialEq for Code

§

fn eq(&self, other: &Code) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Copy for Code

§

impl Eq for Code

§

impl StructuralPartialEq for Code

Auto Trait Implementations§

§

impl Freeze for Code

§

impl RefUnwindSafe for Code

§

impl Send for Code

§

impl Sync for Code

§

impl Unpin for Code

§

impl UnwindSafe for Code

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.UdpStats.html b/pr/2992/docs/iroh/endpoint/struct.UdpStats.html new file mode 100644 index 0000000000..57a3909412 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.UdpStats.html @@ -0,0 +1,38 @@ +UdpStats in iroh::endpoint - Rust

Struct iroh::endpoint::UdpStats

#[non_exhaustive]
pub struct UdpStats { + pub datagrams: u64, + pub bytes: u64, + pub ios: u64, +}
Expand description

Statistics about UDP datagrams transmitted or received on a connection

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§datagrams: u64

The amount of UDP datagrams observed

+
§bytes: u64

The total amount of bytes which have been transferred inside UDP datagrams

+
§ios: u64

The amount of I/O operations executed

+

Can be less than datagrams when GSO, GRO, and/or batched system calls are in use.

+

Trait Implementations§

§

impl Clone for UdpStats

§

fn clone(&self) -> UdpStats

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for UdpStats

§

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

Formats the value using the given formatter. Read more
§

impl Default for UdpStats

§

fn default() -> UdpStats

Returns the “default value” for a type. Read more
§

impl Copy for UdpStats

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.UnsupportedVersion.html b/pr/2992/docs/iroh/endpoint/struct.UnsupportedVersion.html new file mode 100644 index 0000000000..5ae4202afd --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.UnsupportedVersion.html @@ -0,0 +1,27 @@ +UnsupportedVersion in iroh::endpoint - Rust

Struct iroh::endpoint::UnsupportedVersion

pub struct UnsupportedVersion;
Expand description

Error indicating that the specified QUIC version is not supported

+

Trait Implementations§

§

impl Debug for UnsupportedVersion

§

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

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.VarInt.html b/pr/2992/docs/iroh/endpoint/struct.VarInt.html new file mode 100644 index 0000000000..30f03631ab --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.VarInt.html @@ -0,0 +1,62 @@ +VarInt in iroh::endpoint - Rust

Struct iroh::endpoint::VarInt

pub struct VarInt(/* private fields */);
Expand description

An integer less than 2^62

+

Values of this type are suitable for encoding as QUIC variable-length integer.

+

Implementations§

§

impl VarInt

pub const MAX: VarInt = _

The largest representable value

+

pub const MAX_SIZE: usize = 8usize

The largest encoded value length

+

pub const fn from_u32(x: u32) -> VarInt

Construct a VarInt infallibly

+

pub fn from_u64(x: u64) -> Result<VarInt, VarIntBoundsExceeded>

Succeeds iff x < 2^62

+

pub const unsafe fn from_u64_unchecked(x: u64) -> VarInt

Create a VarInt without ensuring it’s in range

+
§Safety
+

x must be less than 2^62.

+

pub const fn into_inner(self) -> u64

Extract the integer value

+

pub fn saturating_add(self, rhs: impl Into<VarInt>) -> VarInt

Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead +of overflowing.

+

Trait Implementations§

§

impl Clone for VarInt

§

fn clone(&self) -> VarInt

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for VarInt

§

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

Formats the value using the given formatter. Read more
§

impl Default for VarInt

§

fn default() -> VarInt

Returns the “default value” for a type. Read more
§

impl Display for VarInt

§

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

Formats the value using the given formatter. Read more
§

impl From<StreamId> for VarInt

§

fn from(x: StreamId) -> VarInt

Converts to this type from the input type.
§

impl From<VarInt> for StreamId

§

fn from(v: VarInt) -> StreamId

Converts to this type from the input type.
§

impl From<u16> for VarInt

§

fn from(x: u16) -> VarInt

Converts to this type from the input type.
§

impl From<u32> for VarInt

§

fn from(x: u32) -> VarInt

Converts to this type from the input type.
§

impl From<u8> for VarInt

§

fn from(x: u8) -> VarInt

Converts to this type from the input type.
§

impl Hash for VarInt

§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
§

impl Ord for VarInt

§

fn cmp(&self, other: &VarInt) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
§

impl PartialEq for VarInt

§

fn eq(&self, other: &VarInt) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialOrd for VarInt

§

fn partial_cmp(&self, other: &VarInt) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl TryFrom<u128> for VarInt

§

fn try_from(x: u128) -> Result<VarInt, VarIntBoundsExceeded>

Succeeds iff x < 2^62

+
§

type Error = VarIntBoundsExceeded

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

impl TryFrom<u64> for VarInt

§

fn try_from(x: u64) -> Result<VarInt, VarIntBoundsExceeded>

Succeeds iff x < 2^62

+
§

type Error = VarIntBoundsExceeded

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

impl TryFrom<usize> for VarInt

§

fn try_from(x: usize) -> Result<VarInt, VarIntBoundsExceeded>

Succeeds iff x < 2^62

+
§

type Error = VarIntBoundsExceeded

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

impl Copy for VarInt

§

impl Eq for VarInt

§

impl StructuralPartialEq for VarInt

Auto Trait Implementations§

§

impl Freeze for VarInt

§

impl RefUnwindSafe for VarInt

§

impl Send for VarInt

§

impl Sync for VarInt

§

impl Unpin for VarInt

§

impl UnwindSafe for VarInt

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.WeakConnectionHandle.html b/pr/2992/docs/iroh/endpoint/struct.WeakConnectionHandle.html new file mode 100644 index 0000000000..2a030c8139 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.WeakConnectionHandle.html @@ -0,0 +1,42 @@ +WeakConnectionHandle in iroh::endpoint - Rust

Struct iroh::endpoint::WeakConnectionHandle

pub struct WeakConnectionHandle(/* private fields */);
Expand description

A handle to some connection internals, use with care.

+

This contains a weak reference to the connection so will not itself keep the connection +alive.

+

Implementations§

§

impl WeakConnectionHandle

pub fn is_alive(&self) -> bool

Returns true if the Connection associated with this handle is still alive.

+

pub fn network_path_changed(&self) -> bool

Resets path-specific state.

+

This resets several subsystems keeping state for a specific network path. It is +useful if it is known that the underlying network path changed substantially.

+

Currently resets:

+
    +
  • RTT Estimator
  • +
  • Congestion Controller
  • +
  • MTU Discovery
  • +
+
§Returns
+

true if the connection still existed and the congestion controller state was +reset. false otherwise.

+

Trait Implementations§

§

impl Debug for WeakConnectionHandle

§

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

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.Written.html b/pr/2992/docs/iroh/endpoint/struct.Written.html new file mode 100644 index 0000000000..bcaf66c51a --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.Written.html @@ -0,0 +1,42 @@ +Written in iroh::endpoint - Rust

Struct iroh::endpoint::Written

pub struct Written {
+    pub bytes: usize,
+    pub chunks: usize,
+}
Expand description

Indicates how many bytes and chunks had been transferred in a write operation

+

Fields§

§bytes: usize

The amount of bytes which had been written

+
§chunks: usize

The amount of full chunks which had been written

+

If a chunk was only partially written, it will not be counted by this field.

+

Trait Implementations§

§

impl Clone for Written

§

fn clone(&self) -> Written

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Written

§

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

Formats the value using the given formatter. Read more
§

impl Default for Written

§

fn default() -> Written

Returns the “default value” for a type. Read more
§

impl PartialEq for Written

§

fn eq(&self, other: &Written) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Copy for Written

§

impl Eq for Written

§

impl StructuralPartialEq for Written

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/struct.ZeroRttAccepted.html b/pr/2992/docs/iroh/endpoint/struct.ZeroRttAccepted.html new file mode 100644 index 0000000000..d7a4cf5045 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/struct.ZeroRttAccepted.html @@ -0,0 +1,106 @@ +ZeroRttAccepted in iroh::endpoint - Rust

Struct iroh::endpoint::ZeroRttAccepted

pub struct ZeroRttAccepted(/* private fields */);
Expand description

Future that completes when a connection is fully established

+

For clients, the resulting value indicates if 0-RTT was accepted. For servers, the resulting +value is meaningless.

+

Trait Implementations§

§

impl Future for ZeroRttAccepted

§

type Output = bool

The type of value produced on completion.
§

fn poll( + self: Pin<&mut ZeroRttAccepted>, + cx: &mut Context<'_> +) -> Poll<<ZeroRttAccepted as Future>::Output>

Attempt to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F> FutureExt for F
where + F: Future + ?Sized,

§

fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll() on !Unpin types.
§

fn or<F>(self, other: F) -> Or<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, preferring self if both are ready. Read more
§

fn race<F>(self, other: F) -> Race<Self, F>
where + Self: Sized, + F: Future<Output = Self::Output>,

Returns the result of self or other future, with no preference if both are ready. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches panics while polling the future. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Boxes the future and changes its type to dyn Future + Send + 'a. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Boxes the future and changes its type to dyn Future + 'a. Read more
§

impl<F1> FutureExt for F1
where + F1: Future,

§

fn join<F2>(self, other: F2) -> Join2<F1, <F2 as IntoFuture>::IntoFuture>
where + F1: Future, + F2: IntoFuture,

Wait for both futures to complete.
§

fn race<T, S2>(self, other: S2) -> Race2<T, F1, <S2 as IntoFuture>::IntoFuture>
where + F1: Future<Output = T>, + S2: IntoFuture<Output = T>,

Wait for the first future to complete.
§

fn wait_until<D>( + self, + deadline: D +) -> WaitUntil<Self, <D as IntoFuture>::IntoFuture>
where + Self: Sized, + D: IntoFuture,

Delay resolving the future until the given deadline. Read more
§

impl<T> FutureExt for T
where + T: Future + ?Sized,

§

fn map<U, F>(self, f: F) -> Map<Self, F>
where + F: FnOnce(Self::Output) -> U, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn map_into<U>(self) -> MapInto<Self, U>
where + Self::Output: Into<U>, + Self: Sized,

Map this future’s output to a different type, returning a new future of +the resulting type. Read more
§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
where + F: FnOnce(Self::Output) -> Fut, + Fut: Future, + Self: Sized,

Chain on a computation for when a future finished, passing the result of +the future to the provided closure f. Read more
§

fn left_future<B>(self) -> Either<Self, B>
where + B: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the left-hand variant +of that Either. Read more
§

fn right_future<A>(self) -> Either<A, Self>
where + A: Future<Output = Self::Output>, + Self: Sized,

Wrap this future in an Either future, making it the right-hand variant +of that Either. Read more
§

fn into_stream(self) -> IntoStream<Self>
where + Self: Sized,

Convert this future into a single element stream. Read more
§

fn flatten(self) -> Flatten<Self>
where + Self::Output: Future, + Self: Sized,

Flatten the execution of this future when the output of this +future is itself another future. Read more
§

fn flatten_stream(self) -> FlattenStream<Self>
where + Self::Output: Stream, + Self: Sized,

Flatten the execution of this future when the successful result of this +future is a stream. Read more
§

fn fuse(self) -> Fuse<Self>
where + Self: Sized,

Fuse a future such that poll will never again be called once it has +completed. This method can be used to turn any Future into a +FusedFuture. Read more
§

fn inspect<F>(self, f: F) -> Inspect<Self, F>
where + F: FnOnce(&Self::Output), + Self: Sized,

Do something with the output of a future before passing it on. Read more
§

fn catch_unwind(self) -> CatchUnwind<Self>
where + Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
§

fn shared(self) -> Shared<Self>
where + Self: Sized, + Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve +to the same result. Read more
§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where + Self: Sized,

Turn this future into a future that yields () on completion and sends +its output to another future on a separate task. Read more
§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where + Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where + Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
§

fn unit_error(self) -> UnitError<Self>
where + Self: Sized,

§

fn never_error(self) -> NeverError<Self>
where + Self: Sized,

§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where + Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
§

fn now_or_never(self) -> Option<Self::Output>
where + Self: Sized,

Evaluates and consumes the future, returning the resulting output if +the future is ready after the first call to Future::poll. Read more
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<F> IntoFuture for F
where + F: Future,

§

type Output = <F as Future>::Output

The output that the future will produce on completion.
§

type IntoFuture = F

Which kind of future are we turning this into?
source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/trait.AeadKey.html b/pr/2992/docs/iroh/endpoint/trait.AeadKey.html new file mode 100644 index 0000000000..61b454e3d1 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/trait.AeadKey.html @@ -0,0 +1,32 @@ +AeadKey in iroh::endpoint - Rust

Trait iroh::endpoint::AeadKey

pub trait AeadKey {
+    // Required methods
+    fn seal(
+        &self,
+        data: &mut Vec<u8>,
+        additional_data: &[u8]
+    ) -> Result<(), CryptoError>;
+    fn open<'a>(
+        &self,
+        data: &'a mut [u8],
+        additional_data: &[u8]
+    ) -> Result<&'a mut [u8], CryptoError>;
+}
Expand description

A key for sealing data with AEAD-based algorithms

+

Required Methods§

fn seal( + &self, + data: &mut Vec<u8>, + additional_data: &[u8] +) -> Result<(), CryptoError>

Method for sealing message data

+

fn open<'a>( + &self, + data: &'a mut [u8], + additional_data: &[u8] +) -> Result<&'a mut [u8], CryptoError>

Method for opening a sealed message data

+

Implementations on Foreign Types§

§

impl AeadKey for LessSafeKey

§

fn seal( + &self, + data: &mut Vec<u8>, + additional_data: &[u8] +) -> Result<(), CryptoError>

§

fn open<'a>( + &self, + data: &'a mut [u8], + additional_data: &[u8] +) -> Result<&'a mut [u8], CryptoError>

Implementors§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/trait.Controller.html b/pr/2992/docs/iroh/endpoint/trait.Controller.html new file mode 100644 index 0000000000..4d3ac60a7f --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/trait.Controller.html @@ -0,0 +1,68 @@ +Controller in iroh::endpoint - Rust

Trait iroh::endpoint::Controller

pub trait Controller: Send + Sync {
+    // Required methods
+    fn on_congestion_event(
+        &mut self,
+        now: Instant,
+        sent: Instant,
+        is_persistent_congestion: bool,
+        lost_bytes: u64
+    );
+    fn on_mtu_update(&mut self, new_mtu: u16);
+    fn window(&self) -> u64;
+    fn clone_box(&self) -> Box<dyn Controller>;
+    fn initial_window(&self) -> u64;
+    fn into_any(self: Box<Self>) -> Box<dyn Any>;
+
+    // Provided methods
+    fn on_sent(&mut self, now: Instant, bytes: u64, last_packet_number: u64) { ... }
+    fn on_ack(
+        &mut self,
+        now: Instant,
+        sent: Instant,
+        bytes: u64,
+        app_limited: bool,
+        rtt: &RttEstimator
+    ) { ... }
+    fn on_end_acks(
+        &mut self,
+        now: Instant,
+        in_flight: u64,
+        app_limited: bool,
+        largest_packet_num_acked: Option<u64>
+    ) { ... }
+}
Expand description

Common interface for different congestion controllers

+

Required Methods§

fn on_congestion_event( + &mut self, + now: Instant, + sent: Instant, + is_persistent_congestion: bool, + lost_bytes: u64 +)

Packets were deemed lost or marked congested

+

in_persistent_congestion indicates whether all packets sent within the persistent +congestion threshold period ending when the most recent packet in this batch was sent were +lost. +lost_bytes indicates how many bytes were lost. This value will be 0 for ECN triggers.

+

fn on_mtu_update(&mut self, new_mtu: u16)

The known MTU for the current network path has been updated

+

fn window(&self) -> u64

Number of ack-eliciting bytes that may be in flight

+

fn clone_box(&self) -> Box<dyn Controller>

Duplicate the controller’s state

+

fn initial_window(&self) -> u64

Initial congestion window

+

fn into_any(self: Box<Self>) -> Box<dyn Any>

Returns Self for use in down-casting to extract implementation details

+

Provided Methods§

fn on_sent(&mut self, now: Instant, bytes: u64, last_packet_number: u64)

One or more packets were just sent

+

fn on_ack( + &mut self, + now: Instant, + sent: Instant, + bytes: u64, + app_limited: bool, + rtt: &RttEstimator +)

Packet deliveries were confirmed

+

app_limited indicates whether the connection was blocked on outgoing +application data prior to receiving these acknowledgements.

+

fn on_end_acks( + &mut self, + now: Instant, + in_flight: u64, + app_limited: bool, + largest_packet_num_acked: Option<u64> +)

Packets are acked in batches, all with the same now argument. This indicates one of those batches has completed.

+

Implementors§

§

impl Controller for Bbr

§

impl Controller for Cubic

§

impl Controller for NewReno

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/trait.ControllerFactory.html b/pr/2992/docs/iroh/endpoint/trait.ControllerFactory.html new file mode 100644 index 0000000000..3f1b1617cf --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/trait.ControllerFactory.html @@ -0,0 +1,10 @@ +ControllerFactory in iroh::endpoint - Rust

Trait iroh::endpoint::ControllerFactory

pub trait ControllerFactory {
+    // Required method
+    fn build(
+        self: Arc<Self>,
+        now: Instant,
+        current_mtu: u16
+    ) -> Box<dyn Controller>;
+}
Expand description

Constructs controllers on demand

+

Required Methods§

fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller>

Construct a fresh Controller

+

Implementors§

§

impl ControllerFactory for BbrConfig

§

impl ControllerFactory for CubicConfig

§

impl ControllerFactory for NewRenoConfig

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/trait.CryptoServerConfig.html b/pr/2992/docs/iroh/endpoint/trait.CryptoServerConfig.html new file mode 100644 index 0000000000..20f965be46 --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/trait.CryptoServerConfig.html @@ -0,0 +1,38 @@ +CryptoServerConfig in iroh::endpoint - Rust

Trait iroh::endpoint::CryptoServerConfig

pub trait CryptoServerConfig: Send + Sync {
+    // Required methods
+    fn initial_keys(
+        &self,
+        version: u32,
+        dst_cid: &ConnectionId
+    ) -> Result<Keys, UnsupportedVersion>;
+    fn retry_tag(
+        &self,
+        version: u32,
+        orig_dst_cid: &ConnectionId,
+        packet: &[u8]
+    ) -> [u8; 16];
+    fn start_session(
+        self: Arc<Self>,
+        version: u32,
+        params: &TransportParameters
+    ) -> Box<dyn Session>;
+}
Expand description

Server-side configuration for the crypto protocol

+

Required Methods§

fn initial_keys( + &self, + version: u32, + dst_cid: &ConnectionId +) -> Result<Keys, UnsupportedVersion>

Create the initial set of keys given the client’s initial destination ConnectionId

+

fn retry_tag( + &self, + version: u32, + orig_dst_cid: &ConnectionId, + packet: &[u8] +) -> [u8; 16]

Generate the integrity tag for a retry packet

+

Never called if initial_keys rejected version.

+

fn start_session( + self: Arc<Self>, + version: u32, + params: &TransportParameters +) -> Box<dyn Session>

Start a server session with this configuration

+

Never called if initial_keys rejected version.

+

Implementors§

§

impl ServerConfig for QuicServerConfig

\ No newline at end of file diff --git a/pr/2992/docs/iroh/endpoint/trait.HandshakeTokenKey.html b/pr/2992/docs/iroh/endpoint/trait.HandshakeTokenKey.html new file mode 100644 index 0000000000..97398624ba --- /dev/null +++ b/pr/2992/docs/iroh/endpoint/trait.HandshakeTokenKey.html @@ -0,0 +1,6 @@ +HandshakeTokenKey in iroh::endpoint - Rust

Trait iroh::endpoint::HandshakeTokenKey

pub trait HandshakeTokenKey: Send + Sync {
+    // Required method
+    fn aead_from_hkdf(&self, random_bytes: &[u8]) -> Box<dyn AeadKey>;
+}
Expand description

A pseudo random key for HKDF

+

Required Methods§

fn aead_from_hkdf(&self, random_bytes: &[u8]) -> Box<dyn AeadKey>

Derive AEAD using hkdf

+

Implementations on Foreign Types§

§

impl HandshakeTokenKey for Prk

§

fn aead_from_hkdf(&self, random_bytes: &[u8]) -> Box<dyn AeadKey>

Implementors§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/enum.AddrInfoOptions.html b/pr/2992/docs/iroh/enum.AddrInfoOptions.html new file mode 100644 index 0000000000..65fce8e101 --- /dev/null +++ b/pr/2992/docs/iroh/enum.AddrInfoOptions.html @@ -0,0 +1,57 @@ +AddrInfoOptions in iroh - Rust

Enum iroh::AddrInfoOptions

source ·
pub enum AddrInfoOptions {
+    Id,
+    RelayAndAddresses,
+    Relay,
+    Addresses,
+}
Expand description

Options to configure what is included in a NodeAddr and AddrInfo.

+

Variants§

§

Id

Only the Node ID is added.

+

This usually means that iroh-dns discovery is used to find address information.

+
§

RelayAndAddresses

Includes the Node ID and both the relay URL, and the direct addresses.

+
§

Relay

Includes the Node ID and the relay URL.

+
§

Addresses

Includes the Node ID and the direct addresses.

+

Trait Implementations§

source§

impl Clone for AddrInfoOptions

source§

fn clone(&self) -> AddrInfoOptions

Returns a copy 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 AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfoOptions

source§

fn default() -> AddrInfoOptions

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfoOptions

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<AddrInfoOptions, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for AddrInfoOptions

§

type Err = FromStrError

The associated error which can be returned from parsing.
source§

fn from_str( + src: &str +) -> Result<AddrInfoOptions, <AddrInfoOptions as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for AddrInfoOptions

source§

fn eq(&self, other: &AddrInfoOptions) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for AddrInfoOptions

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for AddrInfoOptions

source§

impl Eq for AddrInfoOptions

source§

impl StructuralPartialEq for AddrInfoOptions

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/hash/enum.BlobFormat.html b/pr/2992/docs/iroh/hash/enum.BlobFormat.html new file mode 100644 index 0000000000..3c76f6388f --- /dev/null +++ b/pr/2992/docs/iroh/hash/enum.BlobFormat.html @@ -0,0 +1,64 @@ +BlobFormat in iroh::hash - Rust

Enum iroh::hash::BlobFormat

source ·
pub enum BlobFormat {
+    Raw,
+    HashSeq,
+}
Expand description

A format identifier

+

Variants§

§

Raw

Raw blob

+
§

HashSeq

A sequence of BLAKE3 hashes

+

Implementations§

source§

impl BlobFormat

source

pub const fn is_raw(&self) -> bool

Is raw format

+
source

pub const fn is_hash_seq(&self) -> bool

Is hash seq format

+

Trait Implementations§

source§

impl Clone for BlobFormat

source§

fn clone(&self) -> BlobFormat

Returns a copy 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 BlobFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for BlobFormat

source§

fn default() -> BlobFormat

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for BlobFormat

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<BlobFormat, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for BlobFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl Hash for BlobFormat

source§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl MaxSize for BlobFormat

source§

const POSTCARD_MAX_SIZE: usize = 1usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for BlobFormat

source§

fn cmp(&self, other: &BlobFormat) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for BlobFormat

source§

fn eq(&self, other: &BlobFormat) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for BlobFormat

source§

fn partial_cmp(&self, other: &BlobFormat) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for BlobFormat

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for BlobFormat

source§

impl Eq for BlobFormat

source§

impl StructuralPartialEq for BlobFormat

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/hash/index.html b/pr/2992/docs/iroh/hash/index.html new file mode 100644 index 0000000000..19cd095d11 --- /dev/null +++ b/pr/2992/docs/iroh/hash/index.html @@ -0,0 +1,2 @@ +iroh::hash - Rust

Module iroh::hash

source ·
Expand description

The blake3 hash used in Iroh.

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/hash/sidebar-items.js b/pr/2992/docs/iroh/hash/sidebar-items.js new file mode 100644 index 0000000000..8b279d4eb3 --- /dev/null +++ b/pr/2992/docs/iroh/hash/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["BlobFormat"],"struct":["Hash","HashAndFormat"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/hash/struct.Hash.html b/pr/2992/docs/iroh/hash/struct.Hash.html new file mode 100644 index 0000000000..62c5db201d --- /dev/null +++ b/pr/2992/docs/iroh/hash/struct.Hash.html @@ -0,0 +1,75 @@ +Hash in iroh::hash - Rust

Struct iroh::hash::Hash

source ·
pub struct Hash(/* private fields */);
Expand description

Hash type used throughout.

+

Implementations§

source§

impl Hash

source

pub const EMPTY: Hash = _

The hash for the empty byte range (b"").

+
source

pub fn new(buf: impl AsRef<[u8]>) -> Hash

Calculate the hash of the provided bytes.

+
source

pub fn as_bytes(&self) -> &[u8; 32]

Bytes of the hash.

+
source

pub const fn from_bytes(bytes: [u8; 32]) -> Hash

Create a Hash from its raw bytes representation.

+
source

pub fn to_hex(&self) -> String

Convert the hash to a hex string.

+
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string +representation of the hash.

+

Trait Implementations§

source§

impl AsRef<[u8]> for Hash

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Borrow<[u8]> for Hash

source§

fn borrow(&self) -> &[u8]

Immutably borrows from an owned value. Read more
source§

impl Borrow<[u8; 32]> for Hash

source§

fn borrow(&self) -> &[u8; 32]

Immutably borrows from an owned value. Read more
source§

impl Clone for Hash

source§

fn clone(&self) -> Hash

Returns a copy 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 Hash

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Hash

source§

fn deserialize<D>( + deserializer: D +) -> Result<Hash, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Hash

source§

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

Formats the value using the given formatter. Read more
source§

impl From<&[u8; 32]> for Hash

source§

fn from(value: &[u8; 32]) -> Hash

Converts to this type from the input type.
source§

impl From<[u8; 32]> for Hash

source§

fn from(value: [u8; 32]) -> Hash

Converts to this type from the input type.
source§

impl From<Hash> for [u8; 32]

source§

fn from(value: Hash) -> [u8; 32]

Converts to this type from the input type.
source§

impl From<Hash> for Hash

source§

fn from(value: Hash) -> Hash

Converts to this type from the input type.
source§

impl FromStr for Hash

§

type Err = HexOrBase32ParseError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Hash, <Hash as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for Hash

source§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Key for Hash

source§

fn compare(data1: &[u8], data2: &[u8]) -> Ordering

Compare data1 with data2
source§

impl MaxSize for Hash

source§

const POSTCARD_MAX_SIZE: usize = 32usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for Hash

source§

fn cmp(&self, other: &Hash) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for Hash

source§

fn eq(&self, other: &Hash) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for Hash

source§

fn partial_cmp(&self, other: &Hash) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for Hash

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Value for Hash

§

type SelfType<'a> = Hash

SelfType<’a> must be the same type as Self with all lifetimes replaced with ’a
§

type AsBytes<'a> = &'a [u8; 32]

source§

fn fixed_width() -> Option<usize>

Width of a fixed type, or None for variable width
source§

fn from_bytes<'a>(data: &'a [u8]) -> <Hash as Value>::SelfType<'a>
where + Hash: 'a,

Deserializes data +Implementations may return a view over data, or an owned type
source§

fn as_bytes<'a, 'b>( + value: &'a <Hash as Value>::SelfType<'b> +) -> <Hash as Value>::AsBytes<'a>
where + 'b: 'a, + Hash: 'a + 'b,

Serialize the value to a slice
source§

fn type_name() -> TypeName

Globally unique identifier for this type
source§

impl Copy for Hash

source§

impl Eq for Hash

source§

impl StructuralPartialEq for Hash

Auto Trait Implementations§

§

impl Freeze for Hash

§

impl RefUnwindSafe for Hash

§

impl Send for Hash

§

impl Sync for Hash

§

impl Unpin for Hash

§

impl UnwindSafe for Hash

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/hash/struct.HashAndFormat.html b/pr/2992/docs/iroh/hash/struct.HashAndFormat.html new file mode 100644 index 0000000000..1843c6d547 --- /dev/null +++ b/pr/2992/docs/iroh/hash/struct.HashAndFormat.html @@ -0,0 +1,71 @@ +HashAndFormat in iroh::hash - Rust

Struct iroh::hash::HashAndFormat

source ·
pub struct HashAndFormat {
+    pub hash: Hash,
+    pub format: BlobFormat,
+}
Expand description

A hash and format pair

+

Fields§

§hash: Hash

The hash

+
§format: BlobFormat

The format

+

Implementations§

source§

impl HashAndFormat

source

pub fn new(hash: Hash, format: BlobFormat) -> HashAndFormat

Create a new hash and format pair.

+
source

pub fn raw(hash: Hash) -> HashAndFormat

Create a new hash and format pair, using the default (raw) format.

+
source

pub fn hash_seq(hash: Hash) -> HashAndFormat

Create a new hash and format pair, using the collection format.

+

Trait Implementations§

source§

impl Clone for HashAndFormat

source§

fn clone(&self) -> HashAndFormat

Returns a copy 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 HashAndFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for HashAndFormat

source§

fn deserialize<D>( + deserializer: D +) -> Result<HashAndFormat, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for HashAndFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for HashAndFormat

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<HashAndFormat, <HashAndFormat as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for HashAndFormat

source§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl MaxSize for HashAndFormat

source§

const POSTCARD_MAX_SIZE: usize = 33usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for HashAndFormat

source§

fn cmp(&self, other: &HashAndFormat) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for HashAndFormat

source§

fn eq(&self, other: &HashAndFormat) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for HashAndFormat

source§

fn partial_cmp(&self, other: &HashAndFormat) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for HashAndFormat

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Value for HashAndFormat

§

type SelfType<'a> = HashAndFormat

SelfType<’a> must be the same type as Self with all lifetimes replaced with ’a
§

type AsBytes<'a> = [u8; 33]

source§

fn fixed_width() -> Option<usize>

Width of a fixed type, or None for variable width
source§

fn from_bytes<'a>(data: &'a [u8]) -> <HashAndFormat as Value>::SelfType<'a>
where + HashAndFormat: 'a,

Deserializes data +Implementations may return a view over data, or an owned type
source§

fn as_bytes<'a, 'b>( + value: &'a <HashAndFormat as Value>::SelfType<'b> +) -> <HashAndFormat as Value>::AsBytes<'a>
where + 'b: 'a, + HashAndFormat: 'a + 'b,

Serialize the value to a slice
source§

fn type_name() -> TypeName

Globally unique identifier for this type
source§

impl Copy for HashAndFormat

source§

impl Eq for HashAndFormat

source§

impl StructuralPartialEq for HashAndFormat

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/index.html b/pr/2992/docs/iroh/index.html new file mode 100644 index 0000000000..18ebf78ea8 --- /dev/null +++ b/pr/2992/docs/iroh/index.html @@ -0,0 +1,166 @@ +iroh - Rust

Crate iroh

source ·
Expand description

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 node is created and controlled by the Endpoint, e.g. connecting to +another node:

+ +
let addr: NodeAddr = todo!();
+let ep = Endpoint::builder().bind().await?;
+let conn = ep.connect(addr, b"my-alpn").await?;
+let mut send_stream = conn.open_uni().await?;
+send_stream.write_all(b"msg").await?;
+

The other node can accept incoming connections using the Endpoint as well:

+ +
let ep = Endpoint::builder()
+    .alpns(vec![b"my-alpn".to_vec()])
+    .bind()
+    .await?;
+let conn = ep.accept().await.ok_or("err")?.await?;
+let mut recv_stream = conn.accept_uni().await?;
+let mut buf = [0u8; 3];
+recv_stream.read_exact(&mut buf).await?;
+

Of course you can also use bi-directional streams or any other features from QUIC.

+

For more elaborate examples, see below or the examples directory in +the source repository.

+

§Connection Establishment

+

An iroh connection between two iroh nodes 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 nodes want to connect they +first establish connection via this home relay. As soon as connection between the two +nodes 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 nodes can be reached directly, connectivity can also be +established without involving a Relay server. This is done by using the node’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 node has a +unique SecretKey used to authenticate and encrypt the connection. When an iroh +node 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 node it is also known as +the NodeId. As encryption is an integral part of TLS as used in QUIC this +NodeId is always a required parameter to establish a connection.

+

When accepting connections the peer’s NodeId 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 nodes are always reachable. They accept +encrypted traffic for iroh nodes which are connected to them, forwarding it to +the correct destination based on the NodeId only. Since nodes only send encrypted +traffic, the Relay servers can not decode any traffic for other iroh nodes 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 nodes, Relay servers +provide some functions to assist in hole punching. They have various services to help +nodes understand their own network situation. This includes offering a STUN 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 node is managed using the Endpoint and this is used to create or accept +connections to other nodes. To establish a connection to an iroh node you need to +know three pieces of information:

+
    +
  • The NodeId 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, 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.

+
+

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.

+
+

§Node Discovery

+

The need to know the RelayUrl or some direct addresses in addition to the +NodeId to connect to an iroh node can be an obstacle. To address this the +endpoint::Builder allows to configure a discovery service.

+

The DnsDiscovery service is a discovery service which will publish the RelayUrl +and direct addresses to a service publishing those as DNS records. To connect it looks +up the NodeId in the DNS system to find the addressing details. This enables +connecting using only the NodeId which is often more convenient and resilient.

+

See the discovery module for more details.

+

§Examples

+

The central struct is the Endpoint, which allows you to connect to other nodes:

+ +
use anyhow::Result;
+use iroh::{Endpoint, NodeAddr};
+
+async fn connect(addr: NodeAddr) -> Result<()> {
+    // The Endpoint is the central object that manages an iroh node.
+    let ep = Endpoint::builder().bind().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?;
+    send_stream.write_all(b"hello").await?;
+    send_stream.finish()?;
+    let _msg = recv_stream.read_to_end(10).await?;
+
+    // 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:

+ +
use anyhow::{Context, Result};
+use futures_lite::StreamExt;
+use iroh::{ticket::NodeTicket, Endpoint, NodeAddr};
+
+async fn accept() -> Result<()> {
+    // To accept connections at least one ALPN must be configured.
+    let ep = Endpoint::builder()
+        .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?;
+    let (mut send_stream, mut recv_stream) = conn.accept_bi().await?;
+    let _msg = recv_stream.read_to_end(10).await?;
+    send_stream.write_all(b"world").await?;
+    send_stream.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.

+

Re-exports§

Modules§

  • Default values used in iroh
  • A dialer to conveniently dial many nodes.
  • Node address discovery.
  • This module exports a DNS resolver, which is also the default resolver used in the +crate::Endpoint if no custom resolver is configured.
  • The Endpoint allows establishing connections to other iroh nodes.
  • The blake3 hash used in Iroh.
  • Cryptographic key handling for iroh.
  • Co-locating all of the iroh metrics structs
  • Tools for spawning an accept loop that routes incoming requests to the right protocol.
  • test_utilstest or test-utils
    Internal utilities to support testing.
  • TLS configuration based on libp2p TLS specs.

Structs§

  • Network paths to contact an iroh node.
  • Network-level addressing information for an iroh node.
  • Configuration of all the relay servers that can be used.
  • Information on a specific relay server.
  • A URL identifying a relay server.

Enums§

Type Aliases§

  • The identifier for a node in the (iroh) network.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/constant.PUBLIC_KEY_LENGTH.html b/pr/2992/docs/iroh/key/constant.PUBLIC_KEY_LENGTH.html new file mode 100644 index 0000000000..31673d8edb --- /dev/null +++ b/pr/2992/docs/iroh/key/constant.PUBLIC_KEY_LENGTH.html @@ -0,0 +1,2 @@ +PUBLIC_KEY_LENGTH in iroh::key - Rust

Constant iroh::key::PUBLIC_KEY_LENGTH

pub const PUBLIC_KEY_LENGTH: usize = 32; // 32usize
Expand description

The length of an ed25519 PublicKey, in bytes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/enum.KeyParsingError.html b/pr/2992/docs/iroh/key/enum.KeyParsingError.html new file mode 100644 index 0000000000..1b3764657b --- /dev/null +++ b/pr/2992/docs/iroh/key/enum.KeyParsingError.html @@ -0,0 +1,33 @@ +KeyParsingError in iroh::key - Rust

Enum iroh::key::KeyParsingError

source ·
pub enum KeyParsingError {
+    Base32(HexOrBase32ParseError),
+    Key(Error),
+}
Expand description

Error when deserialising a PublicKey or a SecretKey.

+

Variants§

§

Base32(HexOrBase32ParseError)

Error when decoding the base32.

+
§

Key(Error)

Error when decoding the public key.

+

Trait Implementations§

source§

impl Debug for KeyParsingError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for KeyParsingError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for KeyParsingError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for KeyParsingError

source§

fn from(source: Error) -> KeyParsingError

Converts to this type from the input type.
source§

impl From<HexOrBase32ParseError> for KeyParsingError

source§

fn from(source: HexOrBase32ParseError) -> KeyParsingError

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/index.html b/pr/2992/docs/iroh/key/index.html new file mode 100644 index 0000000000..f914463c16 --- /dev/null +++ b/pr/2992/docs/iroh/key/index.html @@ -0,0 +1,2 @@ +iroh::key - Rust

Module iroh::key

source ·
Expand description

Cryptographic key handling for iroh.

+

Structs§

Enums§

Constants§

Type Aliases§

  • The identifier for a node in the (iroh) network.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/sidebar-items.js b/pr/2992/docs/iroh/key/sidebar-items.js new file mode 100644 index 0000000000..b99c392d60 --- /dev/null +++ b/pr/2992/docs/iroh/key/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["PUBLIC_KEY_LENGTH"],"enum":["KeyParsingError"],"struct":["PublicKey","SecretKey","SharedSecret","Signature"],"type":["NodeId"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/key/struct.PublicKey.html b/pr/2992/docs/iroh/key/struct.PublicKey.html new file mode 100644 index 0000000000..afc26aa88c --- /dev/null +++ b/pr/2992/docs/iroh/key/struct.PublicKey.html @@ -0,0 +1,84 @@ +PublicKey in iroh::key - Rust

Struct iroh::key::PublicKey

source ·
pub struct PublicKey(/* private fields */);
Expand description

A public key.

+

The key itself is just a 32 byte array, but a key has associated crypto +information that is cached for performance reasons.

+

The cache item will be refreshed every time a crypto operation is performed, +or when a key is deserialised or created from a byte array.

+

Serialisation or creation from a byte array is cheap if the key is already +in the cache, but expensive if it is not.

+

Implementations§

source§

impl PublicKey

source

pub fn as_bytes(&self) -> &[u8; 32]

Get this public key as a byte array.

+
source

pub fn from_bytes(bytes: &[u8; 32]) -> Result<PublicKey, Error>

Construct a PublicKey from a slice of bytes.

+
§Warning
+

This will return a [SignatureError] if the bytes passed into this method do not represent +a valid ed25519_dalek curve point. Will never fail for bytes return from Self::as_bytes. +See [VerifyingKey::from_bytes] for details.

+
source

pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), Error>

Verify a signature on a message with this secret key’s public key.

+
§Return
+

Returns Ok(()) if the signature is valid, and Err otherwise.

+
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string +representation of the key.

+

Trait Implementations§

source§

impl AsRef<[u8]> for PublicKey

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Clone for PublicKey

source§

fn clone(&self) -> PublicKey

Returns a copy 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 PublicKey

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for PublicKey

source§

fn deserialize<D>( + deserializer: D +) -> Result<PublicKey, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for PublicKey

source§

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

Formats the value using the given formatter. Read more
source§

impl From<PublicKey> for NodeAddr

source§

fn from(node_id: PublicKey) -> NodeAddr

Converts to this type from the input type.
source§

impl From<VerifyingKey> for PublicKey

source§

fn from(verifying_key: VerifyingKey) -> PublicKey

Converts to this type from the input type.
source§

impl FromStr for PublicKey

Deserialises the PublicKey from it’s base32 encoding.

+

Display is capable of serialising this format.

+
§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<PublicKey, <PublicKey as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for PublicKey

source§

fn hash<H>(&self, state: &mut H)
where + H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for PublicKey

source§

fn cmp(&self, other: &PublicKey) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for PublicKey

source§

fn eq(&self, other: &PublicKey) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for PublicKey

source§

fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for PublicKey

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl TryFrom<&[u8]> for PublicKey

§

type Error = Error

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

fn try_from( + bytes: &[u8] +) -> Result<PublicKey, <PublicKey as TryFrom<&[u8]>>::Error>

Performs the conversion.
source§

impl TryFrom<&[u8; 32]> for PublicKey

§

type Error = Error

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

fn try_from( + bytes: &[u8; 32] +) -> Result<PublicKey, <PublicKey as TryFrom<&[u8; 32]>>::Error>

Performs the conversion.
source§

impl Copy for PublicKey

source§

impl Eq for PublicKey

source§

impl StructuralPartialEq for PublicKey

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/struct.SecretKey.html b/pr/2992/docs/iroh/key/struct.SecretKey.html new file mode 100644 index 0000000000..ba7621f8fd --- /dev/null +++ b/pr/2992/docs/iroh/key/struct.SecretKey.html @@ -0,0 +1,53 @@ +SecretKey in iroh::key - Rust

Struct iroh::key::SecretKey

source ·
pub struct SecretKey { /* private fields */ }
Expand description

A secret key.

+

Implementations§

source§

impl SecretKey

source

pub fn shared(&self, other: &PublicKey) -> SharedSecret

Returns the shared key for communication between this key and other.

+
source§

impl SecretKey

source

pub fn public(&self) -> PublicKey

The public key of this SecretKey.

+
source

pub fn generate() -> SecretKey

Generate a new SecretKey with the default randomness generator.

+
source

pub fn generate_with_rng<R>(csprng: &mut R) -> SecretKey
where + R: CryptoRngCore + ?Sized,

Generate a new SecretKey with a randomness generator.

+
source

pub fn to_openssh(&self) -> Result<Zeroizing<String>, Error>

Serialise this key to OpenSSH format.

+
source

pub fn try_from_openssh<T>(data: T) -> Result<SecretKey, Error>
where + T: AsRef<[u8]>,

Deserialise this key from OpenSSH format.

+
source

pub fn sign(&self, msg: &[u8]) -> Signature

Sign the given message and return a digital signature

+
source

pub fn to_bytes(&self) -> [u8; 32]

Convert this to the bytes representing the secret part. +The public part can always be recovered.

+
source

pub fn from_bytes(bytes: &[u8; 32]) -> SecretKey

Create a secret key from its byte representation.

+

Trait Implementations§

source§

impl Clone for SecretKey

source§

fn clone(&self) -> SecretKey

Returns a copy 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 SecretKey

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for SecretKey

source§

fn deserialize<D>( + deserializer: D +) -> Result<SecretKey, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for SecretKey

source§

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

Formats the value using the given formatter. Read more
source§

impl From<[u8; 32]> for SecretKey

source§

fn from(value: [u8; 32]) -> SecretKey

Converts to this type from the input type.
source§

impl From<SigningKey> for SecretKey

source§

fn from(secret: SigningKey) -> SecretKey

Converts to this type from the input type.
source§

impl FromStr for SecretKey

§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<SecretKey, <SecretKey as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Serialize for SecretKey

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl TryFrom<&[u8]> for SecretKey

§

type Error = Error

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

fn try_from( + bytes: &[u8] +) -> Result<SecretKey, <SecretKey as TryFrom<&[u8]>>::Error>

Performs the conversion.

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/struct.SharedSecret.html b/pr/2992/docs/iroh/key/struct.SharedSecret.html new file mode 100644 index 0000000000..a7f05472cb --- /dev/null +++ b/pr/2992/docs/iroh/key/struct.SharedSecret.html @@ -0,0 +1,29 @@ +SharedSecret in iroh::key - Rust

Struct iroh::key::SharedSecret

source ·
pub struct SharedSecret(/* private fields */);
Expand description

Shared Secret.

+

Implementations§

source§

impl SharedSecret

source

pub fn seal(&self, buffer: &mut dyn Buffer)

Seals the provided cleartext.

+
source

pub fn open(&self, buffer: &mut dyn Buffer) -> Result<(), Error>

Opens the ciphertext, which must have been created using Self::seal, and places the clear text into the provided buffer.

+

Trait Implementations§

source§

impl Debug for SharedSecret

source§

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

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/struct.Signature.html b/pr/2992/docs/iroh/key/struct.Signature.html new file mode 100644 index 0000000000..1f4d09417c --- /dev/null +++ b/pr/2992/docs/iroh/key/struct.Signature.html @@ -0,0 +1,66 @@ +Signature in iroh::key - Rust

Struct iroh::key::Signature

#[repr(C)]
pub struct Signature { /* private fields */ }
Expand description

Ed25519 signature.

+

This type represents a container for the byte serialization of an Ed25519 +signature, and does not necessarily represent well-formed field or curve +elements.

+

Signature verification libraries are expected to reject invalid field +elements at the time a signature is verified.

+

Implementations§

§

impl Signature

pub const BYTE_SIZE: usize = 64usize

Size of an encoded Ed25519 signature in bytes.

+

pub fn from_bytes(bytes: &[u8; 64]) -> Signature

Parse an Ed25519 signature from a byte slice.

+

pub fn from_components(R: [u8; 32], s: [u8; 32]) -> Signature

Parse an Ed25519 signature from its R and s components.

+

pub fn from_slice(bytes: &[u8]) -> Result<Signature, Error>

Parse an Ed25519 signature from a byte slice.

+
§Returns
+
    +
  • Ok on success
  • +
  • Err if the input byte slice is not 64-bytes
  • +
+

pub fn r_bytes(&self) -> &[u8; 32]

Bytes for the R component of a signature.

+

pub fn s_bytes(&self) -> &[u8; 32]

Bytes for the s component of a signature.

+

pub fn to_bytes(&self) -> [u8; 64]

Return the inner byte array.

+

pub fn to_vec(&self) -> Vec<u8>

Convert this signature into a byte vector.

+

Trait Implementations§

§

impl Clone for Signature

§

fn clone(&self) -> Signature

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Signature

§

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

Formats the value using the given formatter. Read more
§

impl<'de> Deserialize<'de> for Signature

§

fn deserialize<D>( + deserializer: D +) -> Result<Signature, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
§

impl Display for Signature

§

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

Formats the value using the given formatter. Read more
§

impl From<&[u8; 64]> for Signature

§

fn from(bytes: &[u8; 64]) -> Signature

Converts to this type from the input type.
§

impl From<&Signature> for [u8; 64]

§

fn from(sig: &Signature) -> [u8; 64]

Converts to this type from the input type.
§

impl From<[u8; 64]> for Signature

§

fn from(bytes: [u8; 64]) -> Signature

Converts to this type from the input type.
§

impl From<InternalSignature> for Signature

§

fn from(sig: InternalSignature) -> Signature

Converts to this type from the input type.
§

impl From<Signature> for [u8; 64]

§

fn from(sig: Signature) -> [u8; 64]

Converts to this type from the input type.
§

impl FromStr for Signature

Decode a signature from hexadecimal.

+

Upper and lower case hexadecimal are both accepted, however mixed case is +rejected.

+
§

type Err = Error

The associated error which can be returned from parsing.
§

fn from_str(hex: &str) -> Result<Signature, Error>

Parses a string s to return a value of this type. Read more
§

impl LowerHex for Signature

§

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

Formats the value using the given formatter.
§

impl PartialEq for Signature

§

fn eq(&self, other: &Signature) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Serialize for Signature

§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
§

impl SignatureEncoding for Signature

§

type Repr = [u8; 64]

Byte representation of a signature.
§

fn to_bytes(&self) -> [u8; 64]

Encode signature as its byte representation.
§

fn to_vec(&self) -> Vec<u8>

Encode signature as a byte vector.
§

fn encoded_len(&self) -> usize

Get the length of this signature when encoded.
§

impl TryFrom<&[u8]> for Signature

§

type Error = Error

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

fn try_from(bytes: &[u8]) -> Result<Signature, Error>

Performs the conversion.
§

impl TryFrom<&Signature> for Signature

§

type Error = Error

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

fn try_from(signature: &Signature) -> Result<Signature, Error>

Performs the conversion.
§

impl TryFrom<Signature> for Signature

§

type Error = Error

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

fn try_from(signature: Signature) -> Result<Signature, Error>

Performs the conversion.
§

impl UpperHex for Signature

§

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

Formats the value using the given formatter.
§

impl Copy for Signature

§

impl Eq for Signature

§

impl StructuralPartialEq for Signature

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/key/type.NodeId.html b/pr/2992/docs/iroh/key/type.NodeId.html new file mode 100644 index 0000000000..5157a0c0ca --- /dev/null +++ b/pr/2992/docs/iroh/key/type.NodeId.html @@ -0,0 +1,12 @@ +NodeId in iroh::key - Rust

Type Alias iroh::key::NodeId

source ·
pub type NodeId = PublicKey;
Expand description

The identifier for a node in the (iroh) network.

+

Each node in iroh has a unique identifier created as a cryptographic key. This can be +used to globally identify a node. Since it is also a cryptographic key it is also the +mechanism by which all traffic is always encrypted for a specific node only.

+

This is equivalent to PublicKey. By convention we will (or should) use PublicKey +as type name when performing cryptographic operations, but use NodeId when referencing +a node. E.g.:

+
    +
  • encrypt(key: PublicKey)
  • +
  • send_to(node: NodeId)
  • +
+

Aliased Type§

struct NodeId(/* private fields */);
\ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/enum.DirectAddrType.html b/pr/2992/docs/iroh/magicsock/enum.DirectAddrType.html new file mode 100644 index 0000000000..930bff2eb2 --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/enum.DirectAddrType.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../iroh/endpoint/enum.DirectAddrType.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/metrics/struct.Metrics.html b/pr/2992/docs/iroh/magicsock/metrics/struct.Metrics.html new file mode 100644 index 0000000000..0d513563bf --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/metrics/struct.Metrics.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh/metrics/struct.MagicsockMetrics.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/enum.Source.html b/pr/2992/docs/iroh/magicsock/node_map/enum.Source.html new file mode 100644 index 0000000000..79d417302e --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/enum.Source.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh/endpoint/enum.Source.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ConnectionType.html b/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ConnectionType.html new file mode 100644 index 0000000000..838432cd84 --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ConnectionType.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../iroh/endpoint/enum.ConnectionType.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ControlMsg.html b/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ControlMsg.html new file mode 100644 index 0000000000..45506e89ac --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/node_state/enum.ControlMsg.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../iroh/endpoint/enum.ControlMsg.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.DirectAddrInfo.html b/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.DirectAddrInfo.html new file mode 100644 index 0000000000..a9ea785f7b --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.DirectAddrInfo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../iroh/endpoint/struct.DirectAddrInfo.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.RemoteInfo.html b/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.RemoteInfo.html new file mode 100644 index 0000000000..856de08b65 --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/node_state/struct.RemoteInfo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../iroh/endpoint/struct.RemoteInfo.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/node_map/struct.ConnectionTypeStream.html b/pr/2992/docs/iroh/magicsock/node_map/struct.ConnectionTypeStream.html new file mode 100644 index 0000000000..214c0d9e09 --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/node_map/struct.ConnectionTypeStream.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh/endpoint/struct.ConnectionTypeStream.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/struct.DirectAddr.html b/pr/2992/docs/iroh/magicsock/struct.DirectAddr.html new file mode 100644 index 0000000000..8e0ba531ac --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/struct.DirectAddr.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../iroh/endpoint/struct.DirectAddr.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/magicsock/struct.DirectAddrsStream.html b/pr/2992/docs/iroh/magicsock/struct.DirectAddrsStream.html new file mode 100644 index 0000000000..ae4cbd764d --- /dev/null +++ b/pr/2992/docs/iroh/magicsock/struct.DirectAddrsStream.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../iroh/endpoint/struct.DirectAddrsStream.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/index.html b/pr/2992/docs/iroh/metrics/index.html new file mode 100644 index 0000000000..469ae92063 --- /dev/null +++ b/pr/2992/docs/iroh/metrics/index.html @@ -0,0 +1,2 @@ +iroh::metrics - Rust

Module iroh::metrics

source ·
Expand description

Co-locating all of the iroh metrics structs

+

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/sidebar-items.js b/pr/2992/docs/iroh/metrics/sidebar-items.js new file mode 100644 index 0000000000..d5e5ab673c --- /dev/null +++ b/pr/2992/docs/iroh/metrics/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["MagicsockMetrics","NetReportMetrics","PortmapMetrics","RelayMetrics"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/struct.MagicsockMetrics.html b/pr/2992/docs/iroh/metrics/struct.MagicsockMetrics.html new file mode 100644 index 0000000000..f56f065867 --- /dev/null +++ b/pr/2992/docs/iroh/metrics/struct.MagicsockMetrics.html @@ -0,0 +1,88 @@ +MagicsockMetrics in iroh::metrics - Rust

Struct iroh::metrics::MagicsockMetrics

source ·
#[non_exhaustive]
pub struct MagicsockMetrics {
Show 45 fields + pub re_stun_calls: Counter, + pub update_direct_addrs: Counter, + pub send_ipv4: Counter, + pub send_ipv6: Counter, + pub send_relay: Counter, + pub send_relay_error: Counter, + pub send_data: Counter, + pub send_data_network_down: Counter, + pub recv_data_relay: Counter, + pub recv_data_ipv4: Counter, + pub recv_data_ipv6: Counter, + pub recv_datagrams: Counter, + pub recv_gro_datagrams: Counter, + pub send_disco_udp: Counter, + pub send_disco_relay: Counter, + pub sent_disco_udp: Counter, + pub sent_disco_relay: Counter, + pub sent_disco_ping: Counter, + pub sent_disco_pong: Counter, + pub sent_disco_call_me_maybe: Counter, + pub recv_disco_bad_key: Counter, + pub recv_disco_bad_parse: Counter, + pub recv_disco_udp: Counter, + pub recv_disco_relay: Counter, + pub recv_disco_ping: Counter, + pub recv_disco_pong: Counter, + pub recv_disco_call_me_maybe: Counter, + pub recv_disco_call_me_maybe_bad_disco: Counter, + pub relay_home_change: Counter, + pub num_direct_conns_added: Counter, + pub num_direct_conns_removed: Counter, + pub num_relay_conns_added: Counter, + pub num_relay_conns_removed: Counter, + pub actor_tick_main: Counter, + pub actor_tick_msg: Counter, + pub actor_tick_re_stun: Counter, + pub actor_tick_portmap_changed: Counter, + pub actor_tick_direct_addr_heartbeat: Counter, + pub actor_tick_direct_addr_update_receiver: Counter, + pub actor_link_change: Counter, + pub actor_tick_other: Counter, + pub nodes_contacted: Counter, + pub nodes_contacted_directly: Counter, + pub connection_handshake_success: Counter, + pub connection_became_direct: Counter, +
}
Expand description

Enum of metrics for the module

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§re_stun_calls: Counter§update_direct_addrs: Counter§send_ipv4: Counter§send_ipv6: Counter§send_relay: Counter§send_relay_error: Counter§send_data: Counter§send_data_network_down: Counter§recv_data_relay: Counter§recv_data_ipv4: Counter§recv_data_ipv6: Counter§recv_datagrams: Counter

Number of QUIC datagrams received.

+
§recv_gro_datagrams: Counter

Number of datagrams received using GRO

+
§send_disco_udp: Counter§send_disco_relay: Counter§sent_disco_udp: Counter§sent_disco_relay: Counter§sent_disco_ping: Counter§sent_disco_pong: Counter§sent_disco_call_me_maybe: Counter§recv_disco_bad_key: Counter§recv_disco_bad_parse: Counter§recv_disco_udp: Counter§recv_disco_relay: Counter§recv_disco_ping: Counter§recv_disco_pong: Counter§recv_disco_call_me_maybe: Counter§recv_disco_call_me_maybe_bad_disco: Counter§relay_home_change: Counter§num_direct_conns_added: Counter

The number of direct connections we have made to peers.

+
§num_direct_conns_removed: Counter

The number of direct connections we have lost to peers.

+
§num_relay_conns_added: Counter

The number of connections to peers we have added over relay.

+
§num_relay_conns_removed: Counter

The number of connections to peers we have removed over relay.

+
§actor_tick_main: Counter§actor_tick_msg: Counter§actor_tick_re_stun: Counter§actor_tick_portmap_changed: Counter§actor_tick_direct_addr_heartbeat: Counter§actor_tick_direct_addr_update_receiver: Counter§actor_link_change: Counter§actor_tick_other: Counter§nodes_contacted: Counter

Number of nodes we have attempted to contact.

+
§nodes_contacted_directly: Counter

Number of nodes we have managed to contact directly.

+
§connection_handshake_success: Counter

Number of connections with a successful handshake.

+
§connection_became_direct: Counter

Number of connections with a successful handshake that became direct.

+

Trait Implementations§

source§

impl Clone for Metrics

source§

fn clone(&self) -> Metrics

Returns a copy 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 Metrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Metrics

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Iterable for Metrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a dyn Any)>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for Metrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/struct.NetReportMetrics.html b/pr/2992/docs/iroh/metrics/struct.NetReportMetrics.html new file mode 100644 index 0000000000..71f6a9e596 --- /dev/null +++ b/pr/2992/docs/iroh/metrics/struct.NetReportMetrics.html @@ -0,0 +1,40 @@ +NetReportMetrics in iroh::metrics - Rust

Struct iroh::metrics::NetReportMetrics

source ·
pub struct NetReportMetrics {
+    pub stun_packets_dropped: Counter,
+    pub stun_packets_sent_ipv4: Counter,
+    pub stun_packets_sent_ipv6: Counter,
+    pub stun_packets_recv_ipv4: Counter,
+    pub stun_packets_recv_ipv6: Counter,
+    pub reports: Counter,
+    pub reports_full: Counter,
+}
Expand description

Enum of metrics for the module

+

Fields§

§stun_packets_dropped: Counter§stun_packets_sent_ipv4: Counter§stun_packets_sent_ipv6: Counter§stun_packets_recv_ipv4: Counter§stun_packets_recv_ipv6: Counter§reports: Counter§reports_full: Counter

Trait Implementations§

source§

impl Clone for Metrics

source§

fn clone(&self) -> Metrics

Returns a copy 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 Metrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Metrics

source§

fn default() -> Metrics

Returns the “default value” for a type. Read more
source§

impl Iterable for Metrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a (dyn Any + 'static))>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for Metrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/struct.PortmapMetrics.html b/pr/2992/docs/iroh/metrics/struct.PortmapMetrics.html new file mode 100644 index 0000000000..df8f91edc2 --- /dev/null +++ b/pr/2992/docs/iroh/metrics/struct.PortmapMetrics.html @@ -0,0 +1,44 @@ +PortmapMetrics in iroh::metrics - Rust

Struct iroh::metrics::PortmapMetrics

pub struct PortmapMetrics {
+    pub probes_started: Counter,
+    pub local_port_updates: Counter,
+    pub mapping_attempts: Counter,
+    pub mapping_failures: Counter,
+    pub external_address_updated: Counter,
+    pub upnp_probes: Counter,
+    pub upnp_probes_failed: Counter,
+    pub upnp_available: Counter,
+    pub upnp_gateway_updated: Counter,
+    pub pcp_probes: Counter,
+    pub pcp_available: Counter,
+}
Expand description

Enum of metrics for the module

+

Fields§

§probes_started: Counter§local_port_updates: Counter§mapping_attempts: Counter§mapping_failures: Counter§external_address_updated: Counter§upnp_probes: Counter§upnp_probes_failed: Counter§upnp_available: Counter§upnp_gateway_updated: Counter§pcp_probes: Counter§pcp_available: Counter

Trait Implementations§

§

impl Clone for Metrics

§

fn clone(&self) -> Metrics

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Metrics

§

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

Formats the value using the given formatter. Read more
§

impl Default for Metrics

§

fn default() -> Metrics

Returns the “default value” for a type. Read more
§

impl Iterable for Metrics

§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a (dyn Any + 'static))>

Returns an iterator over the struct’s fields as tuples. Read more
§

impl Metric for Metrics

§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/metrics/struct.RelayMetrics.html b/pr/2992/docs/iroh/metrics/struct.RelayMetrics.html new file mode 100644 index 0000000000..6fadcb5029 --- /dev/null +++ b/pr/2992/docs/iroh/metrics/struct.RelayMetrics.html @@ -0,0 +1,75 @@ +RelayMetrics in iroh::metrics - Rust

Struct iroh::metrics::RelayMetrics

pub struct RelayMetrics {
Show 21 fields + pub bytes_sent: Counter, + pub bytes_recv: Counter, + pub send_packets_sent: Counter, + pub send_packets_recv: Counter, + pub send_packets_dropped: Counter, + pub disco_packets_sent: Counter, + pub disco_packets_recv: Counter, + pub disco_packets_dropped: Counter, + pub other_packets_sent: Counter, + pub other_packets_recv: Counter, + pub other_packets_dropped: Counter, + pub got_ping: Counter, + pub sent_pong: Counter, + pub unknown_frames: Counter, + pub frames_rx_ratelimited_total: Counter, + pub conns_rx_ratelimited_total: Counter, + pub accepts: Counter, + pub disconnects: Counter, + pub unique_client_keys: Counter, + pub websocket_accepts: Counter, + pub derp_accepts: Counter, +
}
Available on crate feature test-utils only.
Expand description

Metrics tracked for the relay server

+

Fields§

§bytes_sent: Counter

Bytes sent from a FrameType::SendPacket

+
§bytes_recv: Counter

Bytes received from a FrameType::SendPacket

+
§send_packets_sent: Counter

FrameType::SendPacket sent, that are not disco messages

+
§send_packets_recv: Counter

FrameType::SendPacket received, that are not disco messages

+
§send_packets_dropped: Counter

FrameType::SendPacket dropped, that are not disco messages

+
§disco_packets_sent: Counter

FrameType::SendPacket sent that are disco messages

+
§disco_packets_recv: Counter

FrameType::SendPacket received that are disco messages

+
§disco_packets_dropped: Counter

FrameType::SendPacket dropped that are disco messages

+
§other_packets_sent: Counter

Packets of other FrameTypes sent

+
§other_packets_recv: Counter

Packets of other FrameTypes received

+
§other_packets_dropped: Counter

Packets of other FrameTypes dropped

+
§got_ping: Counter

Number of FrameType::Pings received

+
§sent_pong: Counter

Number of FrameType::Pongs sent

+
§unknown_frames: Counter

Number of FrameType::Unknown received

+
§frames_rx_ratelimited_total: Counter

Number of frames received from client connection which have been rate-limited.

+
§conns_rx_ratelimited_total: Counter

Number of client connections which have had any frames rate-limited.

+
§accepts: Counter

Number of connections we have accepted

+
§disconnects: Counter

Number of connections we have removed because of an error

+
§unique_client_keys: Counter

Number of unique client keys per day

+
§websocket_accepts: Counter

Number of accepted websocket connections

+
§derp_accepts: Counter

Number of accepted ‘iroh derp http’ connection upgrades

+

Trait Implementations§

§

impl Clone for Metrics

§

fn clone(&self) -> Metrics

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Metrics

§

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

Formats the value using the given formatter. Read more
§

impl Default for Metrics

§

fn default() -> Metrics

Returns the “default value” for a type. Read more
§

impl Iterable for Metrics

§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a (dyn Any + 'static))>

Returns an iterator over the struct’s fields as tuples. Read more
§

impl Metric for Metrics

§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/index.html b/pr/2992/docs/iroh/protocol/index.html new file mode 100644 index 0000000000..6dcdb14861 --- /dev/null +++ b/pr/2992/docs/iroh/protocol/index.html @@ -0,0 +1,31 @@ +iroh::protocol - Rust

Module iroh::protocol

source ·
Expand description

Tools for spawning an accept loop that routes incoming requests to the right protocol.

+

§Example

+
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
+
+const ALPN: &[u8] = b"/my/alpn";
+let router = Router::builder(endpoint)
+    .accept(&ALPN, Arc::new(Echo))
+    .spawn()
+    .await?;
+
+// The protocol definition:
+#[derive(Debug, Clone)]
+struct Echo;
+
+impl ProtocolHandler for Echo {
+    fn accept(self: Arc<Self>, connecting: Connecting) -> BoxedFuture<Result<()>> {
+        Box::pin(async move {
+            let connection = connecting.await?;
+            let (mut send, mut recv) = connection.accept_bi().await?;
+
+            // Echo any bytes received back directly.
+            let bytes_sent = tokio::io::copy(&mut recv, &mut send).await?;
+
+            send.finish()?;
+            connection.closed().await;
+
+            Ok(())
+        })
+    }
+}
+

Structs§

Traits§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/sidebar-items.js b/pr/2992/docs/iroh/protocol/sidebar-items.js new file mode 100644 index 0000000000..8aa777eded --- /dev/null +++ b/pr/2992/docs/iroh/protocol/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["ProtocolMap","Router","RouterBuilder"],"trait":["IntoArcAny","ProtocolHandler"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/struct.ProtocolMap.html b/pr/2992/docs/iroh/protocol/struct.ProtocolMap.html new file mode 100644 index 0000000000..7ea6e9b95a --- /dev/null +++ b/pr/2992/docs/iroh/protocol/struct.ProtocolMap.html @@ -0,0 +1,36 @@ +ProtocolMap in iroh::protocol - Rust

Struct iroh::protocol::ProtocolMap

source ·
pub struct ProtocolMap(/* private fields */);
Expand description

A typed map of protocol handlers, mapping them from ALPNs.

+

Implementations§

source§

impl ProtocolMap

source

pub fn get_typed<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>>

Returns the registered protocol handler for an ALPN as a concrete type.

+
source

pub fn get(&self, alpn: &[u8]) -> Option<Arc<dyn ProtocolHandler>>

Returns the registered protocol handler for an ALPN as a Arc<dyn ProtocolHandler>.

+
source

pub fn insert(&mut self, alpn: Vec<u8>, handler: Arc<dyn ProtocolHandler>)

Inserts a protocol handler.

+
source

pub fn alpns(&self) -> impl Iterator<Item = &Vec<u8>>

Returns an iterator of all registered ALPN protocol identifiers.

+
source

pub async fn shutdown(&self)

Shuts down all protocol handlers.

+

Calls and awaits ProtocolHandler::shutdown for all registered handlers concurrently.

+

Trait Implementations§

source§

impl Clone for ProtocolMap

source§

fn clone(&self) -> ProtocolMap

Returns a copy 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 ProtocolMap

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for ProtocolMap

source§

fn default() -> ProtocolMap

Returns the “default value” for a type. 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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/struct.Router.html b/pr/2992/docs/iroh/protocol/struct.Router.html new file mode 100644 index 0000000000..0bc1b3b3ff --- /dev/null +++ b/pr/2992/docs/iroh/protocol/struct.Router.html @@ -0,0 +1,59 @@ +Router in iroh::protocol - Rust

Struct iroh::protocol::Router

source ·
pub struct Router { /* private fields */ }
Expand description

The built router.

+

Construct this using Router::builder.

+

When dropped, this will abort listening the tasks, so make sure to store it.

+

Even with this abort-on-drop behaviour, it’s recommended to call and await +Router::shutdown before ending the process.

+

As an example for graceful shutdown, e.g. for tests or CLI tools, +wait for [tokio::signal::ctrl_c()]:

+ +
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
+
+let router = Router::builder(endpoint)
+    // .accept(&ALPN, <something>)
+    .spawn()
+    .await?;
+
+// wait until the user wants to
+tokio::signal::ctrl_c().await?;
+router.shutdown().await?;
+

Implementations§

source§

impl Router

source

pub fn builder(endpoint: Endpoint) -> RouterBuilder

Creates a new Router using given Endpoint.

+
source

pub fn get_protocol<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>>

Returns a protocol handler for an ALPN.

+

This downcasts to the concrete type and returns None if the handler registered for alpn +does not match the passed type.

+
source

pub fn endpoint(&self) -> &Endpoint

Returns the Endpoint stored in this router.

+
source

pub fn is_shutdown(&self) -> bool

Checks if the router is already shutdown.

+
source

pub async fn shutdown(&self) -> Result<()>

Shuts down the accept loop cleanly.

+

When this function returns, all ProtocolHandlers will be shutdown and +Endpoint::close will have been called.

+

If already shutdown, it returns Ok.

+

If some ProtocolHandler panicked in the accept loop, this will propagate +that panic into the result here.

+

Trait Implementations§

source§

impl Clone for Router

source§

fn clone(&self) -> Router

Returns a copy 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 Router

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Router

§

impl !RefUnwindSafe for Router

§

impl Send for Router

§

impl Sync for Router

§

impl Unpin for Router

§

impl !UnwindSafe for Router

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> 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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/struct.RouterBuilder.html b/pr/2992/docs/iroh/protocol/struct.RouterBuilder.html new file mode 100644 index 0000000000..8f1ae2dc7c --- /dev/null +++ b/pr/2992/docs/iroh/protocol/struct.RouterBuilder.html @@ -0,0 +1,39 @@ +RouterBuilder in iroh::protocol - Rust

Struct iroh::protocol::RouterBuilder

source ·
pub struct RouterBuilder { /* private fields */ }
Expand description

Builder for creating a Router for accepting protocols.

+

Implementations§

source§

impl RouterBuilder

source

pub fn new(endpoint: Endpoint) -> Self

Creates a new router builder using given Endpoint.

+
source

pub fn accept( + self, + alpn: impl AsRef<[u8]>, + handler: Arc<dyn ProtocolHandler> +) -> Self

Configures the router to accept the ProtocolHandler when receiving a connection +with this alpn.

+
source

pub fn endpoint(&self) -> &Endpoint

Returns the Endpoint of the node.

+
source

pub fn get_protocol<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>>

Returns a protocol handler for an ALPN.

+

This downcasts to the concrete type and returns None if the handler registered for alpn +does not match the passed type.

+
source

pub async fn spawn(self) -> Result<Router>

Spawns an accept loop and returns a handle to it encapsulated as the Router.

+

Trait Implementations§

source§

impl Debug for RouterBuilder

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/trait.IntoArcAny.html b/pr/2992/docs/iroh/protocol/trait.IntoArcAny.html new file mode 100644 index 0000000000..977bce2bea --- /dev/null +++ b/pr/2992/docs/iroh/protocol/trait.IntoArcAny.html @@ -0,0 +1,7 @@ +IntoArcAny in iroh::protocol - Rust

Trait iroh::protocol::IntoArcAny

source ·
pub trait IntoArcAny {
+    // Required method
+    fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
+}
Expand description

Helper trait to facilite casting from Arc<dyn T> to Arc<dyn Any>.

+

This trait has a blanket implementation so there is no need to implement this yourself.

+

Required Methods§

source

fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.

+

Implementors§

source§

impl<T: Send + Sync + 'static> IntoArcAny for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/protocol/trait.ProtocolHandler.html b/pr/2992/docs/iroh/protocol/trait.ProtocolHandler.html new file mode 100644 index 0000000000..988d6cbf2c --- /dev/null +++ b/pr/2992/docs/iroh/protocol/trait.ProtocolHandler.html @@ -0,0 +1,16 @@ +ProtocolHandler in iroh::protocol - Rust

Trait iroh::protocol::ProtocolHandler

source ·
pub trait ProtocolHandler: Send + Sync + IntoArcAny + Debug + 'static {
+    // Required method
+    fn accept(self: Arc<Self>, conn: Connecting) -> BoxedFuture<Result<()>>;
+
+    // Provided method
+    fn shutdown(self: Arc<Self>) -> BoxedFuture<()> { ... }
+}
Expand description

Handler for incoming connections.

+

A router accepts connections for arbitrary ALPN protocols.

+

With this trait, you can handle incoming connections for any protocol.

+

Implement this trait on a struct that should handle incoming connections. +The protocol handler must then be registered on the node for an ALPN protocol with +crate::protocol::RouterBuilder::accept.

+

Required Methods§

source

fn accept(self: Arc<Self>, conn: Connecting) -> BoxedFuture<Result<()>>

Handle an incoming connection.

+

This runs on a freshly spawned tokio task so this can be long-running.

+

Provided Methods§

source

fn shutdown(self: Arc<Self>) -> BoxedFuture<()>

Called when the node shuts down.

+

Implementors§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/sidebar-items.js b/pr/2992/docs/iroh/sidebar-items.js new file mode 100644 index 0000000000..c406d179f7 --- /dev/null +++ b/pr/2992/docs/iroh/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["AddrInfoOptions"],"mod":["defaults","dialer","discovery","dns","endpoint","hash","key","metrics","protocol","test_utils","ticket","tls"],"struct":["AddrInfo","NodeAddr","RelayMap","RelayNode","RelayUrl"],"type":["NodeId"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/struct.AddrInfo.html b/pr/2992/docs/iroh/struct.AddrInfo.html new file mode 100644 index 0000000000..bcab66531d --- /dev/null +++ b/pr/2992/docs/iroh/struct.AddrInfo.html @@ -0,0 +1,64 @@ +AddrInfo in iroh - Rust

Struct iroh::AddrInfo

source ·
pub struct AddrInfo {
+    pub relay_url: Option<RelayUrl>,
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
Expand description

Network paths to contact an iroh node.

+

This contains zero or more network paths to establish a connection to an iroh node. +Unless a [discovery service] is used at least one path is required to connect to an +other node, see NodeAddr for details.

+

Fields§

§relay_url: Option<RelayUrl>

The node’s home relay url.

+
§direct_addresses: BTreeSet<SocketAddr>

Socket addresses where the peer might be reached directly.

+

Implementations§

source§

impl AddrInfo

source

pub fn is_empty(&self) -> bool

Returns whether this addressing information is empty.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in ab AddrInfo +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+

Trait Implementations§

source§

impl Clone for AddrInfo

source§

fn clone(&self) -> AddrInfo

Returns a copy 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 AddrInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfo

source§

fn default() -> AddrInfo

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfo

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<AddrInfo, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<NodeInfo> for AddrInfo

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl Ord for AddrInfo

source§

fn cmp(&self, other: &AddrInfo) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for AddrInfo

source§

fn eq(&self, other: &AddrInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for AddrInfo

source§

fn partial_cmp(&self, other: &AddrInfo) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for AddrInfo

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for AddrInfo

source§

impl StructuralPartialEq for AddrInfo

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/struct.NodeAddr.html b/pr/2992/docs/iroh/struct.NodeAddr.html new file mode 100644 index 0000000000..16e2020717 --- /dev/null +++ b/pr/2992/docs/iroh/struct.NodeAddr.html @@ -0,0 +1,96 @@ +NodeAddr in iroh - Rust

Struct iroh::NodeAddr

source ·
pub struct NodeAddr {
+    pub node_id: PublicKey,
+    pub info: AddrInfo,
+}
Expand description

Network-level addressing information for an iroh node.

+

This combines a node’s identifier with network-level addressing information of how to +contact the node.

+

To establish a network connection to a node both the NodeId and one or more network +paths are needed. The network paths can come from various sources:

+
    +
  • +

    A discovery service which can provide routing information for a given NodeId.

    +
  • +
  • +

    A RelayUrl of the node’s home relay, this allows establishing the connection via +the Relay server and is very reliable.

    +
  • +
  • +

    One or more direct addresses on which the node might be reachable. Depending on the +network location of both nodes it might not be possible to establish a direct +connection without the help of a Relay server.

    +
  • +
+

This structure will always contain the required NodeId and will contain an optional +number of network-level addressing information. It is a generic addressing type used +whenever a connection to other nodes needs to be established.

+

Fields§

§node_id: PublicKey

The node’s identifier.

+
§info: AddrInfo

Addressing information to connect to Self::node_id.

+

Implementations§

source§

impl NodeAddr

source

pub fn new(node_id: PublicKey) -> NodeAddr

Creates a new NodeAddr with empty AddrInfo.

+
source

pub fn with_relay_url(self, relay_url: RelayUrl) -> NodeAddr

Adds a relay url to the node’s AddrInfo.

+
source

pub fn with_direct_addresses( + self, + addresses: impl IntoIterator<Item = SocketAddr> +) -> NodeAddr

Adds the given direct addresses to the peer’s AddrInfo.

+
source

pub fn from_parts( + node_id: PublicKey, + relay_url: Option<RelayUrl>, + direct_addresses: impl IntoIterator<Item = SocketAddr> +) -> NodeAddr

Creates a new NodeAddr from its parts.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in a NodeAddr +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+
source

pub fn direct_addresses(&self) -> impl Iterator<Item = &SocketAddr>

Returns the direct addresses of this peer.

+
source

pub fn relay_url(&self) -> Option<&RelayUrl>

Returns the relay url of this peer.

+

Trait Implementations§

source§

impl Clone for NodeAddr

source§

fn clone(&self) -> NodeAddr

Returns a copy 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 NodeAddr

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeAddr

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<NodeAddr, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for NodeAddr

source§

fn from(value: (PublicKey, Option<RelayUrl>, &[SocketAddr])) -> NodeAddr

Converts to this type from the input type.
source§

impl From<NodeAddr> for NodeTicket

source§

fn from(addr: NodeAddr) -> NodeTicket

Creates a ticket from given addressing info.

+
source§

impl From<NodeInfo> for NodeAddr

source§

fn from(value: NodeInfo) -> Self

Converts to this type from the input type.
source§

impl From<NodeTicket> for NodeAddr

source§

fn from(ticket: NodeTicket) -> NodeAddr

Returns the addressing info from given ticket.

+
source§

impl From<PublicKey> for NodeAddr

source§

fn from(node_id: PublicKey) -> NodeAddr

Converts to this type from the input type.
source§

impl From<RemoteInfo> for NodeAddr

source§

fn from(info: RemoteInfo) -> Self

Converts to this type from the input type.
source§

impl Ord for NodeAddr

source§

fn cmp(&self, other: &NodeAddr) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for NodeAddr

source§

fn eq(&self, other: &NodeAddr) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for NodeAddr

source§

fn partial_cmp(&self, other: &NodeAddr) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for NodeAddr

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for NodeAddr

source§

impl StructuralPartialEq for NodeAddr

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/struct.RelayMap.html b/pr/2992/docs/iroh/struct.RelayMap.html new file mode 100644 index 0000000000..c2e816c178 --- /dev/null +++ b/pr/2992/docs/iroh/struct.RelayMap.html @@ -0,0 +1,57 @@ +RelayMap in iroh - Rust

Struct iroh::RelayMap

source ·
pub struct RelayMap { /* private fields */ }
Expand description

Configuration of all the relay servers that can be used.

+

Implementations§

source§

impl RelayMap

source

pub fn urls(&self) -> impl Iterator<Item = &RelayUrl>

Returns the sorted relay URLs.

+
source

pub fn empty() -> RelayMap

Create an empty relay map.

+
source

pub fn nodes(&self) -> impl Iterator<Item = &Arc<RelayNode>>

Returns an Iterator over all known nodes.

+
source

pub fn contains_node(&self, url: &RelayUrl) -> bool

Is this a known node?

+
source

pub fn get_node(&self, url: &RelayUrl) -> Option<&Arc<RelayNode>>

Get the given node.

+
source

pub fn len(&self) -> usize

How many nodes are known?

+
source

pub fn is_empty(&self) -> bool

Are there any nodes in this map?

+
source

pub fn default_from_node(url: RelayUrl, stun_port: u16) -> RelayMap

Creates a new RelayMap with a single relay server configured.

+

Allows to set a custom STUN port and different IP addresses for IPv4 and IPv6. +If IP addresses are provided, no DNS lookup will be performed.

+

Sets the port to the default DEFAULT_RELAY_QUIC_PORT.

+
source

pub fn from_url(url: RelayUrl) -> RelayMap

Returns a RelayMap from a RelayUrl.

+

This will use the default STUN port, the default QUIC port +(as defined by the iroh-relay crate) and IP addresses +resolved from the URL’s host name via DNS. +relay nodes are specified at <../../docs/relay_nodes.md>

+
source

pub fn from_nodes<I>( + value: impl IntoIterator<Item = I> +) -> Result<RelayMap, Error>
where + I: Into<Arc<RelayNode>>,

Constructs the RelayMap from an iterator of RelayNodes.

+

Trait Implementations§

source§

impl Clone for RelayMap

source§

fn clone(&self) -> RelayMap

Returns a copy 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 RelayMap

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for RelayMap

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for RelayMap

source§

fn eq(&self, other: &RelayMap) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RelayMap

source§

impl StructuralPartialEq for RelayMap

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/struct.RelayNode.html b/pr/2992/docs/iroh/struct.RelayNode.html new file mode 100644 index 0000000000..a0b6762565 --- /dev/null +++ b/pr/2992/docs/iroh/struct.RelayNode.html @@ -0,0 +1,67 @@ +RelayNode in iroh - Rust

Struct iroh::RelayNode

source ·
pub struct RelayNode {
+    pub url: RelayUrl,
+    pub stun_only: bool,
+    pub stun_port: u16,
+    pub quic: Option<QuicConfig>,
+}
Expand description

Information on a specific relay server.

+

Includes the Url where it can be dialed.

+

Fields§

§url: RelayUrl

The RelayUrl where this relay server can be dialed.

+
§stun_only: bool

Whether this relay server should only be used for STUN requests.

+

This essentially allows you to use a normal STUN server as a relay node, no relay +functionality is used.

+
§stun_port: u16

The stun port of the relay server.

+

Setting this to 0 means the default STUN port is used.

+
§quic: Option<QuicConfig>

Configuration to speak to the QUIC endpoint on the relay server.

+

When None, we will not attempt to do QUIC address discovery +with this relay server.

+

Trait Implementations§

source§

impl Clone for RelayNode

source§

fn clone(&self) -> RelayNode

Returns a copy 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 RelayNode

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RelayNode

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<RelayNode, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayNode

source§

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

Formats the value using the given formatter. Read more
source§

impl Ord for RelayNode

source§

fn cmp(&self, other: &RelayNode) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayNode

source§

fn eq(&self, other: &RelayNode) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayNode

source§

fn partial_cmp(&self, other: &RelayNode) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayNode

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayNode

source§

impl StructuralPartialEq for RelayNode

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/struct.RelayUrl.html b/pr/2992/docs/iroh/struct.RelayUrl.html new file mode 100644 index 0000000000..7e1551c817 --- /dev/null +++ b/pr/2992/docs/iroh/struct.RelayUrl.html @@ -0,0 +1,505 @@ +RelayUrl in iroh - Rust

Struct iroh::RelayUrl

source ·
pub struct RelayUrl(/* private fields */);
Expand description

A URL identifying a relay server.

+

This is but a wrapper around Url, with a few custom tweaks:

+
    +
  • +

    A relay URL is never a relative URL, so an implicit . is added at the end of the +domain name if missing.

    +
  • +
  • +

    fmt::Debug is implemented so it prints the URL rather than the URL struct fields. +Useful when logging e.g. Option<RelayUrl>.

    +
  • +
+

To create a RelayUrl use the From<Url> implementation.

+

Methods from Deref<Target = Url>§

source

pub fn join(&self, input: &str) -> Result<Url, ParseError>

Parse a string as an URL, with this URL as the base URL.

+

The inverse of this is make_relative.

+
§Notes
+
    +
  • A trailing slash is significant. +Without it, the last path component is considered to be a “file” name +to be removed to get at the “directory” that is used as the base.
  • +
  • A scheme relative special URL +as input replaces everything in the base URL after the scheme.
  • +
  • An absolute URL (with a scheme) as input replaces the whole base URL (even the scheme).
  • +
+
§Examples
+
use url::Url;
+
+// Base without a trailing slash
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/c.png");  // Not /a/b.html/c.png
+
+// Base with a trailing slash
+let base = Url::parse("https://example.net/a/b/")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/b/c.png");
+
+// Input as scheme relative special URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("//eve.com/b")?;
+assert_eq!(url.as_str(), "https://eve.com/b");
+
+// Input as absolute URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("http://eve.com/b")?;
+assert_eq!(url.as_str(), "http://eve.com/b");  // http instead of https
+
§Errors
+

If the function can not parse an URL from the given string +with this URL as the base URL, a ParseError variant will be returned.

+
source

pub fn make_relative(&self, url: &Url) -> Option<String>

Creates a relative URL if possible, with this URL as the base URL.

+

This is the inverse of join.

+
§Examples
+
use url::Url;
+
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = Url::parse("https://example.net/a/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/b/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/d/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("../d/c.png"));
+
+let base = Url::parse("https://example.net/a/b.html?c=d")?;
+let url = Url::parse("https://example.net/a/b.html?e=f")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("?e=f"));
+
§Errors
+

If this URL can’t be a base for the given URL, None is returned. +This is for example the case if the scheme, host or port are not the same.

+
source

pub fn as_str(&self) -> &str

Return the serialization of this URL.

+

This is fast since that serialization is already stored in the Url struct.

+
§Examples
+
use url::Url;
+
+let url_str = "https://example.net/";
+let url = Url::parse(url_str)?;
+assert_eq!(url.as_str(), url_str);
+
source

pub fn origin(&self) -> Origin

Return the origin of this URL (https://url.spec.whatwg.org/#origin)

+

Note: this returns an opaque origin for file: URLs, which causes +url.origin() != url.origin().

+
§Examples
+

URL with ftp scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("ftp://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("ftp".into(),
+                         Host::Domain("example.com".into()),
+                         21));
+

URL with blob scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("blob:https://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("https".into(),
+                         Host::Domain("example.com".into()),
+                         443));
+

URL with file scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("file:///tmp/foo")?;
+assert!(!url.origin().is_tuple());
+
+let other_url = Url::parse("file:///tmp/foo")?;
+assert!(url.origin() != other_url.origin());
+

URL with other scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("foo:bar")?;
+assert!(!url.origin().is_tuple());
+
source

pub fn scheme(&self) -> &str

Return the scheme of this URL, lower-cased, as an ASCII string without the ‘:’ delimiter.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.scheme(), "file");
+
source

pub fn is_special(&self) -> bool

Return whether the URL is special (has a special scheme)

+
§Examples
+
use url::Url;
+
+assert!(Url::parse("http:///tmp/foo")?.is_special());
+assert!(Url::parse("file:///tmp/foo")?.is_special());
+assert!(!Url::parse("moz:///tmp/foo")?.is_special());
+
source

pub fn has_authority(&self) -> bool

Return whether the URL has an ‘authority’, +which can contain a username, password, host, and port number.

+

URLs that do not are either path-only like unix:/run/foo.socket +or cannot-be-a-base like data:text/plain,Stuff.

+

See also the authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_authority());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_authority());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_authority());
+
source

pub fn authority(&self) -> &str

Return the authority of this URL as an ASCII string.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets. +Ports are omitted if they match the well known port of a special URL.

+

Username and password are percent-encoded.

+

See also the has_authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("https://user:password@example.com/tmp/foo")?;
+assert_eq!(url.authority(), "user:password@example.com");
+let url = Url::parse("irc://àlex.рф.example.com:6667/foo")?;
+assert_eq!(url.authority(), "%C3%A0lex.%D1%80%D1%84.example.com:6667");
+let url = Url::parse("http://àlex.рф.example.com:80/foo")?;
+assert_eq!(url.authority(), "xn--lex-8ka.xn--p1ai.example.com");
+
source

pub fn cannot_be_a_base(&self) -> bool

Return whether this URL is a cannot-be-a-base URL, +meaning that parsing a relative URL string with this URL as the base will return an error.

+

This is the case if the scheme and : delimiter are not followed by a / slash, +as is typically the case of data: and mailto: URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.cannot_be_a_base());
+
source

pub fn username(&self) -> &str

Return the username for this URL (typically the empty string) +as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.username(), "rms");
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.username(), "");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.username(), "");
+
source

pub fn password(&self) -> Option<&str>

Return the password for this URL, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.password(), None);
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.password(), None);
+
source

pub fn has_host(&self) -> bool

Equivalent to url.host().is_some().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_host());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_host());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_host());
+
source

pub fn host_str(&self) -> Option<&str>

Return the string representation of the host (domain or IP address) for this URL, if any.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert_eq!(url.host_str(), Some("127.0.0.1"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.host_str(), Some("example.com"));
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.host_str(), None);
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert_eq!(url.host_str(), None);
+
source

pub fn host(&self) -> Option<Host<&str>>

Return the parsed representation of the host for this URL. +Non-ASCII domain labels are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host_str method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(url.host().is_none());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.host().is_none());
+
source

pub fn domain(&self) -> Option<&str>

If this URL has a host and it is a domain name (not an IP address), return it. +Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("mailto:rms@example.net")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("https://example.com/")?;
+assert_eq!(url.domain(), Some("example.com"));
+
source

pub fn port(&self) -> Option<u16>

Return the port number for this URL, if any.

+

Note that default port numbers are never reflected by the serialization, +use the port_or_known_default() method if you want a default port number returned.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("https://example.com:443/")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("ssh://example.com:22")?;
+assert_eq!(url.port(), Some(22));
+
source

pub fn port_or_known_default(&self) -> Option<u16>

Return the port number for this URL, or the default port number if it is known.

+

This method only knows the default port number +of the http, https, ws, wss and ftp schemes.

+

For URLs in these schemes, this method always returns Some(_). +For other schemes, it is the same as Url::port().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("foo://example.com")?;
+assert_eq!(url.port_or_known_default(), None);
+
+let url = Url::parse("foo://example.com:1456")?;
+assert_eq!(url.port_or_known_default(), Some(1456));
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port_or_known_default(), Some(443));
+
source

pub fn socket_addrs( + &self, + default_port_number: impl Fn() -> Option<u16> +) -> Result<Vec<SocketAddr>, Error>

Resolve a URL’s host and port number to SocketAddr.

+

If the URL has the default port number of a scheme that is unknown to this library, +default_port_number provides an opportunity to provide the actual port number. +In non-example code this should be implemented either simply as || None, +or by matching on the URL’s .scheme().

+

If the host is a domain, it is resolved using the standard library’s DNS support.

+
§Examples
+
let url = url::Url::parse("https://example.net/").unwrap();
+let addrs = url.socket_addrs(|| None).unwrap();
+std::net::TcpStream::connect(&*addrs)
+ +
/// With application-specific known default port numbers
+fn socket_addrs(url: url::Url) -> std::io::Result<Vec<std::net::SocketAddr>> {
+    url.socket_addrs(|| match url.scheme() {
+        "socks5" | "socks5h" => Some(1080),
+        _ => None,
+    })
+}
+
source

pub fn path(&self) -> &str

Return the path for this URL, as a percent-encoded ASCII string. +For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with ‘/’. +For other URLs, this starts with a ‘/’ slash +and continues with slash-separated path segments.

+
§Examples
+
use url::{Url, ParseError};
+
+let url = Url::parse("https://example.com/api/versions?page=2")?;
+assert_eq!(url.path(), "/api/versions");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.path(), "/");
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+assert_eq!(url.path(), "/countries/vi%E1%BB%87t%20nam");
+
source

pub fn path_segments(&self) -> Option<Split<'_, char>>

Unless this URL is cannot-be-a-base, +return an iterator of ‘/’ slash-separated path segments, +each as a percent-encoded ASCII string.

+

Return None for cannot-be-a-base URLs.

+

When Some is returned, the iterator always contains at least one string +(which may be empty).

+
§Examples
+
use url::Url;
+
+
+let url = Url::parse("https://example.com/foo/bar")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("foo"));
+assert_eq!(path_segments.next(), Some("bar"));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("https://example.com")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some(""));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("data:text/plain,HelloWorld")?;
+assert!(url.path_segments().is_none());
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("countries"));
+assert_eq!(path_segments.next(), Some("vi%E1%BB%87t%20nam"));
+
source

pub fn query(&self) -> Option<&str>

Return this URL’s query string, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+fn run() -> Result<(), ParseError> {
+let url = Url::parse("https://example.com/products?page=2")?;
+let query = url.query();
+assert_eq!(query, Some("page=2"));
+
+let url = Url::parse("https://example.com/products")?;
+let query = url.query();
+assert!(query.is_none());
+
+let url = Url::parse("https://example.com/?country=español")?;
+let query = url.query();
+assert_eq!(query, Some("country=espa%C3%B1ol"));
+
source

pub fn query_pairs(&self) -> Parse<'_>

Parse the URL’s query string, if any, as application/x-www-form-urlencoded +and return an iterator of (key, value) pairs.

+
§Examples
+
use std::borrow::Cow;
+
+use url::Url;
+
+let url = Url::parse("https://example.com/products?page=2&sort=desc")?;
+let mut pairs = url.query_pairs();
+
+assert_eq!(pairs.count(), 2);
+
+assert_eq!(pairs.next(), Some((Cow::Borrowed("page"), Cow::Borrowed("2"))));
+assert_eq!(pairs.next(), Some((Cow::Borrowed("sort"), Cow::Borrowed("desc"))));
+
source

pub fn fragment(&self) -> Option<&str>

Return this URL’s fragment identifier, if any.

+

A fragment is the part of the URL after the # symbol. +The fragment is optional and, if present, contains a fragment identifier +that identifies a secondary resource, such as a section heading +of a document.

+

In HTML, the fragment identifier is usually the id attribute of a an element +that is scrolled to on load. Browsers typically will not send the fragment portion +of a URL to the server.

+

Note: the parser did not percent-encode this component, +but the input may have been percent-encoded already.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com/data.csv#row=4")?;
+
+assert_eq!(url.fragment(), Some("row=4"));
+
+let url = Url::parse("https://example.com/data.csv#cell=4,1-6,2")?;
+
+assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
+
source

pub fn serialize_internal<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize with Serde using the internal representation of the Url struct.

+

The corresponding deserialize_internal method sacrifices some invariant-checking +for speed, compared to the Deserialize trait impl.

+

This method is only available if the serde Cargo feature is enabled.

+
source

pub fn to_file_path(&self) -> Result<PathBuf, ()>

Assuming the URL is in the file scheme or similar, +convert its path to an absolute std::path::Path.

+

Note: This does not actually check the URL’s scheme, +and may give nonsensical results for other schemes. +It is the user’s responsibility to check the URL’s scheme before calling this.

+ +
let path = url.to_file_path();
+

Returns Err if the host is neither empty nor "localhost" (except on Windows, where +file: URLs may have a non-local host), +or if Path::new_opt() returns None. +(That is, if the percent-decoded path contains a NUL byte or, +for a Windows path, is not UTF-8.)

+

This method is only available if the std Cargo feature is enabled.

+

Trait Implementations§

source§

impl Clone for RelayUrl

source§

fn clone(&self) -> RelayUrl

Returns a copy 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 RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl Deref for RelayUrl

Dereferences to the wrapped Url.

+

Note that DerefMut is not implemented on purpose, so this type has more flexibility +to change the inner later.

+
§

type Target = Url

The resulting type after dereferencing.
source§

fn deref(&self) -> &<RelayUrl as Deref>::Target

Dereferences the value.
source§

impl<'de> Deserialize<'de> for RelayUrl

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<RelayUrl, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl From<RelayUrl> for Url

source§

fn from(value: RelayUrl) -> Url

Converts to this type from the input type.
source§

impl From<Url> for RelayUrl

source§

fn from(url: Url) -> RelayUrl

Converts to this type from the input type.
source§

impl FromStr for RelayUrl

Support for parsing strings directly.

+

If you need more control over the error first create a Url and use RelayUrl::from +instead.

+
§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<RelayUrl, <RelayUrl as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for RelayUrl

source§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for RelayUrl

source§

fn cmp(&self, other: &RelayUrl) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayUrl

source§

fn eq(&self, other: &RelayUrl) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayUrl

source§

fn partial_cmp(&self, other: &RelayUrl) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayUrl

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayUrl

source§

impl StructuralPartialEq for RelayUrl

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
source§

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

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/dns_and_pkarr_servers/struct.DnsPkarrServer.html b/pr/2992/docs/iroh/test_utils/dns_and_pkarr_servers/struct.DnsPkarrServer.html new file mode 100644 index 0000000000..87c56b5da4 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/dns_and_pkarr_servers/struct.DnsPkarrServer.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh/test_utils/struct.DnsPkarrServer.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/dns_server/fn.create_dns_resolver.html b/pr/2992/docs/iroh/test_utils/dns_server/fn.create_dns_resolver.html new file mode 100644 index 0000000000..3074cd544d --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/dns_server/fn.create_dns_resolver.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh/test_utils/fn.create_dns_resolver.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/fn.create_dns_resolver.html b/pr/2992/docs/iroh/test_utils/fn.create_dns_resolver.html new file mode 100644 index 0000000000..348dea0ec3 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/fn.create_dns_resolver.html @@ -0,0 +1,2 @@ +create_dns_resolver in iroh::test_utils - Rust

Function iroh::test_utils::create_dns_resolver

source ·
pub fn create_dns_resolver(nameserver: SocketAddr) -> Result<TokioAsyncResolver>
Available on test or crate feature test-utils only.
Expand description

Create a DNS resolver with a single nameserver.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/fn.run_relay_server.html b/pr/2992/docs/iroh/test_utils/fn.run_relay_server.html new file mode 100644 index 0000000000..0f0e537470 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/fn.run_relay_server.html @@ -0,0 +1,4 @@ +run_relay_server in iroh::test_utils - Rust

Function iroh::test_utils::run_relay_server

source ·
pub async fn run_relay_server() -> Result<(RelayMap, RelayUrl, Server)>
Available on test or crate feature test-utils only.
Expand description

Runs a relay server with STUN and QUIC enabled suitable for tests.

+

The returned Url is the url of the relay server in the returned RelayMap. +When dropped, the returned [Server] does will stop running.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with.html b/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with.html new file mode 100644 index 0000000000..8e1bb70cf5 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with.html @@ -0,0 +1,9 @@ +run_relay_server_with in iroh::test_utils - Rust

Function iroh::test_utils::run_relay_server_with

source ·
pub async fn run_relay_server_with(
+    stun: Option<StunConfig>,
+    quic: bool
+) -> Result<(RelayMap, RelayUrl, Server)>
Available on test or crate feature test-utils only.
Expand description

Runs a relay server.

+

stun can be set to None to disable stun, or set to Some StunConfig, +to enable stun on a specific socket.

+

If quic is set to true, it will make the appropriate [QuicConfig] from the generated tls certificates and run the quic server at a random free port.

+

The return value is similar to run_relay_server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with_stun.html b/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with_stun.html new file mode 100644 index 0000000000..7a6ce6a399 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/fn.run_relay_server_with_stun.html @@ -0,0 +1,5 @@ +run_relay_server_with_stun in iroh::test_utils - Rust

Function iroh::test_utils::run_relay_server_with_stun

source ·
pub async fn run_relay_server_with_stun(
+) -> Result<(RelayMap, RelayUrl, Server)>
Available on test or crate feature test-utils only.
Expand description

Runs a relay server with STUN enabled suitable for tests.

+

The returned Url is the url of the relay server in the returned RelayMap. +When dropped, the returned [Server] does will stop running.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/index.html b/pr/2992/docs/iroh/test_utils/index.html new file mode 100644 index 0000000000..12934050b6 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/index.html @@ -0,0 +1,2 @@ +iroh::test_utils - Rust

Module iroh::test_utils

source ·
Available on test or crate feature test-utils only.
Expand description

Internal utilities to support testing.

+

Structs§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/sidebar-items.js b/pr/2992/docs/iroh/test_utils/sidebar-items.js new file mode 100644 index 0000000000..80a5e2fff6 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["create_dns_resolver","run_relay_server","run_relay_server_with","run_relay_server_with_stun"],"struct":["CleanupDropGuard","DnsPkarrServer"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/struct.CleanupDropGuard.html b/pr/2992/docs/iroh/test_utils/struct.CleanupDropGuard.html new file mode 100644 index 0000000000..dfdbe4f870 --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/struct.CleanupDropGuard.html @@ -0,0 +1,29 @@ +CleanupDropGuard in iroh::test_utils - Rust

Struct iroh::test_utils::CleanupDropGuard

source ·
pub struct CleanupDropGuard(/* private fields */);
Available on test or crate feature test-utils only.
Expand description

A drop guard to clean up test infrastructure.

+

After dropping the test infrastructure will asynchronously shutdown and release its +resources.

+

Trait Implementations§

source§

impl Debug for CleanupDropGuard

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/test_utils/struct.DnsPkarrServer.html b/pr/2992/docs/iroh/test_utils/struct.DnsPkarrServer.html new file mode 100644 index 0000000000..7806fc271f --- /dev/null +++ b/pr/2992/docs/iroh/test_utils/struct.DnsPkarrServer.html @@ -0,0 +1,43 @@ +DnsPkarrServer in iroh::test_utils - Rust

Struct iroh::test_utils::DnsPkarrServer

source ·
pub struct DnsPkarrServer {
+    pub node_origin: String,
+    pub nameserver: SocketAddr,
+    pub pkarr_url: Url,
+    /* private fields */
+}
Available on test or crate feature test-utils only.
Expand description

Handle and drop guard for test DNS and Pkarr servers.

+

Once the struct is dropped the servers will shut down.

+

Fields§

§node_origin: String

The node origin domain.

+
§nameserver: SocketAddr

The socket address of the DNS server.

+
§pkarr_url: Url

The HTTP URL of the Pkarr server.

+

Implementations§

source§

impl DnsPkarrServer

source

pub async fn run() -> Result<Self>

Run DNS and Pkarr servers on localhost.

+
source

pub async fn run_with_origin(node_origin: String) -> Result<Self>

Run DNS and Pkarr servers on localhost with the specified node_origin domain.

+
source

pub fn discovery(&self, secret_key: SecretKey) -> Box<ConcurrentDiscovery>

Create a ConcurrentDiscovery with DnsDiscovery and PkarrPublisher +configured to use the test servers.

+
source

pub fn dns_resolver(&self) -> DnsResolver

Create a DnsResolver configured to use the test DNS server.

+
source

pub async fn on_node(&self, node_id: &NodeId, timeout: Duration) -> Result<()>

Wait until a Pkarr announce for a node is published to the server.

+

If timeout elapses an error is returned.

+

Trait Implementations§

source§

impl Debug for DnsPkarrServer

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/enum.Error.html b/pr/2992/docs/iroh/ticket/enum.Error.html new file mode 100644 index 0000000000..7cb3ef2ac2 --- /dev/null +++ b/pr/2992/docs/iroh/ticket/enum.Error.html @@ -0,0 +1,39 @@ +Error in iroh::ticket - Rust

Enum iroh::ticket::Error

source ·
pub enum Error {
+    Kind {
+        expected: &'static str,
+    },
+    Postcard(Error),
+    Encoding(DecodeError),
+    Verify(&'static str),
+}
Expand description

An error deserializing an iroh ticket.

+

Variants§

§

Kind

Found a ticket of with the wrong prefix, indicating the wrong kind.

+

Fields

§expected: &'static str
§

Postcard(Error)

This looks like a ticket, but postcard deserialization failed.

+
§

Encoding(DecodeError)

This looks like a ticket, but base32 decoding failed.

+
§

Verify(&'static str)

Verification of the deserialized bytes failed.

+

Trait Implementations§

source§

impl Debug for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for Error

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<DecodeError> for Error

source§

fn from(source: DecodeError) -> Error

Converts to this type from the input type.
source§

impl From<Error> for Error

source§

fn from(source: Error) -> Error

Converts to this type from the input type.

Auto Trait Implementations§

§

impl Freeze for Error

§

impl RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnwindSafe for Error

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/index.html b/pr/2992/docs/iroh/ticket/index.html new file mode 100644 index 0000000000..e30ea23a88 --- /dev/null +++ b/pr/2992/docs/iroh/ticket/index.html @@ -0,0 +1 @@ +iroh::ticket - Rust

Module iroh::ticket

source ·

Structs§

  • A token containing everything to get a file from the provider.
  • A token containing information for establishing a connection to a node.

Enums§

  • An error deserializing an iroh ticket.

Traits§

  • A ticket is a serializable object combining information required for an operation.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/sidebar-items.js b/pr/2992/docs/iroh/ticket/sidebar-items.js new file mode 100644 index 0000000000..0642f1ee59 --- /dev/null +++ b/pr/2992/docs/iroh/ticket/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Error"],"struct":["BlobTicket","NodeTicket"],"trait":["Ticket"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/struct.BlobTicket.html b/pr/2992/docs/iroh/ticket/struct.BlobTicket.html new file mode 100644 index 0000000000..c994db2aa8 --- /dev/null +++ b/pr/2992/docs/iroh/ticket/struct.BlobTicket.html @@ -0,0 +1,56 @@ +BlobTicket in iroh::ticket - Rust

Struct iroh::ticket::BlobTicket

source ·
pub struct BlobTicket { /* private fields */ }
Expand description

A token containing everything to get a file from the provider.

+

It is a single item which can be easily serialized and deserialized.

+

Implementations§

source§

impl BlobTicket

source

pub fn new( + node: NodeAddr, + hash: Hash, + format: BlobFormat +) -> Result<BlobTicket, Error>

Creates a new ticket.

+
source

pub fn hash(&self) -> Hash

The hash of the item this ticket can retrieve.

+
source

pub fn node_addr(&self) -> &NodeAddr

The NodeAddr of the provider for this ticket.

+
source

pub fn format(&self) -> BlobFormat

The BlobFormat for this ticket.

+
source

pub fn recursive(&self) -> bool

True if the ticket is for a collection and should retrieve all blobs in it.

+
source

pub fn into_parts(self) -> (NodeAddr, Hash, BlobFormat)

Get the contents of the ticket, consuming it.

+

Trait Implementations§

source§

impl Clone for BlobTicket

source§

fn clone(&self) -> BlobTicket

Returns a copy 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 BlobTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for BlobTicket

source§

fn deserialize<D>( + deserializer: D +) -> Result<BlobTicket, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for BlobTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for BlobTicket

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<BlobTicket, <BlobTicket as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for BlobTicket

source§

fn eq(&self, other: &BlobTicket) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for BlobTicket

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Ticket for BlobTicket

source§

const KIND: &'static str = "blob"

String prefix describing the kind of iroh ticket. Read more
source§

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.
source§

fn from_bytes(bytes: &[u8]) -> Result<BlobTicket, Error>

Deserialize from the base32 string representation bytes.
source§

fn serialize(&self) -> String

Serialize to string.
source§

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.
source§

impl Eq for BlobTicket

source§

impl StructuralPartialEq for BlobTicket

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/struct.NodeTicket.html b/pr/2992/docs/iroh/ticket/struct.NodeTicket.html new file mode 100644 index 0000000000..eb7111b18f --- /dev/null +++ b/pr/2992/docs/iroh/ticket/struct.NodeTicket.html @@ -0,0 +1,60 @@ +NodeTicket in iroh::ticket - Rust

Struct iroh::ticket::NodeTicket

source ·
pub struct NodeTicket { /* private fields */ }
Expand description

A token containing information for establishing a connection to a node.

+

Contains

+
    +
  • The NodeId of the node to connect to (a 32-byte ed25519 public key).
  • +
  • If used, the [’RelayUrl`] of on which the node can be reached.
  • +
  • Any direct addresses on which the node might be reachable.
  • +
+

This allows establishing a connection to the node in most circumstances where it is +possible to do so.

+

This NodeTicket is a single item which can be easily serialized and deserialized and +implements the Ticket trait. The Display and FromStr traits can also be +used to round-trip the ticket to string.

+

Implementations§

source§

impl NodeTicket

source

pub fn new(node: NodeAddr) -> NodeTicket

Creates a new ticket.

+
source

pub fn node_addr(&self) -> &NodeAddr

The NodeAddr of the provider for this ticket.

+

Trait Implementations§

source§

impl Clone for NodeTicket

source§

fn clone(&self) -> NodeTicket

Returns a copy 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 NodeTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeTicket

source§

fn deserialize<D>( + deserializer: D +) -> Result<NodeTicket, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for NodeTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl From<NodeAddr> for NodeTicket

source§

fn from(addr: NodeAddr) -> NodeTicket

Creates a ticket from given addressing info.

+
source§

impl From<NodeTicket> for NodeAddr

source§

fn from(ticket: NodeTicket) -> NodeAddr

Returns the addressing info from given ticket.

+
source§

impl FromStr for NodeTicket

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<NodeTicket, <NodeTicket as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for NodeTicket

source§

fn eq(&self, other: &NodeTicket) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for NodeTicket

source§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Ticket for NodeTicket

source§

const KIND: &'static str = "node"

String prefix describing the kind of iroh ticket. Read more
source§

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.
source§

fn from_bytes(bytes: &[u8]) -> Result<NodeTicket, Error>

Deserialize from the base32 string representation bytes.
source§

fn serialize(&self) -> String

Serialize to string.
source§

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.
source§

impl Eq for NodeTicket

source§

impl StructuralPartialEq for NodeTicket

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/ticket/trait.Ticket.html b/pr/2992/docs/iroh/ticket/trait.Ticket.html new file mode 100644 index 0000000000..bdedad50dc --- /dev/null +++ b/pr/2992/docs/iroh/ticket/trait.Ticket.html @@ -0,0 +1,27 @@ +Ticket in iroh::ticket - Rust

Trait iroh::ticket::Ticket

source ·
pub trait Ticket: Sized {
+    const KIND: &'static str;
+
+    // Required methods
+    fn to_bytes(&self) -> Vec<u8> ;
+    fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;
+
+    // Provided methods
+    fn serialize(&self) -> String { ... }
+    fn deserialize(str: &str) -> Result<Self, Error> { ... }
+}
Expand description

A ticket is a serializable object combining information required for an operation.

+

Typically tickets contain all information required for an operation, e.g. an iroh blob +ticket would contain the hash of the data as well as information about how to reach the +provider.

+

Tickets support serialization to a string using base32 encoding. The kind of +ticket will be prepended to the string to make it somewhat self describing.

+

Versioning is left to the implementer. Some kinds of tickets might need +versioning, others might not.

+

The serialization format for converting the ticket from and to bytes is left +to the implementer. We recommend using postcard for serialization.

+

Required Associated Constants§

source

const KIND: &'static str

String prefix describing the kind of iroh ticket.

+

This should be lower case ascii characters.

+

Required Methods§

source

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.

+
source

fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Deserialize from the base32 string representation bytes.

+

Provided Methods§

source

fn serialize(&self) -> String

Serialize to string.

+
source

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.

+

Object Safety§

This trait is not object safe.

Implementors§

source§

impl Ticket for BlobTicket

source§

const KIND: &'static str = "blob"

source§

impl Ticket for NodeTicket

source§

const KIND: &'static str = "node"

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/fn.generate.html b/pr/2992/docs/iroh/tls/certificate/fn.generate.html new file mode 100644 index 0000000000..379872abeb --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/fn.generate.html @@ -0,0 +1,5 @@ +generate in iroh::tls::certificate - Rust

Function iroh::tls::certificate::generate

source ·
pub fn generate(
+    identity_secret_key: &SecretKey
+) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), GenError>
Expand description

Generates a self-signed TLS certificate that includes a libp2p-specific +certificate extension containing the public key of the given secret key.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/fn.parse.html b/pr/2992/docs/iroh/tls/certificate/fn.parse.html new file mode 100644 index 0000000000..b3f1b99e42 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/fn.parse.html @@ -0,0 +1,6 @@ +parse in iroh::tls::certificate - Rust

Function iroh::tls::certificate::parse

source ·
pub fn parse<'a>(
+    certificate: &'a CertificateDer<'_>
+) -> Result<P2pCertificate<'a>, ParseError>
Expand description

Attempts to parse the provided bytes as a P2pCertificate.

+

For this to succeed, the certificate must contain the specified extension and the signature must +match the embedded public key.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/index.html b/pr/2992/docs/iroh/tls/certificate/index.html new file mode 100644 index 0000000000..d7ee48ddc1 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/index.html @@ -0,0 +1,8 @@ +iroh::tls::certificate - Rust

Module iroh::tls::certificate

source ·
Expand description

X.509 certificate handling.

+

This module handles generation, signing, and verification of certificates.

+

Based on rust-libp2p/transports/tls/src/certificate.rs originally licensed under MIT by Parity +Technologies (UK) Ltd.

+

Structs§

  • An error that occurs during certificate generation.
  • An X.509 certificate with a libp2p-specific extension +is used to secure libp2p connections.
  • The contents of the specific libp2p extension, containing the public host key +and a signature performed using the private host key.
  • An error that occurs during certificate parsing.
  • An error that occurs during signature verification.

Functions§

  • Generates a self-signed TLS certificate that includes a libp2p-specific +certificate extension containing the public key of the given secret key.
  • Attempts to parse the provided bytes as a P2pCertificate.
\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/sidebar-items.js b/pr/2992/docs/iroh/tls/certificate/sidebar-items.js new file mode 100644 index 0000000000..82e18259e3 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["generate","parse"],"struct":["GenError","P2pCertificate","P2pExtension","ParseError","VerificationError"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/struct.GenError.html b/pr/2992/docs/iroh/tls/certificate/struct.GenError.html new file mode 100644 index 0000000000..b1ccf6b61c --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/struct.GenError.html @@ -0,0 +1,28 @@ +GenError in iroh::tls::certificate - Rust

Struct iroh::tls::certificate::GenError

source ·
pub struct GenError(/* private fields */);
Expand description

An error that occurs during certificate generation.

+

Trait Implementations§

source§

impl Debug for GenError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for GenError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for GenError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for GenError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<GenError> for CreateConfigError

source§

fn from(source: GenError) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/struct.P2pCertificate.html b/pr/2992/docs/iroh/tls/certificate/struct.P2pCertificate.html new file mode 100644 index 0000000000..20fcd11040 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/struct.P2pCertificate.html @@ -0,0 +1,36 @@ +P2pCertificate in iroh::tls::certificate - Rust

Struct iroh::tls::certificate::P2pCertificate

source ·
pub struct P2pCertificate<'a> { /* private fields */ }
Expand description

An X.509 certificate with a libp2p-specific extension +is used to secure libp2p connections.

+

Implementations§

source§

impl P2pCertificate<'_>

source

pub fn peer_id(&self) -> PublicKey

The PublicKey of the remote peer.

+
source

pub fn verify_signature( + &self, + signature_scheme: SignatureScheme, + message: &[u8], + signature: &[u8] +) -> Result<(), VerificationError>

Verify the signature of the message signed by the secret key corresponding to the public key stored +in the certificate.

+

Trait Implementations§

source§

impl<'a> Debug for P2pCertificate<'a>

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for P2pCertificate<'a>

§

impl<'a> RefUnwindSafe for P2pCertificate<'a>

§

impl<'a> Send for P2pCertificate<'a>

§

impl<'a> Sync for P2pCertificate<'a>

§

impl<'a> Unpin for P2pCertificate<'a>

§

impl<'a> UnwindSafe for P2pCertificate<'a>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/struct.P2pExtension.html b/pr/2992/docs/iroh/tls/certificate/struct.P2pExtension.html new file mode 100644 index 0000000000..ea819f846d --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/struct.P2pExtension.html @@ -0,0 +1,28 @@ +P2pExtension in iroh::tls::certificate - Rust

Struct iroh::tls::certificate::P2pExtension

source ·
pub struct P2pExtension { /* private fields */ }
Expand description

The contents of the specific libp2p extension, containing the public host key +and a signature performed using the private host key.

+

Trait Implementations§

source§

impl Debug for P2pExtension

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/struct.ParseError.html b/pr/2992/docs/iroh/tls/certificate/struct.ParseError.html new file mode 100644 index 0000000000..8236c101f8 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/struct.ParseError.html @@ -0,0 +1,28 @@ +ParseError in iroh::tls::certificate - Rust

Struct iroh::tls::certificate::ParseError

source ·
pub struct ParseError(/* private fields */);
Expand description

An error that occurs during certificate parsing.

+

Trait Implementations§

source§

impl Debug for ParseError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for ParseError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for ParseError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for ParseError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<ParseError> for Error

source§

fn from(certificate::ParseError: ParseError) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/certificate/struct.VerificationError.html b/pr/2992/docs/iroh/tls/certificate/struct.VerificationError.html new file mode 100644 index 0000000000..7e6aaf3628 --- /dev/null +++ b/pr/2992/docs/iroh/tls/certificate/struct.VerificationError.html @@ -0,0 +1,28 @@ +VerificationError in iroh::tls::certificate - Rust

Struct iroh::tls::certificate::VerificationError

source ·
pub struct VerificationError(/* private fields */);
Expand description

An error that occurs during signature verification.

+

Trait Implementations§

source§

impl Debug for VerificationError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for VerificationError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for VerificationError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for VerificationError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<VerificationError> for Error

source§

fn from(certificate::VerificationError: VerificationError) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/enum.CreateConfigError.html b/pr/2992/docs/iroh/tls/enum.CreateConfigError.html new file mode 100644 index 0000000000..80682e2370 --- /dev/null +++ b/pr/2992/docs/iroh/tls/enum.CreateConfigError.html @@ -0,0 +1,33 @@ +CreateConfigError in iroh::tls - Rust

Enum iroh::tls::CreateConfigError

source ·
pub enum CreateConfigError {
+    CertError(GenError),
+    ConfigError(NoInitialCipherSuite),
+}
Expand description

Error for generating iroh p2p TLS configs.

+

Variants§

§

CertError(GenError)

Error generating the certificate.

+
§

ConfigError(NoInitialCipherSuite)

Error creating QUIC config.

+

Trait Implementations§

source§

impl Debug for CreateConfigError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for CreateConfigError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for CreateConfigError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<GenError> for CreateConfigError

source§

fn from(source: GenError) -> Self

Converts to this type from the input type.
source§

impl From<NoInitialCipherSuite> for CreateConfigError

source§

fn from(source: NoInitialCipherSuite) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> IntoArcAny for T
where + T: Send + Sync + 'static,

source§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/fn.make_client_config.html b/pr/2992/docs/iroh/tls/fn.make_client_config.html new file mode 100644 index 0000000000..46027cf7b2 --- /dev/null +++ b/pr/2992/docs/iroh/tls/fn.make_client_config.html @@ -0,0 +1,10 @@ +make_client_config in iroh::tls - Rust

Function iroh::tls::make_client_config

source ·
pub fn make_client_config(
+    secret_key: &SecretKey,
+    remote_peer_id: Option<PublicKey>,
+    alpn_protocols: Vec<Vec<u8>>,
+    keylog: bool
+) -> Result<QuicClientConfig, CreateConfigError>
Expand description

Create a TLS client configuration.

+

If keylog is true this will enable logging of the pre-master key to the file in the +SSLKEYLOGFILE environment variable. This can be used to inspect the traffic for +debugging purposes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/fn.make_server_config.html b/pr/2992/docs/iroh/tls/fn.make_server_config.html new file mode 100644 index 0000000000..dea0d7b506 --- /dev/null +++ b/pr/2992/docs/iroh/tls/fn.make_server_config.html @@ -0,0 +1,9 @@ +make_server_config in iroh::tls - Rust

Function iroh::tls::make_server_config

source ·
pub fn make_server_config(
+    secret_key: &SecretKey,
+    alpn_protocols: Vec<Vec<u8>>,
+    keylog: bool
+) -> Result<QuicServerConfig, CreateConfigError>
Expand description

Create a TLS server configuration.

+

If keylog is true this will enable logging of the pre-master key to the file in the +SSLKEYLOGFILE environment variable. This can be used to inspect the traffic for +debugging purposes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/index.html b/pr/2992/docs/iroh/tls/index.html new file mode 100644 index 0000000000..f2e185908d --- /dev/null +++ b/pr/2992/docs/iroh/tls/index.html @@ -0,0 +1,4 @@ +iroh::tls - Rust

Module iroh::tls

source ·
Expand description

TLS configuration based on libp2p TLS specs.

+

See https://github.com/libp2p/specs/blob/master/tls/tls.md. +Based on rust-libp2p/transports/tls

+

Modules§

Enums§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh/tls/sidebar-items.js b/pr/2992/docs/iroh/tls/sidebar-items.js new file mode 100644 index 0000000000..76534be531 --- /dev/null +++ b/pr/2992/docs/iroh/tls/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["CreateConfigError"],"fn":["make_client_config","make_server_config"],"mod":["certificate"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh/type.NodeId.html b/pr/2992/docs/iroh/type.NodeId.html new file mode 100644 index 0000000000..92c25fb807 --- /dev/null +++ b/pr/2992/docs/iroh/type.NodeId.html @@ -0,0 +1,12 @@ +NodeId in iroh - Rust

Type Alias iroh::NodeId

source ·
pub type NodeId = PublicKey;
Expand description

The identifier for a node in the (iroh) network.

+

Each node in iroh has a unique identifier created as a cryptographic key. This can be +used to globally identify a node. Since it is also a cryptographic key it is also the +mechanism by which all traffic is always encrypted for a specific node only.

+

This is equivalent to PublicKey. By convention we will (or should) use PublicKey +as type name when performing cryptographic operations, but use NodeId when referencing +a node. E.g.:

+
    +
  • encrypt(key: PublicKey)
  • +
  • send_to(node: NodeId)
  • +
+

Aliased Type§

struct NodeId(/* private fields */);
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/all.html b/pr/2992/docs/iroh_base/all.html new file mode 100644 index 0000000000..e8ef490cc9 --- /dev/null +++ b/pr/2992/docs/iroh_base/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Traits

Functions

Type Aliases

Constants

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/enum.DecodeKind.html b/pr/2992/docs/iroh_base/base32/enum.DecodeKind.html new file mode 100644 index 0000000000..2e4aa61003 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/enum.DecodeKind.html @@ -0,0 +1,27 @@ +DecodeKind in iroh_base::base32 - Rust

Enum iroh_base::base32::DecodeKind

pub enum DecodeKind {
+    Length,
+    Symbol,
+    Trailing,
+    Padding,
+}
Available on crate feature base32 only.
Expand description

Decoding error kind

+

Variants§

§

Length

Invalid length

+
§

Symbol

Invalid symbol

+
§

Trailing

Non-zero trailing bits

+
§

Padding

Invalid padding length

+

Trait Implementations§

§

impl Clone for DecodeKind

§

fn clone(&self) -> DecodeKind

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for DecodeKind

§

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

Formats the value using the given formatter. Read more
§

impl Display for DecodeKind

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for DecodeKind

§

fn eq(&self, other: &DecodeKind) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Copy for DecodeKind

§

impl Eq for DecodeKind

§

impl StructuralPartialEq for DecodeKind

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/enum.HexOrBase32ParseError.html b/pr/2992/docs/iroh_base/base32/enum.HexOrBase32ParseError.html new file mode 100644 index 0000000000..b9ffd722a5 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/enum.HexOrBase32ParseError.html @@ -0,0 +1,20 @@ +HexOrBase32ParseError in iroh_base::base32 - Rust

Enum iroh_base::base32::HexOrBase32ParseError

source ·
pub enum HexOrBase32ParseError {
+    Base32(DecodeError),
+    Hex(FromHexError),
+}
Available on crate feature base32 only.
Expand description

Error when parsing a hex or base32 string.

+

Variants§

§

Base32(DecodeError)

Error when decoding the base32.

+
§

Hex(FromHexError)

Error when decoding the public key.

+

Trait Implementations§

source§

impl Debug for HexOrBase32ParseError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for HexOrBase32ParseError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for HexOrBase32ParseError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<DecodeError> for HexOrBase32ParseError

source§

fn from(source: DecodeError) -> Self

Converts to this type from the input type.
source§

impl From<FromHexError> for HexOrBase32ParseError

source§

fn from(source: FromHexError) -> Self

Converts to this type from the input type.
source§

impl From<HexOrBase32ParseError> for KeyParsingError

Available on crate feature key only.
source§

fn from(source: HexOrBase32ParseError) -> Self

Converts to this type from the input type.

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.fmt.html b/pr/2992/docs/iroh_base/base32/fn.fmt.html new file mode 100644 index 0000000000..9f737f3599 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.fmt.html @@ -0,0 +1,2 @@ +fmt in iroh_base::base32 - Rust

Function iroh_base::base32::fmt

source ·
pub fn fmt(bytes: impl AsRef<[u8]>) -> String
Available on crate feature base32 only.
Expand description

Convert to a base32 string

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.fmt_append.html b/pr/2992/docs/iroh_base/base32/fn.fmt_append.html new file mode 100644 index 0000000000..903709b5c1 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.fmt_append.html @@ -0,0 +1,2 @@ +fmt_append in iroh_base::base32 - Rust

Function iroh_base::base32::fmt_append

source ·
pub fn fmt_append(bytes: impl AsRef<[u8]>, out: &mut String)
Available on crate feature base32 only.
Expand description

Convert to a base32 string and append out out

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.fmt_short.html b/pr/2992/docs/iroh_base/base32/fn.fmt_short.html new file mode 100644 index 0000000000..fcf8292031 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.fmt_short.html @@ -0,0 +1,2 @@ +fmt_short in iroh_base::base32 - Rust

Function iroh_base::base32::fmt_short

source ·
pub fn fmt_short(bytes: impl AsRef<[u8]>) -> String
Available on crate feature base32 only.
Expand description

Convert to a base32 string limited to the first 10 bytes

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.parse_array.html b/pr/2992/docs/iroh_base/base32/fn.parse_array.html new file mode 100644 index 0000000000..ce3a3c996a --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.parse_array.html @@ -0,0 +1,2 @@ +parse_array in iroh_base::base32 - Rust

Function iroh_base::base32::parse_array

source ·
pub fn parse_array<const N: usize>(input: &str) -> Result<[u8; N], DecodeError>
Available on crate feature base32 only.
Expand description

Parse from a base32 string into a byte array

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.parse_array_hex_or_base32.html b/pr/2992/docs/iroh_base/base32/fn.parse_array_hex_or_base32.html new file mode 100644 index 0000000000..ad13688e96 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.parse_array_hex_or_base32.html @@ -0,0 +1,5 @@ +parse_array_hex_or_base32 in iroh_base::base32 - Rust

Function iroh_base::base32::parse_array_hex_or_base32

source ·
pub fn parse_array_hex_or_base32<const LEN: usize>(
+    input: &str
+) -> Result<[u8; LEN], HexOrBase32ParseError>
Available on crate feature base32 only.
Expand description

Parse a fixed length hex or base32 string into a byte array

+

For fixed length we can know the encoding by the length of the string.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/fn.parse_vec.html b/pr/2992/docs/iroh_base/base32/fn.parse_vec.html new file mode 100644 index 0000000000..f6995a3c31 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/fn.parse_vec.html @@ -0,0 +1,2 @@ +parse_vec in iroh_base::base32 - Rust

Function iroh_base::base32::parse_vec

source ·
pub fn parse_vec(input: &str) -> Result<Vec<u8>, DecodeError>
Available on crate feature base32 only.
Expand description

Decode form a base32 string to a vector of bytes

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/index.html b/pr/2992/docs/iroh_base/base32/index.html new file mode 100644 index 0000000000..d7106bb726 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/index.html @@ -0,0 +1 @@ +iroh_base::base32 - Rust

Module iroh_base::base32

source ·
Available on crate feature base32 only.

Structs§

Enums§

Functions§

  • Convert to a base32 string
  • Convert to a base32 string and append out out
  • Convert to a base32 string limited to the first 10 bytes
  • Parse from a base32 string into a byte array
  • Parse a fixed length hex or base32 string into a byte array
  • Decode form a base32 string to a vector of bytes
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/sidebar-items.js b/pr/2992/docs/iroh_base/base32/sidebar-items.js new file mode 100644 index 0000000000..9482b521a4 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["DecodeKind","HexOrBase32ParseError"],"fn":["fmt","fmt_append","fmt_short","parse_array","parse_array_hex_or_base32","parse_vec"],"struct":["DecodeError"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/base32/struct.DecodeError.html b/pr/2992/docs/iroh_base/base32/struct.DecodeError.html new file mode 100644 index 0000000000..0fa0781ec4 --- /dev/null +++ b/pr/2992/docs/iroh_base/base32/struct.DecodeError.html @@ -0,0 +1,24 @@ +DecodeError in iroh_base::base32 - Rust

Struct iroh_base::base32::DecodeError

pub struct DecodeError {
+    pub position: usize,
+    pub kind: DecodeKind,
+}
Available on crate feature base32 only.
Expand description

Decoding error

+

Fields§

§position: usize

Error position

+

This position is always a valid input position and represents the first encountered error.

+
§kind: DecodeKind

Error kind

+

Trait Implementations§

§

impl Clone for DecodeError

§

fn clone(&self) -> DecodeError

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for DecodeError

§

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

Formats the value using the given formatter. Read more
§

impl Display for DecodeError

§

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

Formats the value using the given formatter. Read more
§

impl Error for DecodeError

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<DecodeError> for Error

source§

fn from(source: DecodeError) -> Self

Converts to this type from the input type.
source§

impl From<DecodeError> for HexOrBase32ParseError

source§

fn from(source: DecodeError) -> Self

Converts to this type from the input type.
§

impl PartialEq for DecodeError

§

fn eq(&self, other: &DecodeError) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Copy for DecodeError

§

impl Eq for DecodeError

§

impl StructuralPartialEq for DecodeError

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/hash/enum.BlobFormat.html b/pr/2992/docs/iroh_base/hash/enum.BlobFormat.html new file mode 100644 index 0000000000..7a77e716b7 --- /dev/null +++ b/pr/2992/docs/iroh_base/hash/enum.BlobFormat.html @@ -0,0 +1,36 @@ +BlobFormat in iroh_base::hash - Rust

Enum iroh_base::hash::BlobFormat

source ·
pub enum BlobFormat {
+    Raw,
+    HashSeq,
+}
Available on crate feature hash only.
Expand description

A format identifier

+

Variants§

§

Raw

Raw blob

+
§

HashSeq

A sequence of BLAKE3 hashes

+

Implementations§

source§

impl BlobFormat

source

pub const fn is_raw(&self) -> bool

Is raw format

+
source

pub const fn is_hash_seq(&self) -> bool

Is hash seq format

+

Trait Implementations§

source§

impl Clone for BlobFormat

source§

fn clone(&self) -> BlobFormat

Returns a copy 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 BlobFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for BlobFormat

source§

fn default() -> BlobFormat

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for BlobFormat

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for BlobFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl From<BlobFormat> for u64

source§

fn from(value: BlobFormat) -> Self

Converts to this type from the input type.
source§

impl Hash for BlobFormat

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl MaxSize for BlobFormat

source§

const POSTCARD_MAX_SIZE: usize = 1usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for BlobFormat

source§

fn cmp(&self, other: &BlobFormat) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for BlobFormat

source§

fn eq(&self, other: &BlobFormat) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for BlobFormat

source§

fn partial_cmp(&self, other: &BlobFormat) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for BlobFormat

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for BlobFormat

source§

impl Eq for BlobFormat

source§

impl StructuralPartialEq for BlobFormat

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/hash/index.html b/pr/2992/docs/iroh_base/hash/index.html new file mode 100644 index 0000000000..b41a85095d --- /dev/null +++ b/pr/2992/docs/iroh_base/hash/index.html @@ -0,0 +1,2 @@ +iroh_base::hash - Rust

Module iroh_base::hash

source ·
Available on crate feature hash only.
Expand description

The blake3 hash used in Iroh.

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/hash/sidebar-items.js b/pr/2992/docs/iroh_base/hash/sidebar-items.js new file mode 100644 index 0000000000..8b279d4eb3 --- /dev/null +++ b/pr/2992/docs/iroh_base/hash/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["BlobFormat"],"struct":["Hash","HashAndFormat"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/hash/struct.Hash.html b/pr/2992/docs/iroh_base/hash/struct.Hash.html new file mode 100644 index 0000000000..54182e13d6 --- /dev/null +++ b/pr/2992/docs/iroh_base/hash/struct.Hash.html @@ -0,0 +1,44 @@ +Hash in iroh_base::hash - Rust

Struct iroh_base::hash::Hash

source ·
pub struct Hash(/* private fields */);
Available on crate feature hash only.
Expand description

Hash type used throughout.

+

Implementations§

source§

impl Hash

source

pub const EMPTY: Hash = _

The hash for the empty byte range (b"").

+
source

pub fn new(buf: impl AsRef<[u8]>) -> Self

Calculate the hash of the provided bytes.

+
source

pub fn as_bytes(&self) -> &[u8; 32]

Bytes of the hash.

+
source

pub const fn from_bytes(bytes: [u8; 32]) -> Self

Create a Hash from its raw bytes representation.

+
source

pub fn to_hex(&self) -> String

Convert the hash to a hex string.

+
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string +representation of the hash.

+

Trait Implementations§

source§

impl AsRef<[u8]> for Hash

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Borrow<[u8]> for Hash

source§

fn borrow(&self) -> &[u8]

Immutably borrows from an owned value. Read more
source§

impl Borrow<[u8; 32]> for Hash

source§

fn borrow(&self) -> &[u8; 32]

Immutably borrows from an owned value. Read more
source§

impl Clone for Hash

source§

fn clone(&self) -> Hash

Returns a copy 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 Hash

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Hash

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Hash

source§

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

Formats the value using the given formatter. Read more
source§

impl From<&[u8; 32]> for Hash

source§

fn from(value: &[u8; 32]) -> Self

Converts to this type from the input type.
source§

impl From<[u8; 32]> for Hash

source§

fn from(value: [u8; 32]) -> Self

Converts to this type from the input type.
source§

impl From<Hash> for [u8; 32]

source§

fn from(value: Hash) -> Self

Converts to this type from the input type.
source§

impl From<Hash> for Hash

source§

fn from(value: Hash) -> Self

Converts to this type from the input type.
source§

impl From<Hash> for Hash

source§

fn from(value: Hash) -> Self

Converts to this type from the input type.
source§

impl FromStr for Hash

§

type Err = HexOrBase32ParseError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for Hash

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Key for Hash

source§

fn compare(data1: &[u8], data2: &[u8]) -> Ordering

Compare data1 with data2
source§

impl MaxSize for Hash

source§

const POSTCARD_MAX_SIZE: usize = 32usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for Hash

source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for Hash

source§

fn eq(&self, other: &Hash) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for Hash

source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for Hash

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Value for Hash

§

type SelfType<'a> = Hash

SelfType<’a> must be the same type as Self with all lifetimes replaced with ’a
§

type AsBytes<'a> = &'a [u8; 32]

source§

fn fixed_width() -> Option<usize>

Width of a fixed type, or None for variable width
source§

fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
where + Self: 'a,

Deserializes data +Implementations may return a view over data, or an owned type
source§

fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
where + Self: 'a + 'b,

Serialize the value to a slice
source§

fn type_name() -> TypeName

Globally unique identifier for this type
source§

impl Copy for Hash

source§

impl Eq for Hash

source§

impl StructuralPartialEq for Hash

Auto Trait Implementations§

§

impl Freeze for Hash

§

impl RefUnwindSafe for Hash

§

impl Send for Hash

§

impl Sync for Hash

§

impl Unpin for Hash

§

impl UnwindSafe for Hash

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/hash/struct.HashAndFormat.html b/pr/2992/docs/iroh_base/hash/struct.HashAndFormat.html new file mode 100644 index 0000000000..3de6cacdd5 --- /dev/null +++ b/pr/2992/docs/iroh_base/hash/struct.HashAndFormat.html @@ -0,0 +1,40 @@ +HashAndFormat in iroh_base::hash - Rust

Struct iroh_base::hash::HashAndFormat

source ·
pub struct HashAndFormat {
+    pub hash: Hash,
+    pub format: BlobFormat,
+}
Available on crate feature hash only.
Expand description

A hash and format pair

+

Fields§

§hash: Hash

The hash

+
§format: BlobFormat

The format

+

Implementations§

source§

impl HashAndFormat

source

pub fn new(hash: Hash, format: BlobFormat) -> Self

Create a new hash and format pair.

+
source

pub fn raw(hash: Hash) -> Self

Create a new hash and format pair, using the default (raw) format.

+
source

pub fn hash_seq(hash: Hash) -> Self

Create a new hash and format pair, using the collection format.

+

Trait Implementations§

source§

impl Clone for HashAndFormat

source§

fn clone(&self) -> HashAndFormat

Returns a copy 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 HashAndFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for HashAndFormat

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for HashAndFormat

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for HashAndFormat

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for HashAndFormat

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl MaxSize for HashAndFormat

source§

const POSTCARD_MAX_SIZE: usize = 33usize

The maximum possible size that the serialization of this +type can have, in bytes.
source§

impl Ord for HashAndFormat

source§

fn cmp(&self, other: &HashAndFormat) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for HashAndFormat

source§

fn eq(&self, other: &HashAndFormat) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for HashAndFormat

source§

fn partial_cmp(&self, other: &HashAndFormat) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for HashAndFormat

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Value for HashAndFormat

§

type SelfType<'a> = HashAndFormat

SelfType<’a> must be the same type as Self with all lifetimes replaced with ’a
§

type AsBytes<'a> = [u8; 33]

source§

fn fixed_width() -> Option<usize>

Width of a fixed type, or None for variable width
source§

fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
where + Self: 'a,

Deserializes data +Implementations may return a view over data, or an owned type
source§

fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
where + Self: 'a + 'b,

Serialize the value to a slice
source§

fn type_name() -> TypeName

Globally unique identifier for this type
source§

impl Copy for HashAndFormat

source§

impl Eq for HashAndFormat

source§

impl StructuralPartialEq for HashAndFormat

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/index.html b/pr/2992/docs/iroh_base/index.html new file mode 100644 index 0000000000..7b7511bcdc --- /dev/null +++ b/pr/2992/docs/iroh_base/index.html @@ -0,0 +1,2 @@ +iroh_base - Rust

Crate iroh_base

source ·
Expand description

Base types and utilities for Iroh

+

Modules§

  • base32base32
  • hashhash
    The blake3 hash used in Iroh.
  • keykey
    Cryptographic key handling for iroh.
  • Addressing for iroh nodes.
  • based on tailscale/tailcfg/derpmap.go
  • ticketbase32
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/constant.PUBLIC_KEY_LENGTH.html b/pr/2992/docs/iroh_base/key/constant.PUBLIC_KEY_LENGTH.html new file mode 100644 index 0000000000..132880fdf8 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/constant.PUBLIC_KEY_LENGTH.html @@ -0,0 +1,2 @@ +PUBLIC_KEY_LENGTH in iroh_base::key - Rust

Constant iroh_base::key::PUBLIC_KEY_LENGTH

pub const PUBLIC_KEY_LENGTH: usize = 32; // 32usize
Available on crate feature key only.
Expand description

The length of an ed25519 PublicKey, in bytes.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/encryption/struct.SharedSecret.html b/pr/2992/docs/iroh_base/key/encryption/struct.SharedSecret.html new file mode 100644 index 0000000000..23ebeb4ed5 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/encryption/struct.SharedSecret.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_base/key/struct.SharedSecret.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/enum.KeyParsingError.html b/pr/2992/docs/iroh_base/key/enum.KeyParsingError.html new file mode 100644 index 0000000000..e7032a9b0f --- /dev/null +++ b/pr/2992/docs/iroh_base/key/enum.KeyParsingError.html @@ -0,0 +1,20 @@ +KeyParsingError in iroh_base::key - Rust

Enum iroh_base::key::KeyParsingError

source ·
pub enum KeyParsingError {
+    Base32(HexOrBase32ParseError),
+    Key(SignatureError),
+}
Available on crate feature key only.
Expand description

Error when deserialising a PublicKey or a SecretKey.

+

Variants§

§

Base32(HexOrBase32ParseError)

Error when decoding the base32.

+
§

Key(SignatureError)

Error when decoding the public key.

+

Trait Implementations§

source§

impl Debug for KeyParsingError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for KeyParsingError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for KeyParsingError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for KeyParsingError

source§

fn from(source: SignatureError) -> Self

Converts to this type from the input type.
source§

impl From<HexOrBase32ParseError> for KeyParsingError

source§

fn from(source: HexOrBase32ParseError) -> Self

Converts to this type from the input type.

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/index.html b/pr/2992/docs/iroh_base/key/index.html new file mode 100644 index 0000000000..5fb65c6d10 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/index.html @@ -0,0 +1,2 @@ +iroh_base::key - Rust

Module iroh_base::key

source ·
Available on crate feature key only.
Expand description

Cryptographic key handling for iroh.

+

Structs§

Enums§

Constants§

Type Aliases§

  • The identifier for a node in the (iroh) network.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/sidebar-items.js b/pr/2992/docs/iroh_base/key/sidebar-items.js new file mode 100644 index 0000000000..b99c392d60 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["PUBLIC_KEY_LENGTH"],"enum":["KeyParsingError"],"struct":["PublicKey","SecretKey","SharedSecret","Signature"],"type":["NodeId"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/struct.PublicKey.html b/pr/2992/docs/iroh_base/key/struct.PublicKey.html new file mode 100644 index 0000000000..d37f508d4b --- /dev/null +++ b/pr/2992/docs/iroh_base/key/struct.PublicKey.html @@ -0,0 +1,56 @@ +PublicKey in iroh_base::key - Rust

Struct iroh_base::key::PublicKey

source ·
pub struct PublicKey(/* private fields */);
Available on crate feature key only.
Expand description

A public key.

+

The key itself is just a 32 byte array, but a key has associated crypto +information that is cached for performance reasons.

+

The cache item will be refreshed every time a crypto operation is performed, +or when a key is deserialised or created from a byte array.

+

Serialisation or creation from a byte array is cheap if the key is already +in the cache, but expensive if it is not.

+

Implementations§

source§

impl PublicKey

source

pub fn as_bytes(&self) -> &[u8; 32]

Get this public key as a byte array.

+
source

pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError>

Construct a PublicKey from a slice of bytes.

+
§Warning
+

This will return a [SignatureError] if the bytes passed into this method do not represent +a valid ed25519_dalek curve point. Will never fail for bytes return from Self::as_bytes. +See [VerifyingKey::from_bytes] for details.

+
source

pub fn verify( + &self, + message: &[u8], + signature: &Signature +) -> Result<(), SignatureError>

Verify a signature on a message with this secret key’s public key.

+
§Return
+

Returns Ok(()) if the signature is valid, and Err otherwise.

+
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string +representation of the key.

+

Trait Implementations§

source§

impl AsRef<[u8]> for PublicKey

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Clone for PublicKey

source§

fn clone(&self) -> PublicKey

Returns a copy 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 PublicKey

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for PublicKey

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for PublicKey

source§

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

Formats the value using the given formatter. Read more
source§

impl From<PublicKey> for NodeAddr

source§

fn from(node_id: NodeId) -> Self

Converts to this type from the input type.
source§

impl From<VerifyingKey> for PublicKey

source§

fn from(verifying_key: VerifyingKey) -> Self

Converts to this type from the input type.
source§

impl FromStr for PublicKey

Deserialises the PublicKey from it’s base32 encoding.

+

Display is capable of serialising this format.

+
§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for PublicKey

source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for PublicKey

source§

fn cmp(&self, other: &PublicKey) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for PublicKey

source§

fn eq(&self, other: &PublicKey) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for PublicKey

source§

fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for PublicKey

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl TryFrom<&[u8]> for PublicKey

§

type Error = Error

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

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<&[u8; 32]> for PublicKey

§

type Error = Error

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

fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl Copy for PublicKey

source§

impl Eq for PublicKey

source§

impl StructuralPartialEq for PublicKey

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/struct.SecretKey.html b/pr/2992/docs/iroh_base/key/struct.SecretKey.html new file mode 100644 index 0000000000..edab8eddcb --- /dev/null +++ b/pr/2992/docs/iroh_base/key/struct.SecretKey.html @@ -0,0 +1,29 @@ +SecretKey in iroh_base::key - Rust

Struct iroh_base::key::SecretKey

source ·
pub struct SecretKey { /* private fields */ }
Available on crate feature key only.
Expand description

A secret key.

+

Implementations§

source§

impl SecretKey

source

pub fn shared(&self, other: &PublicKey) -> SharedSecret

Returns the shared key for communication between this key and other.

+
source§

impl SecretKey

source

pub fn public(&self) -> PublicKey

The public key of this SecretKey.

+
source

pub fn generate() -> Self

Generate a new SecretKey with the default randomness generator.

+
source

pub fn generate_with_rng<R: CryptoRngCore + ?Sized>(csprng: &mut R) -> Self

Generate a new SecretKey with a randomness generator.

+
source

pub fn to_openssh(&self) -> Result<Zeroizing<String>>

Serialise this key to OpenSSH format.

+
source

pub fn try_from_openssh<T: AsRef<[u8]>>(data: T) -> Result<Self>

Deserialise this key from OpenSSH format.

+
source

pub fn sign(&self, msg: &[u8]) -> Signature

Sign the given message and return a digital signature

+
source

pub fn to_bytes(&self) -> [u8; 32]

Convert this to the bytes representing the secret part. +The public part can always be recovered.

+
source

pub fn from_bytes(bytes: &[u8; 32]) -> Self

Create a secret key from its byte representation.

+

Trait Implementations§

source§

impl Clone for SecretKey

source§

fn clone(&self) -> SecretKey

Returns a copy 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 SecretKey

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for SecretKey

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for SecretKey

source§

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

Formats the value using the given formatter. Read more
source§

impl From<[u8; 32]> for SecretKey

source§

fn from(value: [u8; 32]) -> Self

Converts to this type from the input type.
source§

impl From<SigningKey> for SecretKey

source§

fn from(secret: SigningKey) -> Self

Converts to this type from the input type.
source§

impl FromStr for SecretKey

§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Serialize for SecretKey

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl TryFrom<&[u8]> for SecretKey

§

type Error = Error

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

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error>

Performs the conversion.

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/struct.SharedSecret.html b/pr/2992/docs/iroh_base/key/struct.SharedSecret.html new file mode 100644 index 0000000000..9a907e0b68 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/struct.SharedSecret.html @@ -0,0 +1,16 @@ +SharedSecret in iroh_base::key - Rust

Struct iroh_base::key::SharedSecret

source ·
pub struct SharedSecret(/* private fields */);
Available on crate feature key only.
Expand description

Shared Secret.

+

Implementations§

source§

impl SharedSecret

source

pub fn seal(&self, buffer: &mut dyn Buffer)

Seals the provided cleartext.

+
source

pub fn open(&self, buffer: &mut dyn Buffer) -> Result<()>

Opens the ciphertext, which must have been created using Self::seal, and places the clear text into the provided buffer.

+

Trait Implementations§

source§

impl Debug for SharedSecret

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/struct.Signature.html b/pr/2992/docs/iroh_base/key/struct.Signature.html new file mode 100644 index 0000000000..a7c36d4707 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/struct.Signature.html @@ -0,0 +1,47 @@ +Signature in iroh_base::key - Rust

Struct iroh_base::key::Signature

#[repr(C)]
pub struct Signature { /* private fields */ }
Available on crate feature key only.
Expand description

Ed25519 signature.

+

This type represents a container for the byte serialization of an Ed25519 +signature, and does not necessarily represent well-formed field or curve +elements.

+

Signature verification libraries are expected to reject invalid field +elements at the time a signature is verified.

+

Implementations§

§

impl Signature

pub const BYTE_SIZE: usize = 64usize

Size of an encoded Ed25519 signature in bytes.

+

pub fn from_bytes(bytes: &[u8; 64]) -> Signature

Parse an Ed25519 signature from a byte slice.

+

pub fn from_components(R: [u8; 32], s: [u8; 32]) -> Signature

Parse an Ed25519 signature from its R and s components.

+

pub fn from_slice(bytes: &[u8]) -> Result<Signature, Error>

Parse an Ed25519 signature from a byte slice.

+
§Returns
+
    +
  • Ok on success
  • +
  • Err if the input byte slice is not 64-bytes
  • +
+

pub fn r_bytes(&self) -> &[u8; 32]

Bytes for the R component of a signature.

+

pub fn s_bytes(&self) -> &[u8; 32]

Bytes for the s component of a signature.

+

pub fn to_bytes(&self) -> [u8; 64]

Return the inner byte array.

+

pub fn to_vec(&self) -> Vec<u8>

Convert this signature into a byte vector.

+

Trait Implementations§

§

impl Clone for Signature

§

fn clone(&self) -> Signature

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for Signature

§

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

Formats the value using the given formatter. Read more
§

impl<'de> Deserialize<'de> for Signature

§

fn deserialize<D>( + deserializer: D +) -> Result<Signature, <D as Deserializer<'de>>::Error>
where + D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
§

impl Display for Signature

§

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

Formats the value using the given formatter. Read more
§

impl From<&[u8; 64]> for Signature

§

fn from(bytes: &[u8; 64]) -> Signature

Converts to this type from the input type.
§

impl From<[u8; 64]> for Signature

§

fn from(bytes: [u8; 64]) -> Signature

Converts to this type from the input type.
§

impl From<InternalSignature> for Signature

§

fn from(sig: InternalSignature) -> Signature

Converts to this type from the input type.
§

impl FromStr for Signature

Decode a signature from hexadecimal.

+

Upper and lower case hexadecimal are both accepted, however mixed case is +rejected.

+
§

type Err = Error

The associated error which can be returned from parsing.
§

fn from_str(hex: &str) -> Result<Signature, Error>

Parses a string s to return a value of this type. Read more
§

impl LowerHex for Signature

§

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

Formats the value using the given formatter.
§

impl PartialEq for Signature

§

fn eq(&self, other: &Signature) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl Serialize for Signature

§

fn serialize<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize this value into the given Serde serializer. Read more
§

impl SignatureEncoding for Signature

§

type Repr = [u8; 64]

Byte representation of a signature.
§

fn to_bytes(&self) -> [u8; 64]

Encode signature as its byte representation.
§

fn to_vec(&self) -> Vec<u8>

Encode signature as a byte vector.
§

fn encoded_len(&self) -> usize

Get the length of this signature when encoded.
§

impl TryFrom<&[u8]> for Signature

§

type Error = Error

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

fn try_from(bytes: &[u8]) -> Result<Signature, Error>

Performs the conversion.
§

impl TryFrom<&Signature> for Signature

§

type Error = Error

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

fn try_from(signature: &Signature) -> Result<Signature, Error>

Performs the conversion.
§

impl TryFrom<Signature> for Signature

§

type Error = Error

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

fn try_from(signature: Signature) -> Result<Signature, Error>

Performs the conversion.
§

impl UpperHex for Signature

§

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

Formats the value using the given formatter.
§

impl Copy for Signature

§

impl Eq for Signature

§

impl StructuralPartialEq for Signature

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/key/type.NodeId.html b/pr/2992/docs/iroh_base/key/type.NodeId.html new file mode 100644 index 0000000000..a5b7e2ea86 --- /dev/null +++ b/pr/2992/docs/iroh_base/key/type.NodeId.html @@ -0,0 +1,12 @@ +NodeId in iroh_base::key - Rust

Type Alias iroh_base::key::NodeId

source ·
pub type NodeId = PublicKey;
Available on crate feature key only.
Expand description

The identifier for a node in the (iroh) network.

+

Each node in iroh has a unique identifier created as a cryptographic key. This can be +used to globally identify a node. Since it is also a cryptographic key it is also the +mechanism by which all traffic is always encrypted for a specific node only.

+

This is equivalent to PublicKey. By convention we will (or should) use PublicKey +as type name when performing cryptographic operations, but use NodeId when referencing +a node. E.g.:

+
    +
  • encrypt(key: PublicKey)
  • +
  • send_to(node: NodeId)
  • +
+

Aliased Type§

struct NodeId(/* private fields */);
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/enum.AddrInfoOptions.html b/pr/2992/docs/iroh_base/node_addr/enum.AddrInfoOptions.html new file mode 100644 index 0000000000..4569381a7e --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/enum.AddrInfoOptions.html @@ -0,0 +1,31 @@ +AddrInfoOptions in iroh_base::node_addr - Rust

Enum iroh_base::node_addr::AddrInfoOptions

source ·
pub enum AddrInfoOptions {
+    Id,
+    RelayAndAddresses,
+    Relay,
+    Addresses,
+}
Available on crate feature key only.
Expand description

Options to configure what is included in a NodeAddr and AddrInfo.

+

Variants§

§

Id

Only the Node ID is added.

+

This usually means that iroh-dns discovery is used to find address information.

+
§

RelayAndAddresses

Includes the Node ID and both the relay URL, and the direct addresses.

+
§

Relay

Includes the Node ID and the relay URL.

+
§

Addresses

Includes the Node ID and the direct addresses.

+

Trait Implementations§

source§

impl Clone for AddrInfoOptions

source§

fn clone(&self) -> AddrInfoOptions

Returns a copy 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 AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfoOptions

source§

fn default() -> AddrInfoOptions

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfoOptions

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for AddrInfoOptions

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for AddrInfoOptions

§

type Err = FromStrError

The associated error which can be returned from parsing.
source§

fn from_str(src: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for AddrInfoOptions

source§

fn eq(&self, other: &AddrInfoOptions) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for AddrInfoOptions

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Copy for AddrInfoOptions

source§

impl Eq for AddrInfoOptions

source§

impl StructuralPartialEq for AddrInfoOptions

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/index.html b/pr/2992/docs/iroh_base/node_addr/index.html new file mode 100644 index 0000000000..60b721f31d --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/index.html @@ -0,0 +1,6 @@ +iroh_base::node_addr - Rust

Module iroh_base::node_addr

source ·
Available on crate feature key only.
Expand description

Addressing for iroh nodes.

+

This module contains some common addressing types for iroh. A node is uniquely +identified by the NodeId but that does not make it addressable on the network layer. +For this the addition of a RelayUrl and/or direct addresses are required.

+

The primary way of addressing a node is by using the NodeAddr.

+

Structs§

  • Network paths to contact an iroh node.
  • Network-level addressing information for an iroh node.
  • A URL identifying a relay server.

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/sidebar-items.js b/pr/2992/docs/iroh_base/node_addr/sidebar-items.js new file mode 100644 index 0000000000..dd003b5e3f --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["AddrInfoOptions"],"struct":["AddrInfo","NodeAddr","RelayUrl"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/struct.AddrInfo.html b/pr/2992/docs/iroh_base/node_addr/struct.AddrInfo.html new file mode 100644 index 0000000000..070ebecbeb --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/struct.AddrInfo.html @@ -0,0 +1,38 @@ +AddrInfo in iroh_base::node_addr - Rust

Struct iroh_base::node_addr::AddrInfo

source ·
pub struct AddrInfo {
+    pub relay_url: Option<RelayUrl>,
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
Available on crate feature key only.
Expand description

Network paths to contact an iroh node.

+

This contains zero or more network paths to establish a connection to an iroh node. +Unless a [discovery service] is used at least one path is required to connect to an +other node, see NodeAddr for details.

+

Fields§

§relay_url: Option<RelayUrl>

The node’s home relay url.

+
§direct_addresses: BTreeSet<SocketAddr>

Socket addresses where the peer might be reached directly.

+

Implementations§

source§

impl AddrInfo

source

pub fn is_empty(&self) -> bool

Returns whether this addressing information is empty.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in ab AddrInfo +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+

Trait Implementations§

source§

impl Clone for AddrInfo

source§

fn clone(&self) -> AddrInfo

Returns a copy 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 AddrInfo

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for AddrInfo

source§

fn default() -> AddrInfo

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for AddrInfo

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Ord for AddrInfo

source§

fn cmp(&self, other: &AddrInfo) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for AddrInfo

source§

fn eq(&self, other: &AddrInfo) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for AddrInfo

source§

fn partial_cmp(&self, other: &AddrInfo) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for AddrInfo

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for AddrInfo

source§

impl StructuralPartialEq for AddrInfo

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/struct.NodeAddr.html b/pr/2992/docs/iroh_base/node_addr/struct.NodeAddr.html new file mode 100644 index 0000000000..4abb111c5e --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/struct.NodeAddr.html @@ -0,0 +1,70 @@ +NodeAddr in iroh_base::node_addr - Rust

Struct iroh_base::node_addr::NodeAddr

source ·
pub struct NodeAddr {
+    pub node_id: NodeId,
+    pub info: AddrInfo,
+}
Available on crate feature key only.
Expand description

Network-level addressing information for an iroh node.

+

This combines a node’s identifier with network-level addressing information of how to +contact the node.

+

To establish a network connection to a node both the NodeId and one or more network +paths are needed. The network paths can come from various sources:

+
    +
  • +

    A discovery service which can provide routing information for a given NodeId.

    +
  • +
  • +

    A RelayUrl of the node’s home relay, this allows establishing the connection via +the Relay server and is very reliable.

    +
  • +
  • +

    One or more direct addresses on which the node might be reachable. Depending on the +network location of both nodes it might not be possible to establish a direct +connection without the help of a Relay server.

    +
  • +
+

This structure will always contain the required NodeId and will contain an optional +number of network-level addressing information. It is a generic addressing type used +whenever a connection to other nodes needs to be established.

+

Fields§

§node_id: NodeId

The node’s identifier.

+
§info: AddrInfo

Addressing information to connect to Self::node_id.

+

Implementations§

source§

impl NodeAddr

source

pub fn new(node_id: PublicKey) -> Self

Creates a new NodeAddr with empty AddrInfo.

+
source

pub fn with_relay_url(self, relay_url: RelayUrl) -> Self

Adds a relay url to the node’s AddrInfo.

+
source

pub fn with_direct_addresses( + self, + addresses: impl IntoIterator<Item = SocketAddr> +) -> Self

Adds the given direct addresses to the peer’s AddrInfo.

+
source

pub fn from_parts( + node_id: PublicKey, + relay_url: Option<RelayUrl>, + direct_addresses: impl IntoIterator<Item = SocketAddr> +) -> Self

Creates a new NodeAddr from its parts.

+
source

pub fn apply_options(&mut self, opts: AddrInfoOptions)

Applies the options to self.

+

This is used to more tightly control the information stored in a NodeAddr +received from another API. E.g. to ensure a discovery service is used the +AddrInfoOptions::Id] option could be used to remove all other addressing details.

+
source

pub fn direct_addresses(&self) -> impl Iterator<Item = &SocketAddr>

Returns the direct addresses of this peer.

+
source

pub fn relay_url(&self) -> Option<&RelayUrl>

Returns the relay url of this peer.

+

Trait Implementations§

source§

impl Clone for NodeAddr

source§

fn clone(&self) -> NodeAddr

Returns a copy 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 NodeAddr

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeAddr

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for NodeAddr

source§

fn from(value: (PublicKey, Option<RelayUrl>, &[SocketAddr])) -> Self

Converts to this type from the input type.
source§

impl From<NodeAddr> for NodeTicket

Available on crate feature base32 only.
source§

fn from(addr: NodeAddr) -> Self

Creates a ticket from given addressing info.

+
source§

impl From<NodeTicket> for NodeAddr

Available on crate feature base32 only.
source§

fn from(ticket: NodeTicket) -> Self

Returns the addressing info from given ticket.

+
source§

impl From<PublicKey> for NodeAddr

source§

fn from(node_id: NodeId) -> Self

Converts to this type from the input type.
source§

impl Ord for NodeAddr

source§

fn cmp(&self, other: &NodeAddr) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for NodeAddr

source§

fn eq(&self, other: &NodeAddr) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for NodeAddr

source§

fn partial_cmp(&self, other: &NodeAddr) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for NodeAddr

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for NodeAddr

source§

impl StructuralPartialEq for NodeAddr

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/node_addr/struct.RelayUrl.html b/pr/2992/docs/iroh_base/node_addr/struct.RelayUrl.html new file mode 100644 index 0000000000..0a26352cda --- /dev/null +++ b/pr/2992/docs/iroh_base/node_addr/struct.RelayUrl.html @@ -0,0 +1,478 @@ +RelayUrl in iroh_base::node_addr - Rust

Struct iroh_base::node_addr::RelayUrl

source ·
pub struct RelayUrl(/* private fields */);
Available on crate feature key only.
Expand description

A URL identifying a relay server.

+

This is but a wrapper around Url, with a few custom tweaks:

+
    +
  • +

    A relay URL is never a relative URL, so an implicit . is added at the end of the +domain name if missing.

    +
  • +
  • +

    fmt::Debug is implemented so it prints the URL rather than the URL struct fields. +Useful when logging e.g. Option<RelayUrl>.

    +
  • +
+

To create a RelayUrl use the From<Url> implementation.

+

Methods from Deref<Target = Url>§

source

pub fn join(&self, input: &str) -> Result<Url, ParseError>

Parse a string as an URL, with this URL as the base URL.

+

The inverse of this is make_relative.

+
§Notes
+
    +
  • A trailing slash is significant. +Without it, the last path component is considered to be a “file” name +to be removed to get at the “directory” that is used as the base.
  • +
  • A scheme relative special URL +as input replaces everything in the base URL after the scheme.
  • +
  • An absolute URL (with a scheme) as input replaces the whole base URL (even the scheme).
  • +
+
§Examples
+
use url::Url;
+
+// Base without a trailing slash
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/c.png");  // Not /a/b.html/c.png
+
+// Base with a trailing slash
+let base = Url::parse("https://example.net/a/b/")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/b/c.png");
+
+// Input as scheme relative special URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("//eve.com/b")?;
+assert_eq!(url.as_str(), "https://eve.com/b");
+
+// Input as absolute URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("http://eve.com/b")?;
+assert_eq!(url.as_str(), "http://eve.com/b");  // http instead of https
+
§Errors
+

If the function can not parse an URL from the given string +with this URL as the base URL, a ParseError variant will be returned.

+
source

pub fn make_relative(&self, url: &Url) -> Option<String>

Creates a relative URL if possible, with this URL as the base URL.

+

This is the inverse of join.

+
§Examples
+
use url::Url;
+
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = Url::parse("https://example.net/a/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/b/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/d/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("../d/c.png"));
+
+let base = Url::parse("https://example.net/a/b.html?c=d")?;
+let url = Url::parse("https://example.net/a/b.html?e=f")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("?e=f"));
+
§Errors
+

If this URL can’t be a base for the given URL, None is returned. +This is for example the case if the scheme, host or port are not the same.

+
source

pub fn as_str(&self) -> &str

Return the serialization of this URL.

+

This is fast since that serialization is already stored in the Url struct.

+
§Examples
+
use url::Url;
+
+let url_str = "https://example.net/";
+let url = Url::parse(url_str)?;
+assert_eq!(url.as_str(), url_str);
+
source

pub fn origin(&self) -> Origin

Return the origin of this URL (https://url.spec.whatwg.org/#origin)

+

Note: this returns an opaque origin for file: URLs, which causes +url.origin() != url.origin().

+
§Examples
+

URL with ftp scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("ftp://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("ftp".into(),
+                         Host::Domain("example.com".into()),
+                         21));
+

URL with blob scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("blob:https://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("https".into(),
+                         Host::Domain("example.com".into()),
+                         443));
+

URL with file scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("file:///tmp/foo")?;
+assert!(!url.origin().is_tuple());
+
+let other_url = Url::parse("file:///tmp/foo")?;
+assert!(url.origin() != other_url.origin());
+

URL with other scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("foo:bar")?;
+assert!(!url.origin().is_tuple());
+
source

pub fn scheme(&self) -> &str

Return the scheme of this URL, lower-cased, as an ASCII string without the ‘:’ delimiter.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.scheme(), "file");
+
source

pub fn is_special(&self) -> bool

Return whether the URL is special (has a special scheme)

+
§Examples
+
use url::Url;
+
+assert!(Url::parse("http:///tmp/foo")?.is_special());
+assert!(Url::parse("file:///tmp/foo")?.is_special());
+assert!(!Url::parse("moz:///tmp/foo")?.is_special());
+
source

pub fn has_authority(&self) -> bool

Return whether the URL has an ‘authority’, +which can contain a username, password, host, and port number.

+

URLs that do not are either path-only like unix:/run/foo.socket +or cannot-be-a-base like data:text/plain,Stuff.

+

See also the authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_authority());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_authority());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_authority());
+
source

pub fn authority(&self) -> &str

Return the authority of this URL as an ASCII string.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets. +Ports are omitted if they match the well known port of a special URL.

+

Username and password are percent-encoded.

+

See also the has_authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("https://user:password@example.com/tmp/foo")?;
+assert_eq!(url.authority(), "user:password@example.com");
+let url = Url::parse("irc://àlex.рф.example.com:6667/foo")?;
+assert_eq!(url.authority(), "%C3%A0lex.%D1%80%D1%84.example.com:6667");
+let url = Url::parse("http://àlex.рф.example.com:80/foo")?;
+assert_eq!(url.authority(), "xn--lex-8ka.xn--p1ai.example.com");
+
source

pub fn cannot_be_a_base(&self) -> bool

Return whether this URL is a cannot-be-a-base URL, +meaning that parsing a relative URL string with this URL as the base will return an error.

+

This is the case if the scheme and : delimiter are not followed by a / slash, +as is typically the case of data: and mailto: URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.cannot_be_a_base());
+
source

pub fn username(&self) -> &str

Return the username for this URL (typically the empty string) +as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.username(), "rms");
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.username(), "");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.username(), "");
+
source

pub fn password(&self) -> Option<&str>

Return the password for this URL, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.password(), None);
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.password(), None);
+
source

pub fn has_host(&self) -> bool

Equivalent to url.host().is_some().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_host());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_host());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_host());
+
source

pub fn host_str(&self) -> Option<&str>

Return the string representation of the host (domain or IP address) for this URL, if any.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert_eq!(url.host_str(), Some("127.0.0.1"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.host_str(), Some("example.com"));
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.host_str(), None);
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert_eq!(url.host_str(), None);
+
source

pub fn host(&self) -> Option<Host<&str>>

Return the parsed representation of the host for this URL. +Non-ASCII domain labels are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host_str method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(url.host().is_none());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.host().is_none());
+
source

pub fn domain(&self) -> Option<&str>

If this URL has a host and it is a domain name (not an IP address), return it. +Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("mailto:rms@example.net")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("https://example.com/")?;
+assert_eq!(url.domain(), Some("example.com"));
+
source

pub fn port(&self) -> Option<u16>

Return the port number for this URL, if any.

+

Note that default port numbers are never reflected by the serialization, +use the port_or_known_default() method if you want a default port number returned.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("https://example.com:443/")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("ssh://example.com:22")?;
+assert_eq!(url.port(), Some(22));
+
source

pub fn port_or_known_default(&self) -> Option<u16>

Return the port number for this URL, or the default port number if it is known.

+

This method only knows the default port number +of the http, https, ws, wss and ftp schemes.

+

For URLs in these schemes, this method always returns Some(_). +For other schemes, it is the same as Url::port().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("foo://example.com")?;
+assert_eq!(url.port_or_known_default(), None);
+
+let url = Url::parse("foo://example.com:1456")?;
+assert_eq!(url.port_or_known_default(), Some(1456));
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port_or_known_default(), Some(443));
+
source

pub fn socket_addrs( + &self, + default_port_number: impl Fn() -> Option<u16> +) -> Result<Vec<SocketAddr>, Error>

Resolve a URL’s host and port number to SocketAddr.

+

If the URL has the default port number of a scheme that is unknown to this library, +default_port_number provides an opportunity to provide the actual port number. +In non-example code this should be implemented either simply as || None, +or by matching on the URL’s .scheme().

+

If the host is a domain, it is resolved using the standard library’s DNS support.

+
§Examples
+
let url = url::Url::parse("https://example.net/").unwrap();
+let addrs = url.socket_addrs(|| None).unwrap();
+std::net::TcpStream::connect(&*addrs)
+ +
/// With application-specific known default port numbers
+fn socket_addrs(url: url::Url) -> std::io::Result<Vec<std::net::SocketAddr>> {
+    url.socket_addrs(|| match url.scheme() {
+        "socks5" | "socks5h" => Some(1080),
+        _ => None,
+    })
+}
+
source

pub fn path(&self) -> &str

Return the path for this URL, as a percent-encoded ASCII string. +For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with ‘/’. +For other URLs, this starts with a ‘/’ slash +and continues with slash-separated path segments.

+
§Examples
+
use url::{Url, ParseError};
+
+let url = Url::parse("https://example.com/api/versions?page=2")?;
+assert_eq!(url.path(), "/api/versions");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.path(), "/");
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+assert_eq!(url.path(), "/countries/vi%E1%BB%87t%20nam");
+
source

pub fn path_segments(&self) -> Option<Split<'_, char>>

Unless this URL is cannot-be-a-base, +return an iterator of ‘/’ slash-separated path segments, +each as a percent-encoded ASCII string.

+

Return None for cannot-be-a-base URLs.

+

When Some is returned, the iterator always contains at least one string +(which may be empty).

+
§Examples
+
use url::Url;
+
+
+let url = Url::parse("https://example.com/foo/bar")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("foo"));
+assert_eq!(path_segments.next(), Some("bar"));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("https://example.com")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some(""));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("data:text/plain,HelloWorld")?;
+assert!(url.path_segments().is_none());
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("countries"));
+assert_eq!(path_segments.next(), Some("vi%E1%BB%87t%20nam"));
+
source

pub fn query(&self) -> Option<&str>

Return this URL’s query string, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+fn run() -> Result<(), ParseError> {
+let url = Url::parse("https://example.com/products?page=2")?;
+let query = url.query();
+assert_eq!(query, Some("page=2"));
+
+let url = Url::parse("https://example.com/products")?;
+let query = url.query();
+assert!(query.is_none());
+
+let url = Url::parse("https://example.com/?country=español")?;
+let query = url.query();
+assert_eq!(query, Some("country=espa%C3%B1ol"));
+
source

pub fn query_pairs(&self) -> Parse<'_>

Parse the URL’s query string, if any, as application/x-www-form-urlencoded +and return an iterator of (key, value) pairs.

+
§Examples
+
use std::borrow::Cow;
+
+use url::Url;
+
+let url = Url::parse("https://example.com/products?page=2&sort=desc")?;
+let mut pairs = url.query_pairs();
+
+assert_eq!(pairs.count(), 2);
+
+assert_eq!(pairs.next(), Some((Cow::Borrowed("page"), Cow::Borrowed("2"))));
+assert_eq!(pairs.next(), Some((Cow::Borrowed("sort"), Cow::Borrowed("desc"))));
+
source

pub fn fragment(&self) -> Option<&str>

Return this URL’s fragment identifier, if any.

+

A fragment is the part of the URL after the # symbol. +The fragment is optional and, if present, contains a fragment identifier +that identifies a secondary resource, such as a section heading +of a document.

+

In HTML, the fragment identifier is usually the id attribute of a an element +that is scrolled to on load. Browsers typically will not send the fragment portion +of a URL to the server.

+

Note: the parser did not percent-encode this component, +but the input may have been percent-encoded already.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com/data.csv#row=4")?;
+
+assert_eq!(url.fragment(), Some("row=4"));
+
+let url = Url::parse("https://example.com/data.csv#cell=4,1-6,2")?;
+
+assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
+
source

pub fn serialize_internal<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize with Serde using the internal representation of the Url struct.

+

The corresponding deserialize_internal method sacrifices some invariant-checking +for speed, compared to the Deserialize trait impl.

+

This method is only available if the serde Cargo feature is enabled.

+
source

pub fn to_file_path(&self) -> Result<PathBuf, ()>

Assuming the URL is in the file scheme or similar, +convert its path to an absolute std::path::Path.

+

Note: This does not actually check the URL’s scheme, +and may give nonsensical results for other schemes. +It is the user’s responsibility to check the URL’s scheme before calling this.

+ +
let path = url.to_file_path();
+

Returns Err if the host is neither empty nor "localhost" (except on Windows, where +file: URLs may have a non-local host), +or if Path::new_opt() returns None. +(That is, if the percent-decoded path contains a NUL byte or, +for a Windows path, is not UTF-8.)

+

This method is only available if the std Cargo feature is enabled.

+

Trait Implementations§

source§

impl Clone for RelayUrl

source§

fn clone(&self) -> RelayUrl

Returns a copy 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 RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl Deref for RelayUrl

Dereferences to the wrapped Url.

+

Note that DerefMut is not implemented on purpose, so this type has more flexibility +to change the inner later.

+
§

type Target = Url

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<'de> Deserialize<'de> for RelayUrl

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl From<RelayUrl> for Url

source§

fn from(value: RelayUrl) -> Self

Converts to this type from the input type.
source§

impl From<Url> for RelayUrl

source§

fn from(url: Url) -> Self

Converts to this type from the input type.
source§

impl FromStr for RelayUrl

Support for parsing strings directly.

+

If you need more control over the error first create a Url and use RelayUrl::from +instead.

+
§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for RelayUrl

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for RelayUrl

source§

fn cmp(&self, other: &RelayUrl) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayUrl

source§

fn eq(&self, other: &RelayUrl) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayUrl

source§

fn partial_cmp(&self, other: &RelayUrl) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayUrl

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayUrl

source§

impl StructuralPartialEq for RelayUrl

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_RELAY_QUIC_PORT.html b/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_RELAY_QUIC_PORT.html new file mode 100644 index 0000000000..44844ca5f5 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_RELAY_QUIC_PORT.html @@ -0,0 +1,4 @@ +DEFAULT_RELAY_QUIC_PORT in iroh_base::relay_map - Rust

Constant iroh_base::relay_map::DEFAULT_RELAY_QUIC_PORT

source ·
pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842;
Available on crate feature relay only.
Expand description

The default QUIC port used by the Relay server to accept QUIC connections +for QUIC address discovery

+

The port is “QUIC” typed on a phone keypad.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_STUN_PORT.html b/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_STUN_PORT.html new file mode 100644 index 0000000000..ca46135b82 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/constant.DEFAULT_STUN_PORT.html @@ -0,0 +1,3 @@ +DEFAULT_STUN_PORT in iroh_base::relay_map - Rust

Constant iroh_base::relay_map::DEFAULT_STUN_PORT

source ·
pub const DEFAULT_STUN_PORT: u16 = 3478;
Available on crate feature relay only.
Expand description

The default STUN port used by the Relay server.

+

The STUN port as defined by RFC 8489

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/index.html b/pr/2992/docs/iroh_base/relay_map/index.html new file mode 100644 index 0000000000..70c721c346 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/index.html @@ -0,0 +1,4 @@ +iroh_base::relay_map - Rust

Module iroh_base::relay_map

source ·
Available on crate feature relay only.
Expand description

based on tailscale/tailcfg/derpmap.go

+

Structs§

  • Configuration for speaking to the QUIC endpoint on the relay +server to do QUIC address discovery.
  • Configuration of all the relay servers that can be used.
  • Information on a specific relay server.
  • A URL identifying a relay server.

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/sidebar-items.js b/pr/2992/docs/iroh_base/relay_map/sidebar-items.js new file mode 100644 index 0000000000..69dcccec62 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT"],"struct":["QuicConfig","RelayMap","RelayNode","RelayUrl"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/struct.QuicConfig.html b/pr/2992/docs/iroh_base/relay_map/struct.QuicConfig.html new file mode 100644 index 0000000000..9f75b64799 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/struct.QuicConfig.html @@ -0,0 +1,28 @@ +QuicConfig in iroh_base::relay_map - Rust

Struct iroh_base::relay_map::QuicConfig

source ·
pub struct QuicConfig {
+    pub port: u16,
+}
Available on crate feature relay only.
Expand description

Configuration for speaking to the QUIC endpoint on the relay +server to do QUIC address discovery.

+

Fields§

§port: u16

Trait Implementations§

source§

impl Clone for QuicConfig

source§

fn clone(&self) -> QuicConfig

Returns a copy 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 QuicConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for QuicConfig

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for QuicConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Ord for QuicConfig

source§

fn cmp(&self, other: &QuicConfig) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for QuicConfig

source§

fn eq(&self, other: &QuicConfig) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for QuicConfig

source§

fn partial_cmp(&self, other: &QuicConfig) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for QuicConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for QuicConfig

source§

impl StructuralPartialEq for QuicConfig

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/struct.RelayMap.html b/pr/2992/docs/iroh_base/relay_map/struct.RelayMap.html new file mode 100644 index 0000000000..a022cc61f8 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/struct.RelayMap.html @@ -0,0 +1,37 @@ +RelayMap in iroh_base::relay_map - Rust

Struct iroh_base::relay_map::RelayMap

source ·
pub struct RelayMap { /* private fields */ }
Available on crate feature relay only.
Expand description

Configuration of all the relay servers that can be used.

+

Implementations§

source§

impl RelayMap

source

pub fn urls(&self) -> impl Iterator<Item = &RelayUrl>

Returns the sorted relay URLs.

+
source

pub fn empty() -> Self

Create an empty relay map.

+
source

pub fn nodes(&self) -> impl Iterator<Item = &Arc<RelayNode>>

Returns an Iterator over all known nodes.

+
source

pub fn contains_node(&self, url: &RelayUrl) -> bool

Is this a known node?

+
source

pub fn get_node(&self, url: &RelayUrl) -> Option<&Arc<RelayNode>>

Get the given node.

+
source

pub fn len(&self) -> usize

How many nodes are known?

+
source

pub fn is_empty(&self) -> bool

Are there any nodes in this map?

+
source

pub fn default_from_node(url: RelayUrl, stun_port: u16) -> Self

Creates a new RelayMap with a single relay server configured.

+

Allows to set a custom STUN port and different IP addresses for IPv4 and IPv6. +If IP addresses are provided, no DNS lookup will be performed.

+

Sets the port to the default DEFAULT_RELAY_QUIC_PORT.

+
source

pub fn from_url(url: RelayUrl) -> Self

Returns a RelayMap from a RelayUrl.

+

This will use the default STUN port, the default QUIC port +(as defined by the iroh-relay crate) and IP addresses +resolved from the URL’s host name via DNS. +relay nodes are specified at <../../docs/relay_nodes.md>

+
source

pub fn from_nodes<I: Into<Arc<RelayNode>>>( + value: impl IntoIterator<Item = I> +) -> Result<Self>

Constructs the RelayMap from an iterator of RelayNodes.

+

Trait Implementations§

source§

impl Clone for RelayMap

source§

fn clone(&self) -> RelayMap

Returns a copy 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 RelayMap

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for RelayMap

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for RelayMap

source§

fn eq(&self, other: &RelayMap) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RelayMap

source§

impl StructuralPartialEq for RelayMap

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/struct.RelayNode.html b/pr/2992/docs/iroh_base/relay_map/struct.RelayNode.html new file mode 100644 index 0000000000..dbe28233a5 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/struct.RelayNode.html @@ -0,0 +1,41 @@ +RelayNode in iroh_base::relay_map - Rust

Struct iroh_base::relay_map::RelayNode

source ·
pub struct RelayNode {
+    pub url: RelayUrl,
+    pub stun_only: bool,
+    pub stun_port: u16,
+    pub quic: Option<QuicConfig>,
+}
Available on crate feature relay only.
Expand description

Information on a specific relay server.

+

Includes the Url where it can be dialed.

+

Fields§

§url: RelayUrl

The RelayUrl where this relay server can be dialed.

+
§stun_only: bool

Whether this relay server should only be used for STUN requests.

+

This essentially allows you to use a normal STUN server as a relay node, no relay +functionality is used.

+
§stun_port: u16

The stun port of the relay server.

+

Setting this to 0 means the default STUN port is used.

+
§quic: Option<QuicConfig>

Configuration to speak to the QUIC endpoint on the relay server.

+

When None, we will not attempt to do QUIC address discovery +with this relay server.

+

Trait Implementations§

source§

impl Clone for RelayNode

source§

fn clone(&self) -> RelayNode

Returns a copy 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 RelayNode

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RelayNode

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayNode

source§

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

Formats the value using the given formatter. Read more
source§

impl Ord for RelayNode

source§

fn cmp(&self, other: &RelayNode) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayNode

source§

fn eq(&self, other: &RelayNode) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayNode

source§

fn partial_cmp(&self, other: &RelayNode) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayNode

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayNode

source§

impl StructuralPartialEq for RelayNode

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_map/struct.RelayUrl.html b/pr/2992/docs/iroh_base/relay_map/struct.RelayUrl.html new file mode 100644 index 0000000000..8d9cd37087 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_map/struct.RelayUrl.html @@ -0,0 +1,478 @@ +RelayUrl in iroh_base::relay_map - Rust

Struct iroh_base::relay_map::RelayUrl

source ·
pub struct RelayUrl(/* private fields */);
Available on crate feature relay only.
Expand description

A URL identifying a relay server.

+

This is but a wrapper around Url, with a few custom tweaks:

+
    +
  • +

    A relay URL is never a relative URL, so an implicit . is added at the end of the +domain name if missing.

    +
  • +
  • +

    fmt::Debug is implemented so it prints the URL rather than the URL struct fields. +Useful when logging e.g. Option<RelayUrl>.

    +
  • +
+

To create a RelayUrl use the From<Url> implementation.

+

Methods from Deref<Target = Url>§

source

pub fn join(&self, input: &str) -> Result<Url, ParseError>

Parse a string as an URL, with this URL as the base URL.

+

The inverse of this is make_relative.

+
§Notes
+
    +
  • A trailing slash is significant. +Without it, the last path component is considered to be a “file” name +to be removed to get at the “directory” that is used as the base.
  • +
  • A scheme relative special URL +as input replaces everything in the base URL after the scheme.
  • +
  • An absolute URL (with a scheme) as input replaces the whole base URL (even the scheme).
  • +
+
§Examples
+
use url::Url;
+
+// Base without a trailing slash
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/c.png");  // Not /a/b.html/c.png
+
+// Base with a trailing slash
+let base = Url::parse("https://example.net/a/b/")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/b/c.png");
+
+// Input as scheme relative special URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("//eve.com/b")?;
+assert_eq!(url.as_str(), "https://eve.com/b");
+
+// Input as absolute URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("http://eve.com/b")?;
+assert_eq!(url.as_str(), "http://eve.com/b");  // http instead of https
+
§Errors
+

If the function can not parse an URL from the given string +with this URL as the base URL, a ParseError variant will be returned.

+
source

pub fn make_relative(&self, url: &Url) -> Option<String>

Creates a relative URL if possible, with this URL as the base URL.

+

This is the inverse of join.

+
§Examples
+
use url::Url;
+
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = Url::parse("https://example.net/a/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/b/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/d/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("../d/c.png"));
+
+let base = Url::parse("https://example.net/a/b.html?c=d")?;
+let url = Url::parse("https://example.net/a/b.html?e=f")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("?e=f"));
+
§Errors
+

If this URL can’t be a base for the given URL, None is returned. +This is for example the case if the scheme, host or port are not the same.

+
source

pub fn as_str(&self) -> &str

Return the serialization of this URL.

+

This is fast since that serialization is already stored in the Url struct.

+
§Examples
+
use url::Url;
+
+let url_str = "https://example.net/";
+let url = Url::parse(url_str)?;
+assert_eq!(url.as_str(), url_str);
+
source

pub fn origin(&self) -> Origin

Return the origin of this URL (https://url.spec.whatwg.org/#origin)

+

Note: this returns an opaque origin for file: URLs, which causes +url.origin() != url.origin().

+
§Examples
+

URL with ftp scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("ftp://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("ftp".into(),
+                         Host::Domain("example.com".into()),
+                         21));
+

URL with blob scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("blob:https://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("https".into(),
+                         Host::Domain("example.com".into()),
+                         443));
+

URL with file scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("file:///tmp/foo")?;
+assert!(!url.origin().is_tuple());
+
+let other_url = Url::parse("file:///tmp/foo")?;
+assert!(url.origin() != other_url.origin());
+

URL with other scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("foo:bar")?;
+assert!(!url.origin().is_tuple());
+
source

pub fn scheme(&self) -> &str

Return the scheme of this URL, lower-cased, as an ASCII string without the ‘:’ delimiter.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.scheme(), "file");
+
source

pub fn is_special(&self) -> bool

Return whether the URL is special (has a special scheme)

+
§Examples
+
use url::Url;
+
+assert!(Url::parse("http:///tmp/foo")?.is_special());
+assert!(Url::parse("file:///tmp/foo")?.is_special());
+assert!(!Url::parse("moz:///tmp/foo")?.is_special());
+
source

pub fn has_authority(&self) -> bool

Return whether the URL has an ‘authority’, +which can contain a username, password, host, and port number.

+

URLs that do not are either path-only like unix:/run/foo.socket +or cannot-be-a-base like data:text/plain,Stuff.

+

See also the authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_authority());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_authority());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_authority());
+
source

pub fn authority(&self) -> &str

Return the authority of this URL as an ASCII string.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets. +Ports are omitted if they match the well known port of a special URL.

+

Username and password are percent-encoded.

+

See also the has_authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("https://user:password@example.com/tmp/foo")?;
+assert_eq!(url.authority(), "user:password@example.com");
+let url = Url::parse("irc://àlex.рф.example.com:6667/foo")?;
+assert_eq!(url.authority(), "%C3%A0lex.%D1%80%D1%84.example.com:6667");
+let url = Url::parse("http://àlex.рф.example.com:80/foo")?;
+assert_eq!(url.authority(), "xn--lex-8ka.xn--p1ai.example.com");
+
source

pub fn cannot_be_a_base(&self) -> bool

Return whether this URL is a cannot-be-a-base URL, +meaning that parsing a relative URL string with this URL as the base will return an error.

+

This is the case if the scheme and : delimiter are not followed by a / slash, +as is typically the case of data: and mailto: URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.cannot_be_a_base());
+
source

pub fn username(&self) -> &str

Return the username for this URL (typically the empty string) +as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.username(), "rms");
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.username(), "");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.username(), "");
+
source

pub fn password(&self) -> Option<&str>

Return the password for this URL, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.password(), None);
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.password(), None);
+
source

pub fn has_host(&self) -> bool

Equivalent to url.host().is_some().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_host());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_host());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_host());
+
source

pub fn host_str(&self) -> Option<&str>

Return the string representation of the host (domain or IP address) for this URL, if any.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert_eq!(url.host_str(), Some("127.0.0.1"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.host_str(), Some("example.com"));
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.host_str(), None);
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert_eq!(url.host_str(), None);
+
source

pub fn host(&self) -> Option<Host<&str>>

Return the parsed representation of the host for this URL. +Non-ASCII domain labels are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host_str method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(url.host().is_none());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.host().is_none());
+
source

pub fn domain(&self) -> Option<&str>

If this URL has a host and it is a domain name (not an IP address), return it. +Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("mailto:rms@example.net")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("https://example.com/")?;
+assert_eq!(url.domain(), Some("example.com"));
+
source

pub fn port(&self) -> Option<u16>

Return the port number for this URL, if any.

+

Note that default port numbers are never reflected by the serialization, +use the port_or_known_default() method if you want a default port number returned.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("https://example.com:443/")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("ssh://example.com:22")?;
+assert_eq!(url.port(), Some(22));
+
source

pub fn port_or_known_default(&self) -> Option<u16>

Return the port number for this URL, or the default port number if it is known.

+

This method only knows the default port number +of the http, https, ws, wss and ftp schemes.

+

For URLs in these schemes, this method always returns Some(_). +For other schemes, it is the same as Url::port().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("foo://example.com")?;
+assert_eq!(url.port_or_known_default(), None);
+
+let url = Url::parse("foo://example.com:1456")?;
+assert_eq!(url.port_or_known_default(), Some(1456));
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port_or_known_default(), Some(443));
+
source

pub fn socket_addrs( + &self, + default_port_number: impl Fn() -> Option<u16> +) -> Result<Vec<SocketAddr>, Error>

Resolve a URL’s host and port number to SocketAddr.

+

If the URL has the default port number of a scheme that is unknown to this library, +default_port_number provides an opportunity to provide the actual port number. +In non-example code this should be implemented either simply as || None, +or by matching on the URL’s .scheme().

+

If the host is a domain, it is resolved using the standard library’s DNS support.

+
§Examples
+
let url = url::Url::parse("https://example.net/").unwrap();
+let addrs = url.socket_addrs(|| None).unwrap();
+std::net::TcpStream::connect(&*addrs)
+ +
/// With application-specific known default port numbers
+fn socket_addrs(url: url::Url) -> std::io::Result<Vec<std::net::SocketAddr>> {
+    url.socket_addrs(|| match url.scheme() {
+        "socks5" | "socks5h" => Some(1080),
+        _ => None,
+    })
+}
+
source

pub fn path(&self) -> &str

Return the path for this URL, as a percent-encoded ASCII string. +For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with ‘/’. +For other URLs, this starts with a ‘/’ slash +and continues with slash-separated path segments.

+
§Examples
+
use url::{Url, ParseError};
+
+let url = Url::parse("https://example.com/api/versions?page=2")?;
+assert_eq!(url.path(), "/api/versions");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.path(), "/");
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+assert_eq!(url.path(), "/countries/vi%E1%BB%87t%20nam");
+
source

pub fn path_segments(&self) -> Option<Split<'_, char>>

Unless this URL is cannot-be-a-base, +return an iterator of ‘/’ slash-separated path segments, +each as a percent-encoded ASCII string.

+

Return None for cannot-be-a-base URLs.

+

When Some is returned, the iterator always contains at least one string +(which may be empty).

+
§Examples
+
use url::Url;
+
+
+let url = Url::parse("https://example.com/foo/bar")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("foo"));
+assert_eq!(path_segments.next(), Some("bar"));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("https://example.com")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some(""));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("data:text/plain,HelloWorld")?;
+assert!(url.path_segments().is_none());
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("countries"));
+assert_eq!(path_segments.next(), Some("vi%E1%BB%87t%20nam"));
+
source

pub fn query(&self) -> Option<&str>

Return this URL’s query string, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+fn run() -> Result<(), ParseError> {
+let url = Url::parse("https://example.com/products?page=2")?;
+let query = url.query();
+assert_eq!(query, Some("page=2"));
+
+let url = Url::parse("https://example.com/products")?;
+let query = url.query();
+assert!(query.is_none());
+
+let url = Url::parse("https://example.com/?country=español")?;
+let query = url.query();
+assert_eq!(query, Some("country=espa%C3%B1ol"));
+
source

pub fn query_pairs(&self) -> Parse<'_>

Parse the URL’s query string, if any, as application/x-www-form-urlencoded +and return an iterator of (key, value) pairs.

+
§Examples
+
use std::borrow::Cow;
+
+use url::Url;
+
+let url = Url::parse("https://example.com/products?page=2&sort=desc")?;
+let mut pairs = url.query_pairs();
+
+assert_eq!(pairs.count(), 2);
+
+assert_eq!(pairs.next(), Some((Cow::Borrowed("page"), Cow::Borrowed("2"))));
+assert_eq!(pairs.next(), Some((Cow::Borrowed("sort"), Cow::Borrowed("desc"))));
+
source

pub fn fragment(&self) -> Option<&str>

Return this URL’s fragment identifier, if any.

+

A fragment is the part of the URL after the # symbol. +The fragment is optional and, if present, contains a fragment identifier +that identifies a secondary resource, such as a section heading +of a document.

+

In HTML, the fragment identifier is usually the id attribute of a an element +that is scrolled to on load. Browsers typically will not send the fragment portion +of a URL to the server.

+

Note: the parser did not percent-encode this component, +but the input may have been percent-encoded already.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com/data.csv#row=4")?;
+
+assert_eq!(url.fragment(), Some("row=4"));
+
+let url = Url::parse("https://example.com/data.csv#cell=4,1-6,2")?;
+
+assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
+
source

pub fn serialize_internal<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize with Serde using the internal representation of the Url struct.

+

The corresponding deserialize_internal method sacrifices some invariant-checking +for speed, compared to the Deserialize trait impl.

+

This method is only available if the serde Cargo feature is enabled.

+
source

pub fn to_file_path(&self) -> Result<PathBuf, ()>

Assuming the URL is in the file scheme or similar, +convert its path to an absolute std::path::Path.

+

Note: This does not actually check the URL’s scheme, +and may give nonsensical results for other schemes. +It is the user’s responsibility to check the URL’s scheme before calling this.

+ +
let path = url.to_file_path();
+

Returns Err if the host is neither empty nor "localhost" (except on Windows, where +file: URLs may have a non-local host), +or if Path::new_opt() returns None. +(That is, if the percent-decoded path contains a NUL byte or, +for a Windows path, is not UTF-8.)

+

This method is only available if the std Cargo feature is enabled.

+

Trait Implementations§

source§

impl Clone for RelayUrl

source§

fn clone(&self) -> RelayUrl

Returns a copy 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 RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl Deref for RelayUrl

Dereferences to the wrapped Url.

+

Note that DerefMut is not implemented on purpose, so this type has more flexibility +to change the inner later.

+
§

type Target = Url

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<'de> Deserialize<'de> for RelayUrl

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl From<RelayUrl> for Url

source§

fn from(value: RelayUrl) -> Self

Converts to this type from the input type.
source§

impl From<Url> for RelayUrl

source§

fn from(url: Url) -> Self

Converts to this type from the input type.
source§

impl FromStr for RelayUrl

Support for parsing strings directly.

+

If you need more control over the error first create a Url and use RelayUrl::from +instead.

+
§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for RelayUrl

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for RelayUrl

source§

fn cmp(&self, other: &RelayUrl) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayUrl

source§

fn eq(&self, other: &RelayUrl) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayUrl

source§

fn partial_cmp(&self, other: &RelayUrl) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayUrl

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayUrl

source§

impl StructuralPartialEq for RelayUrl

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/relay_url/struct.RelayUrl.html b/pr/2992/docs/iroh_base/relay_url/struct.RelayUrl.html new file mode 100644 index 0000000000..128d030849 --- /dev/null +++ b/pr/2992/docs/iroh_base/relay_url/struct.RelayUrl.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../iroh_base/node_addr/struct.RelayUrl.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/sidebar-items.js b/pr/2992/docs/iroh_base/sidebar-items.js new file mode 100644 index 0000000000..1705d7b627 --- /dev/null +++ b/pr/2992/docs/iroh_base/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["base32","hash","key","node_addr","relay_map","ticket"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/blob/struct.BlobTicket.html b/pr/2992/docs/iroh_base/ticket/blob/struct.BlobTicket.html new file mode 100644 index 0000000000..2cb39fcdfc --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/blob/struct.BlobTicket.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_base/ticket/struct.BlobTicket.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/enum.Error.html b/pr/2992/docs/iroh_base/ticket/enum.Error.html new file mode 100644 index 0000000000..108b1e01a4 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/enum.Error.html @@ -0,0 +1,26 @@ +Error in iroh_base::ticket - Rust

Enum iroh_base::ticket::Error

source ·
pub enum Error {
+    Kind {
+        expected: &'static str,
+    },
+    Postcard(Error),
+    Encoding(DecodeError),
+    Verify(&'static str),
+}
Available on crate feature base32 only.
Expand description

An error deserializing an iroh ticket.

+

Variants§

§

Kind

Found a ticket of with the wrong prefix, indicating the wrong kind.

+

Fields

§expected: &'static str
§

Postcard(Error)

This looks like a ticket, but postcard deserialization failed.

+
§

Encoding(DecodeError)

This looks like a ticket, but base32 decoding failed.

+
§

Verify(&'static str)

Verification of the deserialized bytes failed.

+

Trait Implementations§

source§

impl Debug for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for Error

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<DecodeError> for Error

source§

fn from(source: DecodeError) -> Self

Converts to this type from the input type.
source§

impl From<Error> for Error

source§

fn from(source: Error) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl Freeze for Error

§

impl RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnwindSafe for Error

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/index.html b/pr/2992/docs/iroh_base/ticket/index.html new file mode 100644 index 0000000000..caf3d420f6 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/index.html @@ -0,0 +1 @@ +iroh_base::ticket - Rust

Module iroh_base::ticket

source ·
Available on crate feature base32 only.

Structs§

  • A token containing everything to get a file from the provider.
  • A token containing information for establishing a connection to a node.

Enums§

  • An error deserializing an iroh ticket.

Traits§

  • A ticket is a serializable object combining information required for an operation.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/node/struct.NodeTicket.html b/pr/2992/docs/iroh_base/ticket/node/struct.NodeTicket.html new file mode 100644 index 0000000000..6627043f62 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/node/struct.NodeTicket.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_base/ticket/struct.NodeTicket.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/sidebar-items.js b/pr/2992/docs/iroh_base/ticket/sidebar-items.js new file mode 100644 index 0000000000..0642f1ee59 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Error"],"struct":["BlobTicket","NodeTicket"],"trait":["Ticket"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/struct.BlobTicket.html b/pr/2992/docs/iroh_base/ticket/struct.BlobTicket.html new file mode 100644 index 0000000000..bd1b3a6fab --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/struct.BlobTicket.html @@ -0,0 +1,26 @@ +BlobTicket in iroh_base::ticket - Rust

Struct iroh_base::ticket::BlobTicket

source ·
pub struct BlobTicket { /* private fields */ }
Available on crate features key and base32 only.
Expand description

A token containing everything to get a file from the provider.

+

It is a single item which can be easily serialized and deserialized.

+

Implementations§

source§

impl BlobTicket

source

pub fn new(node: NodeAddr, hash: Hash, format: BlobFormat) -> Result<Self>

Creates a new ticket.

+
source

pub fn hash(&self) -> Hash

The hash of the item this ticket can retrieve.

+
source

pub fn node_addr(&self) -> &NodeAddr

The NodeAddr of the provider for this ticket.

+
source

pub fn format(&self) -> BlobFormat

The BlobFormat for this ticket.

+
source

pub fn recursive(&self) -> bool

True if the ticket is for a collection and should retrieve all blobs in it.

+
source

pub fn into_parts(self) -> (NodeAddr, Hash, BlobFormat)

Get the contents of the ticket, consuming it.

+

Trait Implementations§

source§

impl Clone for BlobTicket

source§

fn clone(&self) -> BlobTicket

Returns a copy 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 BlobTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for BlobTicket

source§

fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for BlobTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for BlobTicket

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for BlobTicket

source§

fn eq(&self, other: &BlobTicket) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for BlobTicket

source§

fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more
source§

impl Ticket for BlobTicket

source§

const KIND: &'static str = "blob"

String prefix describing the kind of iroh ticket. Read more
source§

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.
source§

fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Deserialize from the base32 string representation bytes.
source§

fn serialize(&self) -> String

Serialize to string.
source§

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.
source§

impl Eq for BlobTicket

source§

impl StructuralPartialEq for BlobTicket

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/struct.NodeTicket.html b/pr/2992/docs/iroh_base/ticket/struct.NodeTicket.html new file mode 100644 index 0000000000..d709e061d2 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/struct.NodeTicket.html @@ -0,0 +1,34 @@ +NodeTicket in iroh_base::ticket - Rust

Struct iroh_base::ticket::NodeTicket

source ·
pub struct NodeTicket { /* private fields */ }
Available on crate features key and base32 only.
Expand description

A token containing information for establishing a connection to a node.

+

Contains

+
    +
  • The NodeId of the node to connect to (a 32-byte ed25519 public key).
  • +
  • If used, the [’RelayUrl`] of on which the node can be reached.
  • +
  • Any direct addresses on which the node might be reachable.
  • +
+

This allows establishing a connection to the node in most circumstances where it is +possible to do so.

+

This NodeTicket is a single item which can be easily serialized and deserialized and +implements the Ticket trait. The Display and FromStr traits can also be +used to round-trip the ticket to string.

+

Implementations§

source§

impl NodeTicket

source

pub fn new(node: NodeAddr) -> Self

Creates a new ticket.

+
source

pub fn node_addr(&self) -> &NodeAddr

The NodeAddr of the provider for this ticket.

+

Trait Implementations§

source§

impl Clone for NodeTicket

source§

fn clone(&self) -> NodeTicket

Returns a copy 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 NodeTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeTicket

source§

fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for NodeTicket

source§

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

Formats the value using the given formatter. Read more
source§

impl From<NodeAddr> for NodeTicket

source§

fn from(addr: NodeAddr) -> Self

Creates a ticket from given addressing info.

+
source§

impl From<NodeTicket> for NodeAddr

source§

fn from(ticket: NodeTicket) -> Self

Returns the addressing info from given ticket.

+
source§

impl FromStr for NodeTicket

§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for NodeTicket

source§

fn eq(&self, other: &NodeTicket) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for NodeTicket

source§

fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more
source§

impl Ticket for NodeTicket

source§

const KIND: &'static str = "node"

String prefix describing the kind of iroh ticket. Read more
source§

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.
source§

fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Deserialize from the base32 string representation bytes.
source§

fn serialize(&self) -> String

Serialize to string.
source§

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.
source§

impl Eq for NodeTicket

source§

impl StructuralPartialEq for NodeTicket

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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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

source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_base/ticket/trait.Ticket.html b/pr/2992/docs/iroh_base/ticket/trait.Ticket.html new file mode 100644 index 0000000000..d6b2db7419 --- /dev/null +++ b/pr/2992/docs/iroh_base/ticket/trait.Ticket.html @@ -0,0 +1,27 @@ +Ticket in iroh_base::ticket - Rust

Trait iroh_base::ticket::Ticket

source ·
pub trait Ticket: Sized {
+    const KIND: &'static str;
+
+    // Required methods
+    fn to_bytes(&self) -> Vec<u8>;
+    fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;
+
+    // Provided methods
+    fn serialize(&self) -> String { ... }
+    fn deserialize(str: &str) -> Result<Self, Error> { ... }
+}
Available on crate feature base32 only.
Expand description

A ticket is a serializable object combining information required for an operation.

+

Typically tickets contain all information required for an operation, e.g. an iroh blob +ticket would contain the hash of the data as well as information about how to reach the +provider.

+

Tickets support serialization to a string using base32 encoding. The kind of +ticket will be prepended to the string to make it somewhat self describing.

+

Versioning is left to the implementer. Some kinds of tickets might need +versioning, others might not.

+

The serialization format for converting the ticket from and to bytes is left +to the implementer. We recommend using postcard for serialization.

+

Required Associated Constants§

source

const KIND: &'static str

String prefix describing the kind of iroh ticket.

+

This should be lower case ascii characters.

+

Required Methods§

source

fn to_bytes(&self) -> Vec<u8>

Serialize to bytes used in the base32 string representation.

+
source

fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Deserialize from the base32 string representation bytes.

+

Provided Methods§

source

fn serialize(&self) -> String

Serialize to string.

+
source

fn deserialize(str: &str) -> Result<Self, Error>

Deserialize from a string.

+

Object Safety§

This trait is not object safe.

Implementors§

source§

impl Ticket for BlobTicket

Available on crate feature key only.
source§

const KIND: &'static str = "blob"

source§

impl Ticket for NodeTicket

Available on crate feature key only.
source§

const KIND: &'static str = "node"

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/all.html b/pr/2992/docs/iroh_dns_server/all.html new file mode 100644 index 0000000000..79dc681d46 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Functions

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/enum.BootstrapOption.html b/pr/2992/docs/iroh_dns_server/config/enum.BootstrapOption.html new file mode 100644 index 0000000000..28e7189552 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/enum.BootstrapOption.html @@ -0,0 +1,34 @@ +BootstrapOption in iroh_dns_server::config - Rust

Enum iroh_dns_server::config::BootstrapOption

source ·
pub enum BootstrapOption {
+    Default,
+    Custom(Vec<String>),
+}
Expand description

Configure the bootstrap servers for mainline DHT resolution.

+

Variants§

§

Default

Use the default bootstrap servers.

+
§

Custom(Vec<String>)

Use custom bootstrap servers.

+

Trait Implementations§

source§

impl Debug for BootstrapOption

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for BootstrapOption

source§

fn default() -> BootstrapOption

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for BootstrapOption

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for BootstrapOption

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/index.html b/pr/2992/docs/iroh_dns_server/config/index.html new file mode 100644 index 0000000000..2a0a128873 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::config - Rust

Module iroh_dns_server::config

source ·
Expand description

Configuration for the server

+

Structs§

Enums§

  • Configure the bootstrap servers for mainline DHT resolution.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/sidebar-items.js b/pr/2992/docs/iroh_dns_server/config/sidebar-items.js new file mode 100644 index 0000000000..e2b72c033d --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["BootstrapOption"],"struct":["Config","MainlineConfig","MetricsConfig"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/struct.Config.html b/pr/2992/docs/iroh_dns_server/config/struct.Config.html new file mode 100644 index 0000000000..772bea05a5 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/struct.Config.html @@ -0,0 +1,52 @@ +Config in iroh_dns_server::config - Rust

Struct iroh_dns_server::config::Config

source ·
pub struct Config {
+    pub http: Option<HttpConfig>,
+    pub https: Option<HttpsConfig>,
+    pub dns: DnsConfig,
+    pub metrics: Option<MetricsConfig>,
+    pub mainline: Option<MainlineConfig>,
+    pub pkarr_put_rate_limit: RateLimitConfig,
+}
Expand description

Server configuration

+

The config is usually loaded from a file with Self::load.

+

The struct also implements Default which creates a config suitable for local development +and testing.

+

Fields§

§http: Option<HttpConfig>

Config for the HTTP server

+

If set to None no HTTP server will be started.

+
§https: Option<HttpsConfig>

Config for the HTTPS server

+

If set to None no HTTPS server will be started.

+
§dns: DnsConfig

Config for the DNS server.

+
§metrics: Option<MetricsConfig>

Config for the metrics server.

+

The metrics server is started by default. To disable the metrics server, set to +Some(MetricsConfig::disabled()).

+
§mainline: Option<MainlineConfig>

Config for the mainline lookup.

+
§pkarr_put_rate_limit: RateLimitConfig

Config for pkarr rate limit

+

Implementations§

source§

impl Config

source

pub async fn load(path: impl AsRef<Path>) -> Result<Config>

Load the config from a file.

+
source

pub fn data_dir() -> Result<PathBuf>

Get the data directory.

+
source

pub fn signed_packet_store_path() -> Result<PathBuf>

Get the path to the store database file.

+

Trait Implementations§

source§

impl Debug for Config

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Config

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for Config

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for Config

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Config

§

impl RefUnwindSafe for Config

§

impl Send for Config

§

impl Sync for Config

§

impl Unpin for Config

§

impl UnwindSafe for Config

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/struct.MainlineConfig.html b/pr/2992/docs/iroh_dns_server/config/struct.MainlineConfig.html new file mode 100644 index 0000000000..6bdf7b89ec --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/struct.MainlineConfig.html @@ -0,0 +1,36 @@ +MainlineConfig in iroh_dns_server::config - Rust

Struct iroh_dns_server::config::MainlineConfig

source ·
pub struct MainlineConfig {
+    pub enabled: bool,
+    pub bootstrap: Option<Vec<String>>,
+}
Expand description

The config for the metrics server.

+

Fields§

§enabled: bool

Set to true to enable the mainline lookup.

+
§bootstrap: Option<Vec<String>>

Set custom bootstrap nodes.

+

Addresses can either be domain:port or ipv4:port.

+

If empty this will use the default bittorrent mainline bootstrap nodes as defined by pkarr.

+

Trait Implementations§

source§

impl Debug for MainlineConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for MainlineConfig

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for MainlineConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for MainlineConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/config/struct.MetricsConfig.html b/pr/2992/docs/iroh_dns_server/config/struct.MetricsConfig.html new file mode 100644 index 0000000000..857afb7e89 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/config/struct.MetricsConfig.html @@ -0,0 +1,35 @@ +MetricsConfig in iroh_dns_server::config - Rust

Struct iroh_dns_server::config::MetricsConfig

source ·
pub struct MetricsConfig {
+    pub disabled: bool,
+    pub bind_addr: Option<SocketAddr>,
+}
Expand description

The config for the metrics server.

+

Fields§

§disabled: bool

Set to true to disable the metrics server.

+
§bind_addr: Option<SocketAddr>

Optionally set a custom address to bind to.

+

Implementations§

source§

impl MetricsConfig

source

pub fn disabled() -> Self

Disable the metrics server.

+

Trait Implementations§

source§

impl Debug for MetricsConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for MetricsConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for MetricsConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/index.html b/pr/2992/docs/iroh_dns_server/dns/index.html new file mode 100644 index 0000000000..ebd3dc3c09 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::dns - Rust

Module iroh_dns_server::dns

source ·
Expand description

Implementation of a DNS name server for iroh node announces

+

Structs§

  • DNS server settings
  • State for serving DNS
  • A DNS server that serves pkarr signed packets.
  • A handle to the channel over which the response to a DNS request will be sent
\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/sidebar-items.js b/pr/2992/docs/iroh_dns_server/dns/sidebar-items.js new file mode 100644 index 0000000000..c5b14d7784 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["DnsConfig","DnsHandler","DnsServer","Handle"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/struct.DnsConfig.html b/pr/2992/docs/iroh_dns_server/dns/struct.DnsConfig.html new file mode 100644 index 0000000000..dab714f204 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/struct.DnsConfig.html @@ -0,0 +1,50 @@ +DnsConfig in iroh_dns_server::dns - Rust

Struct iroh_dns_server::dns::DnsConfig

source ·
pub struct DnsConfig {
+    pub port: u16,
+    pub bind_addr: Option<IpAddr>,
+    pub default_soa: String,
+    pub default_ttl: u32,
+    pub origins: Vec<String>,
+    pub rr_a: Option<Ipv4Addr>,
+    pub rr_aaaa: Option<Ipv6Addr>,
+    pub rr_ns: Option<String>,
+}
Expand description

DNS server settings

+

Fields§

§port: u16

The port to serve a local UDP DNS server at

+
§bind_addr: Option<IpAddr>

The IPv4 or IPv6 address to bind the UDP DNS server. +Uses 0.0.0.0 if unspecified.

+
§default_soa: String

SOA record data for any authoritative DNS records

+
§default_ttl: u32

Default time to live for returned DNS records (TXT & SOA)

+
§origins: Vec<String>

Domain used for serving the _iroh_node.<nodeid>.<origin> DNS TXT entry

+
§rr_a: Option<Ipv4Addr>

A record to set for all origins

+
§rr_aaaa: Option<Ipv6Addr>

AAAA record to set for all origins

+
§rr_ns: Option<String>

NS record to set for all origins

+

Trait Implementations§

source§

impl Clone for DnsConfig

source§

fn clone(&self) -> DnsConfig

Returns a copy 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 DnsConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for DnsConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for DnsConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/struct.DnsHandler.html b/pr/2992/docs/iroh_dns_server/dns/struct.DnsHandler.html new file mode 100644 index 0000000000..5617c4a681 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/struct.DnsHandler.html @@ -0,0 +1,40 @@ +DnsHandler in iroh_dns_server::dns - Rust

Struct iroh_dns_server::dns::DnsHandler

source ·
pub struct DnsHandler { /* private fields */ }
Expand description

State for serving DNS

+

Implementations§

source§

impl DnsHandler

source

pub fn new(zone_store: ZoneStore, config: &DnsConfig) -> Result<Self>

Create a DNS server given some settings, a connection to the DB for DID-by-username lookups +and the server DID to serve under _did.<origin>.

+
source

pub async fn answer_request(&self, request: Request) -> Result<Bytes>

Handle a DNS request

+

Trait Implementations§

source§

impl Clone for DnsHandler

source§

fn clone(&self) -> DnsHandler

Returns a copy 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 DnsHandler

source§

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

Formats the value using the given formatter. Read more
source§

impl RequestHandler for DnsHandler

source§

fn handle_request<'life0, 'life1, 'async_trait, R>( + &'life0 self, + request: &'life1 Request, + response_handle: R +) -> Pin<Box<dyn Future<Output = ResponseInfo> + Send + 'async_trait>>
where + R: 'async_trait + ResponseHandler, + Self: 'async_trait, + 'life0: 'async_trait, + 'life1: 'async_trait,

Determines what needs to happen given the type of request, i.e. Query or Update. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/struct.DnsServer.html b/pr/2992/docs/iroh_dns_server/dns/struct.DnsServer.html new file mode 100644 index 0000000000..02a5ad54fa --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/struct.DnsServer.html @@ -0,0 +1,31 @@ +DnsServer in iroh_dns_server::dns - Rust

Struct iroh_dns_server::dns::DnsServer

source ·
pub struct DnsServer { /* private fields */ }
Expand description

A DNS server that serves pkarr signed packets.

+

Implementations§

source§

impl DnsServer

source

pub async fn spawn(config: DnsConfig, dns_handler: DnsHandler) -> Result<Self>

Spawn the server.

+
source

pub fn local_addr(&self) -> SocketAddr

Get the local address of the UDP/TCP socket.

+
source

pub async fn shutdown(self) -> Result<()>

Shutdown the server an wait for all tasks to complete.

+
source

pub async fn run_until_done(self) -> Result<()>

Wait for all tasks to complete.

+

Runs forever unless tasks fail.

+

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/dns/struct.Handle.html b/pr/2992/docs/iroh_dns_server/dns/struct.Handle.html new file mode 100644 index 0000000000..cc6aa6ceb0 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/dns/struct.Handle.html @@ -0,0 +1,36 @@ +Handle in iroh_dns_server::dns - Rust

Struct iroh_dns_server::dns::Handle

source ·
pub struct Handle(pub Sender<Bytes>);
Expand description

A handle to the channel over which the response to a DNS request will be sent

+

Tuple Fields§

§0: Sender<Bytes>

Trait Implementations§

source§

impl Clone for Handle

source§

fn clone(&self) -> Handle

Returns a copy 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 Handle

source§

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

Formats the value using the given formatter. Read more
source§

impl ResponseHandler for Handle

source§

fn send_response<'a, 'life0, 'life1, 'async_trait>( + &'life0 mut self, + response: MessageResponse<'life1, 'a, impl 'async_trait + Iterator<Item = &'a Record> + Send + 'a, impl 'async_trait + Iterator<Item = &'a Record> + Send + 'a, impl 'async_trait + Iterator<Item = &'a Record> + Send + 'a, impl 'async_trait + Iterator<Item = &'a Record> + Send + 'a> +) -> Pin<Box<dyn Future<Output = Result<ResponseInfo>> + Send + 'async_trait>>
where + Self: 'async_trait, + 'a: 'async_trait, + 'life0: 'async_trait, + 'life1: 'async_trait,

Serializes and sends a message to to the wrapped handle Read more

Auto Trait Implementations§

§

impl Freeze for Handle

§

impl !RefUnwindSafe for Handle

§

impl Send for Handle

§

impl Sync for Handle

§

impl Unpin for Handle

§

impl !UnwindSafe for Handle

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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/enum.CertMode.html b/pr/2992/docs/iroh_dns_server/http/enum.CertMode.html new file mode 100644 index 0000000000..af93be72f8 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/enum.CertMode.html @@ -0,0 +1,46 @@ +CertMode in iroh_dns_server::http - Rust

Enum iroh_dns_server::http::CertMode

source ·
pub enum CertMode {
+    Manual,
+    LetsEncrypt,
+    SelfSigned,
+}
Expand description

The mode how SSL certificates should be created.

+

Variants§

§

Manual

Certs are loaded from a the cert_cache path

+
§

LetsEncrypt

ACME with LetsEncrypt servers

+
§

SelfSigned

Create self-signed certificates and store them in the cert_cache path

+

Trait Implementations§

source§

impl Clone for CertMode

source§

fn clone(&self) -> CertMode

Returns a copy 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 CertMode

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for CertMode

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for CertMode

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for CertMode

source§

fn eq(&self, other: &CertMode) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for CertMode

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for CertMode

source§

impl StructuralPartialEq for CertMode

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/enum.RateLimitConfig.html b/pr/2992/docs/iroh_dns_server/http/enum.RateLimitConfig.html new file mode 100644 index 0000000000..e7c582b381 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/enum.RateLimitConfig.html @@ -0,0 +1,43 @@ +RateLimitConfig in iroh_dns_server::http - Rust

Enum iroh_dns_server::http::RateLimitConfig

source ·
pub enum RateLimitConfig {
+    Disabled,
+    Simple,
+    Smart,
+}
Expand description

Config for http server rate limit.

+

Variants§

§

Disabled

Disable rate limit.

+
§

Simple

Enable rate limit based on the connection’s peer IP address.

+

https://docs.rs/tower_governor/latest/tower_governor/key_extractor/struct.PeerIpKeyExtractor.html

+
§

Smart

Enable rate limit based on headers commonly used by reverse proxies.

+

Uses headers commonly used by reverse proxies to extract the original IP address, +falling back to the connection’s peer IP address. +https://docs.rs/tower_governor/latest/tower_governor/key_extractor/struct.SmartIpKeyExtractor.html

+

Trait Implementations§

source§

impl Clone for RateLimitConfig

source§

fn clone(&self) -> RateLimitConfig

Returns a copy 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 RateLimitConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for &RateLimitConfig

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Default for RateLimitConfig

source§

fn default() -> RateLimitConfig

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for RateLimitConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for RateLimitConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/index.html b/pr/2992/docs/iroh_dns_server/http/index.html new file mode 100644 index 0000000000..e4411b52ba --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::http - Rust

Module iroh_dns_server::http

source ·
Expand description

HTTP server part of iroh-dns-server

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/rate_limiting/enum.RateLimitConfig.html b/pr/2992/docs/iroh_dns_server/http/rate_limiting/enum.RateLimitConfig.html new file mode 100644 index 0000000000..ca7998fa8f --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/rate_limiting/enum.RateLimitConfig.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_dns_server/http/enum.RateLimitConfig.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/sidebar-items.js b/pr/2992/docs/iroh_dns_server/http/sidebar-items.js new file mode 100644 index 0000000000..c4be435282 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["CertMode","RateLimitConfig"],"struct":["HttpConfig","HttpServer","HttpsConfig"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/struct.HttpConfig.html b/pr/2992/docs/iroh_dns_server/http/struct.HttpConfig.html new file mode 100644 index 0000000000..b72843598c --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/struct.HttpConfig.html @@ -0,0 +1,37 @@ +HttpConfig in iroh_dns_server::http - Rust

Struct iroh_dns_server::http::HttpConfig

source ·
pub struct HttpConfig {
+    pub port: u16,
+    pub bind_addr: Option<IpAddr>,
+}
Expand description

Config for the HTTP server

+

Fields§

§port: u16

Port to bind to

+
§bind_addr: Option<IpAddr>

Optionally set a custom bind address (will use 0.0.0.0 if unset)

+

Trait Implementations§

source§

impl Clone for HttpConfig

source§

fn clone(&self) -> HttpConfig

Returns a copy 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 HttpConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for HttpConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for HttpConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/struct.HttpServer.html b/pr/2992/docs/iroh_dns_server/http/struct.HttpServer.html new file mode 100644 index 0000000000..dc06a55ebd --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/struct.HttpServer.html @@ -0,0 +1,37 @@ +HttpServer in iroh_dns_server::http - Rust

Struct iroh_dns_server::http::HttpServer

source ·
pub struct HttpServer { /* private fields */ }
Expand description

The HTTP(S) server part of iroh-dns-server

+

Implementations§

source§

impl HttpServer

source

pub async fn spawn( + http_config: Option<HttpConfig>, + https_config: Option<HttpsConfig>, + rate_limit_config: RateLimitConfig, + state: AppState +) -> Result<HttpServer>

Spawn the server

+
source

pub fn http_addr(&self) -> Option<SocketAddr>

Get the bound address of the HTTP socket.

+
source

pub fn https_addr(&self) -> Option<SocketAddr>

Get the bound address of the HTTPS socket.

+
source

pub async fn shutdown(self) -> Result<()>

Shutdown the server and wait for all tasks to complete.

+
source

pub async fn run_until_done(self) -> Result<()>

Wait for all tasks to complete.

+

Runs forever unless tasks fail.

+

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/struct.HttpsConfig.html b/pr/2992/docs/iroh_dns_server/http/struct.HttpsConfig.html new file mode 100644 index 0000000000..7b32213acf --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/struct.HttpsConfig.html @@ -0,0 +1,45 @@ +HttpsConfig in iroh_dns_server::http - Rust

Struct iroh_dns_server::http::HttpsConfig

source ·
pub struct HttpsConfig {
+    pub port: u16,
+    pub bind_addr: Option<IpAddr>,
+    pub domains: Vec<String>,
+    pub cert_mode: CertMode,
+    pub letsencrypt_contact: Option<String>,
+    pub letsencrypt_prod: Option<bool>,
+}
Expand description

Config for the HTTPS server

+

Fields§

§port: u16

Port to bind to

+
§bind_addr: Option<IpAddr>

Optionally set a custom bind address (will use 0.0.0.0 if unset)

+
§domains: Vec<String>

The list of domains for which SSL certificates should be created.

+
§cert_mode: CertMode

The mode of SSL certificate creation

+
§letsencrypt_contact: Option<String>

Letsencrypt contact email address (required if using CertMode::LetsEncrypt)

+
§letsencrypt_prod: Option<bool>

Whether to use the letsenrypt production servers (only applies to CertMode::LetsEncrypt)

+

Trait Implementations§

source§

impl Clone for HttpsConfig

source§

fn clone(&self) -> HttpsConfig

Returns a copy 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 HttpsConfig

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for HttpsConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for HttpsConfig

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/http/tls/enum.CertMode.html b/pr/2992/docs/iroh_dns_server/http/tls/enum.CertMode.html new file mode 100644 index 0000000000..80b684956f --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/http/tls/enum.CertMode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_dns_server/http/enum.CertMode.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/index.html b/pr/2992/docs/iroh_dns_server/index.html new file mode 100644 index 0000000000..b3b866029e --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/index.html @@ -0,0 +1,2 @@ +iroh_dns_server - Rust

Crate iroh_dns_server

source ·
Expand description

A DNS server and pkarr relay

+

Modules§

  • Configuration for the server
  • Implementation of a DNS name server for iroh node announces
  • HTTP server part of iroh-dns-server
  • Metrics support for the server
  • The main server which combines the DNS and HTTP(S) servers.
  • Shared state and store for the iroh-dns-server
\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/metrics/fn.init_metrics.html b/pr/2992/docs/iroh_dns_server/metrics/fn.init_metrics.html new file mode 100644 index 0000000000..8c6e3a0b30 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/metrics/fn.init_metrics.html @@ -0,0 +1,2 @@ +init_metrics in iroh_dns_server::metrics - Rust

Function iroh_dns_server::metrics::init_metrics

source ·
pub fn init_metrics()
Expand description

Init the metrics collection core.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/metrics/index.html b/pr/2992/docs/iroh_dns_server/metrics/index.html new file mode 100644 index 0000000000..677a3ec0f0 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/metrics/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::metrics - Rust

Module iroh_dns_server::metrics

source ·
Expand description

Metrics support for the server

+

Structs§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/metrics/sidebar-items.js b/pr/2992/docs/iroh_dns_server/metrics/sidebar-items.js new file mode 100644 index 0000000000..ee7af2d236 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/metrics/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["init_metrics"],"struct":["Metrics"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/metrics/struct.Metrics.html b/pr/2992/docs/iroh_dns_server/metrics/struct.Metrics.html new file mode 100644 index 0000000000..ea324cddca --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/metrics/struct.Metrics.html @@ -0,0 +1,47 @@ +Metrics in iroh_dns_server::metrics - Rust

Struct iroh_dns_server::metrics::Metrics

source ·
pub struct Metrics {
Show 15 fields + pub pkarr_publish_update: Counter, + pub pkarr_publish_noop: Counter, + pub dns_requests: Counter, + pub dns_requests_udp: Counter, + pub dns_requests_https: Counter, + pub dns_lookup_success: Counter, + pub dns_lookup_notfound: Counter, + pub dns_lookup_error: Counter, + pub http_requests: Counter, + pub http_requests_success: Counter, + pub http_requests_error: Counter, + pub http_requests_duration_ms: Counter, + pub store_packets_inserted: Counter, + pub store_packets_removed: Counter, + pub store_packets_updated: Counter, +
}
Expand description

Metrics for iroh-dns-server

+

Fields§

§pkarr_publish_update: Counter§pkarr_publish_noop: Counter§dns_requests: Counter§dns_requests_udp: Counter§dns_requests_https: Counter§dns_lookup_success: Counter§dns_lookup_notfound: Counter§dns_lookup_error: Counter§http_requests: Counter§http_requests_success: Counter§http_requests_error: Counter§http_requests_duration_ms: Counter§store_packets_inserted: Counter§store_packets_removed: Counter§store_packets_updated: Counter

Trait Implementations§

source§

impl Clone for Metrics

source§

fn clone(&self) -> Metrics

Returns a copy 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 Metrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Metrics

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Iterable for Metrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a dyn Any)>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for Metrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/server/fn.run_with_config_until_ctrl_c.html b/pr/2992/docs/iroh_dns_server/server/fn.run_with_config_until_ctrl_c.html new file mode 100644 index 0000000000..e36fc9ae61 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/server/fn.run_with_config_until_ctrl_c.html @@ -0,0 +1,2 @@ +run_with_config_until_ctrl_c in iroh_dns_server::server - Rust
pub async fn run_with_config_until_ctrl_c(config: Config) -> Result<()>
Expand description

Spawn the server and run until the Ctrl-C signal is received, then shutdown.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/server/index.html b/pr/2992/docs/iroh_dns_server/server/index.html new file mode 100644 index 0000000000..283008d431 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/server/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::server - Rust

Module iroh_dns_server::server

source ·
Expand description

The main server which combines the DNS and HTTP(S) servers.

+

Structs§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/server/sidebar-items.js b/pr/2992/docs/iroh_dns_server/server/sidebar-items.js new file mode 100644 index 0000000000..964b9787ae --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/server/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["run_with_config_until_ctrl_c"],"struct":["Server"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/server/struct.Server.html b/pr/2992/docs/iroh_dns_server/server/struct.Server.html new file mode 100644 index 0000000000..a82b428d20 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/server/struct.Server.html @@ -0,0 +1,36 @@ +Server in iroh_dns_server::server - Rust

Struct iroh_dns_server::server::Server

source ·
pub struct Server { /* private fields */ }
Expand description

The iroh-dns server.

+

Implementations§

source§

impl Server

source

pub async fn spawn(config: Config, store: ZoneStore) -> Result<Self>

Spawn the server.

+

This will spawn several background tasks:

+
    +
  • A DNS server task
  • +
  • A HTTP server task, if config.http is not empty
  • +
  • A HTTPS server task, if config.https is not empty
  • +
+
source

pub async fn shutdown(self) -> Result<()>

Cancel the server tasks and wait for all tasks to complete.

+
source

pub async fn run_until_error(self) -> Result<()>

Wait for all tasks to complete.

+

This will run forever unless all tasks close with an error, or Self::cancel is called.

+

Auto Trait Implementations§

§

impl Freeze for Server

§

impl !RefUnwindSafe for Server

§

impl Send for Server

§

impl Sync for Server

§

impl Unpin for Server

§

impl !UnwindSafe for Server

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/sidebar-items.js b/pr/2992/docs/iroh_dns_server/sidebar-items.js new file mode 100644 index 0000000000..e6d9caf5c5 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["config","dns","http","metrics","server","state"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/state/index.html b/pr/2992/docs/iroh_dns_server/state/index.html new file mode 100644 index 0000000000..c30fac77ae --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/state/index.html @@ -0,0 +1,2 @@ +iroh_dns_server::state - Rust

Module iroh_dns_server::state

source ·
Expand description

Shared state and store for the iroh-dns-server

+

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/state/sidebar-items.js b/pr/2992/docs/iroh_dns_server/state/sidebar-items.js new file mode 100644 index 0000000000..1162bf9fb9 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/state/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["AppState"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_dns_server/state/struct.AppState.html b/pr/2992/docs/iroh_dns_server/state/struct.AppState.html new file mode 100644 index 0000000000..95787a0645 --- /dev/null +++ b/pr/2992/docs/iroh_dns_server/state/struct.AppState.html @@ -0,0 +1,34 @@ +AppState in iroh_dns_server::state - Rust

Struct iroh_dns_server::state::AppState

source ·
pub struct AppState {
+    pub store: ZoneStore,
+    pub dns_handler: DnsHandler,
+}
Expand description

The shared app state.

+

Fields§

§store: ZoneStore

The pkarr DNS store

+
§dns_handler: DnsHandler

Handler for DNS requests

+

Trait Implementations§

source§

impl Clone for AppState

source§

fn clone(&self) -> AppState

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. 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> 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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/all.html b/pr/2992/docs/iroh_net_bench/all.html new file mode 100644 index 0000000000..05b4fc06b7 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Functions

Constants

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/enum.Commands.html b/pr/2992/docs/iroh_net_bench/enum.Commands.html new file mode 100644 index 0000000000..6487e54084 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/enum.Commands.html @@ -0,0 +1,51 @@ +Commands in iroh_net_bench - Rust

Enum iroh_net_bench::Commands

source ·
pub enum Commands {
+    Iroh(Opt),
+    Quinn(Opt),
+    S2n(Opt),
+}

Variants§

§

Iroh(Opt)

§

Quinn(Opt)

§

S2n(Opt)

Trait Implementations§

source§

impl Clone for Commands

source§

fn clone(&self) -> Commands

Returns a copy 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 CommandFactory for Commands

source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
source§

impl Debug for Commands

source§

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

Formats the value using the given formatter. Read more
source§

impl FromArgMatches for Commands

source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

fn update_from_arg_matches_mut<'b>( + &mut self, + __clap_arg_matches: &mut ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

impl Parser for Commands

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, return Err on error.
source§

impl Subcommand for Commands

source§

fn augment_subcommands<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
source§

fn augment_subcommands_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
source§

fn has_subcommand(__clap_name: &str) -> bool

Test whether Self can parse a specific subcommand
source§

impl Copy for Commands

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/enum.ConnectionSelector.html b/pr/2992/docs/iroh_net_bench/enum.ConnectionSelector.html new file mode 100644 index 0000000000..5bdb8be7ee --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/enum.ConnectionSelector.html @@ -0,0 +1,29 @@ +ConnectionSelector in iroh_net_bench - Rust

Enum iroh_net_bench::ConnectionSelector

source ·
pub enum ConnectionSelector {
+    Iroh(Connection),
+    Quinn(Connection),
+}

Variants§

§

Iroh(Connection)

§

Quinn(Connection)

Implementations§

source§

impl ConnectionSelector

source

pub fn stats(&self)

source

pub fn close(&self, error_code: u32, reason: &[u8])

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/enum.EndpointSelector.html b/pr/2992/docs/iroh_net_bench/enum.EndpointSelector.html new file mode 100644 index 0000000000..df1b3b9314 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/enum.EndpointSelector.html @@ -0,0 +1,29 @@ +EndpointSelector in iroh_net_bench - Rust

Enum iroh_net_bench::EndpointSelector

source ·
pub enum EndpointSelector {
+    Iroh(Endpoint),
+    Quinn(Endpoint),
+}

Variants§

§

Iroh(Endpoint)

§

Quinn(Endpoint)

Implementations§

source§

impl EndpointSelector

source

pub async fn close(self) -> Result<()>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/fn.client_handler.html b/pr/2992/docs/iroh_net_bench/fn.client_handler.html new file mode 100644 index 0000000000..162b7ec3dc --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/fn.client_handler.html @@ -0,0 +1,6 @@ +client_handler in iroh_net_bench - Rust

Function iroh_net_bench::client_handler

source ·
pub async fn client_handler(
+    endpoint: EndpointSelector,
+    connection: ConnectionSelector,
+    opt: Opt
+) -> Result<ClientStats>
Expand description

Take the provided endpoint and run the client benchmark

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/fn.configure_tracing_subscriber.html b/pr/2992/docs/iroh_net_bench/fn.configure_tracing_subscriber.html new file mode 100644 index 0000000000..cd44acc9c2 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/fn.configure_tracing_subscriber.html @@ -0,0 +1 @@ +configure_tracing_subscriber in iroh_net_bench - Rust

Function iroh_net_bench::configure_tracing_subscriber

source ·
pub fn configure_tracing_subscriber()
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/fn.rt.html b/pr/2992/docs/iroh_net_bench/fn.rt.html new file mode 100644 index 0000000000..506819063e --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/fn.rt.html @@ -0,0 +1 @@ +rt in iroh_net_bench - Rust

Function iroh_net_bench::rt

source ·
pub fn rt() -> Runtime
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/index.html b/pr/2992/docs/iroh_net_bench/index.html new file mode 100644 index 0000000000..3fa17e5531 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/index.html @@ -0,0 +1 @@ +iroh_net_bench - Rust

Crate iroh_net_bench

source ·

Modules§

Structs§

Enums§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/constant.ALPN.html b/pr/2992/docs/iroh_net_bench/iroh/constant.ALPN.html new file mode 100644 index 0000000000..055a5564a7 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/constant.ALPN.html @@ -0,0 +1 @@ +ALPN in iroh_net_bench::iroh - Rust

Constant iroh_net_bench::iroh::ALPN

source ·
pub const ALPN: &[u8] = b"n0/iroh-net-bench/0";
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.client.html b/pr/2992/docs/iroh_net_bench/iroh/fn.client.html new file mode 100644 index 0000000000..adb2c91d7e --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.client.html @@ -0,0 +1,6 @@ +client in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::client

source ·
pub async fn client(
+    server_addr: NodeAddr,
+    relay_url: Option<RelayUrl>,
+    opt: Opt
+) -> Result<ClientStats>
Expand description

Create and run a client

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.connect_client.html b/pr/2992/docs/iroh_net_bench/iroh/fn.connect_client.html new file mode 100644 index 0000000000..3984b70c8b --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.connect_client.html @@ -0,0 +1,6 @@ +connect_client in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::connect_client

source ·
pub async fn connect_client(
+    server_addr: NodeAddr,
+    relay_url: Option<RelayUrl>,
+    opt: Opt
+) -> Result<(Endpoint, Connection)>
Expand description

Create a client endpoint and client connection

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.handle_client_stream.html b/pr/2992/docs/iroh_net_bench/iroh/fn.handle_client_stream.html new file mode 100644 index 0000000000..dcb0eeb350 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.handle_client_stream.html @@ -0,0 +1,5 @@ +handle_client_stream in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::handle_client_stream

source ·
pub async fn handle_client_stream(
+    connection: &Connection,
+    upload_size: u64,
+    read_unordered: bool
+) -> Result<(TransferResult, TransferResult)>
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.server.html b/pr/2992/docs/iroh_net_bench/iroh/fn.server.html new file mode 100644 index 0000000000..438cd1b8a4 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.server.html @@ -0,0 +1,2 @@ +server in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::server

source ·
pub async fn server(endpoint: Endpoint, opt: Opt) -> Result<()>
Expand description

Take the provided endpoint and run the server

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.server_endpoint.html b/pr/2992/docs/iroh_net_bench/iroh/fn.server_endpoint.html new file mode 100644 index 0000000000..19729e6cd0 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.server_endpoint.html @@ -0,0 +1,6 @@ +server_endpoint in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::server_endpoint

source ·
pub fn server_endpoint(
+    rt: &Runtime,
+    relay_url: &Option<RelayUrl>,
+    opt: &Opt
+) -> (NodeAddr, Endpoint)
Expand description

Creates a server endpoint which runs on the given runtime

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/fn.transport_config.html b/pr/2992/docs/iroh_net_bench/iroh/fn.transport_config.html new file mode 100644 index 0000000000..9792f751d4 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/fn.transport_config.html @@ -0,0 +1 @@ +transport_config in iroh_net_bench::iroh - Rust

Function iroh_net_bench::iroh::transport_config

source ·
pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/index.html b/pr/2992/docs/iroh_net_bench/iroh/index.html new file mode 100644 index 0000000000..3e31b65f5d --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/index.html @@ -0,0 +1 @@ +iroh_net_bench::iroh - Rust

Module iroh_net_bench::iroh

source ·

Constants§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/iroh/sidebar-items.js b/pr/2992/docs/iroh_net_bench/iroh/sidebar-items.js new file mode 100644 index 0000000000..a0622c160a --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/iroh/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["ALPN"],"fn":["client","connect_client","handle_client_stream","server","server_endpoint","transport_config"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/constant.ALPN.html b/pr/2992/docs/iroh_net_bench/quinn/constant.ALPN.html new file mode 100644 index 0000000000..344da53c39 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/constant.ALPN.html @@ -0,0 +1 @@ +ALPN in iroh_net_bench::quinn - Rust

Constant iroh_net_bench::quinn::ALPN

source ·
pub const ALPN: &[u8] = b"n0/quinn-bench/0";
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.client.html b/pr/2992/docs/iroh_net_bench/quinn/fn.client.html new file mode 100644 index 0000000000..b6f535a8da --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.client.html @@ -0,0 +1,2 @@ +client in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::client

source ·
pub async fn client(server_addr: SocketAddr, opt: Opt) -> Result<ClientStats>
Expand description

Create and run a client

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.connect_client.html b/pr/2992/docs/iroh_net_bench/quinn/fn.connect_client.html new file mode 100644 index 0000000000..b55ec3afaa --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.connect_client.html @@ -0,0 +1,5 @@ +connect_client in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::connect_client

source ·
pub async fn connect_client(
+    server_addr: SocketAddr,
+    opt: Opt
+) -> Result<(Endpoint, Connection)>
Expand description

Create a client endpoint and client connection

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.handle_client_stream.html b/pr/2992/docs/iroh_net_bench/quinn/fn.handle_client_stream.html new file mode 100644 index 0000000000..840fd3e8f4 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.handle_client_stream.html @@ -0,0 +1,5 @@ +handle_client_stream in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::handle_client_stream

source ·
pub async fn handle_client_stream(
+    connection: &Connection,
+    upload_size: u64,
+    read_unordered: bool
+) -> Result<(TransferResult, TransferResult)>
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.server.html b/pr/2992/docs/iroh_net_bench/quinn/fn.server.html new file mode 100644 index 0000000000..4eda1858bd --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.server.html @@ -0,0 +1,2 @@ +server in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::server

source ·
pub async fn server(endpoint: Endpoint, opt: Opt) -> Result<()>
Expand description

Take the provided endpoint and run the server

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.server_endpoint.html b/pr/2992/docs/iroh_net_bench/quinn/fn.server_endpoint.html new file mode 100644 index 0000000000..4212172c01 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.server_endpoint.html @@ -0,0 +1,2 @@ +server_endpoint in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::server_endpoint

source ·
pub fn server_endpoint(rt: &Runtime, opt: &Opt) -> (SocketAddr, Endpoint)
Expand description

Creates a server endpoint which runs on the given runtime

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/fn.transport_config.html b/pr/2992/docs/iroh_net_bench/quinn/fn.transport_config.html new file mode 100644 index 0000000000..32adf1d517 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/fn.transport_config.html @@ -0,0 +1 @@ +transport_config in iroh_net_bench::quinn - Rust

Function iroh_net_bench::quinn::transport_config

source ·
pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/index.html b/pr/2992/docs/iroh_net_bench/quinn/index.html new file mode 100644 index 0000000000..4ed58999f9 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/index.html @@ -0,0 +1 @@ +iroh_net_bench::quinn - Rust

Module iroh_net_bench::quinn

source ·

Constants§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/quinn/sidebar-items.js b/pr/2992/docs/iroh_net_bench/quinn/sidebar-items.js new file mode 100644 index 0000000000..a0622c160a --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/quinn/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["ALPN"],"fn":["client","connect_client","handle_client_stream","server","server_endpoint","transport_config"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/s2n/index.html b/pr/2992/docs/iroh_net_bench/s2n/index.html new file mode 100644 index 0000000000..e6493559fc --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/s2n/index.html @@ -0,0 +1 @@ +iroh_net_bench::s2n - Rust

Module iroh_net_bench::s2n

source ·

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/s2n/sidebar-items.js b/pr/2992/docs/iroh_net_bench/s2n/sidebar-items.js new file mode 100644 index 0000000000..721e637cb7 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/s2n/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["Opt"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/s2n/struct.Opt.html b/pr/2992/docs/iroh_net_bench/s2n/struct.Opt.html new file mode 100644 index 0000000000..25a8ab9462 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/s2n/struct.Opt.html @@ -0,0 +1,47 @@ +Opt in iroh_net_bench::s2n - Rust

Struct iroh_net_bench::s2n::Opt

source ·
pub struct Opt {}

Trait Implementations§

source§

impl Args for Opt

source§

fn group_id() -> Option<Id>

Report the [ArgGroup::id][crate::ArgGroup::id] for this set of arguments
source§

fn augment_args<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
source§

fn augment_args_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
source§

impl Clone for Opt

source§

fn clone(&self) -> Opt

Returns a copy 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 CommandFactory for Opt

source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
source§

impl Debug for Opt

source§

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

Formats the value using the given formatter. Read more
source§

impl FromArgMatches for Opt

source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

fn update_from_arg_matches_mut( + &mut self, + __clap_arg_matches: &mut ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

impl Parser for Opt

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, return Err on error.
source§

impl Copy for Opt

Auto Trait Implementations§

§

impl Freeze for Opt

§

impl RefUnwindSafe for Opt

§

impl Send for Opt

§

impl Sync for Opt

§

impl Unpin for Opt

§

impl UnwindSafe for Opt

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/sidebar-items.js b/pr/2992/docs/iroh_net_bench/sidebar-items.js new file mode 100644 index 0000000000..b9813775f8 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Commands","ConnectionSelector","EndpointSelector"],"fn":["client_handler","configure_tracing_subscriber","rt"],"mod":["iroh","quinn","s2n","stats"],"struct":["ClientStats","Opt"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/fn.throughput_bps.html b/pr/2992/docs/iroh_net_bench/stats/fn.throughput_bps.html new file mode 100644 index 0000000000..9072a24e37 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/fn.throughput_bps.html @@ -0,0 +1 @@ +throughput_bps in iroh_net_bench::stats - Rust

Function iroh_net_bench::stats::throughput_bps

source ·
pub fn throughput_bps(duration: Duration, size: u64) -> f64
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/index.html b/pr/2992/docs/iroh_net_bench/stats/index.html new file mode 100644 index 0000000000..991c5b9584 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/index.html @@ -0,0 +1 @@ +iroh_net_bench::stats - Rust

Module iroh_net_bench::stats

source ·

Structs§

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/sidebar-items.js b/pr/2992/docs/iroh_net_bench/stats/sidebar-items.js new file mode 100644 index 0000000000..6272a13ae8 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["throughput_bps"],"struct":["Stats","StreamStats","TransferResult"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/struct.Stats.html b/pr/2992/docs/iroh_net_bench/stats/struct.Stats.html new file mode 100644 index 0000000000..f0b47220c1 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/struct.Stats.html @@ -0,0 +1,31 @@ +Stats in iroh_net_bench::stats - Rust

Struct iroh_net_bench::stats::Stats

source ·
pub struct Stats {
+    pub total_size: u64,
+    pub total_duration: Duration,
+    pub streams: usize,
+    pub stream_stats: StreamStats,
+}

Fields§

§total_size: u64§total_duration: Duration§streams: usize§stream_stats: StreamStats

Implementations§

source§

impl Stats

source

pub fn stream_finished(&mut self, stream_result: TransferResult)

source

pub fn print(&self, stat_name: &str)

Trait Implementations§

source§

impl Debug for Stats

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Stats

source§

fn default() -> Stats

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Stats

§

impl RefUnwindSafe for Stats

§

impl Send for Stats

§

impl Sync for Stats

§

impl Unpin for Stats

§

impl UnwindSafe for Stats

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/struct.StreamStats.html b/pr/2992/docs/iroh_net_bench/stats/struct.StreamStats.html new file mode 100644 index 0000000000..f07ec633de --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/struct.StreamStats.html @@ -0,0 +1,33 @@ +StreamStats in iroh_net_bench::stats - Rust

Struct iroh_net_bench::stats::StreamStats

source ·
pub struct StreamStats {
+    pub duration_hist: Histogram<u64>,
+    pub throughput_hist: Histogram<u64>,
+    pub ttfb_hist: Histogram<u64>,
+    pub chunk_time: Histogram<u64>,
+    pub chunks: u64,
+    pub chunk_size: Histogram<u64>,
+}

Fields§

§duration_hist: Histogram<u64>§throughput_hist: Histogram<u64>§ttfb_hist: Histogram<u64>§chunk_time: Histogram<u64>§chunks: u64§chunk_size: Histogram<u64>

Trait Implementations§

source§

impl Debug for StreamStats

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for StreamStats

source§

fn default() -> Self

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/stats/struct.TransferResult.html b/pr/2992/docs/iroh_net_bench/stats/struct.TransferResult.html new file mode 100644 index 0000000000..367d7492e3 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/stats/struct.TransferResult.html @@ -0,0 +1,33 @@ +TransferResult in iroh_net_bench::stats - Rust

Struct iroh_net_bench::stats::TransferResult

source ·
pub struct TransferResult {
+    pub duration: Duration,
+    pub size: u64,
+    pub throughput: f64,
+    pub ttfb: Duration,
+    pub chunks: u64,
+    pub avg_chunk_size: u64,
+}

Fields§

§duration: Duration§size: u64§throughput: f64§ttfb: Duration§chunks: u64§avg_chunk_size: u64

Implementations§

source§

impl TransferResult

source

pub fn new(duration: Duration, size: u64, ttfb: Duration, chunks: u64) -> Self

Trait Implementations§

source§

impl Debug for TransferResult

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/struct.ClientStats.html b/pr/2992/docs/iroh_net_bench/struct.ClientStats.html new file mode 100644 index 0000000000..c154dfc1b8 --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/struct.ClientStats.html @@ -0,0 +1,26 @@ +ClientStats in iroh_net_bench - Rust

Struct iroh_net_bench::ClientStats

source ·
pub struct ClientStats { /* private fields */ }

Implementations§

source§

impl ClientStats

source

pub fn print(&self, client_id: usize)

Trait Implementations§

source§

impl Default for ClientStats

source§

fn default() -> ClientStats

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_bench/struct.Opt.html b/pr/2992/docs/iroh_net_bench/struct.Opt.html new file mode 100644 index 0000000000..1327a8835a --- /dev/null +++ b/pr/2992/docs/iroh_net_bench/struct.Opt.html @@ -0,0 +1,77 @@ +Opt in iroh_net_bench - Rust

Struct iroh_net_bench::Opt

source ·
pub struct Opt {
+    pub clients: usize,
+    pub streams: usize,
+    pub max_streams: usize,
+    pub download_size: u64,
+    pub upload_size: u64,
+    pub stats: bool,
+    pub metrics: bool,
+    pub read_unordered: bool,
+    pub initial_mtu: u16,
+    pub with_relay: bool,
+}

Fields§

§clients: usize

The total number of clients which should be created

+
§streams: usize

The total number of streams which should be created

+
§max_streams: usize

The amount of concurrent streams which should be used

+
§download_size: u64

Number of bytes to transmit from server to client

+

This can use SI prefixes for sizes. E.g. 1M will transfer 1MiB, 10G +will transfer 10GiB.

+
§upload_size: u64

Number of bytes to transmit from client to server

+

This can use SI prefixes for sizes. E.g. 1M will transfer 1MiB, 10G +will transfer 10GiB.

+
§stats: bool

Show connection stats the at the end of the benchmark

+
§metrics: bool

Show iroh library counter metrics at the end of the benchmark

+

These metrics are process-wide, so contain metrics for +clients and the server all summed up.

+
§read_unordered: bool

Whether to use the unordered read API

+
§initial_mtu: u16

Starting guess for maximum UDP payload size

+
§with_relay: bool

Whether to run a local relay and have the server and clients connect to that.

+

Can be combined with the DEV_RELAY_ONLY environment variable (at compile time) +to test throughput for relay-only traffic locally. +(e.g. DEV_RELAY_ONLY=true cargo run --release -- iroh --with-relay)

+

Trait Implementations§

source§

impl Args for Opt

source§

fn group_id() -> Option<Id>

Report the [ArgGroup::id][crate::ArgGroup::id] for this set of arguments
source§

fn augment_args<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
source§

fn augment_args_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
source§

impl Clone for Opt

source§

fn clone(&self) -> Opt

Returns a copy 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 CommandFactory for Opt

source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
source§

impl Debug for Opt

source§

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

Formats the value using the given formatter. Read more
source§

impl FromArgMatches for Opt

source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

fn update_from_arg_matches_mut( + &mut self, + __clap_arg_matches: &mut ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

impl Parser for Opt

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, return Err on error.
source§

impl Copy for Opt

Auto Trait Implementations§

§

impl Freeze for Opt

§

impl RefUnwindSafe for Opt

§

impl Send for Opt

§

impl Sync for Opt

§

impl Unpin for Opt

§

impl UnwindSafe for Opt

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/all.html b/pr/2992/docs/iroh_net_report/all.html new file mode 100644 index 0000000000..42cf9c78b8 --- /dev/null +++ b/pr/2992/docs/iroh_net_report/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Functions

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/fn.os_has_ipv6.html b/pr/2992/docs/iroh_net_report/fn.os_has_ipv6.html new file mode 100644 index 0000000000..6adf09d15a --- /dev/null +++ b/pr/2992/docs/iroh_net_report/fn.os_has_ipv6.html @@ -0,0 +1,2 @@ +os_has_ipv6 in iroh_net_report - Rust

Function iroh_net_report::os_has_ipv6

source ·
pub fn os_has_ipv6() -> bool
Expand description

Test if IPv6 works at all, or if it’s been hard disabled at the OS level.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/index.html b/pr/2992/docs/iroh_net_report/index.html new file mode 100644 index 0000000000..2d8c975a2f --- /dev/null +++ b/pr/2992/docs/iroh_net_report/index.html @@ -0,0 +1,5 @@ +iroh_net_report - Rust

Crate iroh_net_report

source ·
Expand description

Checks the network conditions from the current host.

+

NetReport is responsible for finding out the network conditions of the current host, like +whether it is connected to the internet via IPv4 and/or IPv6, what the NAT situation is +etc and reachability to the configured relays.

+

Structs§

Functions§

  • Test if IPv6 works at all, or if it’s been hard disabled at the OS level.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/metrics/struct.Metrics.html b/pr/2992/docs/iroh_net_report/metrics/struct.Metrics.html new file mode 100644 index 0000000000..5241104711 --- /dev/null +++ b/pr/2992/docs/iroh_net_report/metrics/struct.Metrics.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../iroh_net_report/struct.Metrics.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/sidebar-items.js b/pr/2992/docs/iroh_net_report/sidebar-items.js new file mode 100644 index 0000000000..141debba2d --- /dev/null +++ b/pr/2992/docs/iroh_net_report/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["os_has_ipv6"],"struct":["Addr","Client","Metrics","RelayLatencies","Report"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/struct.Addr.html b/pr/2992/docs/iroh_net_report/struct.Addr.html new file mode 100644 index 0000000000..cc15aae8fd --- /dev/null +++ b/pr/2992/docs/iroh_net_report/struct.Addr.html @@ -0,0 +1,39 @@ +Addr in iroh_net_report - Rust

Struct iroh_net_report::Addr

source ·
pub struct Addr { /* private fields */ }
Expand description

Sender to the main service.

+

Unlike Client this is the raw channel to send messages over. Keeping this alive +will not keep the actor alive, which makes this handy to pass to internal tasks.

+

Implementations§

source§

impl Addr

source

pub fn receive_stun_packet(&self, payload: Bytes, src: SocketAddr)

Pass a received STUN packet to the net_reporter.

+

Normally the UDP sockets to send STUN messages from are passed in so that STUN +packets are sent from the sockets that carry the real traffic. However because +these sockets carry real traffic they will also receive non-STUN traffic, thus the +net_report actor does not read from the sockets directly. If you receive a STUN +packet on the socket you should pass it to this method.

+

It is safe to call this even when the net_report actor does not currently have any +in-flight STUN probes. The actor will simply ignore any stray STUN packets.

+

There is an implicit queue here which may drop packets if the actor does not keep up +consuming them.

+

Trait Implementations§

source§

impl Clone for Addr

source§

fn clone(&self) -> Addr

Returns a copy 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 Addr

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Addr

§

impl RefUnwindSafe for Addr

§

impl Send for Addr

§

impl Sync for Addr

§

impl Unpin for Addr

§

impl UnwindSafe for Addr

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/struct.Client.html b/pr/2992/docs/iroh_net_report/struct.Client.html new file mode 100644 index 0000000000..170e05e4a4 --- /dev/null +++ b/pr/2992/docs/iroh_net_report/struct.Client.html @@ -0,0 +1,62 @@ +Client in iroh_net_report - Rust

Struct iroh_net_report::Client

source ·
pub struct Client { /* private fields */ }
Expand description

Client to run net_reports.

+

Creating this creates a net_report actor which runs in the background. Most of the time +it is idle unless Client::get_report is called, which is the main interface.

+

The Client struct can be cloned and results multiple handles to the running actor. +If all Clients are dropped the actor stops running.

+

While running the net_report actor expects to be passed all received stun packets using +Addr::receive_stun_packet.

+

Implementations§

source§

impl Client

source

pub fn new( + port_mapper: Option<Client>, + dns_resolver: DnsResolver +) -> Result<Self>

Creates a new net_report client.

+

This starts a connected actor in the background. Once the client is dropped it will +stop running.

+
source

pub fn addr(&self) -> Addr

Returns a new address to send messages to this actor.

+

Unlike the client itself the returned Addr does not own the actor task, it only +allows sending messages to the actor.

+
source

pub async fn get_report( + &mut self, + dm: RelayMap, + stun_conn4: Option<Arc<UdpSocket>>, + stun_conn6: Option<Arc<UdpSocket>> +) -> Result<Arc<Report>>

Runs a net_report, returning the report.

+

It may not be called concurrently with itself, &mut self takes care of that.

+

The stun_conn4 and stun_conn6 endpoints are bound UDP sockets to use to send out +STUN packets. This function will not read from the sockets, as they may be +receiving other traffic as well, normally they are the sockets carrying the real +traffic. Thus all stun packets received on those sockets should be passed to +Addr::receive_stun_packet in order for this function to receive the stun +responses and function correctly.

+

If these are not passed in this will bind sockets for STUN itself, though results +may not be as reliable.

+
source

pub async fn get_report_channel( + &mut self, + dm: RelayMap, + stun_conn4: Option<Arc<UdpSocket>>, + stun_conn6: Option<Arc<UdpSocket>> +) -> Result<Receiver<Result<Arc<Report>>>>

Get report with channel

+

Trait Implementations§

source§

impl Debug for Client

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Client

§

impl RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl UnwindSafe for Client

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/struct.Metrics.html b/pr/2992/docs/iroh_net_report/struct.Metrics.html new file mode 100644 index 0000000000..2d7473446b --- /dev/null +++ b/pr/2992/docs/iroh_net_report/struct.Metrics.html @@ -0,0 +1,37 @@ +Metrics in iroh_net_report - Rust

Struct iroh_net_report::Metrics

source ·
pub struct Metrics {
+    pub stun_packets_dropped: Counter,
+    pub stun_packets_sent_ipv4: Counter,
+    pub stun_packets_sent_ipv6: Counter,
+    pub stun_packets_recv_ipv4: Counter,
+    pub stun_packets_recv_ipv6: Counter,
+    pub reports: Counter,
+    pub reports_full: Counter,
+}
Expand description

Enum of metrics for the module

+

Fields§

§stun_packets_dropped: Counter§stun_packets_sent_ipv4: Counter§stun_packets_sent_ipv6: Counter§stun_packets_recv_ipv4: Counter§stun_packets_recv_ipv6: Counter§reports: Counter§reports_full: Counter

Trait Implementations§

source§

impl Clone for Metrics

source§

fn clone(&self) -> Metrics

Returns a copy 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 Metrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Metrics

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Iterable for Metrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a dyn Any)>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for Metrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/struct.RelayLatencies.html b/pr/2992/docs/iroh_net_report/struct.RelayLatencies.html new file mode 100644 index 0000000000..6362707079 --- /dev/null +++ b/pr/2992/docs/iroh_net_report/struct.RelayLatencies.html @@ -0,0 +1,34 @@ +RelayLatencies in iroh_net_report - Rust

Struct iroh_net_report::RelayLatencies

source ·
pub struct RelayLatencies(/* private fields */);
Expand description

Latencies per relay node.

+

Implementations§

source§

impl RelayLatencies

source

pub fn iter(&self) -> impl Iterator<Item = (&RelayUrl, Duration)> + '_

Returns an iterator over all the relays and their latencies.

+

Trait Implementations§

source§

impl Clone for RelayLatencies

source§

fn clone(&self) -> RelayLatencies

Returns a copy 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 RelayLatencies

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for RelayLatencies

source§

fn default() -> RelayLatencies

Returns the “default value” for a type. Read more
source§

impl PartialEq for RelayLatencies

source§

fn eq(&self, other: &RelayLatencies) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RelayLatencies

source§

impl StructuralPartialEq for RelayLatencies

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_net_report/struct.Report.html b/pr/2992/docs/iroh_net_report/struct.Report.html new file mode 100644 index 0000000000..eaac5907ae --- /dev/null +++ b/pr/2992/docs/iroh_net_report/struct.Report.html @@ -0,0 +1,78 @@ +Report in iroh_net_report - Rust

Struct iroh_net_report::Report

source ·
pub struct Report {
Show 19 fields + pub udp: bool, + pub ipv6: bool, + pub ipv4: bool, + pub ipv6_can_send: bool, + pub ipv4_can_send: bool, + pub os_has_ipv6: bool, + pub icmpv4: Option<bool>, + pub icmpv6: Option<bool>, + pub mapping_varies_by_dest_ip: Option<bool>, + pub mapping_varies_by_dest_ipv6: Option<bool>, + pub hair_pinning: Option<bool>, + pub portmap_probe: Option<ProbeOutput>, + pub preferred_relay: Option<RelayUrl>, + pub relay_latency: RelayLatencies, + pub relay_v4_latency: RelayLatencies, + pub relay_v6_latency: RelayLatencies, + pub global_v4: Option<SocketAddrV4>, + pub global_v6: Option<SocketAddrV6>, + pub captive_portal: Option<bool>, +
}
Expand description

A net_report report.

+

Can be obtained by calling Client::get_report.

+

Fields§

§udp: bool

A UDP STUN round trip completed.

+
§ipv6: bool

An IPv6 STUN round trip completed.

+
§ipv4: bool

An IPv4 STUN round trip completed.

+
§ipv6_can_send: bool

An IPv6 packet was able to be sent

+
§ipv4_can_send: bool

an IPv4 packet was able to be sent

+
§os_has_ipv6: bool

could bind a socket to ::1

+
§icmpv4: Option<bool>

An ICMPv4 round trip completed, None if not checked.

+
§icmpv6: Option<bool>

An ICMPv6 round trip completed, None if not checked.

+
§mapping_varies_by_dest_ip: Option<bool>

Whether STUN results depend on which STUN server you’re talking to (on IPv4).

+
§mapping_varies_by_dest_ipv6: Option<bool>

Whether STUN results depend on which STUN server you’re talking to (on IPv6).

+

Note that we don’t really expect this to happen and are merely logging this if +detecting rather than using it. For now.

+
§hair_pinning: Option<bool>

Whether the router supports communicating between two local devices through the NATted +public IP address (on IPv4).

+
§portmap_probe: Option<ProbeOutput>

Probe indicating the presence of port mapping protocols on the LAN.

+
§preferred_relay: Option<RelayUrl>

None for unknown

+
§relay_latency: RelayLatencies

keyed by relay Url

+
§relay_v4_latency: RelayLatencies

keyed by relay Url

+
§relay_v6_latency: RelayLatencies

keyed by relay Url

+
§global_v4: Option<SocketAddrV4>

ip:port of global IPv4

+
§global_v6: Option<SocketAddrV6>

[ip]:port of global IPv6

+
§captive_portal: Option<bool>

CaptivePortal is set when we think there’s a captive portal that is +intercepting HTTP traffic.

+

Trait Implementations§

source§

impl Clone for Report

source§

fn clone(&self) -> Report

Returns a copy 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 Report

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Report

source§

fn default() -> Report

Returns the “default value” for a type. Read more
source§

impl Display for Report

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for Report

source§

fn eq(&self, other: &Report) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for Report

source§

impl StructuralPartialEq for Report

Auto Trait Implementations§

§

impl Freeze for Report

§

impl RefUnwindSafe for Report

§

impl Send for Report

§

impl Sync for Report

§

impl Unpin for Report

§

impl UnwindSafe for Report

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/all.html b/pr/2992/docs/iroh_node_util/all.html new file mode 100644 index 0000000000..1ff33f8196 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Traits

Functions

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/index.html b/pr/2992/docs/iroh_node_util/cli/index.html new file mode 100644 index 0000000000..dea8b60d7c --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/index.html @@ -0,0 +1,2 @@ +iroh_node_util::cli - Rust

Module iroh_node_util::cli

source ·
Available on crate feature cli only.
Expand description

Cli commands.

+

Modules§

  • Define the net subcommands.
  • Node commands
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/net/enum.NetCommands.html b/pr/2992/docs/iroh_node_util/cli/net/enum.NetCommands.html new file mode 100644 index 0000000000..46c7f8fa30 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/net/enum.NetCommands.html @@ -0,0 +1,58 @@ +NetCommands in iroh_node_util::cli::net - Rust

Enum iroh_node_util::cli::net::NetCommands

source ·
pub enum NetCommands {
+    RemoteList,
+    Remote {
+        node_id: NodeId,
+    },
+    NodeAddr,
+    AddNodeAddr {
+        node_id: NodeId,
+        relay: Option<RelayUrl>,
+        addresses: Vec<SocketAddr>,
+    },
+    HomeRelay,
+}
Available on crate feature cli only.
Expand description

Commands to manage the iroh network.

+

Variants§

§

RemoteList

Get information about the different remote nodes.

+
§

Remote

Get information about a particular remote node.

+

Fields

§node_id: NodeId
§

NodeAddr

Get the node addr of this node.

+
§

AddNodeAddr

Add this node addr to the known nodes.

+

Fields

§node_id: NodeId
§relay: Option<RelayUrl>
§addresses: Vec<SocketAddr>
§

HomeRelay

Get the relay server we are connected to.

+

Implementations§

source§

impl NetCommands

source

pub async fn run(self, client: &Client) -> Result<()>

Runs the net command given the iroh client.

+

Trait Implementations§

source§

impl Clone for NetCommands

source§

fn clone(&self) -> NetCommands

Returns a copy 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 NetCommands

source§

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

Formats the value using the given formatter. Read more
source§

impl FromArgMatches for NetCommands

source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

fn update_from_arg_matches_mut<'b>( + &mut self, + __clap_arg_matches: &mut ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

impl Subcommand for NetCommands

source§

fn augment_subcommands<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
source§

fn augment_subcommands_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
source§

fn has_subcommand(__clap_name: &str) -> bool

Test whether Self can parse a specific subcommand

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/net/index.html b/pr/2992/docs/iroh_node_util/cli/net/index.html new file mode 100644 index 0000000000..411f566060 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/net/index.html @@ -0,0 +1,2 @@ +iroh_node_util::cli::net - Rust

Module iroh_node_util::cli::net

source ·
Available on crate feature cli only.
Expand description

Define the net subcommands.

+

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/net/sidebar-items.js b/pr/2992/docs/iroh_node_util/cli/net/sidebar-items.js new file mode 100644 index 0000000000..bd8d47f801 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/net/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["NetCommands"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/node/enum.NodeCommands.html b/pr/2992/docs/iroh_node_util/cli/node/enum.NodeCommands.html new file mode 100644 index 0000000000..983a28aab8 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/node/enum.NodeCommands.html @@ -0,0 +1,53 @@ +NodeCommands in iroh_node_util::cli::node - Rust

Enum iroh_node_util::cli::node::NodeCommands

source ·
pub enum NodeCommands {
+    Stats,
+    Status,
+    Shutdown {
+        force: bool,
+    },
+}
Available on crate feature cli only.
Expand description

Commands to manage the iroh RPC.

+

Variants§

§

Stats

Get statistics and metrics from the running node.

+
§

Status

Get status of the running node.

+
§

Shutdown

Shutdown the running node.

+

Fields

§force: bool

Shutdown mode.

+

Hard shutdown will immediately terminate the process, soft shutdown will wait +for all connections to close.

+

Implementations§

source§

impl NodeCommands

source

pub async fn run(self, node: &Client) -> Result<()>

Run the RPC command given the iroh client and the console environment.

+

Trait Implementations§

source§

impl Clone for NodeCommands

source§

fn clone(&self) -> NodeCommands

Returns a copy 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 NodeCommands

source§

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

Formats the value using the given formatter. Read more
source§

impl FromArgMatches for NodeCommands

source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

fn update_from_arg_matches_mut<'b>( + &mut self, + __clap_arg_matches: &mut ArgMatches +) -> Result<(), Error>

Assign values from ArgMatches to self.
source§

impl Subcommand for NodeCommands

source§

fn augment_subcommands<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
source§

fn augment_subcommands_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
source§

fn has_subcommand(__clap_name: &str) -> bool

Test whether Self can parse a specific subcommand

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/node/index.html b/pr/2992/docs/iroh_node_util/cli/node/index.html new file mode 100644 index 0000000000..a39aaefdea --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/node/index.html @@ -0,0 +1,2 @@ +iroh_node_util::cli::node - Rust

Module iroh_node_util::cli::node

source ·
Available on crate feature cli only.
Expand description

Node commands

+

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/node/sidebar-items.js b/pr/2992/docs/iroh_node_util/cli/node/sidebar-items.js new file mode 100644 index 0000000000..522fe70ae0 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/node/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["NodeCommands"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/cli/sidebar-items.js b/pr/2992/docs/iroh_node_util/cli/sidebar-items.js new file mode 100644 index 0000000000..b87a41d035 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/cli/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["net","node"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/config/fn.cache_root.html b/pr/2992/docs/iroh_node_util/config/fn.cache_root.html new file mode 100644 index 0000000000..591b064f38 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/config/fn.cache_root.html @@ -0,0 +1,14 @@ +cache_root in iroh_node_util::config - Rust

Function iroh_node_util::config::cache_root

source ·
pub fn cache_root(bin: &'static str) -> Result<PathBuf>
Available on crate feature config only.
Expand description

Returns the path to the user’s cache directory for the given binary.

+

This is determined by the following steps:

+
    +
  • If the environment variable <BIN>_CACHE_DIR is set, return that.
  • +
  • If the operating environment provides a cache directory, return $CACHE_DIR/<bin>.
  • +
  • Otherwise, return an error.
  • +
+

The default directories are as follows:

+
+ + + +
PlatformValueExample
Linux$XDG_CACHE_HOME/iroh or $HOME/.cache/iroh/home/.cache/iroh
macOS$HOME/Library/Caches/iroh/Users/Alice/Library/Caches/iroh
Windows{FOLDERID_LocalAppData}/irohC:\Users\Alice\AppData\Roaming\iroh
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/config/fn.config_root.html b/pr/2992/docs/iroh_node_util/config/fn.config_root.html new file mode 100644 index 0000000000..3127e421d8 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/config/fn.config_root.html @@ -0,0 +1,14 @@ +config_root in iroh_node_util::config - Rust

Function iroh_node_util::config::config_root

source ·
pub fn config_root(bin: &'static str) -> Result<PathBuf>
Available on crate feature config only.
Expand description

Returns the path to the user’s config directory for the given binary.

+

This is determined by the following steps:

+
    +
  • If the environment variable <BIN>_CONFIG_DIR is set, return that.
  • +
  • If the operating environment provides a config directory, return $CONFIG_DIR/<bin>.
  • +
  • Otherwise, return an error.
  • +
+

The default directories are as follows:

+
+ + + +
PlatformValueExample
Linux$XDG_CONFIG_HOME or $HOME/.config/iroh/home/alice/.config/iroh
macOS$HOME/Library/Application Support/iroh/Users/Alice/Library/Application Support/iroh
Windows{FOLDERID_RoamingAppData}/irohC:\Users\Alice\AppData\Roaming\iroh
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/config/fn.data_root.html b/pr/2992/docs/iroh_node_util/config/fn.data_root.html new file mode 100644 index 0000000000..b5e6ad5ed5 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/config/fn.data_root.html @@ -0,0 +1,14 @@ +data_root in iroh_node_util::config - Rust

Function iroh_node_util::config::data_root

source ·
pub fn data_root(bin: &'static str) -> Result<PathBuf>
Available on crate feature config only.
Expand description

Returns the path to the user’s data directory for the given binary.

+

This is determined by the following steps:

+
    +
  • If the environment variable <BIN>_DATA_DIR is set, return that.
  • +
  • If the operating environment provides a data directory, return $DATA_DIR/<bin>.
  • +
  • Otherwise, return an error.
  • +
+

The default directories are as follows:

+
+ + + +
PlatformValueExample
Linux$XDG_DATA_HOME/iroh or $HOME/.local/share/iroh/home/alice/.local/share/iroh
macOS$HOME/Library/Application Support/iroh/Users/Alice/Library/Application Support/iroh
Windows{FOLDERID_RoamingAppData}/irohC:\Users\Alice\AppData\Roaming\iroh
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/config/index.html b/pr/2992/docs/iroh_node_util/config/index.html new file mode 100644 index 0000000000..7575e93e21 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/config/index.html @@ -0,0 +1,2 @@ +iroh_node_util::config - Rust

Module iroh_node_util::config

source ·
Available on crate feature config only.
Expand description

Utilities to get default paths for configuration, data, and cache directories.

+

Functions§

  • Returns the path to the user’s cache directory for the given binary.
  • Returns the path to the user’s config directory for the given binary.
  • Returns the path to the user’s data directory for the given binary.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/config/sidebar-items.js b/pr/2992/docs/iroh_node_util/config/sidebar-items.js new file mode 100644 index 0000000000..c9213bac4f --- /dev/null +++ b/pr/2992/docs/iroh_node_util/config/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["cache_root","config_root","data_root"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/fn.load_secret_key.html b/pr/2992/docs/iroh_node_util/fn.load_secret_key.html new file mode 100644 index 0000000000..73400d6ae1 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/fn.load_secret_key.html @@ -0,0 +1,3 @@ +load_secret_key in iroh_node_util - Rust

Function iroh_node_util::load_secret_key

source ·
pub async fn load_secret_key(key_path: PathBuf) -> Result<SecretKey>
Expand description

Loads a [SecretKey] from the provided file, or stores a newly generated one +at the given location.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/fs/fn.load_secret_key.html b/pr/2992/docs/iroh_node_util/fs/fn.load_secret_key.html new file mode 100644 index 0000000000..ad27d03ec8 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/fs/fn.load_secret_key.html @@ -0,0 +1,3 @@ +load_secret_key in iroh_node_util::fs - Rust

Function iroh_node_util::fs::load_secret_key

source ·
pub async fn load_secret_key(key_path: PathBuf) -> Result<SecretKey>
Expand description

Loads a [SecretKey] from the provided file, or stores a newly generated one +at the given location.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/fs/index.html b/pr/2992/docs/iroh_node_util/fs/index.html new file mode 100644 index 0000000000..2b1f167194 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/fs/index.html @@ -0,0 +1,3 @@ +iroh_node_util::fs - Rust

Module iroh_node_util::fs

source ·
Expand description

Utilities for filesystem operations.

+

Functions§

  • Loads a [SecretKey] from the provided file, or stores a newly generated one +at the given location.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/fs/sidebar-items.js b/pr/2992/docs/iroh_node_util/fs/sidebar-items.js new file mode 100644 index 0000000000..a29a19d2eb --- /dev/null +++ b/pr/2992/docs/iroh_node_util/fs/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["load_secret_key"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/index.html b/pr/2992/docs/iroh_node_util/index.html new file mode 100644 index 0000000000..fc0a083c9c --- /dev/null +++ b/pr/2992/docs/iroh_node_util/index.html @@ -0,0 +1,3 @@ +iroh_node_util - Rust

Crate iroh_node_util

source ·
Expand description

Utilities for building iroh nodes.

+

Modules§

  • clicli
    Cli commands.
  • configconfig
    Utilities to get default paths for configuration, data, and cache directories.
  • Utilities for filesystem operations.
  • logginglogging
    Utilities for logging
  • RPC client, server and protocol to control iroh endpoints and iroh nodes

Functions§

  • Loads a [SecretKey] from the provided file, or stores a newly generated one +at the given location.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/enum.Rotation.html b/pr/2992/docs/iroh_node_util/logging/enum.Rotation.html new file mode 100644 index 0000000000..b7d039b945 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/enum.Rotation.html @@ -0,0 +1,45 @@ +Rotation in iroh_node_util::logging - Rust

Enum iroh_node_util::logging::Rotation

source ·
pub enum Rotation {
+    Hourly,
+    Daily,
+    Never,
+}
Available on crate feature logging only.
Expand description

How often should a new file be created for file logs.

+

Akin to [tracing_appender::rolling::Rotation].

+

Variants§

§

Hourly

§

Daily

§

Never

Trait Implementations§

source§

impl Clone for Rotation

source§

fn clone(&self) -> Rotation

Returns a copy 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 Rotation

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Rotation

source§

fn default() -> Rotation

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for Rotation

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl PartialEq for Rotation

source§

fn eq(&self, other: &Rotation) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for Rotation

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for Rotation

source§

impl StructuralPartialEq for Rotation

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/fn.env_file_rust_log.html b/pr/2992/docs/iroh_node_util/logging/fn.env_file_rust_log.html new file mode 100644 index 0000000000..0f5063c485 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/fn.env_file_rust_log.html @@ -0,0 +1,3 @@ +env_file_rust_log in iroh_node_util::logging - Rust

Function iroh_node_util::logging::env_file_rust_log

source ·
pub fn env_file_rust_log(bin: &'static str) -> Option<Result<EnvFilter>>
Available on crate feature logging only.
Expand description

Parse <bin>_FILE_RUST_LOG as [tracing_subscriber::EnvFilter]. Returns None if not +present.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_and_file_logging.html b/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_and_file_logging.html new file mode 100644 index 0000000000..87b3eb711f --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_and_file_logging.html @@ -0,0 +1,26 @@ +init_terminal_and_file_logging in iroh_node_util::logging - Rust
pub fn init_terminal_and_file_logging(
+    file_log_config: &FileLogging,
+    logs_root: &Path
+) -> Result<WorkerGuard>
Available on crate feature logging only.
Expand description

Initialize logging both in the terminal and file based.

+

The terminal based logging layer will:

+ +

The file base logging layer will:

+
    +
  • use the default [fmt::format::Format] save for: +
      +
    • including line numbers.
    • +
    • not using ansi colors.
    • +
    +
  • +
  • create log files in the FileLogging::dir directory. If not provided, the logs dir +inside the given logs_root is used.
  • +
  • rotate files every FileLogging::rotation.
  • +
  • keep at most FileLogging::max_files log files.
  • +
  • use the filtering defined by FileLogging::rust_log. When not provided, the default +DEFAULT_FILE_RUST_LOG is used.
  • +
  • create log files with the name iroh-<ROTATION_BASED_NAME>.log (ex: iroh-2024-02-02.log)
  • +
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_logging.html b/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_logging.html new file mode 100644 index 0000000000..4329faaa7c --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/fn.init_terminal_logging.html @@ -0,0 +1,7 @@ +init_terminal_logging in iroh_node_util::logging - Rust

Function iroh_node_util::logging::init_terminal_logging

source ·
pub fn init_terminal_logging() -> Result<()>
Available on crate feature logging only.
Expand description

Initialize logging in the terminal.

+

This will:

+ +
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/index.html b/pr/2992/docs/iroh_node_util/logging/index.html new file mode 100644 index 0000000000..ff14c9e56b --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/index.html @@ -0,0 +1,3 @@ +iroh_node_util::logging - Rust

Module iroh_node_util::logging

source ·
Available on crate feature logging only.
Expand description

Utilities for logging

+

Structs§

  • Wrapper to obtain a [tracing_subscriber::EnvFilter] that satisfies required bounds.
  • Configuration for the logfiles.

Enums§

  • How often should a new file be created for file logs.

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/sidebar-items.js b/pr/2992/docs/iroh_node_util/logging/sidebar-items.js new file mode 100644 index 0000000000..fce2ae1ff0 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Rotation"],"fn":["env_file_rust_log","init_terminal_and_file_logging","init_terminal_logging"],"struct":["EnvFilter","FileLogging"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/struct.EnvFilter.html b/pr/2992/docs/iroh_node_util/logging/struct.EnvFilter.html new file mode 100644 index 0000000000..9c67fd2eab --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/struct.EnvFilter.html @@ -0,0 +1,44 @@ +EnvFilter in iroh_node_util::logging - Rust

Struct iroh_node_util::logging::EnvFilter

source ·
pub struct EnvFilter(/* private fields */);
Available on crate feature logging only.
Expand description

Wrapper to obtain a [tracing_subscriber::EnvFilter] that satisfies required bounds.

+

Trait Implementations§

source§

impl Clone for EnvFilter

source§

fn clone(&self) -> EnvFilter

Returns a copy 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 EnvFilter

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for EnvFilter

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for EnvFilter
where + Self: FromStr, + <Self as FromStr>::Err: Display,

source§

fn deserialize<__D>(deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for EnvFilter

source§

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

Formats the value using the given formatter. Read more
source§

impl FromStr for EnvFilter

§

type Err = <EnvFilter as FromStr>::Err

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
source§

impl PartialEq for EnvFilter

source§

fn eq(&self, other: &EnvFilter) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for EnvFilter
where + Self: Display,

source§

fn serialize<__S>(&self, serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for EnvFilter

source§

impl StructuralPartialEq for EnvFilter

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/logging/struct.FileLogging.html b/pr/2992/docs/iroh_node_util/logging/struct.FileLogging.html new file mode 100644 index 0000000000..26bba7dcb3 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/logging/struct.FileLogging.html @@ -0,0 +1,50 @@ +FileLogging in iroh_node_util::logging - Rust

Struct iroh_node_util::logging::FileLogging

source ·
pub struct FileLogging {
+    pub rust_log: EnvFilter,
+    pub max_files: usize,
+    pub rotation: Rotation,
+    pub dir: Option<PathBuf>,
+}
Available on crate feature logging only.
Expand description

Configuration for the logfiles.

+

Fields§

§rust_log: EnvFilter

RUST_LOG directive to filter file logs.

+
§max_files: usize

Maximum number of files to keep.

+
§rotation: Rotation

How often should a new log file be produced.

+
§dir: Option<PathBuf>

Where to store log files.

+

Trait Implementations§

source§

impl Clone for FileLogging

source§

fn clone(&self) -> FileLogging

Returns a copy 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 FileLogging

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for FileLogging

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for FileLogging

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl PartialEq for FileLogging

source§

fn eq(&self, other: &FileLogging) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Serialize for FileLogging

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for FileLogging

source§

impl StructuralPartialEq for FileLogging

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> DynClone for T
where + T: Clone,

source§

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

§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/index.html b/pr/2992/docs/iroh_node_util/rpc/client/index.html new file mode 100644 index 0000000000..cc5db0c353 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc::client - Rust

Module iroh_node_util::rpc::client

source ·
Expand description

Client to interact with iroh nodes and endpoints.

+

Modules§

  • API to manage the iroh networking stack.
  • Client to interact with an iroh node.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/net/index.html b/pr/2992/docs/iroh_node_util/rpc/client/net/index.html new file mode 100644 index 0000000000..6a7a855835 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/net/index.html @@ -0,0 +1,7 @@ +iroh_node_util::rpc::client::net - Rust

Module iroh_node_util::rpc::client::net

source ·
Expand description

API to manage the iroh networking stack.

+

The main entry point is the Client.

+

The client can be used to get information about the node, such as the +node id or node address.

+

It can also be used to provide additional information to the node, e.g. +using the add_node_addr method.

+

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/net/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/client/net/sidebar-items.js new file mode 100644 index 0000000000..873857f004 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/net/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["Client","NodeStatus"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/net/struct.Client.html b/pr/2992/docs/iroh_node_util/rpc/client/net/struct.Client.html new file mode 100644 index 0000000000..d6a366f958 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/net/struct.Client.html @@ -0,0 +1,52 @@ +Client in iroh_node_util::rpc::client::net - Rust

Struct iroh_node_util::rpc::client::net::Client

source ·
pub struct Client { /* private fields */ }
Expand description

Iroh net Client.

+

Cheaply clonable and threadsafe. Use the iroh net::Client to access the +iroh net methods from a different thread, process, or remote machine.

+

The node::Client api allows you to get information about the iroh node, +its status, and connection status to other nodes. It also allows you to +provide address information about other nodes to your node.

+

Implementations§

source§

impl Client

source

pub fn new(rpc: RpcClient<RpcService>) -> Self

Creates a new net client

+
source

pub async fn remote_info_iter( + &self +) -> Result<impl Stream<Item = Result<RemoteInfo>>>

Fetches information about currently known remote nodes.

+

This streams a current snapshot. It does not keep the stream open after finishing +transferring the snapshot.

+

See also Endpoint::remote_info_iter.

+
source

pub async fn remote_info(&self, node_id: NodeId) -> Result<Option<RemoteInfo>>

Fetches node information about a remote iroh node identified by its [NodeId].

+

See also Endpoint::remote_info.

+
source

pub async fn node_id(&self) -> Result<NodeId>

Fetches the node id of this node.

+

See also Endpoint::node_id.

+
source

pub async fn node_addr(&self) -> Result<NodeAddr>

Fetches the [NodeAddr] for this node.

+

See also Endpoint::node_addr.

+
source

pub async fn add_node_addr(&self, addr: NodeAddr) -> Result<()>

Adds a known node address to this node.

+

See also Endpoint::add_node_addr.

+
source

pub async fn home_relay(&self) -> Result<Option<RelayUrl>>

Returns the relay server we are connected to.

+

See also Endpoint::home_relay.

+

Trait Implementations§

source§

impl Clone for Client

source§

fn clone(&self) -> Client

Returns a copy 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 Client

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Client

§

impl !RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl !UnwindSafe for Client

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/net/struct.NodeStatus.html b/pr/2992/docs/iroh_node_util/rpc/client/net/struct.NodeStatus.html new file mode 100644 index 0000000000..4a6fcee808 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/net/struct.NodeStatus.html @@ -0,0 +1,40 @@ +NodeStatus in iroh_node_util::rpc::client::net - Rust

Struct iroh_node_util::rpc::client::net::NodeStatus

source ·
pub struct NodeStatus {
+    pub addr: NodeAddr,
+    pub listen_addrs: Vec<SocketAddr>,
+    pub version: String,
+    pub rpc_addr: Option<SocketAddr>,
+}
Expand description

The response to a version request

+

Fields§

§addr: NodeAddr

The node id and socket addresses of this node.

+
§listen_addrs: Vec<SocketAddr>

The bound listening addresses of the node

+
§version: String

The version of the node

+
§rpc_addr: Option<SocketAddr>

RPC address, if currently listening.

+

Trait Implementations§

source§

impl Debug for NodeStatus

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeStatus

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for NodeStatus

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/node/index.html b/pr/2992/docs/iroh_node_util/rpc/client/node/index.html new file mode 100644 index 0000000000..10866ab529 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/node/index.html @@ -0,0 +1,3 @@ +iroh_node_util::rpc::client::node - Rust

Module iroh_node_util::rpc::client::node

source ·
Expand description

Client to interact with an iroh node.

+

The main entry point is Client.

+

Structs§

  • Client to interact with an iroh node.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/node/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/client/node/sidebar-items.js new file mode 100644 index 0000000000..85f1e7f444 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/node/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["Client"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/node/struct.Client.html b/pr/2992/docs/iroh_node_util/rpc/client/node/struct.Client.html new file mode 100644 index 0000000000..c821b97d88 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/node/struct.Client.html @@ -0,0 +1,36 @@ +Client in iroh_node_util::rpc::client::node - Rust

Struct iroh_node_util::rpc::client::node::Client

source ·
pub struct Client { /* private fields */ }
Expand description

Client to interact with an iroh node.

+

Implementations§

source§

impl Client

source

pub fn new(rpc: RpcClient<RpcService>) -> Self

Creates a new node client

+
source

pub async fn shutdown(&self, force: bool) -> Result<()>

Shuts down the node.

+

If force is true, the node will be shut down instantly without +waiting for things to stop gracefully.

+
source

pub async fn stats(&self) -> Result<BTreeMap<String, CounterStats>>

Fetches statistics of the running node.

+
source

pub async fn status(&self) -> Result<NodeStatus>

Fetches status information about this node.

+

Trait Implementations§

source§

impl Clone for Client

source§

fn clone(&self) -> Client

Returns a copy 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 Client

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Client

§

impl !RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl !UnwindSafe for Client

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/client/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/client/sidebar-items.js new file mode 100644 index 0000000000..b87a41d035 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/client/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["net","node"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/index.html b/pr/2992/docs/iroh_node_util/rpc/index.html new file mode 100644 index 0000000000..48d1668ee4 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc - Rust

Module iroh_node_util::rpc

source ·
Expand description

RPC client, server and protocol to control iroh endpoints and iroh nodes

+

Modules§

  • Client to interact with iroh nodes and endpoints.
  • RPC protocol definitions for controlling iroh endpoints and iroh nodes
  • Server implementation to handle node and net rpc requests
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/enum.Request.html b/pr/2992/docs/iroh_node_util/rpc/proto/enum.Request.html new file mode 100644 index 0000000000..e9cb5d2595 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/enum.Request.html @@ -0,0 +1,34 @@ +Request in iroh_node_util::rpc::proto - Rust

Enum iroh_node_util::rpc::proto::Request

source ·
pub enum Request {
+    Net(Request),
+    Node(Request),
+}
Expand description

Request, either net or node

+

Variants§

Trait Implementations§

source§

impl Debug for Request

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Request

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<AddAddrRequest> for Request

source§

fn from(value: AddAddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<AddrRequest> for Request

source§

fn from(value: AddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<IdRequest> for Request

source§

fn from(value: IdRequest) -> Self

Converts to this type from the input type.
source§

impl From<NodeWatchRequest> for Request

source§

fn from(value: NodeWatchRequest) -> Self

Converts to this type from the input type.
source§

impl From<RelayRequest> for Request

source§

fn from(value: RelayRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfoRequest> for Request

source§

fn from(value: RemoteInfoRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfosIterRequest> for Request

source§

fn from(value: RemoteInfosIterRequest) -> Self

Converts to this type from the input type.
source§

impl From<Request> for Request

source§

fn from(value: Request) -> Self

Converts to this type from the input type.
source§

impl From<Request> for Request

source§

fn from(value: Request) -> Self

Converts to this type from the input type.
source§

impl From<ShutdownRequest> for Request

source§

fn from(value: ShutdownRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatsRequest> for Request

source§

fn from(value: StatsRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatusRequest> for Request

source§

fn from(value: StatusRequest) -> Self

Converts to this type from the input type.
source§

impl Serialize for Request

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a AddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a IdRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RelayRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a Request

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a Request

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatsRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatusRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddAddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for IdRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for NodeWatchRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RelayRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfoRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfosIterRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for Request

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for Request

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for ShutdownRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatsRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatusRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/enum.Response.html b/pr/2992/docs/iroh_node_util/rpc/proto/enum.Response.html new file mode 100644 index 0000000000..b6cce34cf9 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/enum.Response.html @@ -0,0 +1,34 @@ +Response in iroh_node_util::rpc::proto - Rust

Enum iroh_node_util::rpc::proto::Response

source ·
pub enum Response {
+    Net(Response),
+    Node(Response),
+}
Expand description

Response, either net or node

+

Variants§

Trait Implementations§

source§

impl Debug for Response

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Response

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<()> for Response

source§

fn from(value: ()) -> Self

Converts to this type from the input type.
source§

impl From<Response> for Response

source§

fn from(value: Response) -> Self

Converts to this type from the input type.
source§

impl From<Response> for Response

source§

fn from(value: Response) -> Self

Converts to this type from the input type.
source§

impl From<Result<(), Error>> for Response

source§

fn from(value: Result<(), Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<NodeAddr, Error>> for Response

source§

fn from(value: Result<NodeAddr, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<NodeStatus, Error>> for Response

source§

fn from(value: Result<NodeStatus, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<Option<RelayUrl>, Error>> for Response

source§

fn from(value: Result<Option<RelayUrl>, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<PublicKey, Error>> for Response

source§

fn from(value: Result<NodeId, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<RemoteInfoResponse, Error>> for Response

source§

fn from(value: Result<RemoteInfoResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<RemoteInfosIterResponse, Error>> for Response

source§

fn from(value: Result<RemoteInfosIterResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<StatsResponse, Error>> for Response

source§

fn from(value: Result<StatsResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl From<WatchResponse> for Response

source§

fn from(value: WatchResponse) -> Self

Converts to this type from the input type.
source§

impl Serialize for Response

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Response> for &'a ()

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Response

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Response

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<(), Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeAddr, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeStatus, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<Option<RelayUrl>, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeId, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfoResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfosIterResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<StatsResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a WatchResponse

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for ()

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Response

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Response

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<(), Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeAddr, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeStatus, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<Option<RelayUrl>, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeId, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<RemoteInfoResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<RemoteInfosIterResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<StatsResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for WatchResponse

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/index.html b/pr/2992/docs/iroh_node_util/rpc/proto/index.html new file mode 100644 index 0000000000..24f5a29ba1 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc::proto - Rust

Module iroh_node_util::rpc::proto

source ·
Expand description

RPC protocol definitions for controlling iroh endpoints and iroh nodes

+

Modules§

  • RPC calls to control an iroh endpoint.
  • RPC calls to control a generic node.

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Request.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Request.html new file mode 100644 index 0000000000..68ad0b9ec8 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Request.html @@ -0,0 +1,39 @@ +Request in iroh_node_util::rpc::proto::net - Rust

Enum iroh_node_util::rpc::proto::net::Request

source ·
pub enum Request {
+    Id(IdRequest),
+    Addr(AddrRequest),
+    AddAddr(AddAddrRequest),
+    Relay(RelayRequest),
+    RemoteInfosIter(RemoteInfosIterRequest),
+    RemoteInfo(RemoteInfoRequest),
+    Watch(NodeWatchRequest),
+}

Variants§

Trait Implementations§

source§

impl Debug for Request

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Request

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Request

source§

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

Formats the value using the given formatter. Read more
source§

impl From<AddAddrRequest> for Request

source§

fn from(value: AddAddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<AddrRequest> for Request

source§

fn from(value: AddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<IdRequest> for Request

source§

fn from(value: IdRequest) -> Self

Converts to this type from the input type.
source§

impl From<NodeWatchRequest> for Request

source§

fn from(value: NodeWatchRequest) -> Self

Converts to this type from the input type.
source§

impl From<RelayRequest> for Request

source§

fn from(value: RelayRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfoRequest> for Request

source§

fn from(value: RemoteInfoRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfosIterRequest> for Request

source§

fn from(value: RemoteInfosIterRequest) -> Self

Converts to this type from the input type.
source§

impl From<Request> for Request

source§

fn from(value: Request) -> Self

Converts to this type from the input type.
source§

impl Serialize for Request

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a AddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a IdRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RelayRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a Request

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddAddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for IdRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for NodeWatchRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RelayRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfoRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfosIterRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for Request

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Response.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Response.html new file mode 100644 index 0000000000..0215cdba23 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/enum.Response.html @@ -0,0 +1,39 @@ +Response in iroh_node_util::rpc::proto::net - Rust

Enum iroh_node_util::rpc::proto::net::Response

source ·
pub enum Response {
+    Id(Result<NodeId, Error>),
+    Addr(Result<NodeAddr, Error>),
+    Relay(Result<Option<RelayUrl>, Error>),
+    RemoteInfosIter(Result<RemoteInfosIterResponse, Error>),
+    RemoteInfo(Result<RemoteInfoResponse, Error>),
+    Watch(WatchResponse),
+    Unit(Result<(), Error>),
+}

Variants§

§

Id(Result<NodeId, Error>)

§

Addr(Result<NodeAddr, Error>)

§

Relay(Result<Option<RelayUrl>, Error>)

§

RemoteInfosIter(Result<RemoteInfosIterResponse, Error>)

§

RemoteInfo(Result<RemoteInfoResponse, Error>)

§

Watch(WatchResponse)

§

Unit(Result<(), Error>)

Trait Implementations§

source§

impl Debug for Response

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Response

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Response

source§

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

Formats the value using the given formatter. Read more
source§

impl From<Response> for Response

source§

fn from(value: Response) -> Self

Converts to this type from the input type.
source§

impl From<Result<(), Error>> for Response

source§

fn from(value: Result<(), Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<NodeAddr, Error>> for Response

source§

fn from(value: Result<NodeAddr, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<Option<RelayUrl>, Error>> for Response

source§

fn from(value: Result<Option<RelayUrl>, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<PublicKey, Error>> for Response

source§

fn from(value: Result<NodeId, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<RemoteInfoResponse, Error>> for Response

source§

fn from(value: Result<RemoteInfoResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<RemoteInfosIterResponse, Error>> for Response

source§

fn from(value: Result<RemoteInfosIterResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl From<WatchResponse> for Response

source§

fn from(value: WatchResponse) -> Self

Converts to this type from the input type.
source§

impl Serialize for Response

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Response> for &'a Response

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<(), Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeAddr, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<Option<RelayUrl>, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeId, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfoResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfosIterResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a WatchResponse

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Response

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<(), Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeAddr, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<Option<RelayUrl>, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeId, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<RemoteInfoResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<RemoteInfosIterResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for WatchResponse

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/index.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/index.html new file mode 100644 index 0000000000..785c1f3824 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc::proto::net - Rust

Module iroh_node_util::rpc::proto::net

source ·
Expand description

RPC calls to control an iroh endpoint.

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/proto/net/sidebar-items.js new file mode 100644 index 0000000000..be2687f0c7 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Request","Response"],"struct":["AddAddrRequest","AddrRequest","IdRequest","NodeWatchRequest","RelayRequest","RemoteInfoRequest","RemoteInfoResponse","RemoteInfosIterRequest","RemoteInfosIterResponse","WatchResponse"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddAddrRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddAddrRequest.html new file mode 100644 index 0000000000..82e38c1bd5 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddAddrRequest.html @@ -0,0 +1,34 @@ +AddAddrRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::AddAddrRequest

source ·
pub struct AddAddrRequest {
+    pub addr: NodeAddr,
+}

Fields§

§addr: NodeAddr

Trait Implementations§

source§

impl Debug for AddAddrRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for AddAddrRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<AddAddrRequest> for Request

source§

fn from(value: AddAddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<AddAddrRequest> for Request

source§

fn from(value: AddAddrRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for AddAddrRequest

§

type Response = Result<(), Error>

The type for the response Read more
source§

impl Serialize for AddAddrRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddAddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddAddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddrRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddrRequest.html new file mode 100644 index 0000000000..191256dfbf --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.AddrRequest.html @@ -0,0 +1,32 @@ +AddrRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::AddrRequest

source ·
pub struct AddrRequest;

Trait Implementations§

source§

impl Debug for AddrRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for AddrRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<AddrRequest> for Request

source§

fn from(value: AddrRequest) -> Self

Converts to this type from the input type.
source§

impl From<AddrRequest> for Request

source§

fn from(value: AddrRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for AddrRequest

§

type Response = Result<NodeAddr, Error>

The type for the response Read more
source§

impl Serialize for AddrRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a AddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a AddrRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for AddrRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.IdRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.IdRequest.html new file mode 100644 index 0000000000..876a9ca923 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.IdRequest.html @@ -0,0 +1,33 @@ +IdRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::IdRequest

source ·
pub struct IdRequest;
Expand description

A request to get information the identity of the node.

+

Trait Implementations§

source§

impl Debug for IdRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for IdRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<IdRequest> for Request

source§

fn from(value: IdRequest) -> Self

Converts to this type from the input type.
source§

impl From<IdRequest> for Request

source§

fn from(value: IdRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for IdRequest

§

type Response = Result<PublicKey, Error>

The type for the response Read more
source§

impl Serialize for IdRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a IdRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a IdRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for IdRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for IdRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.NodeWatchRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.NodeWatchRequest.html new file mode 100644 index 0000000000..2e8029e833 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.NodeWatchRequest.html @@ -0,0 +1,31 @@ +NodeWatchRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::NodeWatchRequest

source ·
pub struct NodeWatchRequest;
Expand description

A request to watch for the node status

+

Trait Implementations§

source§

impl Debug for NodeWatchRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for NodeWatchRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<NodeWatchRequest> for Request

source§

fn from(value: NodeWatchRequest) -> Self

Converts to this type from the input type.
source§

impl From<NodeWatchRequest> for Request

source§

fn from(value: NodeWatchRequest) -> Self

Converts to this type from the input type.
source§

impl Msg<RpcService> for NodeWatchRequest

§

type Pattern = ServerStreaming

The interaction pattern for this message with this service.
source§

impl Serialize for NodeWatchRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl ServerStreamingMsg<RpcService> for NodeWatchRequest

§

type Response = WatchResponse

The type for the response Read more
source§

impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for NodeWatchRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for NodeWatchRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RelayRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RelayRequest.html new file mode 100644 index 0000000000..5add24e393 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RelayRequest.html @@ -0,0 +1,32 @@ +RelayRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::RelayRequest

source ·
pub struct RelayRequest;

Trait Implementations§

source§

impl Debug for RelayRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RelayRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<RelayRequest> for Request

source§

fn from(value: RelayRequest) -> Self

Converts to this type from the input type.
source§

impl From<RelayRequest> for Request

source§

fn from(value: RelayRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for RelayRequest

§

type Response = Result<Option<RelayUrl>, Error>

The type for the response Read more
source§

impl Serialize for RelayRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a RelayRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RelayRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RelayRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RelayRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoRequest.html new file mode 100644 index 0000000000..1a3729c6e5 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoRequest.html @@ -0,0 +1,39 @@ +RemoteInfoRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::RemoteInfoRequest

source ·
pub struct RemoteInfoRequest {
+    pub node_id: PublicKey,
+}
Expand description

Get information about a specific remote node.

+

Fields§

§node_id: PublicKey

The node identifier

+

Trait Implementations§

source§

impl Clone for RemoteInfoRequest

source§

fn clone(&self) -> RemoteInfoRequest

Returns a copy 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 RemoteInfoRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RemoteInfoRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<RemoteInfoRequest> for Request

source§

fn from(value: RemoteInfoRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfoRequest> for Request

source§

fn from(value: RemoteInfoRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for RemoteInfoRequest

§

type Response = Result<RemoteInfoResponse, Error>

The type for the response Read more
source§

impl Serialize for RemoteInfoRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfoRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfoRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoResponse.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoResponse.html new file mode 100644 index 0000000000..d7cc099d61 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfoResponse.html @@ -0,0 +1,34 @@ +RemoteInfoResponse in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::RemoteInfoResponse

source ·
pub struct RemoteInfoResponse {
+    pub info: Option<RemoteInfo>,
+}
Expand description

A response to a Request::RemoteInfo request

+

Fields§

§info: Option<RemoteInfo>

Information about a node

+

Trait Implementations§

source§

impl Debug for RemoteInfoResponse

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RemoteInfoResponse

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for RemoteInfoResponse

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterRequest.html new file mode 100644 index 0000000000..c2e7d13d6e --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterRequest.html @@ -0,0 +1,34 @@ +RemoteInfosIterRequest in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::RemoteInfosIterRequest

source ·
pub struct RemoteInfosIterRequest;
Expand description

List network path information about all the remote nodes known by this node.

+

There may never have been connections to these nodes, and connections may not even be +possible. Nodes can also become known due to discovery mechanisms +or be added manually.

+

Trait Implementations§

source§

impl Debug for RemoteInfosIterRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RemoteInfosIterRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<RemoteInfosIterRequest> for Request

source§

fn from(value: RemoteInfosIterRequest) -> Self

Converts to this type from the input type.
source§

impl From<RemoteInfosIterRequest> for Request

source§

fn from(value: RemoteInfosIterRequest) -> Self

Converts to this type from the input type.
source§

impl Msg<RpcService> for RemoteInfosIterRequest

§

type Pattern = ServerStreaming

The interaction pattern for this message with this service.
source§

impl Serialize for RemoteInfosIterRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl ServerStreamingMsg<RpcService> for RemoteInfosIterRequest

§

type Response = Result<RemoteInfosIterResponse, Error>

The type for the response Read more
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfosIterRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for RemoteInfosIterRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterResponse.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterResponse.html new file mode 100644 index 0000000000..fc8bd5f434 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.RemoteInfosIterResponse.html @@ -0,0 +1,34 @@ +RemoteInfosIterResponse in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::RemoteInfosIterResponse

source ·
pub struct RemoteInfosIterResponse {
+    pub info: RemoteInfo,
+}
Expand description

A response to a Request::RemoteInfosIter.

+

Fields§

§info: RemoteInfo

Information about a node.

+

Trait Implementations§

source§

impl Debug for RemoteInfosIterResponse

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for RemoteInfosIterResponse

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for RemoteInfosIterResponse

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.WatchResponse.html b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.WatchResponse.html new file mode 100644 index 0000000000..063e36d08e --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/net/struct.WatchResponse.html @@ -0,0 +1,34 @@ +WatchResponse in iroh_node_util::rpc::proto::net - Rust

Struct iroh_node_util::rpc::proto::net::WatchResponse

source ·
pub struct WatchResponse {
+    pub version: String,
+}
Expand description

The response to a watch request

+

Fields§

§version: String

The version of the node

+

Trait Implementations§

source§

impl Debug for WatchResponse

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for WatchResponse

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<WatchResponse> for Response

source§

fn from(value: WatchResponse) -> Self

Converts to this type from the input type.
source§

impl From<WatchResponse> for Response

source§

fn from(value: WatchResponse) -> Self

Converts to this type from the input type.
source§

impl Serialize for WatchResponse

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Response> for &'a WatchResponse

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a WatchResponse

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for WatchResponse

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for WatchResponse

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Request.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Request.html new file mode 100644 index 0000000000..aef4feda32 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Request.html @@ -0,0 +1,35 @@ +Request in iroh_node_util::rpc::proto::node - Rust

Enum iroh_node_util::rpc::proto::node::Request

source ·
pub enum Request {
+    Status(StatusRequest),
+    Stats(StatsRequest),
+    Shutdown(ShutdownRequest),
+}

Variants§

Trait Implementations§

source§

impl Debug for Request

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Request

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Request

source§

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

Formats the value using the given formatter. Read more
source§

impl From<Request> for Request

source§

fn from(value: Request) -> Self

Converts to this type from the input type.
source§

impl From<ShutdownRequest> for Request

source§

fn from(value: ShutdownRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatsRequest> for Request

source§

fn from(value: StatsRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatusRequest> for Request

source§

fn from(value: StatusRequest) -> Self

Converts to this type from the input type.
source§

impl Serialize for Request

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a Request

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatsRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatusRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for Request

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for ShutdownRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatsRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatusRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Response.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Response.html new file mode 100644 index 0000000000..edb434db36 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/enum.Response.html @@ -0,0 +1,35 @@ +Response in iroh_node_util::rpc::proto::node - Rust

Enum iroh_node_util::rpc::proto::node::Response

source ·
pub enum Response {
+    Status(Result<NodeStatus, Error>),
+    Stats(Result<StatsResponse, Error>),
+    Shutdown(()),
+}

Variants§

§

Status(Result<NodeStatus, Error>)

§

Stats(Result<StatsResponse, Error>)

§

Shutdown(())

Trait Implementations§

source§

impl Debug for Response

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Response

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for Response

source§

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

Formats the value using the given formatter. Read more
source§

impl From<()> for Response

source§

fn from(value: ()) -> Self

Converts to this type from the input type.
source§

impl From<Response> for Response

source§

fn from(value: Response) -> Self

Converts to this type from the input type.
source§

impl From<Result<NodeStatus, Error>> for Response

source§

fn from(value: Result<NodeStatus, Error>) -> Self

Converts to this type from the input type.
source§

impl From<Result<StatsResponse, Error>> for Response

source§

fn from(value: Result<StatsResponse, Error>) -> Self

Converts to this type from the input type.
source§

impl Serialize for Response

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Response> for &'a ()

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Response

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<NodeStatus, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Response> for &'a Result<StatsResponse, Error>

§

type Error = &'a Response

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

fn try_from(value: &'a Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for ()

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Response

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<NodeStatus, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Response> for Result<StatsResponse, Error>

§

type Error = Response

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

fn try_from(value: Response) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/index.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/index.html new file mode 100644 index 0000000000..276e4c7db1 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc::proto::node - Rust

Module iroh_node_util::rpc::proto::node

source ·
Expand description

RPC calls to control a generic node.

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/proto/node/sidebar-items.js new file mode 100644 index 0000000000..a04fd494c2 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Request","Response"],"struct":["CounterStats","ShutdownRequest","StatsRequest","StatsResponse","StatusRequest"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.CounterStats.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.CounterStats.html new file mode 100644 index 0000000000..a5dff1f2ac --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.CounterStats.html @@ -0,0 +1,36 @@ +CounterStats in iroh_node_util::rpc::proto::node - Rust

Struct iroh_node_util::rpc::proto::node::CounterStats

source ·
pub struct CounterStats {
+    pub value: u64,
+    pub description: String,
+}
Expand description

Counter stats

+

Fields§

§value: u64

The counter value

+
§description: String

The counter description

+

Trait Implementations§

source§

impl Debug for CounterStats

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for CounterStats

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for CounterStats

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.ShutdownRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.ShutdownRequest.html new file mode 100644 index 0000000000..e88f5e2156 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.ShutdownRequest.html @@ -0,0 +1,36 @@ +ShutdownRequest in iroh_node_util::rpc::proto::node - Rust

Struct iroh_node_util::rpc::proto::node::ShutdownRequest

source ·
pub struct ShutdownRequest {
+    pub force: bool,
+}
Expand description

A request to shutdown the node

+

Fields§

§force: bool

Force shutdown

+

Trait Implementations§

source§

impl Debug for ShutdownRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for ShutdownRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<ShutdownRequest> for Request

source§

fn from(value: ShutdownRequest) -> Self

Converts to this type from the input type.
source§

impl From<ShutdownRequest> for Request

source§

fn from(value: ShutdownRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for ShutdownRequest

§

type Response = ()

The type for the response Read more
source§

impl Serialize for ShutdownRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for ShutdownRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for ShutdownRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsRequest.html new file mode 100644 index 0000000000..00e4a51933 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsRequest.html @@ -0,0 +1,33 @@ +StatsRequest in iroh_node_util::rpc::proto::node - Rust

Struct iroh_node_util::rpc::proto::node::StatsRequest

source ·
pub struct StatsRequest {}
Expand description

Get stats for the running Iroh node

+

Trait Implementations§

source§

impl Debug for StatsRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for StatsRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<StatsRequest> for Request

source§

fn from(value: StatsRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatsRequest> for Request

source§

fn from(value: StatsRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for StatsRequest

§

type Response = Result<StatsResponse, Error>

The type for the response Read more
source§

impl Serialize for StatsRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a StatsRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatsRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatsRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatsRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsResponse.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsResponse.html new file mode 100644 index 0000000000..079d281296 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatsResponse.html @@ -0,0 +1,34 @@ +StatsResponse in iroh_node_util::rpc::proto::node - Rust

Struct iroh_node_util::rpc::proto::node::StatsResponse

source ·
pub struct StatsResponse {
+    pub stats: BTreeMap<String, CounterStats>,
+}
Expand description

Response to StatsRequest

+

Fields§

§stats: BTreeMap<String, CounterStats>

Map of statistics

+

Trait Implementations§

source§

impl Debug for StatsResponse

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for StatsResponse

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Serialize for StatsResponse

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatusRequest.html b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatusRequest.html new file mode 100644 index 0000000000..610ff20939 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/node/struct.StatusRequest.html @@ -0,0 +1,33 @@ +StatusRequest in iroh_node_util::rpc::proto::node - Rust

Struct iroh_node_util::rpc::proto::node::StatusRequest

source ·
pub struct StatusRequest;
Expand description

A request to get information about the status of the node.

+

Trait Implementations§

source§

impl Debug for StatusRequest

source§

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

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for StatusRequest

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<StatusRequest> for Request

source§

fn from(value: StatusRequest) -> Self

Converts to this type from the input type.
source§

impl From<StatusRequest> for Request

source§

fn from(value: StatusRequest) -> Self

Converts to this type from the input type.
source§

impl RpcMsg<RpcService> for StatusRequest

§

type Response = Result<NodeStatus, Error>

The type for the response Read more
source§

impl Serialize for StatusRequest

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<'a> TryFrom<&'a Request> for &'a StatusRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl<'a> TryFrom<&'a Request> for &'a StatusRequest

§

type Error = &'a Request

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

fn try_from(value: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatusRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.
source§

impl TryFrom<Request> for StatusRequest

§

type Error = Request

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

fn try_from(value: Request) -> Result<Self, Self::Error>

Performs the conversion.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
§

impl<T, S> Msg<S> for T
where + T: RpcMsg<S>, + S: Service,

§

type Pattern = Rpc

The interaction pattern for this message with this service.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

§

impl<T> RpcMessage for T
where + T: Debug + Serialize + DeserializeOwned + Send + Sync + Unpin + 'static,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/proto/sidebar-items.js new file mode 100644 index 0000000000..57c163dd2a --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Request","Response"],"mod":["net","node"],"struct":["RpcService"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/proto/struct.RpcService.html b/pr/2992/docs/iroh_node_util/rpc/proto/struct.RpcService.html new file mode 100644 index 0000000000..50b9b37da7 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/proto/struct.RpcService.html @@ -0,0 +1,30 @@ +RpcService in iroh_node_util::rpc::proto - Rust

Struct iroh_node_util::rpc::proto::RpcService

source ·
pub struct RpcService {}
Expand description

The RPC service

+

Trait Implementations§

source§

impl Clone for RpcService

source§

fn clone(&self) -> RpcService

Returns a copy 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 RpcService

source§

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

Formats the value using the given formatter. Read more
source§

impl Msg<RpcService> for NodeWatchRequest

§

type Pattern = ServerStreaming

The interaction pattern for this message with this service.
source§

impl Msg<RpcService> for RemoteInfosIterRequest

§

type Pattern = ServerStreaming

The interaction pattern for this message with this service.
source§

impl RpcMsg<RpcService> for AddAddrRequest

§

type Response = Result<(), Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for AddrRequest

§

type Response = Result<NodeAddr, Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for IdRequest

§

type Response = Result<PublicKey, Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for RelayRequest

§

type Response = Result<Option<RelayUrl>, Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for RemoteInfoRequest

§

type Response = Result<RemoteInfoResponse, Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for ShutdownRequest

§

type Response = ()

The type for the response Read more
source§

impl RpcMsg<RpcService> for StatsRequest

§

type Response = Result<StatsResponse, Error>

The type for the response Read more
source§

impl RpcMsg<RpcService> for StatusRequest

§

type Response = Result<NodeStatus, Error>

The type for the response Read more
source§

impl ServerStreamingMsg<RpcService> for NodeWatchRequest

§

type Response = WatchResponse

The type for the response Read more
source§

impl ServerStreamingMsg<RpcService> for RemoteInfosIterRequest

§

type Response = Result<RemoteInfosIterResponse, Error>

The type for the response Read more
source§

impl Service for RpcService

§

type Req = Request

Type of request messages
§

type Res = Response

Type of response messages
source§

impl Copy for RpcService

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> 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> IntoArcAny for T
where + T: Send + Sync + 'static,

§

fn into_arc_any(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Casts Arc<Self> into Arc<dyn Any + Send + Sync>.
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/server/fn.handle_rpc_request.html b/pr/2992/docs/iroh_node_util/rpc/server/fn.handle_rpc_request.html new file mode 100644 index 0000000000..7b198599e0 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/server/fn.handle_rpc_request.html @@ -0,0 +1,6 @@ +handle_rpc_request in iroh_node_util::rpc::server - Rust

Function iroh_node_util::rpc::server::handle_rpc_request

source ·
pub async fn handle_rpc_request<C: ChannelTypes<RpcService>>(
+    node: Arc<dyn AbstractNode>,
+    msg: Request,
+    chan: RpcChannel<RpcService, C>
+) -> Result<(), RpcServerError<C>>
Expand description

Handle rpc requests for the node and net services

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/server/index.html b/pr/2992/docs/iroh_node_util/rpc/server/index.html new file mode 100644 index 0000000000..e859baab63 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/server/index.html @@ -0,0 +1,2 @@ +iroh_node_util::rpc::server - Rust

Module iroh_node_util::rpc::server

source ·
Expand description

Server implementation to handle node and net rpc requests

+

Traits§

  • Trait that provides fields used by the rpc handler for the net and node requests.

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/server/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/server/sidebar-items.js new file mode 100644 index 0000000000..3b21e89560 --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/server/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["handle_rpc_request"],"trait":["AbstractNode"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/server/trait.AbstractNode.html b/pr/2992/docs/iroh_node_util/rpc/server/trait.AbstractNode.html new file mode 100644 index 0000000000..6e29371a7b --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/server/trait.AbstractNode.html @@ -0,0 +1,14 @@ +AbstractNode in iroh_node_util::rpc::server - Rust

Trait iroh_node_util::rpc::server::AbstractNode

source ·
pub trait AbstractNode: Send + Sync + 'static {
+    // Required methods
+    fn endpoint(&self) -> &Endpoint;
+    fn shutdown(&self);
+
+    // Provided methods
+    fn rpc_addr(&self) -> Option<SocketAddr> { ... }
+    fn stats(&self) -> Result<BTreeMap<String, CounterStats>> { ... }
+}
Expand description

Trait that provides fields used by the rpc handler for the net and node requests.

+

Required Methods§

source

fn endpoint(&self) -> &Endpoint

Get the endpoint of the node

+
source

fn shutdown(&self)

Shutdown the node, used by the node shutdown rpc call

+

Provided Methods§

source

fn rpc_addr(&self) -> Option<SocketAddr>

Rpc address of the node, used by the node status rpc call

+
source

fn stats(&self) -> Result<BTreeMap<String, CounterStats>>

Stats for the node stats rpc call

+

Implementors§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/rpc/sidebar-items.js b/pr/2992/docs/iroh_node_util/rpc/sidebar-items.js new file mode 100644 index 0000000000..8c846677de --- /dev/null +++ b/pr/2992/docs/iroh_node_util/rpc/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["client","proto","server"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_node_util/sidebar-items.js b/pr/2992/docs/iroh_node_util/sidebar-items.js new file mode 100644 index 0000000000..3dbab0a4ef --- /dev/null +++ b/pr/2992/docs/iroh_node_util/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["load_secret_key"],"mod":["cli","config","fs","logging","rpc"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/all.html b/pr/2992/docs/iroh_relay/all.html new file mode 100644 index 0000000000..e8903de034 --- /dev/null +++ b/pr/2992/docs/iroh_relay/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Functions

Constants

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/conn/enum.ReceivedMessage.html b/pr/2992/docs/iroh_relay/client/conn/enum.ReceivedMessage.html new file mode 100644 index 0000000000..1799f5a642 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/conn/enum.ReceivedMessage.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_relay/enum.ReceivedMessage.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/conn/struct.Conn.html b/pr/2992/docs/iroh_relay/client/conn/struct.Conn.html new file mode 100644 index 0000000000..45e73c09c3 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/conn/struct.Conn.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_relay/struct.RelayConn.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/enum.ClientError.html b/pr/2992/docs/iroh_relay/client/enum.ClientError.html new file mode 100644 index 0000000000..6e4283a0df --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/enum.ClientError.html @@ -0,0 +1,80 @@ +ClientError in iroh_relay::client - Rust

Enum iroh_relay::client::ClientError

source ·
pub enum ClientError {
+
Show 26 variants Closed, + NoClient, + Send, + Receive(Error), + ConnectTimeout, + RelayNodeNotAvail, + NoNodeForTarget(String), + StunOnlyNodesFound(String), + DialIO(Error), + DialTask(JoinError), + IPDisabled, + NoLocalAddr(String), + Hyper(Error), + Http(Error), + UnexpectedStatusCode(StatusCode, StatusCode), + Upgrade(String), + Proxy(String), + Build(String), + PingTimeout, + PingAborted, + CannotAckPings, + InvalidUrl(String), + Dns(Option<Error>), + DnsTimeout, + ActorGone, + WebsocketError(Error), +
}
Expand description

Possible connection errors on the Client

+

Variants§

§

Closed

The client is closed

+
§

NoClient

There no underlying relay super::client::Client client exists for this http relay Client

+
§

Send

There was an error sending a packet

+
§

Receive(Error)

There was an error receiving a packet

+
§

ConnectTimeout

There was a connection timeout error

+
§

RelayNodeNotAvail

No relay nodes are available

+
§

NoNodeForTarget(String)

No relay nodes are available with that name

+
§

StunOnlyNodesFound(String)

The relay node specified only allows STUN requests

+
§

DialIO(Error)

There was an error dialing

+
§

DialTask(JoinError)

There was an error from the task doing the dialing

+
§

IPDisabled

Both IPv4 and IPv6 are disabled for this relay node

+
§

NoLocalAddr(String)

No local addresses exist

+
§

Hyper(Error)

There was http server [hyper::Error]

+
§

Http(Error)

There was an http error [http::Error].

+
§

UnexpectedStatusCode(StatusCode, StatusCode)

There was an unexpected status code

+
§

Upgrade(String)

The connection failed to upgrade

+
§

Proxy(String)

The connection failed to proxy

+
§

Build(String)

The relay super::client::Client failed to build

+
§

PingTimeout

The ping request timed out

+
§

PingAborted

The ping request was aborted

+
§

CannotAckPings

This Client cannot acknowledge pings

+
§

InvalidUrl(String)

The given Url is invalid

+
§

Dns(Option<Error>)

There was an error with DNS resolution

+
§

DnsTimeout

There was a timeout resolving DNS.

+
§

ActorGone

The inner actor is gone, likely means things are shutdown.

+
§

WebsocketError(Error)

An error related to websockets, either errors with parsing ws messages or the handshake

+

Trait Implementations§

source§

impl Debug for ClientError

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for ClientError

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for ClientError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<Error> for ClientError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<Error> for ClientError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<Error> for ClientError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<Error> for ClientError

source§

fn from(source: Error) -> Self

Converts to this type from the input type.
source§

impl From<JoinError> for ClientError

source§

fn from(source: JoinError) -> Self

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/index.html b/pr/2992/docs/iroh_relay/client/index.html new file mode 100644 index 0000000000..f58ef00af3 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/index.html @@ -0,0 +1,3 @@ +iroh_relay::client - Rust

Module iroh_relay::client

source ·
Expand description

Exposes Client, which allows to establish connections to a relay server.

+

Based on tailscale/derp/derphttp/derphttp_client.go

+

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/sidebar-items.js b/pr/2992/docs/iroh_relay/client/sidebar-items.js new file mode 100644 index 0000000000..ff0fe6f7e2 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["ClientError"],"struct":["Client","ClientBuilder","ClientReceiver"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/struct.Client.html b/pr/2992/docs/iroh_relay/client/struct.Client.html new file mode 100644 index 0000000000..7e16fdc778 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/struct.Client.html @@ -0,0 +1,55 @@ +Client in iroh_relay::client - Rust

Struct iroh_relay::client::Client

source ·
pub struct Client { /* private fields */ }
Expand description

An HTTP Relay client.

+

Cheaply clonable.

+

Implementations§

source§

impl Client

source

pub fn public_key(&self) -> PublicKey

The public key for this client

+
source

pub async fn connect(&self) -> Result<Conn, ClientError>

Connects to a relay Server and returns the underlying relay connection.

+

Returns ClientError::Closed if the Client is closed.

+

If there is already an active relay connection, returns the already +connected crate::RelayConn.

+
source

pub async fn note_preferred(&self, is_preferred: bool)

Let the server know that this client is the preferred client

+
source

pub async fn local_addr(&self) -> Option<SocketAddr>

Get the local addr of the connection. If there is no current underlying relay connection +or the Client is closed, returns None.

+
source

pub async fn ping(&self) -> Result<Duration, ClientError>

Send a ping to the server. Return once we get an expected pong.

+

There must be a task polling recv_detail to process the pong response.

+
source

pub async fn send_pong(&self, data: [u8; 8]) -> Result<(), ClientError>

Send a pong back to the server.

+

If there is no underlying active relay connection, it creates one before attempting to +send the pong message.

+

If there is an error sending pong, it closes the underlying relay connection before +returning.

+
source

pub async fn send( + &self, + dst_key: PublicKey, + b: Bytes +) -> Result<(), ClientError>

Send a packet to the server.

+

If there is no underlying active relay connection, it creates one before attempting to +send the message.

+

If there is an error sending the packet, it closes the underlying relay connection before +returning.

+
source

pub async fn close(self) -> Result<(), ClientError>

Close the http relay connection.

+
source

pub async fn close_for_reconnect(&self) -> Result<(), ClientError>

Disconnect the http relay connection.

+
source

pub async fn is_connected(&self) -> Result<bool, ClientError>

Returns true if the underlying relay connection is established.

+

Trait Implementations§

source§

impl Clone for Client

source§

fn clone(&self) -> Client

Returns a copy 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 Client

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Client

§

impl RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl UnwindSafe for Client

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/struct.ClientBuilder.html b/pr/2992/docs/iroh_relay/client/struct.ClientBuilder.html new file mode 100644 index 0000000000..2e59be04d8 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/struct.ClientBuilder.html @@ -0,0 +1,50 @@ +ClientBuilder in iroh_relay::client - Rust

Struct iroh_relay::client::ClientBuilder

source ·
pub struct ClientBuilder { /* private fields */ }
Expand description

Build a Client.

+

Implementations§

source§

impl ClientBuilder

source

pub fn new(url: impl Into<RelayUrl>) -> Self

Create a new ClientBuilder

+
source

pub fn server_url(self, url: impl Into<RelayUrl>) -> Self

Sets the server url

+
source

pub fn protocol(self, protocol: Protocol) -> Self

Sets whether to connect to the relay via websockets or not. +Set to use non-websocket, normal relaying by default.

+
source

pub fn address_family_selector<S>(self, selector: S) -> Self
where + S: Fn() -> BoxFuture<bool> + Send + Sync + 'static,

Returns if we should prefer ipv6 +it replaces the relayhttp.AddressFamilySelector we pass +It provides the hint as to whether in an IPv4-vs-IPv6 race that +IPv4 should be held back a bit to give IPv6 a better-than-50/50 +chance of winning. We only return true when we believe IPv6 will +work anyway, so we don’t artificially delay the connection speed.

+
source

pub fn can_ack_pings(self, can: bool) -> Self

Enable this Client to acknowledge pings.

+
source

pub fn is_preferred(self, is: bool) -> Self

Indicate this client is the preferred way to communicate +to the peer with this client’s PublicKey

+
source

pub fn is_prober(self, is: bool) -> Self

Indicates this client is a prober

+
source

pub fn insecure_skip_cert_verify(self, skip: bool) -> Self

Available on test or crate feature test-utils only.

Skip the verification of the relay server’s SSL certificates.

+

May only be used in tests.

+
source

pub fn proxy_url(self, url: Url) -> Self

Set an explicit proxy url to proxy all HTTP(S) traffic through.

+
source

pub fn build( + self, + key: SecretKey, + dns_resolver: DnsResolver +) -> (Client, ClientReceiver)

Build the Client

+
source

pub fn server_public_key(self, server_public_key: PublicKey) -> Self

The expected PublicKey of the relay server we are connecting to.

+

Trait Implementations§

source§

impl Debug for ClientBuilder

source§

fn fmt(&self, __derive_more_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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/client/struct.ClientReceiver.html b/pr/2992/docs/iroh_relay/client/struct.ClientReceiver.html new file mode 100644 index 0000000000..4ece53e304 --- /dev/null +++ b/pr/2992/docs/iroh_relay/client/struct.ClientReceiver.html @@ -0,0 +1,27 @@ +ClientReceiver in iroh_relay::client - Rust

Struct iroh_relay::client::ClientReceiver

source ·
pub struct ClientReceiver { /* private fields */ }
Expand description

Receiving end of a Client.

+

Implementations§

source§

impl ClientReceiver

source

pub async fn recv(&mut self) -> Option<Result<ReceivedMessage, ClientError>>

Reads a message from the server.

+

Trait Implementations§

source§

impl Debug for ClientReceiver

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTPS_PORT.html b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTPS_PORT.html new file mode 100644 index 0000000000..8f9d48a39a --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTPS_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_HTTPS_PORT in iroh_relay::defaults - Rust

Constant iroh_relay::defaults::DEFAULT_HTTPS_PORT

source ·
pub const DEFAULT_HTTPS_PORT: u16 = 443;
Expand description

The default HTTPS port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTP_PORT.html b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTP_PORT.html new file mode 100644 index 0000000000..fad657be1d --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_HTTP_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_HTTP_PORT in iroh_relay::defaults - Rust

Constant iroh_relay::defaults::DEFAULT_HTTP_PORT

source ·
pub const DEFAULT_HTTP_PORT: u16 = 80;
Expand description

The default HTTP port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_METRICS_PORT.html b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_METRICS_PORT.html new file mode 100644 index 0000000000..b2e410e9fd --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_METRICS_PORT.html @@ -0,0 +1,2 @@ +DEFAULT_METRICS_PORT in iroh_relay::defaults - Rust

Constant iroh_relay::defaults::DEFAULT_METRICS_PORT

source ·
pub const DEFAULT_METRICS_PORT: u16 = 9090;
Expand description

The default metrics port used by the Relay server.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html new file mode 100644 index 0000000000..ea28b1a21f --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_RELAY_QUIC_PORT.html @@ -0,0 +1,4 @@ +DEFAULT_RELAY_QUIC_PORT in iroh_relay::defaults - Rust

Constant iroh_relay::defaults::DEFAULT_RELAY_QUIC_PORT

source ·
pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842; // 7_842u16
Expand description

The default QUIC port used by the Relay server to accept QUIC connections +for QUIC address discovery

+

The port is “QUIC” typed on a phone keypad.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_STUN_PORT.html b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_STUN_PORT.html new file mode 100644 index 0000000000..5ff94fe6cd --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/constant.DEFAULT_STUN_PORT.html @@ -0,0 +1,3 @@ +DEFAULT_STUN_PORT in iroh_relay::defaults - Rust

Constant iroh_relay::defaults::DEFAULT_STUN_PORT

source ·
pub const DEFAULT_STUN_PORT: u16 = 3478; // 3_478u16
Expand description

The default STUN port used by the Relay server.

+

The STUN port as defined by RFC 8489

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/index.html b/pr/2992/docs/iroh_relay/defaults/index.html new file mode 100644 index 0000000000..7f14a38a8b --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/index.html @@ -0,0 +1,3 @@ +iroh_relay::defaults - Rust

Module iroh_relay::defaults

source ·
Expand description

Default values used in the relay.

+

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/defaults/sidebar-items.js b/pr/2992/docs/iroh_relay/defaults/sidebar-items.js new file mode 100644 index 0000000000..1bbea1bf51 --- /dev/null +++ b/pr/2992/docs/iroh_relay/defaults/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["DEFAULT_HTTPS_PORT","DEFAULT_HTTP_PORT","DEFAULT_METRICS_PORT","DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/enum.ReceivedMessage.html b/pr/2992/docs/iroh_relay/enum.ReceivedMessage.html new file mode 100644 index 0000000000..82cff28479 --- /dev/null +++ b/pr/2992/docs/iroh_relay/enum.ReceivedMessage.html @@ -0,0 +1,67 @@ +ReceivedMessage in iroh_relay - Rust

Enum iroh_relay::ReceivedMessage

source ·
pub enum ReceivedMessage {
+    ReceivedPacket {
+        source: NodeId,
+        data: Bytes,
+    },
+    NodeGone(NodeId),
+    Ping([u8; 8]),
+    Pong([u8; 8]),
+    KeepAlive,
+    Health {
+        problem: Option<String>,
+    },
+    ServerRestarting {
+        reconnect_in: Duration,
+        try_for: Duration,
+    },
+}
Expand description

The type of message received by the Conn from a relay server.

+

Variants§

§

ReceivedPacket

Represents an incoming packet.

+

Fields

§source: NodeId

The NodeId of the packet sender.

+
§data: Bytes

The received packet bytes.

+
§

NodeGone(NodeId)

Indicates that the client identified by the underlying public key had previously sent you a +packet but has now disconnected from the server.

+
§

Ping([u8; 8])

Request from a client or server to reply to the +other side with a ReceivedMessage::Pong with the given payload.

+
§

Pong([u8; 8])

Reply to a ReceivedMessage::Ping from a client or server +with the payload sent previously in the ping.

+
§

KeepAlive

A one-way empty message from server to client, just to +keep the connection alive. It’s like a ReceivedMessage::Ping, but doesn’t solicit +a reply from the client.

+
§

Health

A one-way message from server to client, declaring the connection health state.

+

Fields

§problem: Option<String>

If set, is a description of why the connection is unhealthy.

+

If None means the connection is healthy again.

+

The default condition is healthy, so the server doesn’t broadcast a ReceivedMessage::Health +until a problem exists.

+
§

ServerRestarting

A one-way message from server to client, advertising that the server is restarting.

+

Fields

§reconnect_in: Duration

An advisory duration that the client should wait before attempting to reconnect. +It might be zero. It exists for the server to smear out the reconnects.

+
§try_for: Duration

An advisory duration for how long the client should attempt to reconnect +before giving up and proceeding with its normal connection failure logic. The interval +between retries is undefined for now. A server should not send a TryFor duration more +than a few seconds.

+

Trait Implementations§

source§

impl Clone for ReceivedMessage

source§

fn clone(&self) -> ReceivedMessage

Returns a copy 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 ReceivedMessage

source§

fn fmt(&self, __derive_more_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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/http/constant.RELAY_PATH.html b/pr/2992/docs/iroh_relay/http/constant.RELAY_PATH.html new file mode 100644 index 0000000000..d8cfef1f6e --- /dev/null +++ b/pr/2992/docs/iroh_relay/http/constant.RELAY_PATH.html @@ -0,0 +1,3 @@ +RELAY_PATH in iroh_relay::http - Rust

Constant iroh_relay::http::RELAY_PATH

source ·
pub const RELAY_PATH: &str = "/relay";
Expand description

The HTTP path under which the relay accepts relaying connections +(over websockets and a custom upgrade protocol).

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/http/constant.RELAY_PROBE_PATH.html b/pr/2992/docs/iroh_relay/http/constant.RELAY_PROBE_PATH.html new file mode 100644 index 0000000000..d99d67d729 --- /dev/null +++ b/pr/2992/docs/iroh_relay/http/constant.RELAY_PROBE_PATH.html @@ -0,0 +1,2 @@ +RELAY_PROBE_PATH in iroh_relay::http - Rust

Constant iroh_relay::http::RELAY_PROBE_PATH

source ·
pub const RELAY_PROBE_PATH: &str = "/ping";
Expand description

The HTTP path under which the relay allows doing latency queries for testing.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/http/enum.Protocol.html b/pr/2992/docs/iroh_relay/http/enum.Protocol.html new file mode 100644 index 0000000000..1a3fd76d75 --- /dev/null +++ b/pr/2992/docs/iroh_relay/http/enum.Protocol.html @@ -0,0 +1,41 @@ +Protocol in iroh_relay::http - Rust

Enum iroh_relay::http::Protocol

source ·
pub enum Protocol {
+    Relay,
+    Websocket,
+}
Expand description

The HTTP upgrade protocol used for relaying.

+

Variants§

§

Relay

Relays over the custom relaying protocol with a custom HTTP upgrade header.

+
§

Websocket

Relays over websockets.

+

Originally introduced to support browser connections.

+

Implementations§

source§

impl Protocol

source

pub const fn upgrade_header(&self) -> &'static str

The HTTP upgrade header used or expected.

+
source

pub fn parse_header(header: &HeaderValue) -> Option<Self>

Tries to match the value of an HTTP upgrade header to figure out which protocol should be initiated.

+

Trait Implementations§

source§

impl Clone for Protocol

source§

fn clone(&self) -> Protocol

Returns a copy 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 Protocol

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for Protocol

source§

fn eq(&self, other: &Protocol) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for Protocol

source§

impl Eq for Protocol

source§

impl StructuralPartialEq for Protocol

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/http/index.html b/pr/2992/docs/iroh_relay/http/index.html new file mode 100644 index 0000000000..5a1ddbf9b7 --- /dev/null +++ b/pr/2992/docs/iroh_relay/http/index.html @@ -0,0 +1,3 @@ +iroh_relay::http - Rust

Module iroh_relay::http

source ·
Expand description

HTTP-specific constants for the relay server and client.

+

Enums§

  • The HTTP upgrade protocol used for relaying.

Constants§

  • The HTTP path under which the relay accepts relaying connections +(over websockets and a custom upgrade protocol).
  • The HTTP path under which the relay allows doing latency queries for testing.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/http/sidebar-items.js b/pr/2992/docs/iroh_relay/http/sidebar-items.js new file mode 100644 index 0000000000..3f7df87d82 --- /dev/null +++ b/pr/2992/docs/iroh_relay/http/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["RELAY_PATH","RELAY_PROBE_PATH"],"enum":["Protocol"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/index.html b/pr/2992/docs/iroh_relay/index.html new file mode 100644 index 0000000000..0f34ad054b --- /dev/null +++ b/pr/2992/docs/iroh_relay/index.html @@ -0,0 +1,21 @@ +iroh_relay - Rust

Crate iroh_relay

source ·
Expand description

Iroh’s relay is a feature within iroh, a peer-to-peer +networking system designed to facilitate direct, encrypted connections between devices. Iroh +aims to simplify decentralized communication by automatically handling connections through +“relays” when direct connections aren’t immediately possible. The relay server helps establish +connections by temporarily routing encrypted traffic until a direct, P2P connection is +feasible. Once this direct path is set up, the relay server steps back, and the data flows +directly between devices. This approach allows Iroh to maintain a secure, low-latency +connection, even in challenging network situations.

+

This crate provides a complete setup for creating and interacting with iroh relays, including:

+
    +
  • protos::relay: The protocol used to communicate between relay servers and clients. It’s a +revised version of the Designated Encrypted Relay for Packets (DERP) protocol written by +Tailscale.
  • +
  • server: A fully-fledged iroh-relay server over HTTP or HTTPS. Optionally will also +expose a stun endpoint and metrics.
  • +
  • client: A client for establishing connections to the relay.
  • +
  • Server Binary: A CLI for running your own relay server. It can be configured to also offer +STUN support and expose metrics.
  • +
+

Re-exports§

Modules§

  • Exposes Client, which allows to establish connections to a relay server.
  • Default values used in the relay.
  • HTTP-specific constants for the relay server and client.
  • Protocols used by the iroh-relay
  • Create a QUIC server that accepts connections +for QUIC address discovery.
  • serverserver
    A fully-fledged iroh-relay server over HTTP or HTTPS.

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/disco/constant.MAGIC.html b/pr/2992/docs/iroh_relay/protos/disco/constant.MAGIC.html new file mode 100644 index 0000000000..70112a759b --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/disco/constant.MAGIC.html @@ -0,0 +1,2 @@ +MAGIC in iroh_relay::protos::disco - Rust

Constant iroh_relay::protos::disco::MAGIC

source ·
pub const MAGIC: &str = "TS💬";
Expand description

The 6 byte header of all discovery messages.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/disco/fn.looks_like_disco_wrapper.html b/pr/2992/docs/iroh_relay/protos/disco/fn.looks_like_disco_wrapper.html new file mode 100644 index 0000000000..441d477edb --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/disco/fn.looks_like_disco_wrapper.html @@ -0,0 +1,2 @@ +looks_like_disco_wrapper in iroh_relay::protos::disco - Rust

Function iroh_relay::protos::disco::looks_like_disco_wrapper

source ·
pub fn looks_like_disco_wrapper(p: &[u8]) -> bool
Expand description

Reports whether p looks like it’s a packet containing an encrypted disco message.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/disco/index.html b/pr/2992/docs/iroh_relay/protos/disco/index.html new file mode 100644 index 0000000000..60293045ed --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/disco/index.html @@ -0,0 +1,5 @@ +iroh_relay::protos::disco - Rust

Module iroh_relay::protos::disco

source ·
Expand description

This module exports looks_like_disco_wrapper as the only disco-related relay +functionality.

+

Despite the relay not being able to read disco messages by design, it does attempt to +identify this traffic to ensure hole-punching messages are not lost do to congestion.

+

Constants§

  • The 6 byte header of all discovery messages.

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/disco/sidebar-items.js b/pr/2992/docs/iroh_relay/protos/disco/sidebar-items.js new file mode 100644 index 0000000000..76f050d88e --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/disco/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["MAGIC"],"fn":["looks_like_disco_wrapper"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/index.html b/pr/2992/docs/iroh_relay/protos/index.html new file mode 100644 index 0000000000..2b2eb5e33d --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/index.html @@ -0,0 +1,3 @@ +iroh_relay::protos - Rust

Module iroh_relay::protos

source ·
Expand description

Protocols used by the iroh-relay

+

Modules§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/relay/constant.MAX_PACKET_SIZE.html b/pr/2992/docs/iroh_relay/protos/relay/constant.MAX_PACKET_SIZE.html new file mode 100644 index 0000000000..2d8770ec98 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/relay/constant.MAX_PACKET_SIZE.html @@ -0,0 +1,4 @@ +MAX_PACKET_SIZE in iroh_relay::protos::relay - Rust

Constant iroh_relay::protos::relay::MAX_PACKET_SIZE

source ·
pub const MAX_PACKET_SIZE: usize = _; // 65_536usize
Expand description

The maximum size of a packet sent over relay. +(This only includes the data bytes visible to magicsock, not +including its on-wire framing overhead)

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/relay/index.html b/pr/2992/docs/iroh_relay/protos/relay/index.html new file mode 100644 index 0000000000..4f9ccf9af1 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/relay/index.html @@ -0,0 +1,17 @@ +iroh_relay::protos::relay - Rust

Module iroh_relay::protos::relay

source ·
Expand description

This module implements the relaying protocol used the crate::server and crate::client.

+

Protocol flow:

+

Login:

+
    +
  • client connects
  • +
  • -> client sends FrameType::ClientInfo
  • +
+

Steady state:

+
    +
  • server occasionally sends FrameType::KeepAlive (or FrameType::Ping)
  • +
  • client responds to any FrameType::Ping with a FrameType::Pong
  • +
  • clients sends FrameType::SendPacket
  • +
  • server then sends FrameType::RecvPacket to recipient
  • +
+

Constants§

  • The maximum size of a packet sent over relay. +(This only includes the data bytes visible to magicsock, not +including its on-wire framing overhead)
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/relay/sidebar-items.js b/pr/2992/docs/iroh_relay/protos/relay/sidebar-items.js new file mode 100644 index 0000000000..8c93ecfb86 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/relay/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["MAX_PACKET_SIZE"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/sidebar-items.js b/pr/2992/docs/iroh_relay/protos/sidebar-items.js new file mode 100644 index 0000000000..0b51f511d3 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["disco","relay","stun"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/enum.Error.html b/pr/2992/docs/iroh_relay/protos/stun/enum.Error.html new file mode 100644 index 0000000000..61223d6fda --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/enum.Error.html @@ -0,0 +1,40 @@ +Error in iroh_relay::protos::stun - Rust

Enum iroh_relay::protos::stun::Error

source ·
pub enum Error {
+    InvalidMessage,
+    NotBinding,
+    NotSuccessResponse,
+    MalformedAttrs,
+    NoFingerprint,
+    InvalidFingerprint,
+}
Expand description

Errors that can occur when handling a STUN packet.

+

Variants§

§

InvalidMessage

The STUN message could not be parsed or is otherwise invalid.

+
§

NotBinding

STUN request is not a binding request when it should be.

+
§

NotSuccessResponse

STUN packet is not a response when it should be.

+
§

MalformedAttrs

STUN response has malformed attributes.

+
§

NoFingerprint

STUN request didn’t end in fingerprint.

+
§

InvalidFingerprint

STUN request had bogus fingerprint.

+

Trait Implementations§

source§

impl Debug for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Display for Error

source§

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

Formats the value using the given formatter. Read more
source§

impl Error for Error

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more

Auto Trait Implementations§

§

impl Freeze for Error

§

impl RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnwindSafe for Error

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/enum.MessageClass.html b/pr/2992/docs/iroh_relay/protos/stun/enum.MessageClass.html new file mode 100644 index 0000000000..37ae0b9959 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/enum.MessageClass.html @@ -0,0 +1,49 @@ +MessageClass in iroh_relay::protos::stun - Rust

Enum iroh_relay::protos::stun::MessageClass

pub enum MessageClass {
+    Request,
+    Indication,
+    SuccessResponse,
+    ErrorResponse,
+}
Expand description

The STUN message class. Although there are four +message classes, there are only two types of transactions in STUN: +request/response transactions (which consist of a request message and +a response message) and indication transactions (which consist of a +single indication message). Response classes are split into error +and success responses to aid in quickly processing the STUN message.

+

Variants§

§

Request

request

+
§

Indication

indication

+
§

SuccessResponse

success response

+
§

ErrorResponse

error response

+

Trait Implementations§

§

impl Clone for MessageClass

§

fn clone(&self) -> MessageClass

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for MessageClass

§

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

Formats the value using the given formatter. Read more
§

impl PartialEq for MessageClass

§

fn eq(&self, other: &MessageClass) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl TryFrom<u8> for MessageClass

§

type Error = StunError

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

fn try_from( + value: u8 +) -> Result<MessageClass, <MessageClass as TryFrom<u8>>::Error>

Performs the conversion.
§

impl Copy for MessageClass

§

impl Eq for MessageClass

§

impl StructuralPartialEq for MessageClass

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/enum.StunAttribute.html b/pr/2992/docs/iroh_relay/protos/stun/enum.StunAttribute.html new file mode 100644 index 0000000000..7f1832005a --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/enum.StunAttribute.html @@ -0,0 +1,143 @@ +StunAttribute in iroh_relay::protos::stun - Rust

Enum iroh_relay::protos::stun::StunAttribute

pub enum StunAttribute {
+
Show 16 variants Unknown(Unknown), + AlternateServer(AlternateServer), + ErrorCode(ErrorCode), + Fingerprint(Fingerprint), + MappedAddress(MappedAddress), + MessageIntegrity(MessageIntegrity), + MessageIntegritySha256(MessageIntegritySha256), + Nonce(Nonce), + PasswordAlgorithm(PasswordAlgorithm), + PasswordAlgorithms(PasswordAlgorithms), + Realm(Realm), + Software(Software), + UnknownAttributes(UnknownAttributes), + UserHash(UserHash), + UserName(UserName), + XorMappedAddress(XorMappedAddress), +
}
Expand description

STUN Attributes that can be attached to a StunMessage

+

Variants§

§

Unknown(Unknown)

The Unknownatribute

+
§

AlternateServer(AlternateServer)

The AlternateServeratribute

+
§

ErrorCode(ErrorCode)

The ErrorCodeatribute

+
§

Fingerprint(Fingerprint)

The Fingerprintatribute

+
§

MappedAddress(MappedAddress)

The MappedAddressatribute

+
§

MessageIntegrity(MessageIntegrity)

The MessageIntegrityatribute

+
§

MessageIntegritySha256(MessageIntegritySha256)

The MessageIntegritySha256atribute

+
§

Nonce(Nonce)

The Nonceatribute

+
§

PasswordAlgorithm(PasswordAlgorithm)

The PasswordAlgorithmatribute

+
§

PasswordAlgorithms(PasswordAlgorithms)

The PasswordAlgorithmsatribute

+
§

Realm(Realm)

The Realmatribute

+
§

Software(Software)

The Softwareatribute

+
§

UnknownAttributes(UnknownAttributes)

The UnknownAttributesatribute

+
§

UserHash(UserHash)

The UserHashatribute

+
§

UserName(UserName)

The UserNameatribute

+
§

XorMappedAddress(XorMappedAddress)

The XorMappedAddressatribute

+

Implementations§

§

impl StunAttribute

pub fn attribute_type(&self) -> AttributeType

Returns the STUN attribute type of this instance.

+

pub fn is_unknown(&self) -> bool

Returns true if this StunAttribute is Unknown

+

pub fn as_unknown(&self) -> Result<&Unknown, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not Unknown

+

pub fn expect_unknown(&self) -> &Unknown

Returns a reference to the Unknown attribute.

+
§Panics
+

Panics if the attribute is not an Unknown

+

pub fn is_alternate_server(&self) -> bool

Returns true if this StunAttribute is AlternateServer

+

pub fn as_alternate_server(&self) -> Result<&AlternateServer, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not AlternateServer

+

pub fn expect_alternate_server(&self) -> &AlternateServer

Returns a reference to the AlternateServer attribute.

+
§Panics
+

Panics if the attribute is not an AlternateServer

+

pub fn is_error_code(&self) -> bool

Returns true if this StunAttribute is ErrorCode

+

pub fn as_error_code(&self) -> Result<&ErrorCode, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not ErrorCode

+

pub fn expect_error_code(&self) -> &ErrorCode

Returns a reference to the ErrorCode attribute.

+
§Panics
+

Panics if the attribute is not an ErrorCode

+

pub fn is_fingerprint(&self) -> bool

Returns true if this StunAttribute is Fingerprint

+

pub fn as_fingerprint(&self) -> Result<&Fingerprint, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not Fingerprint

+

pub fn expect_fingerprint(&self) -> &Fingerprint

Returns a reference to the Fingerprint attribute.

+
§Panics
+

Panics if the attribute is not an Fingerprint

+

pub fn is_mapped_address(&self) -> bool

Returns true if this StunAttribute is MappedAddress

+

pub fn as_mapped_address(&self) -> Result<&MappedAddress, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not MappedAddress

+

pub fn expect_mapped_address(&self) -> &MappedAddress

Returns a reference to the MappedAddress attribute.

+
§Panics
+

Panics if the attribute is not an MappedAddress

+

pub fn is_message_integrity(&self) -> bool

Returns true if this StunAttribute is MessageIntegrity

+

pub fn as_message_integrity(&self) -> Result<&MessageIntegrity, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not MessageIntegrity

+

pub fn expect_message_integrity(&self) -> &MessageIntegrity

Returns a reference to the MessageIntegrity attribute.

+
§Panics
+

Panics if the attribute is not an MessageIntegrity

+

pub fn is_message_integrity_sha256(&self) -> bool

Returns true if this StunAttribute is MessageIntegritySha256

+

pub fn as_message_integrity_sha256( + &self +) -> Result<&MessageIntegritySha256, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not MessageIntegritySha256

+

pub fn expect_message_integrity_sha256(&self) -> &MessageIntegritySha256

Returns a reference to the MessageIntegritySha256 attribute.

+
§Panics
+

Panics if the attribute is not an MessageIntegritySha256

+

pub fn is_nonce(&self) -> bool

Returns true if this StunAttribute is Nonce

+

pub fn as_nonce(&self) -> Result<&Nonce, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not Nonce

+

pub fn expect_nonce(&self) -> &Nonce

Returns a reference to the Nonce attribute.

+
§Panics
+

Panics if the attribute is not an Nonce

+

pub fn is_password_algorithm(&self) -> bool

Returns true if this StunAttribute is PasswordAlgorithm

+

pub fn as_password_algorithm(&self) -> Result<&PasswordAlgorithm, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not PasswordAlgorithm

+

pub fn expect_password_algorithm(&self) -> &PasswordAlgorithm

Returns a reference to the PasswordAlgorithm attribute.

+
§Panics
+

Panics if the attribute is not an PasswordAlgorithm

+

pub fn is_password_algorithms(&self) -> bool

Returns true if this StunAttribute is PasswordAlgorithms

+

pub fn as_password_algorithms(&self) -> Result<&PasswordAlgorithms, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not PasswordAlgorithms

+

pub fn expect_password_algorithms(&self) -> &PasswordAlgorithms

Returns a reference to the PasswordAlgorithms attribute.

+
§Panics
+

Panics if the attribute is not an PasswordAlgorithms

+

pub fn is_realm(&self) -> bool

Returns true if this StunAttribute is Realm

+

pub fn as_realm(&self) -> Result<&Realm, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not Realm

+

pub fn expect_realm(&self) -> &Realm

Returns a reference to the Realm attribute.

+
§Panics
+

Panics if the attribute is not an Realm

+

pub fn is_software(&self) -> bool

Returns true if this StunAttribute is Software

+

pub fn as_software(&self) -> Result<&Software, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not Software

+

pub fn expect_software(&self) -> &Software

Returns a reference to the Software attribute.

+
§Panics
+

Panics if the attribute is not an Software

+

pub fn is_unknown_attributes(&self) -> bool

Returns true if this StunAttribute is UnknownAttributes

+

pub fn as_unknown_attributes(&self) -> Result<&UnknownAttributes, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not UnknownAttributes

+

pub fn expect_unknown_attributes(&self) -> &UnknownAttributes

Returns a reference to the UnknownAttributes attribute.

+
§Panics
+

Panics if the attribute is not an UnknownAttributes

+

pub fn is_user_hash(&self) -> bool

Returns true if this StunAttribute is UserHash

+

pub fn as_user_hash(&self) -> Result<&UserHash, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not UserHash

+

pub fn expect_user_hash(&self) -> &UserHash

Returns a reference to the UserHash attribute.

+
§Panics
+

Panics if the attribute is not an UserHash

+

pub fn is_user_name(&self) -> bool

Returns true if this StunAttribute is UserName

+

pub fn as_user_name(&self) -> Result<&UserName, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not UserName

+

pub fn expect_user_name(&self) -> &UserName

Returns a reference to the UserName attribute.

+
§Panics
+

Panics if the attribute is not an UserName

+

pub fn is_xor_mapped_address(&self) -> bool

Returns true if this StunAttribute is XorMappedAddress

+

pub fn as_xor_mapped_address(&self) -> Result<&XorMappedAddress, StunError>

Returns a reference to the internal attribute value or an error if the type of the attribute is not XorMappedAddress

+

pub fn expect_xor_mapped_address(&self) -> &XorMappedAddress

Returns a reference to the XorMappedAddress attribute.

+
§Panics
+

Panics if the attribute is not an XorMappedAddress

+

Trait Implementations§

§

impl Clone for StunAttribute

§

fn clone(&self) -> StunAttribute

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for StunAttribute

§

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

Formats the value using the given formatter. Read more
§

impl From<AlternateServer> for StunAttribute

§

fn from(value: AlternateServer) -> StunAttribute

Converts to this type from the input type.
§

impl From<ErrorCode> for StunAttribute

§

fn from(value: ErrorCode) -> StunAttribute

Converts to this type from the input type.
§

impl From<Fingerprint> for StunAttribute

§

fn from(value: Fingerprint) -> StunAttribute

Converts to this type from the input type.
§

impl From<MappedAddress> for StunAttribute

§

fn from(value: MappedAddress) -> StunAttribute

Converts to this type from the input type.
§

impl From<MessageIntegrity> for StunAttribute

§

fn from(value: MessageIntegrity) -> StunAttribute

Converts to this type from the input type.
§

impl From<MessageIntegritySha256> for StunAttribute

§

fn from(value: MessageIntegritySha256) -> StunAttribute

Converts to this type from the input type.
§

impl From<Nonce> for StunAttribute

§

fn from(value: Nonce) -> StunAttribute

Converts to this type from the input type.
§

impl From<PasswordAlgorithm> for StunAttribute

§

fn from(value: PasswordAlgorithm) -> StunAttribute

Converts to this type from the input type.
§

impl From<PasswordAlgorithms> for StunAttribute

§

fn from(value: PasswordAlgorithms) -> StunAttribute

Converts to this type from the input type.
§

impl From<Realm> for StunAttribute

§

fn from(value: Realm) -> StunAttribute

Converts to this type from the input type.
§

impl From<Software> for StunAttribute

§

fn from(value: Software) -> StunAttribute

Converts to this type from the input type.
§

impl From<Unknown> for StunAttribute

§

fn from(value: Unknown) -> StunAttribute

Converts to this type from the input type.
§

impl From<UnknownAttributes> for StunAttribute

§

fn from(value: UnknownAttributes) -> StunAttribute

Converts to this type from the input type.
§

impl From<UserHash> for StunAttribute

§

fn from(value: UserHash) -> StunAttribute

Converts to this type from the input type.
§

impl From<UserName> for StunAttribute

§

fn from(value: UserName) -> StunAttribute

Converts to this type from the input type.
§

impl From<XorMappedAddress> for StunAttribute

§

fn from(value: XorMappedAddress) -> StunAttribute

Converts to this type from the input type.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/fn.is.html b/pr/2992/docs/iroh_relay/protos/stun/fn.is.html new file mode 100644 index 0000000000..b3c5a8cabf --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/fn.is.html @@ -0,0 +1,2 @@ +is in iroh_relay::protos::stun - Rust

Function iroh_relay::protos::stun::is

source ·
pub fn is(b: &[u8]) -> bool
Expand description

Reports whether b is a STUN message.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/fn.parse_binding_request.html b/pr/2992/docs/iroh_relay/protos/stun/fn.parse_binding_request.html new file mode 100644 index 0000000000..90ff7219cb --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/fn.parse_binding_request.html @@ -0,0 +1,2 @@ +parse_binding_request in iroh_relay::protos::stun - Rust

Function iroh_relay::protos::stun::parse_binding_request

source ·
pub fn parse_binding_request(b: &[u8]) -> Result<TransactionId, Error>
Expand description

Parses a STUN binding request.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/fn.parse_response.html b/pr/2992/docs/iroh_relay/protos/stun/fn.parse_response.html new file mode 100644 index 0000000000..2a798b641b --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/fn.parse_response.html @@ -0,0 +1,3 @@ +parse_response in iroh_relay::protos::stun - Rust

Function iroh_relay::protos::stun::parse_response

source ·
pub fn parse_response(b: &[u8]) -> Result<(TransactionId, SocketAddr), Error>
Expand description

Parses a successful binding response STUN packet. +The IP address is extracted from the XOR-MAPPED-ADDRESS attribute.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/fn.request.html b/pr/2992/docs/iroh_relay/protos/stun/fn.request.html new file mode 100644 index 0000000000..813b8cdf48 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/fn.request.html @@ -0,0 +1,2 @@ +request in iroh_relay::protos::stun - Rust

Function iroh_relay::protos::stun::request

source ·
pub fn request(tx: TransactionId) -> Vec<u8> 
Expand description

Generates a binding request STUN packet.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/fn.response.html b/pr/2992/docs/iroh_relay/protos/stun/fn.response.html new file mode 100644 index 0000000000..90672c6a89 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/fn.response.html @@ -0,0 +1,2 @@ +response in iroh_relay::protos::stun - Rust

Function iroh_relay::protos::stun::response

source ·
pub fn response(tx: TransactionId, addr: SocketAddr) -> Vec<u8> 
Expand description

Generates a binding response.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/index.html b/pr/2992/docs/iroh_relay/protos/stun/index.html new file mode 100644 index 0000000000..180a50fe76 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/index.html @@ -0,0 +1,12 @@ +iroh_relay::protos::stun - Rust

Module iroh_relay::protos::stun

source ·
Expand description

STUN packets sending and receiving.

+

Modules§

Structs§

  • Class used to decode STUN messages
  • Describes an error decoding a StunMessage
  • The transaction ID is a 96-bit identifier, used to uniquely identify +STUN transactions. It primarily serves to correlate requests with +responses, though it also plays a small role in helping to prevent +certain types of attacks. The server also uses the transaction ID as +a key to identify each transaction uniquely across all clients.

Enums§

  • Errors that can occur when handling a STUN packet.
  • The STUN message class. Although there are four +message classes, there are only two types of transactions in STUN: +request/response transactions (which consist of a request message and +a response message) and indication transactions (which consist of a +single indication message). Response classes are split into error +and success responses to aid in quickly processing the STUN message.
  • STUN Attributes that can be attached to a StunMessage

Functions§

  • Reports whether b is a STUN message.
  • Parses a STUN binding request.
  • Parses a successful binding response STUN packet. +The IP address is extracted from the XOR-MAPPED-ADDRESS attribute.
  • Generates a binding request STUN packet.
  • Generates a binding response.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/methods/constant.BINDING.html b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.BINDING.html new file mode 100644 index 0000000000..a57d291628 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.BINDING.html @@ -0,0 +1,2 @@ +BINDING in iroh_relay::protos::stun::methods - Rust

Constant iroh_relay::protos::stun::methods::BINDING

pub const BINDING: MessageMethod;
Expand description

Binding

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/methods/constant.RESERVED.html b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.RESERVED.html new file mode 100644 index 0000000000..14b80e409a --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.RESERVED.html @@ -0,0 +1,2 @@ +RESERVED in iroh_relay::protos::stun::methods - Rust

Constant iroh_relay::protos::stun::methods::RESERVED

pub const RESERVED: MessageMethod;
Expand description

Reserved

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/methods/constant.SHARED_SECRET.html b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.SHARED_SECRET.html new file mode 100644 index 0000000000..51a1b604de --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/methods/constant.SHARED_SECRET.html @@ -0,0 +1,2 @@ +SHARED_SECRET in iroh_relay::protos::stun::methods - Rust

Constant iroh_relay::protos::stun::methods::SHARED_SECRET

pub const SHARED_SECRET: MessageMethod;
Expand description

Shared secret

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/methods/index.html b/pr/2992/docs/iroh_relay/protos/stun/methods/index.html new file mode 100644 index 0000000000..840beed359 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/methods/index.html @@ -0,0 +1,2 @@ +iroh_relay::protos::stun::methods - Rust

Module iroh_relay::protos::stun::methods

Expand description

STUN Methods Registry

+

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/methods/sidebar-items.js b/pr/2992/docs/iroh_relay/protos/stun/methods/sidebar-items.js new file mode 100644 index 0000000000..a5120a8f76 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/methods/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["BINDING","RESERVED","SHARED_SECRET"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/sidebar-items.js b/pr/2992/docs/iroh_relay/protos/stun/sidebar-items.js new file mode 100644 index 0000000000..2c6cf51d32 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Error","MessageClass","StunAttribute"],"fn":["is","parse_binding_request","parse_response","request","response"],"mod":["methods"],"struct":["MessageDecoder","StunDecodeError","TransactionId"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/struct.MessageDecoder.html b/pr/2992/docs/iroh_relay/protos/stun/struct.MessageDecoder.html new file mode 100644 index 0000000000..d9b0197e7a --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/struct.MessageDecoder.html @@ -0,0 +1,39 @@ +MessageDecoder in iroh_relay::protos::stun - Rust

Struct iroh_relay::protos::stun::MessageDecoder

pub struct MessageDecoder { /* private fields */ }
Expand description

Class used to decode STUN messages

+

Implementations§

§

impl MessageDecoder

pub fn decode( + &self, + buffer: &[u8] +) -> Result<(StunMessage, usize), StunDecodeError>

Decodes the STUN raw buffer

+
§Arguments:
+
    +
  • buffer - Raw buffer containing the STUN message
  • +
+
§Returns:
+

A tuple with [StunMessage] itself and the size consumed to decode the message, +or an error describing the problem if the message could not be decoded.

+

pub fn get_context(&self) -> Option<&DecoderContext>

Gets the context associated to this decoder

+

Trait Implementations§

§

impl Clone for MessageDecoder

§

fn clone(&self) -> MessageDecoder

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for MessageDecoder

§

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

Formats the value using the given formatter. Read more
§

impl Default for MessageDecoder

§

fn default() -> MessageDecoder

Returns the “default value” for a type. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/struct.StunDecodeError.html b/pr/2992/docs/iroh_relay/protos/stun/struct.StunDecodeError.html new file mode 100644 index 0000000000..b055bdf531 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/struct.StunDecodeError.html @@ -0,0 +1,27 @@ +StunDecodeError in iroh_relay::protos::stun - Rust

Struct iroh_relay::protos::stun::StunDecodeError

pub struct StunDecodeError(pub StunErrorLevel);
Expand description

Describes an error decoding a StunMessage

+

Tuple Fields§

§0: StunErrorLevel

Trait Implementations§

§

impl Debug for StunDecodeError

§

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

Formats the value using the given formatter. Read more
§

impl Display for StunDecodeError

§

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

Formats the value using the given formatter. Read more
§

impl Error for StunDecodeError

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. 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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/protos/stun/struct.TransactionId.html b/pr/2992/docs/iroh_relay/protos/stun/struct.TransactionId.html new file mode 100644 index 0000000000..aa514b7515 --- /dev/null +++ b/pr/2992/docs/iroh_relay/protos/stun/struct.TransactionId.html @@ -0,0 +1,1160 @@ +TransactionId in iroh_relay::protos::stun - Rust

Struct iroh_relay::protos::stun::TransactionId

pub struct TransactionId(/* private fields */);
Expand description

The transaction ID is a 96-bit identifier, used to uniquely identify +STUN transactions. It primarily serves to correlate requests with +responses, though it also plays a small role in helping to prevent +certain types of attacks. The server also uses the transaction ID as +a key to identify each transaction uniquely across all clients.

+

Implementations§

§

impl TransactionId

pub fn as_bytes(&self) -> &[u8; 12]

Returns a reference to the bytes that represents the identifier.

+

Methods from Deref<Target = [u8]>§

source

pub fn as_str(&self) -> &str

🔬This is a nightly-only experimental API. (ascii_char)

Views this slice of ASCII characters as a UTF-8 str.

+
source

pub fn as_bytes(&self) -> &[u8]

🔬This is a nightly-only experimental API. (ascii_char)

Views this slice of ASCII characters as a slice of u8 bytes.

+
1.0.0 · source

pub fn len(&self) -> usize

Returns the number of elements in the slice.

+
§Examples
+
let a = [1, 2, 3];
+assert_eq!(a.len(), 3);
+
1.0.0 · source

pub fn is_empty(&self) -> bool

Returns true if the slice has a length of 0.

+
§Examples
+
let a = [1, 2, 3];
+assert!(!a.is_empty());
+
+let b: &[i32] = &[];
+assert!(b.is_empty());
+
1.0.0 · source

pub fn first(&self) -> Option<&T>

Returns the first element of the slice, or None if it is empty.

+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&10), v.first());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.first());
+
1.5.0 · source

pub fn split_first(&self) -> Option<(&T, &[T])>

Returns the first and all the rest of the elements of the slice, or None if it is empty.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((first, elements)) = x.split_first() {
+    assert_eq!(first, &0);
+    assert_eq!(elements, &[1, 2]);
+}
+
1.5.0 · source

pub fn split_last(&self) -> Option<(&T, &[T])>

Returns the last and all the rest of the elements of the slice, or None if it is empty.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((last, elements)) = x.split_last() {
+    assert_eq!(last, &2);
+    assert_eq!(elements, &[0, 1]);
+}
+
1.0.0 · source

pub fn last(&self) -> Option<&T>

Returns the last element of the slice, or None if it is empty.

+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&30), v.last());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.last());
+
1.77.0 · source

pub fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>

Return an array reference to the first N items in the slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let u = [10, 40, 30];
+assert_eq!(Some(&[10, 40]), u.first_chunk::<2>());
+
+let v: &[i32] = &[10];
+assert_eq!(None, v.first_chunk::<2>());
+
+let w: &[i32] = &[];
+assert_eq!(Some(&[]), w.first_chunk::<0>());
+
1.77.0 · source

pub fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>

Return an array reference to the first N items in the slice and the remaining slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((first, elements)) = x.split_first_chunk::<2>() {
+    assert_eq!(first, &[0, 1]);
+    assert_eq!(elements, &[2]);
+}
+
+assert_eq!(None, x.split_first_chunk::<4>());
+
1.77.0 · source

pub fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>

Return an array reference to the last N items in the slice and the remaining slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let x = &[0, 1, 2];
+
+if let Some((elements, last)) = x.split_last_chunk::<2>() {
+    assert_eq!(elements, &[0]);
+    assert_eq!(last, &[1, 2]);
+}
+
+assert_eq!(None, x.split_last_chunk::<4>());
+
1.77.0 · source

pub fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>

Return an array reference to the last N items in the slice.

+

If the slice is not at least N in length, this will return None.

+
§Examples
+
let u = [10, 40, 30];
+assert_eq!(Some(&[40, 30]), u.last_chunk::<2>());
+
+let v: &[i32] = &[10];
+assert_eq!(None, v.last_chunk::<2>());
+
+let w: &[i32] = &[];
+assert_eq!(Some(&[]), w.last_chunk::<0>());
+
1.0.0 · source

pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
where + I: SliceIndex<[T]>,

Returns a reference to an element or subslice depending on the type of +index.

+
    +
  • If given a position, returns a reference to the element at that +position or None if out of bounds.
  • +
  • If given a range, returns the subslice corresponding to that range, +or None if out of bounds.
  • +
+
§Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&40), v.get(1));
+assert_eq!(Some(&[10, 40][..]), v.get(0..2));
+assert_eq!(None, v.get(3));
+assert_eq!(None, v.get(0..4));
+
1.0.0 · source

pub unsafe fn get_unchecked<I>( + &self, + index: I +) -> &<I as SliceIndex<[T]>>::Output
where + I: SliceIndex<[T]>,

Returns a reference to an element or subslice, without doing bounds +checking.

+

For a safe alternative see get.

+
§Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used.

+

You can think of this like .get(index).unwrap_unchecked(). It’s UB +to call .get_unchecked(len), even if you immediately convert to a +pointer. And it’s UB to call .get_unchecked(..len + 1), +.get_unchecked(..=len), or similar.

+
§Examples
+
let x = &[1, 2, 4];
+
+unsafe {
+    assert_eq!(x.get_unchecked(1), &2);
+}
+
1.0.0 · source

pub fn as_ptr(&self) -> *const T

Returns a raw pointer to the slice’s buffer.

+

The caller must ensure that the slice outlives the pointer this +function returns, or else it will end up pointing to garbage.

+

The caller must also ensure that the memory the pointer (non-transitively) points to +is never written to (except inside an UnsafeCell) using this pointer or any pointer +derived from it. If you need to mutate the contents of the slice, use as_mut_ptr.

+

Modifying the container referenced by this slice may cause its buffer +to be reallocated, which would also make any pointers to it invalid.

+
§Examples
+
let x = &[1, 2, 4];
+let x_ptr = x.as_ptr();
+
+unsafe {
+    for i in 0..x.len() {
+        assert_eq!(x.get_unchecked(i), &*x_ptr.add(i));
+    }
+}
+
1.48.0 · source

pub fn as_ptr_range(&self) -> Range<*const T>

Returns the two raw pointers spanning the slice.

+

The returned range is half-open, which means that the end pointer +points one past the last element of the slice. This way, an empty +slice is represented by two equal pointers, and the difference between +the two pointers represents the size of the slice.

+

See as_ptr for warnings on using these pointers. The end pointer +requires extra caution, as it does not point to a valid element in the +slice.

+

This function is useful for interacting with foreign interfaces which +use two pointers to refer to a range of elements in memory, as is +common in C++.

+

It can also be useful to check if a pointer to an element refers to an +element of this slice:

+ +
let a = [1, 2, 3];
+let x = &a[1] as *const _;
+let y = &5 as *const _;
+
+assert!(a.as_ptr_range().contains(&x));
+assert!(!a.as_ptr_range().contains(&y));
+
1.0.0 · source

pub fn iter(&self) -> Iter<'_, T>

Returns an iterator over the slice.

+

The iterator yields all items from start to end.

+
§Examples
+
let x = &[1, 2, 4];
+let mut iterator = x.iter();
+
+assert_eq!(iterator.next(), Some(&1));
+assert_eq!(iterator.next(), Some(&2));
+assert_eq!(iterator.next(), Some(&4));
+assert_eq!(iterator.next(), None);
+
1.0.0 · source

pub fn windows(&self, size: usize) -> Windows<'_, T>

Returns an iterator over all contiguous windows of length +size. The windows overlap. If the slice is shorter than +size, the iterator returns no values.

+
§Panics
+

Panics if size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.windows(3);
+assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']);
+assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']);
+assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']);
+assert!(iter.next().is_none());
+

If the slice is shorter than size:

+ +
let slice = ['f', 'o', 'o'];
+let mut iter = slice.windows(4);
+assert!(iter.next().is_none());
+

There’s no windows_mut, as that existing would let safe code violate the +“only one &mut at a time to the same thing” rule. However, you can sometimes +use Cell::as_slice_of_cells in +conjunction with windows to accomplish something similar:

+ +
use std::cell::Cell;
+
+let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5'];
+let slice = &mut array[..];
+let slice_of_cells: &[Cell<char>] = Cell::from_mut(slice).as_slice_of_cells();
+for w in slice_of_cells.windows(3) {
+    Cell::swap(&w[0], &w[2]);
+}
+assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']);
+
1.0.0 · source

pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See chunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and rchunks for the same iterator but starting at the end of the +slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert_eq!(iter.next().unwrap(), &['m']);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of chunks.

+

See chunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and rchunks_exact for the same iterator but starting at the end of the slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+
source

pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]]

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +assuming that there’s no remainder.

+
§Safety
+

This may only be called when

+
    +
  • The slice splits exactly into N-element chunks (aka self.len() % N == 0).
  • +
  • N != 0.
  • +
+
§Examples
+
#![feature(slice_as_chunks)]
+let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
+let chunks: &[[char; 1]] =
+    // SAFETY: 1-element chunks never have remainder
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+let chunks: &[[char; 3]] =
+    // SAFETY: The slice length (6) is a multiple of 3
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
+
+// These would be unsound:
+// let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
+// let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
+
source

pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T])

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the beginning of the slice, +and a remainder slice with length strictly less than N.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (chunks, remainder) = slice.as_chunks();
+assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
+assert_eq!(remainder, &['m']);
+

If you expect the slice to be an exact multiple, you can combine +let-else with an empty slice pattern:

+ +
#![feature(slice_as_chunks)]
+let slice = ['R', 'u', 's', 't'];
+let (chunks, []) = slice.as_chunks::<2>() else {
+    panic!("slice didn't have even length")
+};
+assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
+
source

pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]])

🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the end of the slice, +and a remainder slice with length strictly less than N.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (remainder, chunks) = slice.as_rchunks();
+assert_eq!(remainder, &['l']);
+assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
+
source

pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N>

🔬This is a nightly-only experimental API. (array_chunks)

Returns an iterator over N elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are array references and do not overlap. If N does not divide the +length of the slice, then the last up to N-1 elements will be omitted and can be +retrieved from the remainder function of the iterator.

+

This method is the const generic equivalent of chunks_exact.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(array_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.array_chunks();
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+
source

pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N>

🔬This is a nightly-only experimental API. (array_windows)

Returns an iterator over overlapping windows of N elements of a slice, +starting at the beginning of the slice.

+

This is the const generic equivalent of windows.

+

If N is greater than the size of the slice, it will return no windows.

+
§Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
§Examples
+
#![feature(array_windows)]
+let slice = [0, 1, 2, 3];
+let mut iter = slice.array_windows();
+assert_eq!(iter.next().unwrap(), &[0, 1]);
+assert_eq!(iter.next().unwrap(), &[1, 2]);
+assert_eq!(iter.next().unwrap(), &[2, 3]);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the end +of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See rchunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and chunks for the same iterator but starting at the beginning +of the slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert_eq!(iter.next().unwrap(), &['l']);
+assert!(iter.next().is_none());
+
1.31.0 · source

pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the +end of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of rchunks.

+

See rchunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and chunks_exact for the same iterator but starting at the beginning of the +slice.

+
§Panics
+

Panics if chunk_size is 0.

+
§Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['l']);
+
1.77.0 · source

pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F>
where + F: FnMut(&T, &T) -> bool,

Returns an iterator over the slice producing non-overlapping runs +of elements using the predicate to separate them.

+

The predicate is called for every pair of consecutive elements, +meaning that it is called on slice[0] and slice[1], +followed by slice[1] and slice[2], and so on.

+
§Examples
+
let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
+
+let mut iter = slice.chunk_by(|a, b| a == b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+assert_eq!(iter.next(), Some(&[3, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+assert_eq!(iter.next(), None);
+

This method can be used to extract the sorted subslices:

+ +
let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4];
+
+let mut iter = slice.chunk_by(|a, b| a <= b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3, 4][..]));
+assert_eq!(iter.next(), None);
+
1.0.0 · source

pub fn split_at(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+
§Panics
+

Panics if mid > len. For a non-panicking alternative see +split_at_checked.

+
§Examples
+
let v = [1, 2, 3, 4, 5, 6];
+
+{
+   let (left, right) = v.split_at(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
1.80.0 · source

pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index, without doing bounds checking.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+

For a safe alternative see split_at.

+
§Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used. The caller has to ensure that +0 <= mid <= self.len().

+
§Examples
+
let v = [1, 2, 3, 4, 5, 6];
+
+unsafe {
+   let (left, right) = v.split_at_unchecked(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
source

pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])>

🔬This is a nightly-only experimental API. (split_at_checked)

Divides one slice into two at an index, returning None if the slice is +too short.

+

If mid ≤ len returns a pair of slices where the first will contain all +indices from [0, mid) (excluding the index mid itself) and the +second will contain all indices from [mid, len) (excluding the index +len itself).

+

Otherwise, if mid > len, returns None.

+
§Examples
+
#![feature(split_at_checked)]
+
+let v = [1, -2, 3, -4, 5, -6];
+
+{
+   let (left, right) = v.split_at_checked(0).unwrap();
+   assert_eq!(left, []);
+   assert_eq!(right, [1, -2, 3, -4, 5, -6]);
+}
+
+{
+    let (left, right) = v.split_at_checked(2).unwrap();
+    assert_eq!(left, [1, -2]);
+    assert_eq!(right, [3, -4, 5, -6]);
+}
+
+{
+    let (left, right) = v.split_at_checked(6).unwrap();
+    assert_eq!(left, [1, -2, 3, -4, 5, -6]);
+    assert_eq!(right, []);
+}
+
+assert_eq!(None, v.split_at_checked(7));
+
1.0.0 · source

pub fn split<F>(&self, pred: F) -> Split<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred. The matched element is not contained in the subslices.

+
§Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the first element is matched, an empty slice will be the first item +returned by the iterator. Similarly, if the last element in the slice +is matched, an empty slice will be the last item returned by the +iterator:

+ +
let slice = [10, 40, 33];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert!(iter.next().is_none());
+

If two matched elements are directly adjacent, an empty slice will be +present between them:

+ +
let slice = [10, 6, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+
1.51.0 · source

pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred. The matched element is contained in the end of the previous +subslice as a terminator.

+
§Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the last element of the slice is matched, +that element will be considered the terminator of the preceding slice. +That slice will be the last item returned by the iterator.

+ +
let slice = [3, 10, 40, 33];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[3]);
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert!(iter.next().is_none());
+
1.27.0 · source

pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred, starting at the end of the slice and working backwards. +The matched element is not contained in the subslices.

+
§Examples
+
let slice = [11, 22, 33, 0, 44, 55];
+let mut iter = slice.rsplit(|num| *num == 0);
+
+assert_eq!(iter.next().unwrap(), &[44, 55]);
+assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+assert_eq!(iter.next(), None);
+

As with split(), if the first or last element is matched, an empty +slice will be the first (or last) item returned by the iterator.

+ +
let v = &[0, 1, 1, 2, 3, 5, 8];
+let mut it = v.rsplit(|n| *n % 2 == 0);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next().unwrap(), &[3, 5]);
+assert_eq!(it.next().unwrap(), &[1, 1]);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next(), None);
+
1.0.0 · source

pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred, limited to returning at most n items. The matched element is +not contained in the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
§Examples
+

Print the slice split once by numbers divisible by 3 (i.e., [10, 40], +[20, 60, 50]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.splitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+
1.0.0 · source

pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F>
where + F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match +pred limited to returning at most n items. This starts at the end of +the slice and works backwards. The matched element is not contained in +the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
§Examples
+

Print the slice split once, starting from the end, by numbers divisible +by 3 (i.e., [50], [10, 40, 30, 20]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.rsplitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+
source

pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where + F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the first element that matches the specified +predicate.

+

If any matching elements are present in the slice, returns the prefix +before the match and suffix after. The matching element itself is not +included. If no elements match, returns None.

+
§Examples
+
#![feature(slice_split_once)]
+let s = [1, 2, 3, 2, 4];
+assert_eq!(s.split_once(|&x| x == 2), Some((
+    &[1][..],
+    &[3, 2, 4][..]
+)));
+assert_eq!(s.split_once(|&x| x == 0), None);
+
source

pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where + F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the last element that matches the specified +predicate.

+

If any matching elements are present in the slice, returns the prefix +before the match and suffix after. The matching element itself is not +included. If no elements match, returns None.

+
§Examples
+
#![feature(slice_split_once)]
+let s = [1, 2, 3, 2, 4];
+assert_eq!(s.rsplit_once(|&x| x == 2), Some((
+    &[1, 2, 3][..],
+    &[4][..]
+)));
+assert_eq!(s.rsplit_once(|&x| x == 0), None);
+
1.0.0 · source

pub fn contains(&self, x: &T) -> bool
where + T: PartialEq,

Returns true if the slice contains an element with the given value.

+

This operation is O(n).

+

Note that if you have a sorted slice, binary_search may be faster.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.contains(&30));
+assert!(!v.contains(&50));
+

If you do not have a &T, but some other value that you can compare +with one (for example, String implements PartialEq<str>), you can +use iter().any:

+ +
let v = [String::from("hello"), String::from("world")]; // slice of `String`
+assert!(v.iter().any(|e| e == "hello")); // search with `&str`
+assert!(!v.iter().any(|e| e == "hi"));
+
1.0.0 · source

pub fn starts_with(&self, needle: &[T]) -> bool
where + T: PartialEq,

Returns true if needle is a prefix of the slice or equal to the slice.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.starts_with(&[10]));
+assert!(v.starts_with(&[10, 40]));
+assert!(v.starts_with(&v));
+assert!(!v.starts_with(&[50]));
+assert!(!v.starts_with(&[10, 50]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.starts_with(&[]));
+let v: &[u8] = &[];
+assert!(v.starts_with(&[]));
+
1.0.0 · source

pub fn ends_with(&self, needle: &[T]) -> bool
where + T: PartialEq,

Returns true if needle is a suffix of the slice or equal to the slice.

+
§Examples
+
let v = [10, 40, 30];
+assert!(v.ends_with(&[30]));
+assert!(v.ends_with(&[40, 30]));
+assert!(v.ends_with(&v));
+assert!(!v.ends_with(&[50]));
+assert!(!v.ends_with(&[50, 30]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.ends_with(&[]));
+let v: &[u8] = &[];
+assert!(v.ends_with(&[]));
+
1.51.0 · source

pub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]>
where + P: SlicePattern<Item = T> + ?Sized, + T: PartialEq,

Returns a subslice with the prefix removed.

+

If the slice starts with prefix, returns the subslice after the prefix, wrapped in Some. +If prefix is empty, simply returns the original slice. If prefix is equal to the +original slice, returns an empty slice.

+

If the slice does not start with prefix, returns None.

+
§Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
+assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
+assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
+assert_eq!(v.strip_prefix(&[50]), None);
+assert_eq!(v.strip_prefix(&[10, 50]), None);
+
+let prefix : &str = "he";
+assert_eq!(b"hello".strip_prefix(prefix.as_bytes()),
+           Some(b"llo".as_ref()));
+
1.51.0 · source

pub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]>
where + P: SlicePattern<Item = T> + ?Sized, + T: PartialEq,

Returns a subslice with the suffix removed.

+

If the slice ends with suffix, returns the subslice before the suffix, wrapped in Some. +If suffix is empty, simply returns the original slice. If suffix is equal to the +original slice, returns an empty slice.

+

If the slice does not end with suffix, returns None.

+
§Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
+assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
+assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..]));
+assert_eq!(v.strip_suffix(&[50]), None);
+assert_eq!(v.strip_suffix(&[50, 30]), None);
+

Binary searches this slice for a given element. +If the slice is not sorted, the returned result is unspecified and +meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search_by, binary_search_by_key, and partition_point.

+
§Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+assert_eq!(s.binary_search(&13),  Ok(9));
+assert_eq!(s.binary_search(&4),   Err(7));
+assert_eq!(s.binary_search(&100), Err(13));
+let r = s.binary_search(&1);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+

If you want to find that whole range of matching items, rather than +an arbitrary matching one, that can be done using partition_point:

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let low = s.partition_point(|x| x < &1);
+assert_eq!(low, 1);
+let high = s.partition_point(|x| x <= &1);
+assert_eq!(high, 5);
+let r = s.binary_search(&1);
+assert!((low..high).contains(&r.unwrap()));
+
+assert!(s[..low].iter().all(|&x| x < 1));
+assert!(s[low..high].iter().all(|&x| x == 1));
+assert!(s[high..].iter().all(|&x| x > 1));
+
+// For something not found, the "range" of equal items is empty
+assert_eq!(s.partition_point(|x| x < &11), 9);
+assert_eq!(s.partition_point(|x| x <= &11), 9);
+assert_eq!(s.binary_search(&11), Err(9));
+

If you want to insert an item to a sorted vector, while maintaining +sort order, consider using partition_point:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x <= num);
+// If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+// `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert`
+// to shift less elements.
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+
1.0.0 · source

pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
where + F: FnMut(&'a T) -> Ordering,

Binary searches this slice with a comparator function.

+

The comparator function should return an order code that indicates +whether its argument is Less, Equal or Greater the desired +target. +If the slice is not sorted or if the comparator function does not +implement an order consistent with the sort order of the underlying +slice, the returned result is unspecified and meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by_key, and partition_point.

+
§Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let seek = 13;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+let seek = 4;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+let seek = 100;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+let seek = 1;
+let r = s.binary_search_by(|probe| probe.cmp(&seek));
+assert!(match r { Ok(1..=4) => true, _ => false, });
+
1.10.0 · source

pub fn binary_search_by_key<'a, B, F>( + &'a self, + b: &B, + f: F +) -> Result<usize, usize>
where + F: FnMut(&'a T) -> B, + B: Ord,

Binary searches this slice with a key extraction function.

+

Assumes that the slice is sorted by the key, for instance with +sort_by_key using the same key extraction function. +If the slice is not sorted by the key, the returned result is +unspecified and meaningless.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by, and partition_point.

+
§Examples
+

Looks up a series of four elements in a slice of pairs sorted by +their second elements. The first is found, with a uniquely +determined position; the second and third are not found; the +fourth could match any position in [1, 4].

+ +
let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
+         (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+         (1, 21), (2, 34), (4, 55)];
+
+assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b),  Ok(9));
+assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b),   Err(7));
+assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
+let r = s.binary_search_by_key(&1, |&(a, b)| b);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+
1.30.0 · source

pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])

Transmute the slice to a slice of another type, ensuring alignment of the types is +maintained.

+

This method splits the slice into three distinct slices: prefix, correctly aligned middle +slice of a new type, and the suffix slice. The middle part will be as big as possible under +the given alignment constraint and element size.

+

This method has no purpose when either input element T or output element U are +zero-sized and will return the original slice without splitting anything.

+
§Safety
+

This method is essentially a transmute with respect to the elements in the returned +middle slice, so all the usual caveats pertaining to transmute::<T, U> also apply here.

+
§Examples
+

Basic usage:

+ +
unsafe {
+    let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, shorts, suffix) = bytes.align_to::<u16>();
+    // less_efficient_algorithm_for_bytes(prefix);
+    // more_efficient_algorithm_for_aligned_shorts(shorts);
+    // less_efficient_algorithm_for_bytes(suffix);
+}
+
source

pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
where + Simd<T, LANES>: AsRef<[T; LANES]>, + T: SimdElement, + LaneCount<LANES>: SupportedLaneCount,

🔬This is a nightly-only experimental API. (portable_simd)

Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.

+

This is a safe wrapper around slice::align_to, so has the same weak +postconditions as that method. You’re only assured that +self.len() == prefix.len() + middle.len() * LANES + suffix.len().

+

Notably, all of the following are possible:

+
    +
  • prefix.len() >= LANES.
  • +
  • middle.is_empty() despite self.len() >= 3 * LANES.
  • +
  • suffix.len() >= LANES.
  • +
+

That said, this is a safe method, so if you’re only writing safe code, +then this can at most cause incorrect logic, not unsoundness.

+
§Panics
+

This will panic if the size of the SIMD type is different from +LANES times that of the scalar.

+

At the time of writing, the trait restrictions on Simd<T, LANES> keeps +that from ever happening, as only power-of-two numbers of lanes are +supported. It’s possible that, in the future, those restrictions might +be lifted in a way that would make it possible to see panics from this +method for something like LANES == 3.

+
§Examples
+
#![feature(portable_simd)]
+use core::simd::prelude::*;
+
+let short = &[1, 2, 3];
+let (prefix, middle, suffix) = short.as_simd::<4>();
+assert_eq!(middle, []); // Not enough elements for anything in the middle
+
+// They might be split in any possible way between prefix and suffix
+let it = prefix.iter().chain(suffix).copied();
+assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
+
+fn basic_simd_sum(x: &[f32]) -> f32 {
+    use std::ops::Add;
+    let (prefix, middle, suffix) = x.as_simd();
+    let sums = f32x4::from_array([
+        prefix.iter().copied().sum(),
+        0.0,
+        0.0,
+        suffix.iter().copied().sum(),
+    ]);
+    let sums = middle.iter().copied().fold(sums, f32x4::add);
+    sums.reduce_sum()
+}
+
+let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
+assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
+
source

pub fn is_sorted(&self) -> bool
where + T: PartialOrd,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted.

+

That is, for each element a and its following element b, a <= b must hold. If the +slice yields exactly zero or one element, true is returned.

+

Note that if Self::Item is only PartialOrd, but not Ord, the above definition +implies that this function returns false if any two consecutive items are not +comparable.

+
§Examples
+
#![feature(is_sorted)]
+let empty: [i32; 0] = [];
+
+assert!([1, 2, 2, 9].is_sorted());
+assert!(![1, 3, 2, 4].is_sorted());
+assert!([0].is_sorted());
+assert!(empty.is_sorted());
+assert!(![0.0, 1.0, f32::NAN].is_sorted());
+
source

pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool
where + F: FnMut(&'a T, &'a T) -> bool,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given comparator function.

+

Instead of using PartialOrd::partial_cmp, this function uses the given compare +function to determine whether two elements are to be considered in sorted order.

+
§Examples
+
#![feature(is_sorted)]
+
+assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b));
+assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b));
+
+assert!([0].is_sorted_by(|a, b| true));
+assert!([0].is_sorted_by(|a, b| false));
+
+let empty: [i32; 0] = [];
+assert!(empty.is_sorted_by(|a, b| false));
+assert!(empty.is_sorted_by(|a, b| true));
+
source

pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
where + F: FnMut(&'a T) -> K, + K: PartialOrd,

🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given key extraction function.

+

Instead of comparing the slice’s elements directly, this function compares the keys of the +elements, as determined by f. Apart from that, it’s equivalent to is_sorted; see its +documentation for more information.

+
§Examples
+
#![feature(is_sorted)]
+
+assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+
1.52.0 · source

pub fn partition_point<P>(&self, pred: P) -> usize
where + P: FnMut(&T) -> bool,

Returns the index of the partition point according to the given predicate +(the index of the first element of the second partition).

+

The slice is assumed to be partitioned according to the given predicate. +This means that all elements for which the predicate returns true are at the start of the slice +and all elements for which the predicate returns false are at the end. +For example, [7, 15, 3, 5, 4, 12, 6] is partitioned under the predicate x % 2 != 0 +(all odd numbers are at the start, all even at the end).

+

If this slice is not partitioned, the returned result is unspecified and meaningless, +as this method performs a kind of binary search.

+

See also binary_search, binary_search_by, and binary_search_by_key.

+
§Examples
+
let v = [1, 2, 3, 3, 5, 6, 7];
+let i = v.partition_point(|&x| x < 5);
+
+assert_eq!(i, 4);
+assert!(v[..i].iter().all(|&x| x < 5));
+assert!(v[i..].iter().all(|&x| !(x < 5)));
+

If all elements of the slice match the predicate, including if the slice +is empty, then the length of the slice will be returned:

+ +
let a = [2, 4, 8];
+assert_eq!(a.partition_point(|x| x < &100), a.len());
+let a: [i32; 0] = [];
+assert_eq!(a.partition_point(|x| x < &100), 0);
+

If you want to insert an item to a sorted vector, while maintaining +sort order:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x <= num);
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+
source

pub fn flatten(&self) -> &[T]

🔬This is a nightly-only experimental API. (slice_flatten)

Takes a &[[T; N]], and flattens it to a &[T].

+
§Panics
+

This panics if the length of the resulting slice would overflow a usize.

+

This is only possible when flattening a slice of arrays of zero-sized +types, and thus tends to be irrelevant in practice. If +size_of::<T>() > 0, this will never panic.

+
§Examples
+
#![feature(slice_flatten)]
+
+assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
+
+assert_eq!(
+    [[1, 2, 3], [4, 5, 6]].flatten(),
+    [[1, 2], [3, 4], [5, 6]].flatten(),
+);
+
+let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
+assert!(slice_of_empty_arrays.flatten().is_empty());
+
+let empty_slice_of_arrays: &[[u32; 10]] = &[];
+assert!(empty_slice_of_arrays.flatten().is_empty());
+
1.23.0 · source

pub fn is_ascii(&self) -> bool

Checks if all bytes in this slice are within the ASCII range.

+
source

pub fn as_ascii(&self) -> Option<&[AsciiChar]>

🔬This is a nightly-only experimental API. (ascii_char)

If this slice is_ascii, returns it as a slice of +ASCII characters, otherwise returns None.

+
source

pub unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar]

🔬This is a nightly-only experimental API. (ascii_char)

Converts this slice of bytes into a slice of ASCII characters, +without checking whether they’re valid.

+
§Safety
+

Every byte in the slice must be in 0..=127, or else this is UB.

+
1.23.0 · source

pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool

Checks that two slices are an ASCII case-insensitive match.

+

Same as to_ascii_lowercase(a) == to_ascii_lowercase(b), +but without allocating and copying temporaries.

+
1.60.0 · source

pub fn escape_ascii(&self) -> EscapeAscii<'_>

Returns an iterator that produces an escaped version of this slice, +treating it as an ASCII string.

+
§Examples
+

+let s = b"0\t\r\n'\"\\\x9d";
+let escaped = s.escape_ascii().to_string();
+assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
+
source

pub fn trim_ascii_start(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
+assert_eq!(b"  ".trim_ascii_start(), b"");
+assert_eq!(b"".trim_ascii_start(), b"");
+
source

pub fn trim_ascii_end(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with trailing ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
+assert_eq!(b"  ".trim_ascii_end(), b"");
+assert_eq!(b"".trim_ascii_end(), b"");
+
source

pub fn trim_ascii(&self) -> &[u8]

🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading and trailing ASCII whitespace bytes +removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
§Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
+assert_eq!(b"  ".trim_ascii(), b"");
+assert_eq!(b"".trim_ascii(), b"");
+
1.80.0 · source

pub fn utf8_chunks(&self) -> Utf8Chunks<'_>

Creates an iterator over the contiguous valid UTF-8 ranges of this +slice, and the non-UTF-8 fragments in between.

+
§Examples
+

This function formats arbitrary but mostly-UTF-8 bytes into Rust source +code in the form of a C-string literal (c"...").

+ +
use std::fmt::Write as _;
+
+pub fn cstr_literal(bytes: &[u8]) -> String {
+    let mut repr = String::new();
+    repr.push_str("c\"");
+    for chunk in bytes.utf8_chunks() {
+        for ch in chunk.valid().chars() {
+            // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for non-printable characters.
+            write!(repr, "{}", ch.escape_debug()).unwrap();
+        }
+        for byte in chunk.invalid() {
+            write!(repr, "\\x{:02X}", byte).unwrap();
+        }
+    }
+    repr.push('"');
+    repr
+}
+
+fn main() {
+    let lit = cstr_literal(b"\xferris the \xf0\x9f\xa6\x80\x07");
+    let expected = stringify!(c"\xFErris the 🦀\u{7}");
+    assert_eq!(lit, expected);
+}
+
1.23.0 · source

pub fn to_ascii_uppercase(&self) -> Vec<u8>

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII upper case equivalent.

+

ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, +but non-ASCII letters are unchanged.

+

To uppercase the value in-place, use make_ascii_uppercase.

+
1.23.0 · source

pub fn to_ascii_lowercase(&self) -> Vec<u8>

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII lower case equivalent.

+

ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, +but non-ASCII letters are unchanged.

+

To lowercase the value in-place, use make_ascii_lowercase.

+
1.0.0 · source

pub fn to_vec(&self) -> Vec<T>
where + T: Clone,

Copies self into a new Vec.

+
§Examples
+
let s = [10, 40, 30];
+let x = s.to_vec();
+// Here, `s` and `x` can be modified independently.
+
source

pub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A>
where + A: Allocator, + T: Clone,

🔬This is a nightly-only experimental API. (allocator_api)

Copies self into a new Vec with an allocator.

+
§Examples
+
#![feature(allocator_api)]
+
+use std::alloc::System;
+
+let s = [10, 40, 30];
+let x = s.to_vec_in(System);
+// Here, `s` and `x` can be modified independently.
+
1.40.0 · source

pub fn repeat(&self, n: usize) -> Vec<T>
where + T: Copy,

Creates a vector by copying a slice n times.

+
§Panics
+

This function will panic if the capacity would overflow.

+
§Examples
+

Basic usage:

+ +
assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
+

A panic upon overflow:

+ +
// this will panic at runtime
+b"0123456789abcdef".repeat(usize::MAX);
+
1.0.0 · source

pub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output
where + [T]: Concat<Item>, + Item: ?Sized,

Flattens a slice of T into a single value Self::Output.

+
§Examples
+
assert_eq!(["hello", "world"].concat(), "helloworld");
+assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
+
1.3.0 · source

pub fn join<Separator>( + &self, + sep: Separator +) -> <[T] as Join<Separator>>::Output
where + [T]: Join<Separator>,

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
§Examples
+
assert_eq!(["hello", "world"].join(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
+assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
+
1.0.0 · source

pub fn connect<Separator>( + &self, + sep: Separator +) -> <[T] as Join<Separator>>::Output
where + [T]: Join<Separator>,

👎Deprecated since 1.3.0: renamed to join

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
§Examples
+
assert_eq!(["hello", "world"].connect(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
+

Trait Implementations§

§

impl AsRef<[u8]> for TransactionId

§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
§

impl Clone for TransactionId

§

fn clone(&self) -> TransactionId

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
§

impl Debug for TransactionId

§

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

Formats the value using the given formatter. Read more
§

impl Default for TransactionId

§

fn default() -> TransactionId

Creates a cryptographically random transaction ID chosen from the interval 0 .. 2**96-1.

+
§

impl Deref for TransactionId

§

type Target = [u8]

The resulting type after dereferencing.
§

fn deref(&self) -> &[u8]

Dereferences the value.
§

impl Display for TransactionId

§

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

Formats the value using the given formatter. Read more
§

impl From<&[u8; 12]> for TransactionId

§

fn from(buff: &[u8; 12]) -> TransactionId

Converts to this type from the input type.
§

impl From<[u8; 12]> for TransactionId

§

fn from(buff: [u8; 12]) -> TransactionId

Converts to this type from the input type.
§

impl Hash for TransactionId

§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
§

impl Ord for TransactionId

§

fn cmp(&self, other: &TransactionId) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
§

impl PartialEq for TransactionId

§

fn eq(&self, other: &TransactionId) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl PartialOrd for TransactionId

§

fn partial_cmp(&self, other: &TransactionId) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl Copy for TransactionId

§

impl Eq for TransactionId

§

impl StructuralPartialEq for TransactionId

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToHex for T
where + T: AsRef<[u8]>,

source§

fn encode_hex<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Lower case +letters are used (e.g. f9b4ca)
source§

fn encode_hex_upper<U>(&self) -> U
where + U: FromIterator<char>,

Encode the hex strict representing self into the result. Upper case +letters are used (e.g. F9B4CA)
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

source§

impl<T> RuleType for T
where + T: Copy + Debug + Eq + Hash + Ord,

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/constant.ALPN_QUIC_ADDR_DISC.html b/pr/2992/docs/iroh_relay/quic/constant.ALPN_QUIC_ADDR_DISC.html new file mode 100644 index 0000000000..e50ec40612 --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/constant.ALPN_QUIC_ADDR_DISC.html @@ -0,0 +1,2 @@ +ALPN_QUIC_ADDR_DISC in iroh_relay::quic - Rust

Constant iroh_relay::quic::ALPN_QUIC_ADDR_DISC

source ·
pub const ALPN_QUIC_ADDR_DISC: &[u8] = b"/iroh-qad/0";
Expand description

ALPN for our quic addr discovery

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_CODE.html b/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_CODE.html new file mode 100644 index 0000000000..f17f9686c5 --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_CODE.html @@ -0,0 +1,2 @@ +QUIC_ADDR_DISC_CLOSE_CODE in iroh_relay::quic - Rust

Constant iroh_relay::quic::QUIC_ADDR_DISC_CLOSE_CODE

source ·
pub const QUIC_ADDR_DISC_CLOSE_CODE: VarInt;
Expand description

Endpoint close error code

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_REASON.html b/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_REASON.html new file mode 100644 index 0000000000..b1ff6870a4 --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/constant.QUIC_ADDR_DISC_CLOSE_REASON.html @@ -0,0 +1,2 @@ +QUIC_ADDR_DISC_CLOSE_REASON in iroh_relay::quic - Rust

Constant iroh_relay::quic::QUIC_ADDR_DISC_CLOSE_REASON

source ·
pub const QUIC_ADDR_DISC_CLOSE_REASON: &[u8] = b"finished";
Expand description

Endpoint close reason

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/index.html b/pr/2992/docs/iroh_relay/quic/index.html new file mode 100644 index 0000000000..2413932728 --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/index.html @@ -0,0 +1,3 @@ +iroh_relay::quic - Rust

Module iroh_relay::quic

source ·
Expand description

Create a QUIC server that accepts connections +for QUIC address discovery.

+

Structs§

  • Handles the client side of QUIC address discovery.

Constants§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/sidebar-items.js b/pr/2992/docs/iroh_relay/quic/sidebar-items.js new file mode 100644 index 0000000000..b0144e1009 --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["ALPN_QUIC_ADDR_DISC","QUIC_ADDR_DISC_CLOSE_CODE","QUIC_ADDR_DISC_CLOSE_REASON"],"struct":["QuicClient"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/quic/struct.QuicClient.html b/pr/2992/docs/iroh_relay/quic/struct.QuicClient.html new file mode 100644 index 0000000000..f252d99cfd --- /dev/null +++ b/pr/2992/docs/iroh_relay/quic/struct.QuicClient.html @@ -0,0 +1,36 @@ +QuicClient in iroh_relay::quic - Rust

Struct iroh_relay::quic::QuicClient

source ·
pub struct QuicClient { /* private fields */ }
Expand description

Handles the client side of QUIC address discovery.

+

Implementations§

source§

impl QuicClient

source

pub fn new(ep: Endpoint, client_config: ClientConfig) -> Result<Self>

Create a new QuicClient to handle the client side of QUIC +address discovery.

+
source

pub async fn get_addr_and_latency( + &self, + server_addr: SocketAddr, + host: &str +) -> Result<(SocketAddr, Duration)>

Client side of QUIC address discovery.

+

Creates a connection and returns the observed address +and estimated latency of the connection.

+

Consumes and gracefully closes the connection.

+

Trait Implementations§

source§

impl Debug for QuicClient

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/enum.CertConfig.html b/pr/2992/docs/iroh_relay/server/enum.CertConfig.html new file mode 100644 index 0000000000..d43f09d5fc --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/enum.CertConfig.html @@ -0,0 +1,37 @@ +CertConfig in iroh_relay::server - Rust

Enum iroh_relay::server::CertConfig

source ·
pub enum CertConfig<EC: Debug, EA: Debug = EC> {
+    LetsEncrypt {
+        state: AcmeState<EC, EA>,
+    },
+    Manual {
+        certs: Vec<CertificateDer<'static>>,
+    },
+}
Available on crate feature server only.
Expand description

TLS certificate configuration.

+

Variants§

§

LetsEncrypt

Use Let’s Encrypt.

+

Fields

§state: AcmeState<EC, EA>

State for Let’s Encrypt certificates.

+
§

Manual

Use a static TLS key and certificate chain.

+

Fields

§certs: Vec<CertificateDer<'static>>

The TLS certificate chain.

+

Trait Implementations§

source§

impl<EC: Debug, EA: Debug> Debug for CertConfig<EC, EA>

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<EC, EA> Freeze for CertConfig<EC, EA>

§

impl<EC, EA = EC> !RefUnwindSafe for CertConfig<EC, EA>

§

impl<EC, EA> Send for CertConfig<EC, EA>

§

impl<EC, EA = EC> !Sync for CertConfig<EC, EA>

§

impl<EC, EA> Unpin for CertConfig<EC, EA>

§

impl<EC, EA = EC> !UnwindSafe for CertConfig<EC, EA>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/enum.MaybeTlsStreamServer.html b/pr/2992/docs/iroh_relay/server/enum.MaybeTlsStreamServer.html new file mode 100644 index 0000000000..02d5e8000f --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/enum.MaybeTlsStreamServer.html @@ -0,0 +1,173 @@ +MaybeTlsStreamServer in iroh_relay::server - Rust

Enum iroh_relay::server::MaybeTlsStreamServer

source ·
pub enum MaybeTlsStreamServer {
+    Plain(TcpStream),
+    Tls(TlsStream<TcpStream>),
+}
Available on crate feature server only.
Expand description

The main underlying IO stream type used for the relay server.

+

Allows choosing whether or not the underlying [tokio::net::TcpStream] is served over Tls

+

Variants§

§

Plain(TcpStream)

A plain non-Tls [tokio::net::TcpStream]

+
§

Tls(TlsStream<TcpStream>)

A Tls wrapped [tokio::net::TcpStream]

+

Trait Implementations§

source§

impl AsyncRead for MaybeTlsStream

source§

fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_> +) -> Poll<Result<()>>

Attempts to read from the AsyncRead into buf. Read more
source§

impl AsyncWrite for MaybeTlsStream

source§

fn poll_flush( + self: Pin<&mut Self>, + cx: &mut Context<'_> +) -> Poll<Result<(), Error>>

Attempts to flush the object, ensuring that any buffered data reach +their destination. Read more
source§

fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut Context<'_> +) -> Poll<Result<(), Error>>

Initiates or attempts to shut down this writer, returning success when +the I/O connection has completely shut down. Read more
source§

fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8] +) -> Poll<Result<usize, Error>>

Attempt to write bytes from buf into the object. Read more
source§

fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>] +) -> Poll<Result<usize, Error>>

Like poll_write, except that it writes from a slice of buffers. Read more
§

fn is_write_vectored(&self) -> bool

Determines if this writer has an efficient poll_write_vectored +implementation. Read more
source§

impl Debug for MaybeTlsStream

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>

§

impl<R> AsyncReadExt for R
where + R: AsyncRead + ?Sized,

§

fn chain<R>(self, next: R) -> Chain<Self, R>
where + Self: Sized, + R: AsyncRead,

Creates a new AsyncRead instance that chains this stream with +next. Read more
§

fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>
where + Self: Unpin,

Pulls some bytes from this source into the specified buffer, +returning how many bytes were read. Read more
§

fn read_buf<'a, B>(&'a mut self, buf: &'a mut B) -> ReadBuf<'a, Self, B>
where + Self: Unpin, + B: BufMut + ?Sized,

Pulls some bytes from this source into the specified buffer, +advancing the buffer’s internal cursor. Read more
§

fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>
where + Self: Unpin,

Reads the exact number of bytes required to fill buf. Read more
§

fn read_u8(&mut self) -> ReadU8<&mut Self>
where + Self: Unpin,

Reads an unsigned 8 bit integer from the underlying reader. Read more
§

fn read_i8(&mut self) -> ReadI8<&mut Self>
where + Self: Unpin,

Reads a signed 8 bit integer from the underlying reader. Read more
§

fn read_u16(&mut self) -> ReadU16<&mut Self>
where + Self: Unpin,

Reads an unsigned 16-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i16(&mut self) -> ReadI16<&mut Self>
where + Self: Unpin,

Reads a signed 16-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u32(&mut self) -> ReadU32<&mut Self>
where + Self: Unpin,

Reads an unsigned 32-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i32(&mut self) -> ReadI32<&mut Self>
where + Self: Unpin,

Reads a signed 32-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u64(&mut self) -> ReadU64<&mut Self>
where + Self: Unpin,

Reads an unsigned 64-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i64(&mut self) -> ReadI64<&mut Self>
where + Self: Unpin,

Reads an signed 64-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_u128(&mut self) -> ReadU128<&mut Self>
where + Self: Unpin,

Reads an unsigned 128-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_i128(&mut self) -> ReadI128<&mut Self>
where + Self: Unpin,

Reads an signed 128-bit integer in big-endian order from the +underlying reader. Read more
§

fn read_f32(&mut self) -> ReadF32<&mut Self>
where + Self: Unpin,

Reads an 32-bit floating point type in big-endian order from the +underlying reader. Read more
§

fn read_f64(&mut self) -> ReadF64<&mut Self>
where + Self: Unpin,

Reads an 64-bit floating point type in big-endian order from the +underlying reader. Read more
§

fn read_u16_le(&mut self) -> ReadU16Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 16-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i16_le(&mut self) -> ReadI16Le<&mut Self>
where + Self: Unpin,

Reads a signed 16-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u32_le(&mut self) -> ReadU32Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 32-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i32_le(&mut self) -> ReadI32Le<&mut Self>
where + Self: Unpin,

Reads a signed 32-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u64_le(&mut self) -> ReadU64Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 64-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i64_le(&mut self) -> ReadI64Le<&mut Self>
where + Self: Unpin,

Reads an signed 64-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_u128_le(&mut self) -> ReadU128Le<&mut Self>
where + Self: Unpin,

Reads an unsigned 128-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_i128_le(&mut self) -> ReadI128Le<&mut Self>
where + Self: Unpin,

Reads an signed 128-bit integer in little-endian order from the +underlying reader. Read more
§

fn read_f32_le(&mut self) -> ReadF32Le<&mut Self>
where + Self: Unpin,

Reads an 32-bit floating point type in little-endian order from the +underlying reader. Read more
§

fn read_f64_le(&mut self) -> ReadF64Le<&mut Self>
where + Self: Unpin,

Reads an 64-bit floating point type in little-endian order from the +underlying reader. Read more
§

fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
where + Self: Unpin,

Reads all bytes until EOF in this source, placing them into buf. Read more
§

fn read_to_string<'a>( + &'a mut self, + dst: &'a mut String +) -> ReadToString<'a, Self>
where + Self: Unpin,

Reads all bytes until EOF in this source, appending them to buf. Read more
§

fn take(self, limit: u64) -> Take<Self>
where + Self: Sized,

Creates an adaptor which reads at most limit bytes from it. Read more
§

impl<W> AsyncWriteExt for W
where + W: AsyncWrite + ?Sized,

§

fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self>
where + Self: Unpin,

Writes a buffer into this writer, returning how many bytes were +written. Read more
§

fn write_vectored<'a, 'b>( + &'a mut self, + bufs: &'a [IoSlice<'b>] +) -> WriteVectored<'a, 'b, Self>
where + Self: Unpin,

Like write, except that it writes from a slice of buffers. Read more
§

fn write_buf<'a, B>(&'a mut self, src: &'a mut B) -> WriteBuf<'a, Self, B>
where + Self: Sized + Unpin, + B: Buf,

Writes a buffer into this writer, advancing the buffer’s internal +cursor. Read more
§

fn write_all_buf<'a, B>( + &'a mut self, + src: &'a mut B +) -> WriteAllBuf<'a, Self, B>
where + Self: Sized + Unpin, + B: Buf,

Attempts to write an entire buffer into this writer. Read more
§

fn write_all<'a>(&'a mut self, src: &'a [u8]) -> WriteAll<'a, Self>
where + Self: Unpin,

Attempts to write an entire buffer into this writer. Read more
§

fn write_u8(&mut self, n: u8) -> WriteU8<&mut Self>
where + Self: Unpin,

Writes an unsigned 8-bit integer to the underlying writer. Read more
§

fn write_i8(&mut self, n: i8) -> WriteI8<&mut Self>
where + Self: Unpin,

Writes a signed 8-bit integer to the underlying writer. Read more
§

fn write_u16(&mut self, n: u16) -> WriteU16<&mut Self>
where + Self: Unpin,

Writes an unsigned 16-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i16(&mut self, n: i16) -> WriteI16<&mut Self>
where + Self: Unpin,

Writes a signed 16-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u32(&mut self, n: u32) -> WriteU32<&mut Self>
where + Self: Unpin,

Writes an unsigned 32-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i32(&mut self, n: i32) -> WriteI32<&mut Self>
where + Self: Unpin,

Writes a signed 32-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u64(&mut self, n: u64) -> WriteU64<&mut Self>
where + Self: Unpin,

Writes an unsigned 64-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i64(&mut self, n: i64) -> WriteI64<&mut Self>
where + Self: Unpin,

Writes an signed 64-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_u128(&mut self, n: u128) -> WriteU128<&mut Self>
where + Self: Unpin,

Writes an unsigned 128-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_i128(&mut self, n: i128) -> WriteI128<&mut Self>
where + Self: Unpin,

Writes an signed 128-bit integer in big-endian order to the +underlying writer. Read more
§

fn write_f32(&mut self, n: f32) -> WriteF32<&mut Self>
where + Self: Unpin,

Writes an 32-bit floating point type in big-endian order to the +underlying writer. Read more
§

fn write_f64(&mut self, n: f64) -> WriteF64<&mut Self>
where + Self: Unpin,

Writes an 64-bit floating point type in big-endian order to the +underlying writer. Read more
§

fn write_u16_le(&mut self, n: u16) -> WriteU16Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 16-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i16_le(&mut self, n: i16) -> WriteI16Le<&mut Self>
where + Self: Unpin,

Writes a signed 16-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u32_le(&mut self, n: u32) -> WriteU32Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 32-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i32_le(&mut self, n: i32) -> WriteI32Le<&mut Self>
where + Self: Unpin,

Writes a signed 32-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u64_le(&mut self, n: u64) -> WriteU64Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 64-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i64_le(&mut self, n: i64) -> WriteI64Le<&mut Self>
where + Self: Unpin,

Writes an signed 64-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_u128_le(&mut self, n: u128) -> WriteU128Le<&mut Self>
where + Self: Unpin,

Writes an unsigned 128-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_i128_le(&mut self, n: i128) -> WriteI128Le<&mut Self>
where + Self: Unpin,

Writes an signed 128-bit integer in little-endian order to the +underlying writer. Read more
§

fn write_f32_le(&mut self, n: f32) -> WriteF32Le<&mut Self>
where + Self: Unpin,

Writes an 32-bit floating point type in little-endian order to the +underlying writer. Read more
§

fn write_f64_le(&mut self, n: f64) -> WriteF64Le<&mut Self>
where + Self: Unpin,

Writes an 64-bit floating point type in little-endian order to the +underlying writer. Read more
§

fn flush(&mut self) -> Flush<'_, Self>
where + Self: Unpin,

Flushes this output stream, ensuring that all intermediately buffered +contents reach their destination. Read more
§

fn shutdown(&mut self) -> Shutdown<'_, Self>
where + Self: Unpin,

Shuts down the output stream, ensuring that the value can be dropped +cleanly. Read more
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/index.html b/pr/2992/docs/iroh_relay/server/index.html new file mode 100644 index 0000000000..5c783d00e7 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/index.html @@ -0,0 +1,16 @@ +iroh_relay::server - Rust

Module iroh_relay::server

source ·
Available on crate feature server only.
Expand description

A fully-fledged iroh-relay server over HTTP or HTTPS.

+

This module provides an API to run a full fledged iroh-relay server. It is primarily +used by the iroh-relay binary in this crate. It can be used to run a relay server in +other locations however.

+

This code is fully written in a form of structured-concurrency: every spawned task is +always attached to a handle and when the handle is dropped the tasks abort. So tasks +can not outlive their handle. It is also always possible to await for completion of a +task. Some tasks additionally have a method to do graceful shutdown.

+

The relay server hosts the following services:

+
    +
  • HTTPS /relay: The main URL endpoint to which clients connect and sends traffic over.
  • +
  • HTTPS /ping: Used for net_report probes.
  • +
  • HTTPS /generate_204: Used for net_report probes.
  • +
  • STUN: UDP port for STUN requests/responses.
  • +
+

Modules§

  • Exposes functions to quickly configure a server suitable for testing.

Structs§

Enums§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/metrics/struct.Metrics.html b/pr/2992/docs/iroh_relay/server/metrics/struct.Metrics.html new file mode 100644 index 0000000000..6fd1dafe3f --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/metrics/struct.Metrics.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_relay/server/struct.Metrics.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/metrics/struct.StunMetrics.html b/pr/2992/docs/iroh_relay/server/metrics/struct.StunMetrics.html new file mode 100644 index 0000000000..109537c22f --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/metrics/struct.StunMetrics.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_relay/server/struct.StunMetrics.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/sidebar-items.js b/pr/2992/docs/iroh_relay/server/sidebar-items.js new file mode 100644 index 0000000000..221d689620 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["CertConfig","MaybeTlsStreamServer"],"mod":["testing"],"struct":["ClientConnRateLimit","Limits","Metrics","QuicConfig","RelayConfig","Server","ServerConfig","StunConfig","StunMetrics","TlsConfig"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/streams/enum.MaybeTlsStream.html b/pr/2992/docs/iroh_relay/server/streams/enum.MaybeTlsStream.html new file mode 100644 index 0000000000..1276e167e1 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/streams/enum.MaybeTlsStream.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../iroh_relay/server/enum.MaybeTlsStreamServer.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.ClientConnRateLimit.html b/pr/2992/docs/iroh_relay/server/struct.ClientConnRateLimit.html new file mode 100644 index 0000000000..ee1cecb1c6 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.ClientConnRateLimit.html @@ -0,0 +1,32 @@ +ClientConnRateLimit in iroh_relay::server - Rust

Struct iroh_relay::server::ClientConnRateLimit

source ·
pub struct ClientConnRateLimit {
+    pub bytes_per_second: NonZeroU32,
+    pub max_burst_bytes: Option<NonZeroU32>,
+}
Available on crate feature server only.
Expand description

Per-client rate limit configuration.

+

Fields§

§bytes_per_second: NonZeroU32

Max number of bytes per second to read from the client connection.

+
§max_burst_bytes: Option<NonZeroU32>

Max number of bytes to read in a single burst.

+

Trait Implementations§

source§

impl Clone for ClientConnRateLimit

source§

fn clone(&self) -> ClientConnRateLimit

Returns a copy 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 ClientConnRateLimit

source§

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

Formats the value using the given formatter. Read more
source§

impl Copy for ClientConnRateLimit

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.Limits.html b/pr/2992/docs/iroh_relay/server/struct.Limits.html new file mode 100644 index 0000000000..5af68e4e1e --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.Limits.html @@ -0,0 +1,33 @@ +Limits in iroh_relay::server - Rust

Struct iroh_relay::server::Limits

source ·
pub struct Limits {
+    pub accept_conn_limit: Option<f64>,
+    pub accept_conn_burst: Option<usize>,
+    pub client_rx: Option<ClientConnRateLimit>,
+}
Available on crate feature server only.
Expand description

Rate limits.

+

Fields§

§accept_conn_limit: Option<f64>

Rate limit for accepting new connection. Unlimited if not set.

+
§accept_conn_burst: Option<usize>

Burst limit for accepting new connection. Unlimited if not set.

+
§client_rx: Option<ClientConnRateLimit>

Rate limits for incoming traffic from a client connection.

+

Trait Implementations§

source§

impl Debug for Limits

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Limits

source§

fn default() -> Limits

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Limits

§

impl RefUnwindSafe for Limits

§

impl Send for Limits

§

impl Sync for Limits

§

impl Unpin for Limits

§

impl UnwindSafe for Limits

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.Metrics.html b/pr/2992/docs/iroh_relay/server/struct.Metrics.html new file mode 100644 index 0000000000..bd73fd1e73 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.Metrics.html @@ -0,0 +1,72 @@ +Metrics in iroh_relay::server - Rust

Struct iroh_relay::server::Metrics

source ·
pub struct Metrics {
Show 21 fields + pub bytes_sent: Counter, + pub bytes_recv: Counter, + pub send_packets_sent: Counter, + pub send_packets_recv: Counter, + pub send_packets_dropped: Counter, + pub disco_packets_sent: Counter, + pub disco_packets_recv: Counter, + pub disco_packets_dropped: Counter, + pub other_packets_sent: Counter, + pub other_packets_recv: Counter, + pub other_packets_dropped: Counter, + pub got_ping: Counter, + pub sent_pong: Counter, + pub unknown_frames: Counter, + pub frames_rx_ratelimited_total: Counter, + pub conns_rx_ratelimited_total: Counter, + pub accepts: Counter, + pub disconnects: Counter, + pub unique_client_keys: Counter, + pub websocket_accepts: Counter, + pub derp_accepts: Counter, +
}
Available on crate feature server only.
Expand description

Metrics tracked for the relay server

+

Fields§

§bytes_sent: Counter

Bytes sent from a FrameType::SendPacket

+
§bytes_recv: Counter

Bytes received from a FrameType::SendPacket

+
§send_packets_sent: Counter

FrameType::SendPacket sent, that are not disco messages

+
§send_packets_recv: Counter

FrameType::SendPacket received, that are not disco messages

+
§send_packets_dropped: Counter

FrameType::SendPacket dropped, that are not disco messages

+
§disco_packets_sent: Counter

FrameType::SendPacket sent that are disco messages

+
§disco_packets_recv: Counter

FrameType::SendPacket received that are disco messages

+
§disco_packets_dropped: Counter

FrameType::SendPacket dropped that are disco messages

+
§other_packets_sent: Counter

Packets of other FrameTypes sent

+
§other_packets_recv: Counter

Packets of other FrameTypes received

+
§other_packets_dropped: Counter

Packets of other FrameTypes dropped

+
§got_ping: Counter

Number of FrameType::Pings received

+
§sent_pong: Counter

Number of FrameType::Pongs sent

+
§unknown_frames: Counter

Number of FrameType::Unknown received

+
§frames_rx_ratelimited_total: Counter

Number of frames received from client connection which have been rate-limited.

+
§conns_rx_ratelimited_total: Counter

Number of client connections which have had any frames rate-limited.

+
§accepts: Counter

Number of connections we have accepted

+
§disconnects: Counter

Number of connections we have removed because of an error

+
§unique_client_keys: Counter

Number of unique client keys per day

+
§websocket_accepts: Counter

Number of accepted websocket connections

+
§derp_accepts: Counter

Number of accepted ‘iroh derp http’ connection upgrades

+

Trait Implementations§

source§

impl Clone for Metrics

source§

fn clone(&self) -> Metrics

Returns a copy 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 Metrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for Metrics

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Iterable for Metrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a dyn Any)>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for Metrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.QuicConfig.html b/pr/2992/docs/iroh_relay/server/struct.QuicConfig.html new file mode 100644 index 0000000000..a462014ba9 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.QuicConfig.html @@ -0,0 +1,34 @@ +QuicConfig in iroh_relay::server - Rust

Struct iroh_relay::server::QuicConfig

source ·
pub struct QuicConfig {
+    pub bind_addr: SocketAddr,
+    pub server_config: ServerConfig,
+}
Available on crate feature server only.
Expand description

Configuration for the QUIC server.

+

Fields§

§bind_addr: SocketAddr

The socket address on which the QUIC server should bind.

+

Normally you’d chose port 7842, see crate::defaults::DEFAULT_RELAY_QUIC_PORT.

+
§server_config: ServerConfig

The TLS server configuration for the QUIC server.

+

If this [rustls::ServerConfig] does not support TLS 1.3, the QUIC server will fail +to spawn.

+

Trait Implementations§

source§

impl Debug for QuicConfig

source§

fn fmt(&self, __derive_more_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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.RelayConfig.html b/pr/2992/docs/iroh_relay/server/struct.RelayConfig.html new file mode 100644 index 0000000000..6cb5ed18d0 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.RelayConfig.html @@ -0,0 +1,42 @@ +RelayConfig in iroh_relay::server - Rust

Struct iroh_relay::server::RelayConfig

source ·
pub struct RelayConfig<EC: Debug, EA: Debug = EC> {
+    pub http_bind_addr: SocketAddr,
+    pub tls: Option<TlsConfig<EC, EA>>,
+    pub limits: Limits,
+}
Available on crate feature server only.
Expand description

Configuration for the Relay HTTP and HTTPS server.

+

This includes the HTTP services hosted by the Relay server, the Relay /relay HTTP +endpoint is only one of the services served.

+

Fields§

§http_bind_addr: SocketAddr

The socket address on which the Relay HTTP server should bind.

+

Normally you’d choose port 80. The bind address for the HTTPS server is +configured in RelayConfig::tls.

+

If RelayConfig::tls is None then this serves all the HTTP services without +TLS.

+
§tls: Option<TlsConfig<EC, EA>>

TLS configuration for the HTTPS server.

+

If None all the HTTP services that would be served here are served from +RelayConfig::http_bind_addr.

+
§limits: Limits

Rate limits.

+

Trait Implementations§

source§

impl<EC: Debug, EA: Debug> Debug for RelayConfig<EC, EA>
where + Option<TlsConfig<EC, EA>>: Debug,

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<EC, EA> Freeze for RelayConfig<EC, EA>

§

impl<EC, EA = EC> !RefUnwindSafe for RelayConfig<EC, EA>

§

impl<EC, EA> Send for RelayConfig<EC, EA>

§

impl<EC, EA = EC> !Sync for RelayConfig<EC, EA>

§

impl<EC, EA> Unpin for RelayConfig<EC, EA>

§

impl<EC, EA = EC> !UnwindSafe for RelayConfig<EC, EA>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.Server.html b/pr/2992/docs/iroh_relay/server/struct.Server.html new file mode 100644 index 0000000000..8067e53b5a --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.Server.html @@ -0,0 +1,45 @@ +Server in iroh_relay::server - Rust

Struct iroh_relay::server::Server

source ·
pub struct Server { /* private fields */ }
Available on crate feature server only.
Expand description

A running Relay + STUN server.

+

This is a full Relay server, including STUN, Relay and various associated HTTP services.

+

Dropping this will stop the server.

+

Implementations§

source§

impl Server

source

pub async fn spawn<EC, EA>(config: ServerConfig<EC, EA>) -> Result<Self>
where + EC: Debug + 'static, + EA: Debug + 'static,

Starts the server.

+
source

pub async fn shutdown(self) -> Result<()>

Requests graceful shutdown.

+

Returns once all server tasks have stopped.

+
source

pub fn task_handle(&mut self) -> &mut AbortOnDropHandle<Result<()>>

Returns the handle for the task.

+

This allows waiting for the server’s supervisor task to finish. Can be useful in +case there is an error in the server before it is shut down.

+
source

pub fn https_addr(&self) -> Option<SocketAddr>

The socket address the HTTPS server is listening on.

+
source

pub fn http_addr(&self) -> Option<SocketAddr>

The socket address the HTTP server is listening on.

+
source

pub fn quic_addr(&self) -> Option<SocketAddr>

The socket address the QUIC server is listening on.

+
source

pub fn stun_addr(&self) -> Option<SocketAddr>

The socket address the STUN server is listening on.

+
source

pub fn certificates(&self) -> Option<Vec<CertificateDer<'static>>>

The certificates chain if configured with manual TLS certificates.

+
source

pub fn https_url(&self) -> Option<RelayUrl>

Get the server’s https RelayUrl.

+

This uses Self::https_addr so it’s mostly useful for local development.

+
source

pub fn http_url(&self) -> Option<RelayUrl>

Get the server’s http RelayUrl.

+

This uses Self::http_addr so it’s mostly useful for local development.

+

Trait Implementations§

source§

impl Debug for Server

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Server

§

impl RefUnwindSafe for Server

§

impl Send for Server

§

impl Sync for Server

§

impl Unpin for Server

§

impl UnwindSafe for Server

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.ServerConfig.html b/pr/2992/docs/iroh_relay/server/struct.ServerConfig.html new file mode 100644 index 0000000000..fea66aebff --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.ServerConfig.html @@ -0,0 +1,38 @@ +ServerConfig in iroh_relay::server - Rust

Struct iroh_relay::server::ServerConfig

source ·
pub struct ServerConfig<EC: Debug, EA: Debug = EC> {
+    pub relay: Option<RelayConfig<EC, EA>>,
+    pub stun: Option<StunConfig>,
+    pub quic: Option<QuicConfig>,
+    pub metrics_addr: Option<SocketAddr>,
+}
Available on crate feature server only.
Expand description

Configuration for the full Relay & STUN server.

+

Be aware the generic parameters are for when using the Let’s Encrypt TLS configuration. +If not used dummy ones need to be provided, e.g. ServerConfig::<(), ()>::default().

+

Fields§

§relay: Option<RelayConfig<EC, EA>>

Configuration for the Relay server, disabled if None.

+
§stun: Option<StunConfig>

Configuration for the STUN server, disabled if None.

+
§quic: Option<QuicConfig>

Configuration for the QUIC server, disabled if None.

+
§metrics_addr: Option<SocketAddr>
Available on crate feature metrics only.

Socket to serve metrics on.

+

Trait Implementations§

source§

impl<EC: Debug, EA: Debug> Debug for ServerConfig<EC, EA>
where + Option<RelayConfig<EC, EA>>: Debug,

source§

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

Formats the value using the given formatter. Read more
source§

impl<EC: Default + Debug, EA: Default + Debug> Default for ServerConfig<EC, EA>

source§

fn default() -> ServerConfig<EC, EA>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<EC, EA> Freeze for ServerConfig<EC, EA>

§

impl<EC, EA = EC> !RefUnwindSafe for ServerConfig<EC, EA>

§

impl<EC, EA> Send for ServerConfig<EC, EA>

§

impl<EC, EA = EC> !Sync for ServerConfig<EC, EA>

§

impl<EC, EA> Unpin for ServerConfig<EC, EA>

§

impl<EC, EA = EC> !UnwindSafe for ServerConfig<EC, EA>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.StunConfig.html b/pr/2992/docs/iroh_relay/server/struct.StunConfig.html new file mode 100644 index 0000000000..d4e42fb792 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.StunConfig.html @@ -0,0 +1,30 @@ +StunConfig in iroh_relay::server - Rust

Struct iroh_relay::server::StunConfig

source ·
pub struct StunConfig {
+    pub bind_addr: SocketAddr,
+}
Available on crate feature server only.
Expand description

Configuration for the STUN server.

+

Fields§

§bind_addr: SocketAddr

The socket address on which the STUN server should bind.

+

Normally you’d chose port 3478, see crate::defaults::DEFAULT_STUN_PORT.

+

Trait Implementations§

source§

impl Debug for StunConfig

source§

fn fmt(&self, __derive_more_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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.StunMetrics.html b/pr/2992/docs/iroh_relay/server/struct.StunMetrics.html new file mode 100644 index 0000000000..ff05e6d09c --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.StunMetrics.html @@ -0,0 +1,40 @@ +StunMetrics in iroh_relay::server - Rust

Struct iroh_relay::server::StunMetrics

source ·
pub struct StunMetrics {
+    pub requests: Counter,
+    pub ipv4_success: Counter,
+    pub ipv6_success: Counter,
+    pub bad_requests: Counter,
+    pub failures: Counter,
+}
Available on crate feature server only.
Expand description

StunMetrics tracked for the DERPER

+

Fields§

§requests: Counter

Number of stun requests made

+
§ipv4_success: Counter

Number of successful requests over ipv4

+
§ipv6_success: Counter

Number of successful requests over ipv6

+
§bad_requests: Counter

Number of bad requests, either non-stun packets or incorrect binding request

+
§failures: Counter

Number of failures

+

Trait Implementations§

source§

impl Clone for StunMetrics

source§

fn clone(&self) -> StunMetrics

Returns a copy 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 StunMetrics

source§

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

Formats the value using the given formatter. Read more
source§

impl Default for StunMetrics

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Iterable for StunMetrics

source§

fn iter<'a>(&'a self) -> IntoIter<(&'static str, &'a dyn Any)>

Returns an iterator over the struct’s fields as tuples. Read more
source§

impl Metric for StunMetrics

source§

fn name() -> &'static str

The name of this metric group.
§

fn new(registry: &mut Registry) -> Self

Initializes this metric group.
§

fn with_metric<T, F>(f: F)
where + F: FnOnce(&Self) -> T,

Access to this metrics group to record a metric. +Only records if this metric is registered in the global registry.
§

fn try_get() -> Option<&'static Self>

Attempts to get the current metric from the global registry.

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/struct.TlsConfig.html b/pr/2992/docs/iroh_relay/server/struct.TlsConfig.html new file mode 100644 index 0000000000..2c86d28148 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/struct.TlsConfig.html @@ -0,0 +1,41 @@ +TlsConfig in iroh_relay::server - Rust

Struct iroh_relay::server::TlsConfig

source ·
pub struct TlsConfig<EC: Debug, EA: Debug = EC> {
+    pub https_bind_addr: SocketAddr,
+    pub quic_bind_addr: SocketAddr,
+    pub cert: CertConfig<EC, EA>,
+    pub server_config: ServerConfig,
+}
Available on crate feature server only.
Expand description

TLS configuration for Relay server.

+

Normally the Relay server accepts connections on both HTTPS and HTTP.

+

Fields§

§https_bind_addr: SocketAddr

The socket address on which to serve the HTTPS server.

+

Since the captive portal probe has to run over plain text HTTP and TLS is used for +the main relay server this has to be on a different port. When TLS is not enabled +this is served on the RelayConfig::http_bind_addr socket address.

+

Normally you’d choose port 80.

+
§quic_bind_addr: SocketAddr

The socket address on which to server the QUIC server is QUIC is enabled.

+
§cert: CertConfig<EC, EA>

Mode for getting a cert.

+
§server_config: ServerConfig

The server configuration.

+

Trait Implementations§

source§

impl<EC: Debug, EA: Debug> Debug for TlsConfig<EC, EA>
where + CertConfig<EC, EA>: Debug,

source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<EC, EA> Freeze for TlsConfig<EC, EA>

§

impl<EC, EA = EC> !RefUnwindSafe for TlsConfig<EC, EA>

§

impl<EC, EA> Send for TlsConfig<EC, EA>

§

impl<EC, EA = EC> !Sync for TlsConfig<EC, EA>

§

impl<EC, EA> Unpin for TlsConfig<EC, EA>

§

impl<EC, EA = EC> !UnwindSafe for TlsConfig<EC, EA>

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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.quic_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.quic_config.html new file mode 100644 index 0000000000..3dc6a07295 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.quic_config.html @@ -0,0 +1,6 @@ +quic_config in iroh_relay::server::testing - Rust

Function iroh_relay::server::testing::quic_config

source ·
pub fn quic_config() -> QuicConfig
Available on crate feature server only.
Expand description

Creates a QuicConfig suitable for testing.

+ +
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.relay_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.relay_config.html new file mode 100644 index 0000000000..950ecc1343 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.relay_config.html @@ -0,0 +1,7 @@ +relay_config in iroh_relay::server::testing - Rust

Function iroh_relay::server::testing::relay_config

source ·
pub fn relay_config() -> RelayConfig<()>
Available on crate feature server only.
Expand description

Creates a RelayConfig suitable for testing.

+
    +
  • Binds http to an OS assigned port on ipv4.
  • +
  • Uses tls_config to enable TLS.
  • +
  • Uses default limits.
  • +
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.self_signed_tls_certs_and_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.self_signed_tls_certs_and_config.html new file mode 100644 index 0000000000..26edda2685 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.self_signed_tls_certs_and_config.html @@ -0,0 +1,6 @@ +self_signed_tls_certs_and_config in iroh_relay::server::testing - Rust
pub fn self_signed_tls_certs_and_config(
+) -> (Vec<CertificateDer<'static>>, ServerConfig)
Available on crate feature server only.
Expand description

Creates a [rustls::ServerConfig] and certificates suitable for testing.

+
    +
  • Uses a self signed certificate valid for the "localhost" and "127.0.0.1" domains.
  • +
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.server_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.server_config.html new file mode 100644 index 0000000000..bd37875803 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.server_config.html @@ -0,0 +1,8 @@ +server_config in iroh_relay::server::testing - Rust

Function iroh_relay::server::testing::server_config

source ·
pub fn server_config() -> ServerConfig<()>
Available on crate feature server only.
Expand description

Creates a ServerConfig suitable for testing.

+
    +
  • Relaying is enabled using relay_config
  • +
  • Stun is enabled using stun_config
  • +
  • QUIC addr discovery is disabled.
  • +
  • Metrics are not enabled.
  • +
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.stun_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.stun_config.html new file mode 100644 index 0000000000..a59df1d175 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.stun_config.html @@ -0,0 +1,3 @@ +stun_config in iroh_relay::server::testing - Rust

Function iroh_relay::server::testing::stun_config

source ·
pub fn stun_config() -> StunConfig
Available on crate feature server only.
Expand description

Creates a StunConfig suitable for testing.

+

To ensure port availability for testing, the port is configured to be assigned by the OS.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/fn.tls_config.html b/pr/2992/docs/iroh_relay/server/testing/fn.tls_config.html new file mode 100644 index 0000000000..8be13e7ad1 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/fn.tls_config.html @@ -0,0 +1,6 @@ +tls_config in iroh_relay::server::testing - Rust

Function iroh_relay::server::testing::tls_config

source ·
pub fn tls_config() -> TlsConfig<()>
Available on crate feature server only.
Expand description

Creates a TlsConfig suitable for testing.

+
    +
  • Uses a self signed certificate valid for the "localhost" and "127.0.0.1" domains.
  • +
  • Configures https to be served on an OS assigned port on ipv4.
  • +
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/index.html b/pr/2992/docs/iroh_relay/server/testing/index.html new file mode 100644 index 0000000000..ccc9f34f7a --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/index.html @@ -0,0 +1,2 @@ +iroh_relay::server::testing - Rust

Module iroh_relay::server::testing

source ·
Available on crate feature server only.
Expand description

Exposes functions to quickly configure a server suitable for testing.

+

Functions§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/server/testing/sidebar-items.js b/pr/2992/docs/iroh_relay/server/testing/sidebar-items.js new file mode 100644 index 0000000000..2006891511 --- /dev/null +++ b/pr/2992/docs/iroh_relay/server/testing/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["quic_config","relay_config","self_signed_tls_certs_and_config","server_config","stun_config","tls_config"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/sidebar-items.js b/pr/2992/docs/iroh_relay/sidebar-items.js new file mode 100644 index 0000000000..4a914b50fe --- /dev/null +++ b/pr/2992/docs/iroh_relay/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["ReceivedMessage"],"mod":["client","defaults","http","protos","quic","server"],"struct":["RelayConn","RelayUrl"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/struct.RelayConn.html b/pr/2992/docs/iroh_relay/struct.RelayConn.html new file mode 100644 index 0000000000..119bfeb51a --- /dev/null +++ b/pr/2992/docs/iroh_relay/struct.RelayConn.html @@ -0,0 +1,50 @@ +RelayConn in iroh_relay - Rust

Struct iroh_relay::RelayConn

source ·
pub struct RelayConn { /* private fields */ }
Expand description

A connection to a relay server.

+

Cheaply clonable. +Call close to shut down the write loop and read functionality.

+

Implementations§

source§

impl Conn

source

pub async fn send(&self, dst: NodeId, packet: Bytes) -> Result<()>

Sends a packet to the node identified by dstkey

+

Errors if the packet is larger than MAX_PACKET_SIZE

+
source

pub async fn send_ping(&self, data: [u8; 8]) -> Result<()>

Send a ping with 8 bytes of random data.

+
source

pub async fn send_pong(&self, data: [u8; 8]) -> Result<()>

Respond to a ping request. The data field should be filled +by the 8 bytes of random data send by the ping.

+
source

pub async fn note_preferred(&self, preferred: bool) -> Result<()>

Sends a packet that tells the server whether this +connection is to the user’s preferred server. This is only +used in the server for stats.

+
source

pub fn local_addr(&self) -> Option<SocketAddr>

The local address that the Conn is listening on.

+

None, when run in a testing environment or when using websockets.

+
source

pub fn is_closed(&self) -> bool

Whether or not this Conn is closed.

+

The Conn is considered closed if the write side of the connection is no longer running.

+
source

pub async fn close(&self)

Close the connection

+

Shuts down the write loop directly and marks the connection as closed. The Conn will +check if the it is closed before attempting to read from it.

+

Trait Implementations§

source§

impl Clone for Conn

source§

fn clone(&self) -> Conn

Returns a copy 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 Conn

source§

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

Formats the value using the given formatter. Read more
source§

impl PartialEq for Conn

source§

fn eq(&self, other: &Self) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for Conn

Auto Trait Implementations§

§

impl Freeze for Conn

§

impl RefUnwindSafe for Conn

§

impl Send for Conn

§

impl Sync for Conn

§

impl Unpin for Conn

§

impl UnwindSafe for Conn

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
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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>,

§

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
§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_relay/struct.RelayUrl.html b/pr/2992/docs/iroh_relay/struct.RelayUrl.html new file mode 100644 index 0000000000..da1d7d31cd --- /dev/null +++ b/pr/2992/docs/iroh_relay/struct.RelayUrl.html @@ -0,0 +1,502 @@ +RelayUrl in iroh_relay - Rust

Struct iroh_relay::RelayUrl

source ·
pub struct RelayUrl(/* private fields */);
Expand description

A URL identifying a relay server.

+

This is but a wrapper around Url, with a few custom tweaks:

+
    +
  • +

    A relay URL is never a relative URL, so an implicit . is added at the end of the +domain name if missing.

    +
  • +
  • +

    fmt::Debug is implemented so it prints the URL rather than the URL struct fields. +Useful when logging e.g. Option<RelayUrl>.

    +
  • +
+

To create a RelayUrl use the From<Url> implementation.

+

Methods from Deref<Target = Url>§

source

pub fn join(&self, input: &str) -> Result<Url, ParseError>

Parse a string as an URL, with this URL as the base URL.

+

The inverse of this is make_relative.

+
§Notes
+
    +
  • A trailing slash is significant. +Without it, the last path component is considered to be a “file” name +to be removed to get at the “directory” that is used as the base.
  • +
  • A scheme relative special URL +as input replaces everything in the base URL after the scheme.
  • +
  • An absolute URL (with a scheme) as input replaces the whole base URL (even the scheme).
  • +
+
§Examples
+
use url::Url;
+
+// Base without a trailing slash
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/c.png");  // Not /a/b.html/c.png
+
+// Base with a trailing slash
+let base = Url::parse("https://example.net/a/b/")?;
+let url = base.join("c.png")?;
+assert_eq!(url.as_str(), "https://example.net/a/b/c.png");
+
+// Input as scheme relative special URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("//eve.com/b")?;
+assert_eq!(url.as_str(), "https://eve.com/b");
+
+// Input as absolute URL
+let base = Url::parse("https://alice.com/a")?;
+let url = base.join("http://eve.com/b")?;
+assert_eq!(url.as_str(), "http://eve.com/b");  // http instead of https
+
§Errors
+

If the function can not parse an URL from the given string +with this URL as the base URL, a ParseError variant will be returned.

+
source

pub fn make_relative(&self, url: &Url) -> Option<String>

Creates a relative URL if possible, with this URL as the base URL.

+

This is the inverse of join.

+
§Examples
+
use url::Url;
+
+let base = Url::parse("https://example.net/a/b.html")?;
+let url = Url::parse("https://example.net/a/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/b/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("c.png"));
+
+let base = Url::parse("https://example.net/a/b/")?;
+let url = Url::parse("https://example.net/a/d/c.png")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("../d/c.png"));
+
+let base = Url::parse("https://example.net/a/b.html?c=d")?;
+let url = Url::parse("https://example.net/a/b.html?e=f")?;
+let relative = base.make_relative(&url);
+assert_eq!(relative.as_ref().map(|s| s.as_str()), Some("?e=f"));
+
§Errors
+

If this URL can’t be a base for the given URL, None is returned. +This is for example the case if the scheme, host or port are not the same.

+
source

pub fn as_str(&self) -> &str

Return the serialization of this URL.

+

This is fast since that serialization is already stored in the Url struct.

+
§Examples
+
use url::Url;
+
+let url_str = "https://example.net/";
+let url = Url::parse(url_str)?;
+assert_eq!(url.as_str(), url_str);
+
source

pub fn origin(&self) -> Origin

Return the origin of this URL (https://url.spec.whatwg.org/#origin)

+

Note: this returns an opaque origin for file: URLs, which causes +url.origin() != url.origin().

+
§Examples
+

URL with ftp scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("ftp://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("ftp".into(),
+                         Host::Domain("example.com".into()),
+                         21));
+

URL with blob scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("blob:https://example.com/foo")?;
+assert_eq!(url.origin(),
+           Origin::Tuple("https".into(),
+                         Host::Domain("example.com".into()),
+                         443));
+

URL with file scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("file:///tmp/foo")?;
+assert!(!url.origin().is_tuple());
+
+let other_url = Url::parse("file:///tmp/foo")?;
+assert!(url.origin() != other_url.origin());
+

URL with other scheme:

+ +
use url::{Host, Origin, Url};
+
+let url = Url::parse("foo:bar")?;
+assert!(!url.origin().is_tuple());
+
source

pub fn scheme(&self) -> &str

Return the scheme of this URL, lower-cased, as an ASCII string without the ‘:’ delimiter.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.scheme(), "file");
+
source

pub fn is_special(&self) -> bool

Return whether the URL is special (has a special scheme)

+
§Examples
+
use url::Url;
+
+assert!(Url::parse("http:///tmp/foo")?.is_special());
+assert!(Url::parse("file:///tmp/foo")?.is_special());
+assert!(!Url::parse("moz:///tmp/foo")?.is_special());
+
source

pub fn has_authority(&self) -> bool

Return whether the URL has an ‘authority’, +which can contain a username, password, host, and port number.

+

URLs that do not are either path-only like unix:/run/foo.socket +or cannot-be-a-base like data:text/plain,Stuff.

+

See also the authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_authority());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_authority());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_authority());
+
source

pub fn authority(&self) -> &str

Return the authority of this URL as an ASCII string.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets. +Ports are omitted if they match the well known port of a special URL.

+

Username and password are percent-encoded.

+

See also the has_authority method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("file:///tmp/foo")?;
+assert_eq!(url.authority(), "");
+let url = Url::parse("https://user:password@example.com/tmp/foo")?;
+assert_eq!(url.authority(), "user:password@example.com");
+let url = Url::parse("irc://àlex.рф.example.com:6667/foo")?;
+assert_eq!(url.authority(), "%C3%A0lex.%D1%80%D1%84.example.com:6667");
+let url = Url::parse("http://àlex.рф.example.com:80/foo")?;
+assert_eq!(url.authority(), "xn--lex-8ka.xn--p1ai.example.com");
+
source

pub fn cannot_be_a_base(&self) -> bool

Return whether this URL is a cannot-be-a-base URL, +meaning that parsing a relative URL string with this URL as the base will return an error.

+

This is the case if the scheme and : delimiter are not followed by a / slash, +as is typically the case of data: and mailto: URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.cannot_be_a_base());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.cannot_be_a_base());
+
source

pub fn username(&self) -> &str

Return the username for this URL (typically the empty string) +as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.username(), "rms");
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.username(), "");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.username(), "");
+
source

pub fn password(&self) -> Option<&str>

Return the password for this URL, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://:secret123@example.com")?;
+assert_eq!(url.password(), Some("secret123"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.password(), None);
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.password(), None);
+
source

pub fn has_host(&self) -> bool

Equivalent to url.host().is_some().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.has_host());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(!url.has_host());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(!url.has_host());
+
source

pub fn host_str(&self) -> Option<&str>

Return the string representation of the host (domain or IP address) for this URL, if any.

+

Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs. +IPv6 addresses are given between [ and ] brackets.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert_eq!(url.host_str(), Some("127.0.0.1"));
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert_eq!(url.host_str(), Some("example.com"));
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert_eq!(url.host_str(), None);
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert_eq!(url.host_str(), None);
+
source

pub fn host(&self) -> Option<Host<&str>>

Return the parsed representation of the host for this URL. +Non-ASCII domain labels are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+

Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs +don’t have a host.

+

See also the host_str method.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/index.html")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("ftp://rms@example.com")?;
+assert!(url.host().is_some());
+
+let url = Url::parse("unix:/run/foo.socket")?;
+assert!(url.host().is_none());
+
+let url = Url::parse("data:text/plain,Stuff")?;
+assert!(url.host().is_none());
+
source

pub fn domain(&self) -> Option<&str>

If this URL has a host and it is a domain name (not an IP address), return it. +Non-ASCII domains are punycode-encoded per IDNA if this is the host +of a special URL, or percent encoded for non-special URLs.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://127.0.0.1/")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("mailto:rms@example.net")?;
+assert_eq!(url.domain(), None);
+
+let url = Url::parse("https://example.com/")?;
+assert_eq!(url.domain(), Some("example.com"));
+
source

pub fn port(&self) -> Option<u16>

Return the port number for this URL, if any.

+

Note that default port numbers are never reflected by the serialization, +use the port_or_known_default() method if you want a default port number returned.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("https://example.com:443/")?;
+assert_eq!(url.port(), None);
+
+let url = Url::parse("ssh://example.com:22")?;
+assert_eq!(url.port(), Some(22));
+
source

pub fn port_or_known_default(&self) -> Option<u16>

Return the port number for this URL, or the default port number if it is known.

+

This method only knows the default port number +of the http, https, ws, wss and ftp schemes.

+

For URLs in these schemes, this method always returns Some(_). +For other schemes, it is the same as Url::port().

+
§Examples
+
use url::Url;
+
+let url = Url::parse("foo://example.com")?;
+assert_eq!(url.port_or_known_default(), None);
+
+let url = Url::parse("foo://example.com:1456")?;
+assert_eq!(url.port_or_known_default(), Some(1456));
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.port_or_known_default(), Some(443));
+
source

pub fn socket_addrs( + &self, + default_port_number: impl Fn() -> Option<u16> +) -> Result<Vec<SocketAddr>, Error>

Resolve a URL’s host and port number to SocketAddr.

+

If the URL has the default port number of a scheme that is unknown to this library, +default_port_number provides an opportunity to provide the actual port number. +In non-example code this should be implemented either simply as || None, +or by matching on the URL’s .scheme().

+

If the host is a domain, it is resolved using the standard library’s DNS support.

+
§Examples
+
let url = url::Url::parse("https://example.net/").unwrap();
+let addrs = url.socket_addrs(|| None).unwrap();
+std::net::TcpStream::connect(&*addrs)
+ +
/// With application-specific known default port numbers
+fn socket_addrs(url: url::Url) -> std::io::Result<Vec<std::net::SocketAddr>> {
+    url.socket_addrs(|| match url.scheme() {
+        "socks5" | "socks5h" => Some(1080),
+        _ => None,
+    })
+}
+
source

pub fn path(&self) -> &str

Return the path for this URL, as a percent-encoded ASCII string. +For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with ‘/’. +For other URLs, this starts with a ‘/’ slash +and continues with slash-separated path segments.

+
§Examples
+
use url::{Url, ParseError};
+
+let url = Url::parse("https://example.com/api/versions?page=2")?;
+assert_eq!(url.path(), "/api/versions");
+
+let url = Url::parse("https://example.com")?;
+assert_eq!(url.path(), "/");
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+assert_eq!(url.path(), "/countries/vi%E1%BB%87t%20nam");
+
source

pub fn path_segments(&self) -> Option<Split<'_, char>>

Unless this URL is cannot-be-a-base, +return an iterator of ‘/’ slash-separated path segments, +each as a percent-encoded ASCII string.

+

Return None for cannot-be-a-base URLs.

+

When Some is returned, the iterator always contains at least one string +(which may be empty).

+
§Examples
+
use url::Url;
+
+
+let url = Url::parse("https://example.com/foo/bar")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("foo"));
+assert_eq!(path_segments.next(), Some("bar"));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("https://example.com")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some(""));
+assert_eq!(path_segments.next(), None);
+
+let url = Url::parse("data:text/plain,HelloWorld")?;
+assert!(url.path_segments().is_none());
+
+let url = Url::parse("https://example.com/countries/việt nam")?;
+let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
+assert_eq!(path_segments.next(), Some("countries"));
+assert_eq!(path_segments.next(), Some("vi%E1%BB%87t%20nam"));
+
source

pub fn query(&self) -> Option<&str>

Return this URL’s query string, if any, as a percent-encoded ASCII string.

+
§Examples
+
use url::Url;
+
+fn run() -> Result<(), ParseError> {
+let url = Url::parse("https://example.com/products?page=2")?;
+let query = url.query();
+assert_eq!(query, Some("page=2"));
+
+let url = Url::parse("https://example.com/products")?;
+let query = url.query();
+assert!(query.is_none());
+
+let url = Url::parse("https://example.com/?country=español")?;
+let query = url.query();
+assert_eq!(query, Some("country=espa%C3%B1ol"));
+
source

pub fn query_pairs(&self) -> Parse<'_>

Parse the URL’s query string, if any, as application/x-www-form-urlencoded +and return an iterator of (key, value) pairs.

+
§Examples
+
use std::borrow::Cow;
+
+use url::Url;
+
+let url = Url::parse("https://example.com/products?page=2&sort=desc")?;
+let mut pairs = url.query_pairs();
+
+assert_eq!(pairs.count(), 2);
+
+assert_eq!(pairs.next(), Some((Cow::Borrowed("page"), Cow::Borrowed("2"))));
+assert_eq!(pairs.next(), Some((Cow::Borrowed("sort"), Cow::Borrowed("desc"))));
+
source

pub fn fragment(&self) -> Option<&str>

Return this URL’s fragment identifier, if any.

+

A fragment is the part of the URL after the # symbol. +The fragment is optional and, if present, contains a fragment identifier +that identifies a secondary resource, such as a section heading +of a document.

+

In HTML, the fragment identifier is usually the id attribute of a an element +that is scrolled to on load. Browsers typically will not send the fragment portion +of a URL to the server.

+

Note: the parser did not percent-encode this component, +but the input may have been percent-encoded already.

+
§Examples
+
use url::Url;
+
+let url = Url::parse("https://example.com/data.csv#row=4")?;
+
+assert_eq!(url.fragment(), Some("row=4"));
+
+let url = Url::parse("https://example.com/data.csv#cell=4,1-6,2")?;
+
+assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
+
source

pub fn serialize_internal<S>( + &self, + serializer: S +) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where + S: Serializer,

Serialize with Serde using the internal representation of the Url struct.

+

The corresponding deserialize_internal method sacrifices some invariant-checking +for speed, compared to the Deserialize trait impl.

+

This method is only available if the serde Cargo feature is enabled.

+
source

pub fn to_file_path(&self) -> Result<PathBuf, ()>

Assuming the URL is in the file scheme or similar, +convert its path to an absolute std::path::Path.

+

Note: This does not actually check the URL’s scheme, +and may give nonsensical results for other schemes. +It is the user’s responsibility to check the URL’s scheme before calling this.

+ +
let path = url.to_file_path();
+

Returns Err if the host is neither empty nor "localhost" (except on Windows, where +file: URLs may have a non-local host), +or if Path::new_opt() returns None. +(That is, if the percent-decoded path contains a NUL byte or, +for a Windows path, is not UTF-8.)

+

This method is only available if the std Cargo feature is enabled.

+

Trait Implementations§

source§

impl Clone for RelayUrl

source§

fn clone(&self) -> RelayUrl

Returns a copy 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 RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl Deref for RelayUrl

Dereferences to the wrapped Url.

+

Note that DerefMut is not implemented on purpose, so this type has more flexibility +to change the inner later.

+
§

type Target = Url

The resulting type after dereferencing.
source§

fn deref(&self) -> &<RelayUrl as Deref>::Target

Dereferences the value.
source§

impl<'de> Deserialize<'de> for RelayUrl

source§

fn deserialize<__D>( + __deserializer: __D +) -> Result<RelayUrl, <__D as Deserializer<'de>>::Error>
where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl Display for RelayUrl

source§

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

Formats the value using the given formatter. Read more
source§

impl From<RelayUrl> for Url

source§

fn from(value: RelayUrl) -> Url

Converts to this type from the input type.
source§

impl From<Url> for RelayUrl

source§

fn from(url: Url) -> RelayUrl

Converts to this type from the input type.
source§

impl FromStr for RelayUrl

Support for parsing strings directly.

+

If you need more control over the error first create a Url and use RelayUrl::from +instead.

+
§

type Err = Error

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<RelayUrl, <RelayUrl as FromStr>::Err>

Parses a string s to return a value of this type. Read more
source§

impl Hash for RelayUrl

source§

fn hash<__H>(&self, state: &mut __H)
where + __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for RelayUrl

source§

fn cmp(&self, other: &RelayUrl) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for RelayUrl

source§

fn eq(&self, other: &RelayUrl) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for RelayUrl

source§

fn partial_cmp(&self, other: &RelayUrl) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Serialize for RelayUrl

source§

fn serialize<__S>( + &self, + __serializer: __S +) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where + __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl Eq for RelayUrl

source§

impl StructuralPartialEq for RelayUrl

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
§

impl<Q, K> Comparable<K> for Q
where + Q: Ord + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

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>,

§

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
source§

impl<T> DeserializeOwned for T
where + T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where + T: 'static,

§

impl<T> MaybeSendSync for T

\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/all.html b/pr/2992/docs/iroh_test/all.html new file mode 100644 index 0000000000..453b3677ff --- /dev/null +++ b/pr/2992/docs/iroh_test/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Macros

Functions

\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/hexdump/fn.parse_hexdump.html b/pr/2992/docs/iroh_test/hexdump/fn.parse_hexdump.html new file mode 100644 index 0000000000..16e752fa14 --- /dev/null +++ b/pr/2992/docs/iroh_test/hexdump/fn.parse_hexdump.html @@ -0,0 +1,3 @@ +parse_hexdump in iroh_test::hexdump - Rust

Function iroh_test::hexdump::parse_hexdump

source ·
pub fn parse_hexdump(s: &str) -> Result<Vec<u8>>
Expand description

Parses a commented multi line hexdump into a vector of bytes.

+

This is useful to write wire level protocol tests.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/hexdump/fn.print_hexdump.html b/pr/2992/docs/iroh_test/hexdump/fn.print_hexdump.html new file mode 100644 index 0000000000..5e2303d171 --- /dev/null +++ b/pr/2992/docs/iroh_test/hexdump/fn.print_hexdump.html @@ -0,0 +1,5 @@ +print_hexdump in iroh_test::hexdump - Rust

Function iroh_test::hexdump::print_hexdump

source ·
pub fn print_hexdump(
+    bytes: impl AsRef<[u8]>,
+    line_lengths: impl AsRef<[usize]>
+) -> String
Expand description

Returns a hexdump of the given bytes in multiple lines as a String.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/hexdump/index.html b/pr/2992/docs/iroh_test/hexdump/index.html new file mode 100644 index 0000000000..67cff93f29 --- /dev/null +++ b/pr/2992/docs/iroh_test/hexdump/index.html @@ -0,0 +1 @@ +iroh_test::hexdump - Rust

Module iroh_test::hexdump

source ·

Functions§

  • Parses a commented multi line hexdump into a vector of bytes.
  • Returns a hexdump of the given bytes in multiple lines as a String.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/hexdump/sidebar-items.js b/pr/2992/docs/iroh_test/hexdump/sidebar-items.js new file mode 100644 index 0000000000..5356689348 --- /dev/null +++ b/pr/2992/docs/iroh_test/hexdump/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["parse_hexdump","print_hexdump"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_test/index.html b/pr/2992/docs/iroh_test/index.html new file mode 100644 index 0000000000..5afc62b597 --- /dev/null +++ b/pr/2992/docs/iroh_test/index.html @@ -0,0 +1,2 @@ +iroh_test - Rust

Crate iroh_test

source ·
Expand description

Internal utilities to support testing.

+

Modules§

Macros§

  • This is a macro to assert that two byte slices are equal.

Structs§

\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/logging/fn.setup.html b/pr/2992/docs/iroh_test/logging/fn.setup.html new file mode 100644 index 0000000000..4089da95db --- /dev/null +++ b/pr/2992/docs/iroh_test/logging/fn.setup.html @@ -0,0 +1,14 @@ +setup in iroh_test::logging - Rust

Function iroh_test::logging::setup

source ·
pub fn setup() -> DefaultGuard
Expand description

Configures logging for the current test, single-threaded runtime only.

+

This setup can be used for any sync test or async test using a single-threaded tokio +runtime (the default).

+

This configures logging that will interact well with tests: logs will be captured by the +test framework and only printed on failure.

+

The logging is unfiltered, it logs all crates and modules on TRACE level. If that’s too +much consider if your test is too large (or write a version that allows filtering…).

+

§Example

+
#[tokio::test]
+async fn test_something() {
+    let _guard = iroh_test::logging::setup();
+    assert!(true);
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/logging/fn.setup_multithreaded.html b/pr/2992/docs/iroh_test/logging/fn.setup_multithreaded.html new file mode 100644 index 0000000000..0c64e3a342 --- /dev/null +++ b/pr/2992/docs/iroh_test/logging/fn.setup_multithreaded.html @@ -0,0 +1,6 @@ +setup_multithreaded in iroh_test::logging - Rust

Function iroh_test::logging::setup_multithreaded

source ·
pub fn setup_multithreaded()
Expand description

The first call to this function will install a global logger.

+

The logger uses the RUST_LOG environment variable to decide on what level to log +anything, which is set by our CI. When running the tests with nextest the log +output will be captured for just the executing test.

+

Logs to stdout since the assertion messages are logged on stderr by default.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/logging/fn.testing_subscriber.html b/pr/2992/docs/iroh_test/logging/fn.testing_subscriber.html new file mode 100644 index 0000000000..c009ff9441 --- /dev/null +++ b/pr/2992/docs/iroh_test/logging/fn.testing_subscriber.html @@ -0,0 +1,17 @@ +testing_subscriber in iroh_test::logging - Rust

Function iroh_test::logging::testing_subscriber

source ·
pub fn testing_subscriber() -> impl Subscriber
Expand description

Returns the a [tracing::Subscriber] configured for our tests.

+

This subscriber will ensure that log output is captured by the test’s default output +capturing and thus is only shown with the test on failure. By default it uses +RUST_LOG=trace as configuration but you can specify the RUST_LOG environment +variable explicitly to override this.

+

To use this in a tokio multi-threaded runtime use:

+ +
use tracing_future::WithSubscriber;
+use iroh_test::logging::testing_subscriber;
+
+#[tokio::test(flavor = "multi_thread")]
+async fn test_something() -> Result<()> {
+   async move {
+       Ok(())
+   }.with_subscriber(testing_subscriber()).await
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/logging/index.html b/pr/2992/docs/iroh_test/logging/index.html new file mode 100644 index 0000000000..464aee55bc --- /dev/null +++ b/pr/2992/docs/iroh_test/logging/index.html @@ -0,0 +1,2 @@ +iroh_test::logging - Rust

Module iroh_test::logging

source ·
Expand description

Logging during tests.

+

Functions§

  • Configures logging for the current test, single-threaded runtime only.
  • The first call to this function will install a global logger.
  • Returns the a [tracing::Subscriber] configured for our tests.
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/logging/sidebar-items.js b/pr/2992/docs/iroh_test/logging/sidebar-items.js new file mode 100644 index 0000000000..63203f3437 --- /dev/null +++ b/pr/2992/docs/iroh_test/logging/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["setup","setup_multithreaded","testing_subscriber"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_test/macro.assert_eq_hex!.html b/pr/2992/docs/iroh_test/macro.assert_eq_hex!.html new file mode 100644 index 0000000000..5c32880d4b --- /dev/null +++ b/pr/2992/docs/iroh_test/macro.assert_eq_hex!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.assert_eq_hex.html...

+ + + \ No newline at end of file diff --git a/pr/2992/docs/iroh_test/macro.assert_eq_hex.html b/pr/2992/docs/iroh_test/macro.assert_eq_hex.html new file mode 100644 index 0000000000..5381c96e84 --- /dev/null +++ b/pr/2992/docs/iroh_test/macro.assert_eq_hex.html @@ -0,0 +1,8 @@ +assert_eq_hex in iroh_test - Rust

Macro iroh_test::assert_eq_hex

source ·
macro_rules! assert_eq_hex {
+    ($a:expr, $b:expr) => { ... };
+    ($a:expr, $b:expr, $hint:expr) => { ... };
+}
Expand description

This is a macro to assert that two byte slices are equal.

+

It is like assert_eq!, but it will print a nicely formatted hexdump of the +two slices if they are not equal. This makes it much easier to track down +a difference in a large byte slice.

+
\ No newline at end of file diff --git a/pr/2992/docs/iroh_test/sidebar-items.js b/pr/2992/docs/iroh_test/sidebar-items.js new file mode 100644 index 0000000000..6b47faef42 --- /dev/null +++ b/pr/2992/docs/iroh_test/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"macro":["assert_eq_hex"],"mod":["hexdump","logging"],"struct":["CallOnDrop"]}; \ No newline at end of file diff --git a/pr/2992/docs/iroh_test/struct.CallOnDrop.html b/pr/2992/docs/iroh_test/struct.CallOnDrop.html new file mode 100644 index 0000000000..39867a61d2 --- /dev/null +++ b/pr/2992/docs/iroh_test/struct.CallOnDrop.html @@ -0,0 +1,16 @@ +CallOnDrop in iroh_test - Rust

Struct iroh_test::CallOnDrop

source ·
pub struct CallOnDrop(/* private fields */);

Implementations§

source§

impl CallOnDrop

source

pub fn new(f: impl FnOnce() + 'static) -> Self

Trait Implementations§

source§

impl Drop for CallOnDrop

source§

fn drop(&mut self)

Executes the destructor for this type. 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
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> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

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.

+
source§

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

§

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>,

§

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<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
\ No newline at end of file diff --git a/pr/2992/docs/search-index.js b/pr/2992/docs/search-index.js new file mode 100644 index 0000000000..6a23415758 --- /dev/null +++ b/pr/2992/docs/search-index.js @@ -0,0 +1,13 @@ +var searchIndex = new Map(JSON.parse('[\ +["bulk",{"t":"HHHHH","n":["collect_and_print","main","run_iroh","run_quinn","run_s2n"],"q":[[0,"bulk"],[5,"core::option"],[6,"struct_iterable_internal"],[7,"iroh_net_bench"],[8,"anyhow"],[9,"iroh_net_bench::s2n"]],"i":[0,0,0,0,0],"f":"{{b{d{c}}}fh}{{}f}{j{{l{f}}}}0{n{{l{f}}}}","D":"`","p":[[1,"str"],[6,"Option",5],[1,"unit"],[10,"Iterable",6],[5,"Opt",7],[8,"Result",8],[5,"Opt",9]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAAUAAQAAAAUA"}],\ +["iroh",{"t":"FGPEPFIPPFEFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNCNNNNNNCNOCCNCNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNCNONNNNNNNNNNNNNNCNCNONNNNNCOENONNNNNOOCCCNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNSSSSSCCSSSHHHHSSHHHFNNNNNNNNNNNNNNNNNNNNNNNNFKFNNONNNNNNNCNNNNNNNNNNNNOCOCONNNNCNNNNNNNNNNNFSSNNNNNNNNNNNNNFSNNNNNNNNNNNNNNSSSSFFFNNNNNNNNNNNNNNNCNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTFNNNNNNNNNNNNNNNNNNNIKHMNMNMNMNMNMNMNMNMNMNCHPSGFPFNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNHNNNNNNNNNNNONONNNNNNHNNNNNNNNNNNNNTTFFFFFGPKPFPFFTTTPFPFPPFFFPGPPPPPFGFGKKFKPPPFFGFPPPSFFTTTPFKTTPPFFTPPTTPFTTPFPFFTFPPPPFGPGGFPPPPGFPPGFTTPGFFGPPGFPPTPPPFFPFPFPPFFPFGFFPPPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONONNNOOONMNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNOOONNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNONONNNONNNOONOOOONNNONNNNNNNNNNNHNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNHOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNHNNONNNNNNNNNNNONNNOMNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNOOONOOONNNNOOOHNNNONNNOOONNNNNNNNNNNOONNOOONONMNMNMNNNNNNNNNNNNNOOONNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOONNNNNNOONNNNNNNNNOONMNNONMNNNNNNOONNNNNNNNNNNNNNNNNNNNNONNNMNNONOONOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNOOGTFFPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTPPGISFFFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFFFFNNNNOOOOOOOOONNNNNNNNOONNNNNNNNOOONNNNOOOOOONNNNONNNNNNNNONNNNNNNNNNNNOOONNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNOOOOOOONNNNOKKFFFNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNNNNNFFNNNNHNNNNNNNNNNOONONHHHNNNNNNNNNFPGTPFPKPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNOPPGNNCNNNNNNNHHNNNNNNFFFFFNNNNNNNNNNNNNNNNNNNNNNNNNNHNNNNNNNNNNHNNNNNNNNNNNNNNNNNNNNNNNNNNNN","n":["AddrInfo","AddrInfoOptions","Addresses","Endpoint","Id","NodeAddr","NodeId","Relay","RelayAndAddresses","RelayMap","RelayMode","RelayNode","RelayUrl","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","apply_options","apply_options","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","cmp","compare","compare","compare","compare","contains_node","default","default","default_from_node","defaults","deref","deserialize","deserialize","deserialize","deserialize","deserialize","dialer","direct_addresses","direct_addresses","discovery","dns","empty","endpoint","eq","eq","eq","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from_nodes","from_parts","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_str","from_str","from_url","get_node","hash","hash","info","into","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","is_empty","is_empty","key","len","metrics","new","node_id","nodes","partial_cmp","partial_cmp","partial_cmp","partial_cmp","protocol","quic","relay","relay_url","relay_url","serialize","serialize","serialize","serialize","serialize","stun_only","stun_port","test_utils","ticket","tls","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","url","urls","vzip","vzip","vzip","vzip","vzip","vzip","with_direct_addresses","with_relay_url","DEFAULT_HTTPS_PORT","DEFAULT_HTTP_PORT","DEFAULT_METRICS_PORT","DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT","prod","staging","AP_RELAY_HOSTNAME","EU_RELAY_HOSTNAME","NA_RELAY_HOSTNAME","default_ap_relay_node","default_eu_relay_node","default_na_relay_node","default_relay_map","EU_RELAY_HOSTNAME","NA_RELAY_HOSTNAME","default_eu_relay_node","default_na_relay_node","default_relay_map","Dialer","abort_dial","borrow","borrow_mut","chain","endpoint","fmt","from","into","into_arc_any","into_stream","is_pending","merge","new","next_conn","pending_count","poll_next","queue_dial","ratelimit_stream","ratelimit_stream_with_jitter","try_from","try_into","type_id","vzip","zip","ConcurrentDiscovery","Discovery","DiscoveryItem","__clone_box","add","addr_info","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","default","dns","empty","fmt","fmt","from","from","from","from_ref","from_services","into","into","into_arc_any","into_arc_any","last_updated","local_swarm_discovery","node_id","pkarr","provenance","publish","publish","resolve","resolve","static_provider","subscribe","subscribe","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","vzip","vzip","DnsDiscovery","N0_DNS_NODE_ORIGIN_PROD","N0_DNS_NODE_ORIGIN_STAGING","borrow","borrow_mut","fmt","from","into","into_arc_any","n0_dns","new","resolve","try_from","try_into","type_id","vzip","LocalSwarmDiscovery","NAME","borrow","borrow_mut","fmt","from","into","into_arc_any","new","publish","resolve","subscribe","try_from","try_into","type_id","vzip","DEFAULT_PKARR_TTL","DEFAULT_REPUBLISH_INTERVAL","N0_DNS_PKARR_RELAY_PROD","N0_DNS_PKARR_RELAY_STAGING","PkarrPublisher","PkarrRelayClient","PkarrResolver","__clone_box","__clone_box","__clone_box","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","dht","drop","fmt","fmt","fmt","from","from","from","from_ref","from_ref","from_ref","into","into","into","into_arc_any","into_arc_any","into_arc_any","n0_dns","n0_dns","new","new","new","publish","publish","resolve","resolve","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","update_addr_info","vzip","vzip","vzip","with_options","Builder","DhtDiscovery","__clone_box","borrow","borrow","borrow_mut","borrow_mut","build","builder","client","clone","clone_into","default","default","dht","fmt","fmt","from","from","from_ref","include_direct_addresses","initial_publish_delay","into","into","into_arc_any","into_arc_any","n0_dns_pkarr_relay","pkarr_relay","publish","republish_delay","resolve","secret_key","to_owned","try_from","try_from","try_into","try_into","ttl","type_id","type_id","vzip","vzip","PROVENANCE","StaticProvider","add_node_addr","borrow","borrow_mut","default","fmt","from","from_node_addrs","get_node_addr","into","into_arc_any","new","publish","remove_node_addr","resolve","set_node_addr","try_from","try_into","type_id","vzip","DnsResolver","ResolverExt","default_resolver","lookup_by_id","lookup_by_id","lookup_by_id_staggered","lookup_by_id_staggered","lookup_by_name","lookup_by_name","lookup_by_name_staggered","lookup_by_name_staggered","lookup_ipv4","lookup_ipv4","lookup_ipv4_ipv6","lookup_ipv4_ipv6","lookup_ipv4_ipv6_staggered","lookup_ipv4_ipv6_staggered","lookup_ipv4_staggered","lookup_ipv4_staggered","lookup_ipv6","lookup_ipv6","lookup_ipv6_staggered","lookup_ipv6_staggered","node_info","resolver","Addr","IROH_TXT_NAME","IrohAttr","NodeInfo","Relay","TxtAttrs","__clone_box","as_ref","attrs","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","cmp","compare","direct_addresses","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from_hickory_records","from_hickory_records","from_parts","from_pkarr_signed_packet","from_pkarr_signed_packet","from_ref","from_str","from_strings","from_z32","hash","into","into","into","into_arc_any","into_arc_any","into_arc_any","lookup_by_id","lookup_by_name","new","node_id","node_id","partial_cmp","relay_url","to_hickory_records","to_hickory_records","to_owned","to_pkarr_signed_packet","to_pkarr_signed_packet","to_string","to_z32","try_from","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","AEAD_LIMIT_REACHED","APPLICATION_ERROR","Accept","AcceptBi","AcceptUni","AckFrequencyConfig","AddrInfo","AddrInfoOptions","Addresses","AeadKey","App","ApplicationClose","ApplicationClosed","Builder","Bytes","CONNECTION_ID_LIMIT_ERROR","CONNECTION_REFUSED","CRYPTO_BUFFER_EXCEEDED","CallMeMaybe","Chunk","CidsExhausted","ClosedStream","ClosedStream","ClosedStream","Connecting","Connection","ConnectionClose","ConnectionClosed","ConnectionError","ConnectionLost","ConnectionLost","ConnectionLost","ConnectionLost","ConnectionLost","ConnectionStats","ConnectionType","ConnectionTypeStream","ControlMsg","Controller","ControllerFactory","CryptoError","CryptoServerConfig","Custom","Default","Direct","DirectAddr","DirectAddrInfo","DirectAddrType","DirectAddrsStream","Disabled","Disabled","Discovery","ENV_FORCE_STAGING_RELAYS","Endpoint","ExportKeyingMaterialError","FINAL_SIZE_ERROR","FLOW_CONTROL_ERROR","FRAME_ENCODING_ERROR","FinishedEarly","FrameStats","HandshakeTokenKey","INTERNAL_ERROR","INVALID_TOKEN","Id","IllegalOrderedRead","Incoming","IncomingFuture","KEY_UPDATE_ERROR","Local","LocallyClosed","MAX","MAX_SIZE","Mixed","MtuDiscoveryConfig","NO_ERROR","NO_VIABLE_PATH","NamedApp","NodeAddr","None","OpenBi","OpenUni","PROTOCOL_VIOLATION","PathStats","Ping","Pong","Portmapped","Read","ReadDatagram","ReadError","ReadError","ReadExactError","ReadToEndError","RecvStream","Relay","Relay","Relay","RelayAndAddresses","RelayMode","RemoteInfo","Reset","Reset","ResetError","RetryError","STREAM_LIMIT_ERROR","STREAM_STATE_ERROR","Saved","SendDatagramError","SendStream","ServerConfig","Source","Staging","Stopped","StoppedError","StreamId","Stun","Stun4LocalPort","TRANSPORT_PARAMETER_ERROR","TimedOut","TooLarge","TooLong","TransportConfig","TransportError","TransportError","TransportErrorCode","Udp","UdpStats","Unknown","UnsupportedByPeer","UnsupportedVersion","VarInt","VersionMismatch","WeakConnectionHandle","WriteError","Written","ZeroRttAccepted","ZeroRttRejected","ZeroRttRejected","ZeroRttRejected","ZeroRttRejected","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","__clone_box","accept","accept","accept_bi","accept_uni","accept_with","ack_eliciting_threshold","ack_frequency","ack_frequency_config","acks","add_discovery","add_node_addr","add_node_addr_with_source","addr","addr","addrs","advance","aead_from_hkdf","allow_spin","alpn","alpns","as_ref","bind","bind_addr_v4","bind_addr_v6","black_hole_cooldown","black_holes_detected","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","bound_sockets","build","builder","bytes","bytes","bytes","call","chain","chain","chunk","chunks","clear","clear_discovery","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_box","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","close","close","close_reason","closed","cmp","cmp","cmp","cmp","cmp","code","compare","compare","compare","compare","compare","congestion_controller_factory","congestion_events","congestion_state","conn_type","conn_type_stream","connect","connect_by_node_id","connection_close","copy_from_slice","copy_to_bytes","crypto","crypto","crypto","crypto_buffer_size","current_mtu","cwnd","data_blocked","datagram","datagram_receive_buffer_size","datagram_send_buffer_size","datagram_send_buffer_space","datagrams","default","default","default","default","default","default","default","default","default","default","default","default_relay_mode","deref","deserialize","deserialize","deserialize","deserialize","deserialize","dir","direct_addresses","direct_addresses","discovery","discovery","discovery_dht","discovery_local_network","discovery_n0","dns_resolver","dns_resolver","drop","drop","drop","enable_segmentation_offload","encode_hex","encode_hex_upper","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","error_code","error_code","export_keying_material","finish","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","force_staging_infra","frame","frame_rx","frame_tx","frame_type","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_iter","from_owner","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_ref","from_request","from_static","from_u32","from_u64","from_u64_unchecked","get_remote_node_id","handshake_data","handshake_data","handshake_done","has_send_address","hash","hash","hash","hash","hash","hash","home_relay","id","id","ignore","immediate_ack","incoming_buffer_size","incoming_buffer_size_total","index","info","initial_keys","initial_mtu","initial_rtt","initial_window","initiator","insecure_skip_relay_cert_verify","interval","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into_0rtt","into_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_future","into_future","into_future","into_future","into_future","into_future","into_future","into_future","into_future","into_future","into_incoming","into_inner","into_iter","into_iter","into_make_service","into_make_service_with_connect_info","into_response","into_service","into_stream","into_stream","ios","is_0rtt","is_alive","is_closed","is_empty","is_unique","join","join","join","join","join","join","join","join","join","keep_alive_interval","keylog","known_nodes","last_alive","last_control","last_payload","last_received","last_used","latency","latency","len","local_ip","local_ip","local_ip","lost_bytes","lost_packets","lost_plpmtud_probes","make_server_config","max_ack_delay","max_concurrent_bidi_streams","max_concurrent_uni_streams","max_data","max_datagram_size","max_idle_timeout","max_incoming","max_stream_data","max_streams_bidi","max_streams_uni","merge","merge","migration","min_mtu","minimum_change","mtu_discovery_config","network_change","network_path_changed","new","new","new","new_connection_id","new_token","node_addr","node_id","node_id","node_id","observed_addr","observed_external_addr","offset","on_ack","on_congestion_event","on_end_acks","on_mtu_update","on_sent","open","open_bi","open_uni","packet_threshold","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","path","path_challenge","path_response","peer_identity","persistent_congestion_threshold","ping","poll","poll","poll","poll","poll","poll","poll","poll","poll","poll_flush","poll_next","poll_next","poll_read","poll_read","poll_shutdown","poll_write","poll_write","preferred_address_v4","preferred_address_v6","priority","proxy_from_env","proxy_url","race","race","race","race","race","race","race","race","race","ratelimit_stream","ratelimit_stream","ratelimit_stream_with_jitter","ratelimit_stream_with_jitter","read","read_chunk","read_chunks","read_datagram","read_exact","read_to_end","reason","reason","reason","receive_observed_address_reports","receive_window","received_reset","refuse","relay_map","relay_mode","relay_url","relay_url","remaining","remote_address","remote_address","remote_address","remote_address_validated","remote_info","remote_info_iter","reordering_threshold","reset","reset_stream","retire_connection_id","retry","retry_tag","retry_token_lifetime","rtt","rtt","saturating_add","seal","secret_key","secret_key","send_datagram","send_datagram_wait","send_observed_address_reports","send_window","sent_packets","sent_plpmtud_probes","serialize","serialize","serialize","serialize","serialize","set_alpns","set_max_concurrent_bi_streams","set_max_concurrent_uni_streams","set_priority","set_receive_window","slice","slice_ref","source","source","source","source","source","source","source","source","sources","sources","split_off","split_to","stable_id","start_session","stats","stop","stop_sending","stopped","stream","stream_data_blocked","stream_receive_window","streams_blocked_bidi","streams_blocked_uni","time_threshold","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","token_key","transport","transport_config","transport_config","truncate","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into_mut","try_poll","try_poll","try_poll","try_poll","try_poll","try_poll","try_poll","typ","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","udp_rx","udp_tx","upper_bound","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","watch_home_relay","weak_handle","window","with_crypto","with_single_cert","write","write_all","write_all_chunks","write_chunk","write_chunks","zip","zip","name","name","BlobFormat","EMPTY","Hash","HashAndFormat","HashSeq","Raw","__clone_box","__clone_box","__clone_box","as_bytes","as_bytes","as_bytes","as_ref","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","cmp","cmp","cmp","compare","compare","compare","compare","default","deserialize","deserialize","deserialize","encode_hex","encode_hex_upper","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fixed_width","fixed_width","fmt","fmt","fmt","fmt","fmt","fmt","fmt_short","format","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_ref","from_ref","from_ref","from_str","from_str","hash","hash","hash","hash","hash_seq","into","into","into","into_arc_any","into_arc_any","into_arc_any","is_hash_seq","is_raw","new","new","partial_cmp","partial_cmp","partial_cmp","raw","serialize","serialize","serialize","to_hex","to_owned","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","type_name","type_name","vzip","vzip","vzip","BYTE_SIZE","Base32","Key","KeyParsingError","NodeId","PUBLIC_KEY_LENGTH","PublicKey","SecretKey","SharedSecret","Signature","__clone_box","__clone_box","__clone_box","as_bytes","as_ref","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","cmp","compare","deserialize","deserialize","deserialize","encode_hex","encode_hex_upper","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt_short","from","from","from","from","from","from","from","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_components","from_ref","from_ref","from_ref","from_slice","from_str","from_str","from_str","generate","generate_with_rng","hash","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","open","partial_cmp","public","r_bytes","s_bytes","seal","serialize","serialize","serialize","shared","sign","source","to_bytes","to_bytes","to_bytes","to_openssh","to_owned","to_owned","to_owned","to_string","to_string","to_string","to_string","to_vec","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from_openssh","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","verify","vzip","vzip","vzip","vzip","vzip","MagicsockMetrics","NetReportMetrics","PortmapMetrics","RelayMetrics","__clone_box","__clone_box","__clone_box","__clone_box","accepts","actor_link_change","actor_tick_direct_addr_heartbeat","actor_tick_direct_addr_update_receiver","actor_tick_main","actor_tick_msg","actor_tick_other","actor_tick_portmap_changed","actor_tick_re_stun","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","bytes_recv","bytes_sent","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","connection_became_direct","connection_handshake_success","conns_rx_ratelimited_total","default","default","default","default","derp_accepts","disco_packets_dropped","disco_packets_recv","disco_packets_sent","disconnects","external_address_updated","fmt","fmt","fmt","fmt","frames_rx_ratelimited_total","from","from","from","from","from_ref","from_ref","from_ref","from_ref","got_ping","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","iter","iter","iter","iter","local_port_updates","mapping_attempts","mapping_failures","name","name","name","name","nodes_contacted","nodes_contacted_directly","num_direct_conns_added","num_direct_conns_removed","num_relay_conns_added","num_relay_conns_removed","other_packets_dropped","other_packets_recv","other_packets_sent","pcp_available","pcp_probes","probes_started","re_stun_calls","recv_data_ipv4","recv_data_ipv6","recv_data_relay","recv_datagrams","recv_disco_bad_key","recv_disco_bad_parse","recv_disco_call_me_maybe","recv_disco_call_me_maybe_bad_disco","recv_disco_ping","recv_disco_pong","recv_disco_relay","recv_disco_udp","recv_gro_datagrams","relay_home_change","reports","reports_full","send_data","send_data_network_down","send_disco_relay","send_disco_udp","send_ipv4","send_ipv6","send_packets_dropped","send_packets_recv","send_packets_sent","send_relay","send_relay_error","sent_disco_call_me_maybe","sent_disco_ping","sent_disco_pong","sent_disco_relay","sent_disco_udp","sent_pong","stun_packets_dropped","stun_packets_recv_ipv4","stun_packets_recv_ipv6","stun_packets_sent_ipv4","stun_packets_sent_ipv6","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","unique_client_keys","unknown_frames","update_direct_addrs","upnp_available","upnp_gateway_updated","upnp_probes","upnp_probes_failed","vzip","vzip","vzip","vzip","websocket_accepts","IntoArcAny","ProtocolHandler","ProtocolMap","Router","RouterBuilder","__clone_box","__clone_box","accept","accept","alpns","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","builder","clone","clone","clone_into","clone_into","default","endpoint","endpoint","fmt","fmt","fmt","from","from","from","from_ref","from_ref","get","get_protocol","get_protocol","get_typed","insert","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","is_shutdown","new","shutdown","shutdown","shutdown","spawn","to_owned","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","CleanupDropGuard","DnsPkarrServer","borrow","borrow","borrow_mut","borrow_mut","create_dns_resolver","discovery","dns_resolver","fmt","fmt","from","from","into","into","into_arc_any","into_arc_any","nameserver","node_origin","on_node","pkarr_url","run","run_relay_server","run_relay_server_with","run_relay_server_with_stun","run_with_origin","try_from","try_from","try_into","try_into","type_id","type_id","vzip","vzip","BlobTicket","Encoding","Error","KIND","Kind","NodeTicket","Postcard","Ticket","Verify","__clone_box","__clone_box","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","deserialize","deserialize","deserialize","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","fmt","format","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_ref","from_ref","from_str","from_str","hash","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_parts","new","new","node_addr","node_addr","recursive","serialize","serialize","serialize","source","to_bytes","to_bytes","to_bytes","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","expected","CertError","ConfigError","CreateConfigError","borrow","borrow_mut","certificate","fmt","fmt","from","from","from","into","into_arc_any","make_client_config","make_server_config","source","to_string","try_from","try_into","type_id","vzip","GenError","P2pCertificate","P2pExtension","ParseError","VerificationError","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","generate","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","parse","peer_id","source","source","source","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","verify_signature","vzip","vzip","vzip","vzip","vzip"],"q":[[0,"iroh"],[210,"iroh::defaults"],[217,"iroh::defaults::prod"],[224,"iroh::defaults::staging"],[229,"iroh::dialer"],[254,"iroh::discovery"],[301,"iroh::discovery::dns"],[317,"iroh::discovery::local_swarm_discovery"],[333,"iroh::discovery::pkarr"],[398,"iroh::discovery::pkarr::dht"],[440,"iroh::discovery::static_provider"],[461,"iroh::dns"],[486,"iroh::dns::node_info"],[567,"iroh::endpoint"],[2031,"iroh::endpoint::Source"],[2033,"iroh::hash"],[2152,"iroh::key"],[2299,"iroh::metrics"],[2459,"iroh::protocol"],[2523,"iroh::test_utils"],[2557,"iroh::ticket"],[2646,"iroh::ticket::Error"],[2647,"iroh::tls"],[2668,"iroh::tls::certificate"],[2739,"dyn_clone::sealed"],[2740,"iroh_base::node_addr"],[2741,"iroh_base::relay_map"],[2742,"iroh_base::relay_url"],[2743,"core::cmp"],[2744,"core::result"],[2745,"serde::de"],[2746,"core::net::socket_addr"],[2747,"core::iter::traits::iterator"],[2748,"core::fmt"],[2749,"iroh_base::ticket::node"],[2750,"iroh_base::key"],[2751,"iroh::magicsock::node_map::node_state"],[2752,"core::option"],[2753,"url"],[2754,"anyhow"],[2755,"alloc::sync"],[2756,"core::convert"],[2757,"core::iter::traits::collect"],[2758,"core::hash"],[2759,"core::any"],[2760,"serde::ser"],[2761,"alloc::string"],[2762,"futures_concurrency::stream::chain::tuple"],[2763,"futures_concurrency::stream::into_stream"],[2764,"futures_core::stream"],[2765,"futures_concurrency::stream::merge::tuple"],[2766,"iroh_quinn::connection"],[2767,"core::pin"],[2768,"core::task::wake"],[2769,"core::task::poll"],[2770,"governor::state::direct"],[2771,"governor::state"],[2772,"governor::state::direct::streams"],[2773,"governor::clock::with_std"],[2774,"governor::middleware"],[2775,"governor::jitter"],[2776,"futures_concurrency::stream::zip::tuple"],[2777,"alloc::boxed"],[2778,"alloc::vec"],[2779,"futures_lite::stream"],[2780,"pkarr::signed_packet"],[2781,"core::time"],[2782,"pkarr::client"],[2783,"core::future::future"],[2784,"core::net::ip_addr"],[2785,"hickory_proto::rr::domain::name"],[2786,"core::clone"],[2787,"hickory_resolver::async_resolver"],[2788,"alloc::collections::btree::map"],[2789,"core::str::traits"],[2790,"hickory_proto::rr::resource"],[2791,"alloc::collections::btree::set"],[2792,"iroh_quinn_proto::connection"],[2793,"iroh_quinn_proto::config"],[2794,"iroh_quinn_proto::varint"],[2795,"core::ops::function"],[2796,"core::marker"],[2797,"bytes::bytes"],[2798,"iroh_quinn_proto::crypto"],[2799,"iroh_quinn_proto::congestion"],[2800,"std::time"],[2801,"axum_core::body"],[2802,"http::request"],[2803,"iroh_quinn::recv_stream"],[2804,"iroh_quinn::send_stream"],[2805,"iroh_quinn_proto::connection::stats"],[2806,"iroh_quinn_proto::connection::streams::send"],[2807,"iroh_quinn_proto::connection::streams"],[2808,"iroh::magicsock::node_map"],[2809,"iroh_quinn_proto::frame"],[2810,"iroh_quinn_proto"],[2811,"iroh::magicsock"],[2812,"bytes::bytes_mut"],[2813,"iroh_quinn_proto::connection::assembler"],[2814,"iroh_quinn::incoming"],[2815,"http::header::name"],[2816,"hyper::ext::h1_reason_phrase"],[2817,"http::byte_str"],[2818,"iroh_quinn_proto::connection::streams::recv"],[2819,"ring::error"],[2820,"iroh_quinn_proto::transport_parameters"],[2821,"iroh_quinn_proto::shared"],[2822,"axum::handler::service"],[2823,"axum::routing::into_make_service"],[2824,"axum::extract::connect_info"],[2825,"http::response"],[2826,"futures_concurrency::future::join::tuple"],[2827,"core::future::into_future"],[2828,"tokio::sync::watch"],[2829,"iroh_quinn_proto::connection::paths"],[2830,"std::io::error"],[2831,"tokio::io::read_buf"],[2832,"futures_concurrency::future::race::tuple"],[2833,"core::ops::range"],[2834,"core::error"],[2835,"rustls_pki_types"],[2836,"rustls::error"],[2837,"iroh_base::hash"],[2838,"iroh_blake3"],[2839,"redb::types"],[2840,"ed25519"],[2841,"iroh_base::key::encryption"],[2842,"ed25519_dalek::signature"],[2843,"ed25519_dalek::verifying"],[2844,"signature::error"],[2845,"iroh_base::base32"],[2846,"ed25519_dalek::signing"],[2847,"rand_core"],[2848,"aead"],[2849,"zeroize"],[2850,"ssh_key::error"],[2851,"ssh_key::signature"],[2852,"alloc::vec::into_iter"],[2853,"futures_lite::future"],[2854,"iroh::test_utils::dns_and_pkarr_servers"],[2855,"iroh_relay::server"],[2856,"iroh_base::ticket::blob"],[2857,"iroh_base::ticket"],[2858,"postcard::error"],[2859,"data_encoding"],[2860,"iroh_quinn_proto::crypto::rustls"],[2861,"rcgen::error"],[2862,"webpki::error"],[2863,"rustls::enums"],[2864,"iroh_base"],[2865,"ed25519_dalek::constants"],[2866,"iroh::test_utils::dns_server"]],"i":[0,0,4,0,4,0,0,4,4,0,0,0,0,3,5,4,6,7,8,3,5,3,5,4,6,7,8,3,5,4,6,7,8,3,5,4,6,7,8,3,5,4,6,7,8,3,5,7,8,3,5,7,8,6,5,4,6,0,8,3,5,4,7,8,0,3,5,0,0,6,0,3,5,4,6,7,8,3,3,3,5,5,5,4,4,4,6,6,6,7,7,7,8,8,8,3,5,4,4,6,6,7,7,8,8,3,3,3,3,3,3,5,5,4,6,7,8,8,6,3,3,5,4,6,7,8,4,8,6,6,0,8,3,3,5,4,6,7,8,3,5,4,6,7,8,5,6,0,6,0,3,3,6,3,5,7,8,0,7,0,3,5,3,5,4,7,8,7,7,0,0,0,3,5,4,6,7,8,4,6,7,8,3,5,4,6,7,8,3,5,4,6,7,8,3,5,4,6,7,8,7,6,3,5,4,6,7,8,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,0,0,0,62,60,62,62,60,62,60,62,62,60,0,60,62,60,62,60,60,62,60,62,60,62,60,62,0,62,0,62,61,60,61,60,0,61,60,62,62,60,62,60,62,60,62,60,0,0,0,66,66,66,66,66,66,66,66,66,66,66,66,66,0,0,67,67,67,67,67,67,67,67,67,67,67,67,67,67,0,0,0,0,0,0,0,68,69,70,68,69,70,68,69,70,68,69,70,68,69,70,0,68,68,69,70,68,69,70,68,69,70,68,69,70,68,69,70,68,69,68,69,70,68,70,69,70,68,69,70,68,69,70,68,69,70,68,69,70,68,68,69,70,68,0,0,77,77,76,77,76,76,77,76,77,77,77,76,76,77,76,77,76,77,76,76,77,76,77,76,76,76,77,76,77,76,77,77,76,77,76,76,77,76,77,76,79,0,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,0,0,0,81,80,81,80,81,80,81,80,81,80,81,80,81,80,81,80,81,80,81,80,0,0,89,0,0,0,89,0,20,89,90,89,20,90,89,20,90,20,20,89,89,20,89,20,89,89,89,20,20,20,89,89,20,90,89,20,20,20,90,90,20,90,90,20,90,20,89,90,0,89,89,20,90,89,20,90,90,90,20,90,20,89,20,20,90,20,20,90,89,0,89,89,20,90,89,20,90,89,20,90,89,20,90,145,145,0,0,0,0,0,0,4,0,141,0,102,0,0,145,145,145,138,0,102,0,126,129,0,0,0,102,0,124,126,127,129,130,0,0,0,0,0,0,0,0,136,136,140,0,0,0,0,124,136,141,0,0,0,145,145,145,128,0,0,145,145,4,126,0,0,145,148,102,107,107,140,0,145,145,141,0,140,0,0,145,0,138,138,148,125,0,0,128,0,0,0,4,140,141,4,0,0,126,102,0,0,145,145,141,0,0,0,0,136,129,0,0,148,148,145,102,124,125,0,0,102,0,141,0,148,124,0,0,102,0,0,0,0,126,127,129,130,113,46,124,125,126,127,128,129,130,107,43,131,132,133,134,135,136,137,138,139,22,140,102,106,118,105,141,142,143,144,145,146,147,148,43,100,46,46,100,106,132,108,132,109,43,43,139,147,22,113,114,108,101,109,113,109,109,109,118,133,181,113,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,43,119,43,158,131,135,113,149,151,113,135,113,109,113,46,124,125,126,127,128,129,130,107,43,131,132,133,134,135,136,137,138,139,22,140,102,106,118,105,141,142,143,144,145,146,147,148,121,113,46,124,125,126,127,128,129,130,107,43,131,132,133,134,135,136,137,138,139,22,140,102,106,118,105,141,142,143,144,145,146,147,148,46,43,46,46,113,107,146,147,148,144,113,107,146,147,148,108,133,46,22,43,43,43,132,113,113,145,132,105,108,133,133,132,132,108,108,46,131,113,108,107,109,131,132,133,134,135,106,118,0,113,138,139,22,140,141,146,43,5,109,43,109,109,109,109,43,113,152,153,108,113,113,113,113,113,113,113,113,113,124,125,126,127,128,129,130,107,158,135,136,137,138,139,22,140,102,159,141,142,143,144,145,146,147,148,113,113,113,124,124,124,125,125,125,126,126,126,127,127,127,128,128,128,129,129,129,130,130,130,107,107,107,158,158,158,135,135,135,136,136,136,137,137,137,138,138,138,139,139,139,22,22,22,140,140,140,102,102,102,159,159,159,141,141,141,142,142,142,143,143,143,144,144,144,145,145,145,146,146,146,147,147,147,148,148,148,142,143,46,153,113,113,113,46,160,124,124,161,161,152,125,125,126,126,127,127,128,128,153,129,129,130,130,108,107,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,137,138,138,139,22,140,140,102,102,106,118,105,159,163,164,141,141,142,142,143,143,149,144,144,145,145,146,146,151,147,148,148,0,144,134,134,142,181,113,113,113,113,113,113,113,113,113,113,113,113,46,193,192,104,103,194,160,124,124,161,152,125,125,126,126,126,126,127,127,128,128,153,129,129,129,129,130,130,108,107,107,107,107,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,102,102,106,118,105,159,163,163,164,141,142,142,143,149,144,144,144,144,145,146,146,151,147,148,113,113,113,46,124,125,126,127,128,129,130,107,43,131,132,133,134,135,136,137,138,139,22,140,102,106,118,105,141,142,143,144,145,146,147,148,113,113,107,107,107,0,46,101,132,22,113,107,141,146,147,148,43,152,153,100,132,105,105,146,3,177,108,108,121,146,109,118,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,101,121,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,181,193,192,104,103,194,99,100,162,101,161,107,113,113,113,113,113,113,149,151,131,152,160,43,113,113,181,193,192,104,103,194,99,162,101,108,109,109,139,139,139,22,22,139,22,113,46,100,101,133,133,133,0,106,108,108,132,46,108,105,132,132,132,149,151,105,108,118,108,43,160,113,105,146,132,132,43,43,3,22,132,46,158,121,121,121,121,121,115,46,46,108,113,113,113,113,113,113,107,146,147,148,134,132,132,46,108,132,181,193,192,104,103,194,99,162,101,153,149,151,152,152,153,153,153,105,105,153,109,109,181,193,192,104,103,194,99,162,101,149,151,149,151,152,152,152,46,152,152,142,143,144,108,108,152,100,136,109,5,22,113,46,100,101,100,43,43,106,153,132,132,100,177,105,46,133,107,115,109,43,46,46,108,108,133,133,138,139,22,140,141,43,46,46,153,46,113,113,124,125,126,127,128,129,130,102,22,139,113,113,46,177,46,152,132,153,132,132,108,132,132,108,113,46,124,125,126,127,128,129,130,107,43,131,132,133,134,135,136,137,138,139,22,140,102,106,118,105,141,142,143,144,145,146,147,148,124,161,125,126,127,128,129,130,107,137,138,140,102,141,142,143,144,145,146,148,105,105,109,105,113,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,107,107,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,113,193,192,104,103,194,162,101,147,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,134,134,118,181,113,46,193,192,104,103,194,160,124,161,152,125,126,127,128,153,129,130,108,107,158,109,43,131,132,133,134,135,99,100,162,101,136,137,138,139,22,140,102,106,118,105,159,163,164,141,142,143,149,144,145,146,151,147,148,43,46,121,105,105,153,153,153,153,153,149,151,260,261,0,210,0,0,211,211,210,211,212,210,210,212,210,210,210,210,211,212,210,211,212,210,211,212,210,211,212,210,211,212,210,210,211,212,211,210,211,212,210,210,210,211,212,210,210,210,211,211,211,212,212,212,210,212,210,210,211,211,212,212,210,212,210,210,210,210,211,212,210,210,212,210,211,212,210,212,210,211,212,212,212,210,211,212,210,211,212,211,211,210,212,210,211,212,212,210,211,212,210,210,211,212,210,211,212,210,211,212,210,211,212,210,211,212,210,212,210,211,212,215,217,217,0,0,0,0,0,0,0,215,21,71,21,21,215,216,21,217,71,215,216,21,217,71,215,21,71,215,21,71,21,21,215,21,71,21,21,215,21,215,215,215,21,21,21,215,215,215,215,216,21,21,217,217,71,71,21,215,215,215,215,216,21,21,217,217,217,71,71,71,215,21,71,215,215,21,71,215,215,21,71,71,71,21,215,216,21,217,71,215,216,21,217,71,216,21,71,215,215,216,215,21,71,71,71,217,215,215,71,71,215,21,71,215,21,217,71,215,215,215,215,215,216,21,21,21,217,71,71,71,215,216,21,217,71,215,216,21,217,71,21,215,216,21,217,71,0,0,0,0,228,229,230,231,230,231,231,231,231,231,231,231,231,228,229,230,231,228,229,230,231,230,230,228,229,230,231,228,229,230,231,231,231,230,228,229,230,231,230,230,230,230,230,228,228,229,230,231,230,228,229,230,231,228,229,230,231,230,228,229,230,231,228,229,230,231,228,229,230,231,228,228,228,228,229,230,231,231,231,231,231,231,231,230,230,230,228,228,228,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,229,229,231,231,231,231,231,231,230,230,230,231,231,231,231,231,231,231,230,229,229,229,229,229,228,229,230,231,228,229,230,231,228,229,230,231,228,229,230,231,230,230,231,228,228,228,228,228,229,230,231,230,0,0,0,0,0,237,236,233,235,236,237,235,236,237,235,236,237,237,236,237,236,236,237,235,237,235,236,237,235,236,237,236,236,237,235,236,236,237,235,236,238,237,235,236,237,235,233,237,236,235,237,236,237,235,236,237,235,236,237,235,236,237,235,236,0,0,240,239,240,239,0,239,239,240,239,240,239,240,239,240,239,239,239,239,239,239,0,0,0,239,240,239,240,239,240,239,240,239,0,245,0,244,245,0,245,0,245,243,19,243,19,245,243,19,245,243,19,243,19,244,243,19,243,19,243,243,243,19,19,19,243,243,19,19,245,245,243,243,19,19,245,245,245,244,243,19,243,19,243,19,243,243,19,245,243,19,245,243,243,19,243,19,243,244,243,19,245,244,243,19,243,19,243,19,245,243,19,245,243,19,245,243,19,245,243,19,245,262,248,248,0,248,248,0,248,248,248,248,248,248,248,0,0,248,248,248,248,248,248,0,0,0,0,0,253,254,249,255,256,253,254,249,255,256,253,254,249,249,255,255,256,256,253,254,249,249,255,255,256,256,0,253,254,249,255,256,253,254,249,255,256,0,253,249,255,256,249,255,256,253,254,249,255,256,253,254,249,255,256,253,254,249,255,256,253,253,254,249,255,256],"f":"`````````````{{cb}d{}}00000{{fh}d}{{jh}d}{ce{}{}}00000000000{ff}{jj}{hh}{ll}{nn}{A`A`}{{ce}d{}{}}00000{{ff}Ab}{{jj}Ab}{{nn}Ab}{{A`A`}Ab}{{ce}Ab{}{}}000{{lA`}Ad}{{}j}{{}h}{{A`Af}l}`{A`}{c{{Ah{f}}}Aj}{c{{Ah{j}}}Aj}{c{{Ah{h}}}Aj}{c{{Ah{n}}}Aj}{c{{Ah{A`}}}Aj}`{f{{`{{B`{}{{Al{An}}}}}}}}```{{}l}`{{ff}Ad}{{jj}Ad}{{hh}Ad}{{ll}Ad}{{nn}Ad}{{A`A`}Ad}{{ce}Ad{}{}}00000000000000000{{fBb}{{Ah{dBd}}}}{{jBb}{{Ah{dBd}}}}{{hBb}{{Ah{dBd}}}}0{{lBb}{{Ah{dBd}}}}0{{nBb}{{Ah{dBd}}}}0{{A`Bb}{{Ah{dBd}}}}0{Bff}{Bhf}{cc{}}{Bjf}{Blf}{{{Cb{Bj{Bn{A`}}{C`{An}}}}}f}{Bhj}44444{CdA`}{e{{Ah{lCf}}}{{Cj{{Ch{n}}}}}{{Cl{}{{Al{c}}}}}}{{Bj{Bn{A`}}c}f{{Cl{}{{Al{An}}}}}}777777{Cn{{Ah{h}}}}{Cn{{Ah{A`}}}}{A`l}{{lA`}{{Bn{{Ch{n}}}}}}`{{A`c}dD`}`{ce{}{}}00000{{{Ch{c}}}{{Ch{Db}}}{}}00000{jAd}{lAd}`{lDd}`{Bjf}`{l{{`{{B`{}{{Al{{Ch{n}}}}}}}}}}{{ff}{{Bn{Ab}}}}{{jj}{{Bn{Ab}}}}{{nn}{{Bn{Ab}}}}{{A`A`}{{Bn{Ab}}}}```{f{{Bn{A`}}}}`{{fc}AhDf}{{jc}AhDf}{{hc}AhDf}{{nc}AhDf}{{A`c}AhDf}`````{ce{}{}}00000{cDh{}}000{c{{Ah{e}}}{}{}}00000000000{cDj{}}00000`{l{{`{{B`{}{{Al{A`}}}}}}}}444444{{fc}f{{Cl{}{{Al{An}}}}}}{{fA`}f}``````````{{}n}00{{}l}``110`{{DlDn}d}99{{cg}{{E`{i}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}{DlEf}{{DlBb}Eh}{cc{}}={{{Ch{c}}}{{Ch{Db}}}{}}>{{DlDn}Ad}{{cg}{{Ej{ei}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}{EfDl}{Dl{{Cb{Dn{En{El}}}}}}{DlDd}{{{F`{Dl}}Fb}{{Fd{{Bn{c}}}}}{}}{{DlDn{C`{Ff}}}d}{{c{Fj{Fhegi}}}{{Fl{kegi}}}{}FnG`Gb{}}{{c{Fj{Fhegi}}Gd}{{Fl{kegi}}}{}FnG`Gb{}}{c{{Ah{e}}}{}{}}0{cDj{}}{ce{}{}}{{cg}{{Gf{i}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}```{{cb}d{}}{{Ghc}dGj}`3333{GlGl}{{ce}d{}{}}{{}Gh}`0{{GlBb}Eh}{{GhBb}Eh}{cc{}}{cGh{{Cl{}{{Al{{Gn{Gj}}}}}}}}11{{{H`{{Gn{Gj}}}}}Gh};;{{{Ch{c}}}{{Ch{Db}}}{}}0`````{{Gjj}d}{{Ghj}d}{{GjEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}{{GhEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}`{Gj{{Bn{{Hb{Gl}}}}}}{Gh{{Bn{{Hb{Gl}}}}}}{ce{}{}}{c{{Ah{e}}}{}{}}000{cDj{}}022```22{{HdBb}Eh}=3:{{}Hd}{DhHd}{{HdEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}5546``66{{HfBb}Eh}{cc{}}8?{Dn{{En{Hf}}}}{{Hfj}d}{{HfEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}{Hf{{Bn{{Hb{Gl}}}}}};;:<```````{{cb}d{}}00======{HhHh}{HjHj}{HlHl}{{ce}d{}{}}00`{Hhd}{{HhBb}Eh}{{HjBb}Eh}{{HlBb}Eh}======{ce{}{}}00{{{Ch{c}}}{{Ch{Db}}}{}}00{HnHh}{{}Hj}{{HnCd}Hh}{CdHj}{CdHl}{{Hhj}d}{{HlI`}{{En{d}}}}{{HjEfDn}{{Bn{{Ib{{En{Gl}}}}}}}}{{HlDn}{{En{I`}}}}:::{c{{Ah{e}}}{}{}}00000{cDj{}}005<<<{{HnCdIdIf}Hh}``{{cb}d{}}>>>>{Ih{{En{Ij}}}}{{}Ih}{{IhIl}Ih}{IjIj}{{ce}d{}{}}{{}Ij}4{{IhAd}Ih}{{IjBb}Eh}{{IhBb}Eh}{cc{}}003{{IhIf}Ih}{ce{}{}}0{{{Ch{c}}}{{Ch{Db}}}{}}0{IhIh}{{IhCd}Ih}{{Ijj}d}5{{IjEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}{{IhHn}Ih}6{c{{Ah{e}}}{}{}}000{{IhId}Ih}{cDj{}}099``{{Inc}d{{Cj{f}}}}::{{}In}{{InBb}Eh}>{eIn{{Cj{f}}}{{Cl{}{{Al{c}}}}}}{{InDn}{{Bn{f}}}}>=3{{Inj}d}1{{InEfDn}{{Bn{{Hb{{En{Gl}}}}}}}}{{Inc}{{Bn{f}}}{{Cj{f}}}}::8{ce{}{}}``{{}J`}{{JbDnCn}{{`{{Jf{}{{Jd{{En{f}}}}}}}}}}{{J`DnCn}{{En{f}}}}{{JbDnCn{C`{Jh}}}{{`{{Jf{}{{Jd{{En{f}}}}}}}}}}{{J`DnCn{C`{Jh}}}{{En{f}}}}{{JbCn}{{`{{Jf{}{{Jd{{En{f}}}}}}}}}}{{J`Cn}{{En{f}}}}{{JbCn{C`{Jh}}}{{`{{Jf{}{{Jd{{En{f}}}}}}}}}}{{J`Cn{C`{Jh}}}{{En{f}}}}{{JbcIf}{{`{{Jf{}{{Jd{{En{{`{{B`{}{{Al{Jj}}}}}}}}}}}}}}}Jl}{{J`cIf}{{En{{`{{B`{}{{Al{Jj}}}}}}}}}Jl}{{JbcIf}{{`{{Jf{}{{Jd{{En{{`{{B`{}{{Al{Jj}}}}}}}}}}}}}}}{JlJn}}{{J`cIf}{{En{{`{{B`{}{{Al{Jj}}}}}}}}}{JlJn}}{{JbcIf{C`{Jh}}}{{`{{Jf{}{{Jd{{En{{`{{B`{}{{Al{Jj}}}}}}}}}}}}}}}{JlJn}}{{J`cIf{C`{Jh}}}{{En{{`{{B`{}{{Al{Jj}}}}}}}}}{JlJn}}105410`{{}K`}``````{{cb}d{}}{KbCn}{{{Kd{c}}}{{Kf{c{H`{Dh}}}}}{KhKjKlKn}}{ce{}{}}00000{BhBh}{{ce}d{}{}}{{KbKb}Ab}{{ce}Ab{}{}}`{{KbKb}Ad}{{BhBh}Ad}{{ce}Ad{}{}}00000{{KbBb}Eh}{{KbBb}{{Ah{dBd}}}}{{BhBb}Eh}{{{Kd{c}}Bb}EhL`}{cc{}}{{{Kd{Kb}}}Bh}01{Bh{{Kd{Kb}}}}2{{{C`{Lb}}}{{En{Bh}}}}{{{C`{Lb}}}{{En{{Kd{c}}}}}{KhKjKlKn}}{{Dne}{{Kd{c}}}{KhKjKlKn}{{B`{}{{Al{{Cb{cDh}}}}}}}}{I`{{En{Bh}}}}{I`{{En{{Kd{c}}}}}{KhKjKlKn}}7{Cn{{Ah{Kbc}}}{}}{{Dnc}{{En{{Kd{e}}}}}{{B`{}{{Al{Dh}}}}}{KhKjKlKn}}{Cn{{En{Dn}}}}{{Kbc}dD`}{ce{}{}}00{{{Ch{c}}}{{Ch{Db}}}{}}00{{K`DnCn}{{En{{Kd{c}}}}}{KhKjKlKn}}{{K`Cn}{{En{{Kd{c}}}}}{KhKjKlKn}}{{Dn{Bn{Cd}}{Ld{An}}}Bh}{{{Kd{c}}}Dn{KhKjKlKn}}`{{KbKb}{{Bn{Ab}}}}`{{BhCnId}{{En{{`{{B`{}{{Al{Lb}}}}}}}}}}{{{Kd{c}}CnId}{{En{{`{{B`{}{{Al{Lb}}}}}}}}}{KhKjKlKn}}8{{BhHnId}{{En{I`}}}}{{{Kd{c}}HnId}{{En{I`}}}{KhKjKlKn}}{cDh{}}{DnDh}{Cn{{Ah{Kbc}}}{}}{c{{Ah{e}}}{}{}}00000{cDj{}}00???```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````{{cb}d{}}000000000000000000000000000000000{EfLf}{Lh{{En{LjLl}}}}{ElLn}{ElM`}{{Lh{Ch{Mb}}}{{En{LjLl}}}}{{MdMf}Md}`{{Mh{Bn{Md}}}Mh}`{{Mje}MjGj{{Ml{Hn}{{Jd{{Bn{c}}}}}}MnN`}}{{Eff}{{En{d}}}}{{EffCn}{{En{d}}}}```{{NbDd}d}{{Nd{C`{Ff}}}{{Gn{Nf}}}}{{MhAd}Mh}{Lj{{En{{H`{Ff}}}}}}{{Mj{H`{{H`{Ff}}}}}Mj}{Nb{{C`{Ff}}}}{Mj{{En{Ef}}}}{{MjNh}Mj}{{MjNj}Mj}{{NlIf}Nl}`{ce{}{}}0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000{Ef{{Cb{An{Bn{An}}}}}}{{{Ch{Nn}}O`Af}{{Gn{Ob}}}}{{}Mj}```{{c{Of{Od}}e}{}{}{}}{{cg}{{E`{i}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}0:`{Nbd}{MjMj}{NbNb}{ElEl}{OhOh}{OjOj}{OlOl}{OnOn}{A@`A@`}{A@bA@b}{A@dA@d}{MfMf}{EfEf}{A@fA@f}{A@hA@h}{A@jA@j}{A@lA@l}{A@nA@n}{AA`AA`}{AAbAAb}{AAdAAd}{AAfAAf}{BlBl}{AAhAAh}{LlLl}{MdMd}{NlNl}{MbMb}{AAjAAj}{AAlAAl}{AAnAAn}{AB`AB`}{ABbABb}{ABdABd}{ABfABf}{ABhABh}{Ob{{Gn{Ob}}}}{{ce}d{}{}}000000000000000000000000000000000{{ElMf{C`{Ff}}}d}{Ef{{En{d}}}}{El{{Bn{Ll}}}}{ElLl}{{NbNb}Ab}{{MfMf}Ab}{{ABdABd}Ab}{{ABfABf}Ab}{{ABhABh}Ab}`{{ce}Ab{}{}}0000{{Mh{Ch{Nn}}}Mh}`{El{{Gn{Ob}}}}`{{EfDn}{{En{ABj}}}}{{Efc{C`{Ff}}}{{En{El}}}{{Cj{f}}}}{{EfDn{C`{Ff}}}{{En{El}}}}`{{{C`{Ff}}}Nb}{{NbDd}Nb}{FfABb}``{{MhDd}Mh}````{{Mh{Bn{Dd}}}Mh}1{ElDd}`{{}Nb}{{}Mh}{{}Mf}{{}Mj}{{}A@f}{{}A@h}{{}A@j}{{}A@l}{{}A@n}{{}Md}{{}Nl}{{}AA`}{Nb{{C`{Ff}}}}{c{{Ah{AAd}}}Aj}{c{{Ah{AAf}}}Aj}{c{{Ah{Bl}}}Aj}{c{{Ah{AAh}}}Aj}{c{{Ah{AAj}}}Aj}{ABdABl}{EfABn}`{{Mj{Gn{Gj}}}Mj}{Ef{{Bn{Gj}}}}{MjMj}00{{MjJ`}Mj}{EfJ`}{Nbd}{AC`d}{ACbd}{{MhAd}Mh}{ce{}{{ACf{ACd}}}}0{{Nb{H`{Ff}}}Ad}{{Nbc}AdACh}{{NbCn}Ad}{{NbDh}Ad}{{Nb{C`{Ff}}}Ad}{{NbACj}Ad}{{NbNb}Ad}{{OhOh}Ad}{{OjOj}Ad}{{OlOl}Ad}{{OnOn}Ad}{{A@`A@`}Ad}{{A@bA@b}Ad}{{A@dA@d}Ad}{{MfMf}Ad}{{AClACl}Ad}{{A@nA@n}Ad}{{AA`AA`}Ad}{{AAbAAb}Ad}{{AAdAAd}Ad}{{AAfAAf}Ad}{{BlBl}Ad}{{AAhAAh}Ad}{{LlLl}Ad}{{ACnACn}Ad}{{AAjAAj}Ad}{{AAlAAl}Ad}{{AAnAAn}Ad}{{AB`AB`}Ad}{{ABbABb}Ad}{{ABdABd}Ad}{{ABfABf}Ad}{{ABhABh}Ad}{{ce}Ad{}{}}00000000000000000000000000000000000000000000000000000000000000000000000000000000``{{El{C`{Ff}}{C`{Ff}}{C`{Ff}}}{{Ah{dACn}}}}{ACb{{Ah{dAAb}}}}{{NbBb}{{Ah{dBd}}}}00{{ElBb}{{Ah{dBd}}}}{{AD`Bb}{{Ah{dBd}}}}{{OhBb}{{Ah{dBd}}}}0{{ADbBb}{{Ah{dBd}}}}0{{AC`Bb}{{Ah{dBd}}}}{{OjBb}{{Ah{dBd}}}}0{{OlBb}{{Ah{dBd}}}}0{{OnBb}{{Ah{dBd}}}}0{{A@`Bb}{{Ah{dBd}}}}0{{ACbBb}{{Ah{dBd}}}}{{A@bBb}{{Ah{dBd}}}}0{{A@dBb}{{Ah{dBd}}}}0{{MhBb}{{Ah{dBd}}}}{{MfBb}{{Ah{dBd}}}}0{{AClBb}{{Ah{dBd}}}}{{MjBb}Eh}{{EfBb}Eh}{{A@fBb}{{Ah{dBd}}}}{{A@hBb}{{Ah{dBd}}}}{{A@jBb}{{Ah{dBd}}}}{{A@lBb}{{Ah{dBd}}}}{{A@nBb}{{Ah{dBd}}}}{{LfBb}Eh}{{LhBb}Eh}{{ADdBb}Eh}{{LjBb}Eh}{{AA`Bb}Eh}{{AAbBb}{{Ah{dBd}}}}0{{AAdBb}Eh}0{{AAfBb}Eh}{{BlBb}Eh}{{AAhBb}Eh}0{{LlBb}{{Ah{dBd}}}}0{{MdBb}{{Ah{dBd}}}}{{NlBb}{{Ah{dBd}}}}{{MbBb}{{Ah{dBd}}}}{{ACnBb}{{Ah{dBd}}}}{{ADfBb}{{Ah{dBd}}}}{{ADhBb}{{Ah{dBd}}}}{{AAjBb}Eh}{{AAjBb}{{Ah{dBd}}}}{{AAlBb}{{Ah{dBd}}}}0{{AAnBb}{{Ah{dBd}}}}0{{ABjBb}Eh}{{AB`Bb}{{Ah{dBd}}}}0{{ABbBb}{{Ah{dBd}}}}0{{ABdBb}{{Ah{dBd}}}}0{{ABnBb}Eh}{{ABfBb}Eh}{{ABhBb}Eh}0{{}Ad}````{cc{}}{CnNb}1{ADjNb}{ADlNb}{ADnNb}{ACjNb}{{{Gn{{C`{Ff}}}}}Nb}{DhNb}{{{H`{Ff}}}Nb}{AE`Nb}{{{C`{Ff}}}Nb}{AEbNb};;;;;;;{LlOh}<<<{OlOj}={AEdOl}{LlOl}?{OnOl}{LlOn}{cc{}}0{OlA@`}1{LlA@b}2{AAbA@b}{A@dA@b}{LlA@d}55{FfMf}{IdMf}{ABdMf}8{AfMf}9999999999999999999{AB`Ll}{AEfLl};;;;{AEhADf}<<<{AB`AAl}==={ABbAB`}{AEjAB`}?{AElAB`}{cc{}}0{MfABd}111{cNb{{Cl{}{{Al{Ff}}}}}}{cNb{{AEn{{C`{Ff}}}}Mn}}3333333333333333333333333333333333{{{Of{Od}}c}{{F`{{Gn{Jf}}}}}{MnN`}}{{{C`{Ff}}}Nb}?{Jh{{Ah{MfAF`}}}}{JhMf}{El{{En{Bj}}}}{El{{Bn{{Gn{Db}}}}}}{Lj{{En{{Gn{Db}}Ll}}}}`{BlAd}{{Nbc}dD`}{{Mfc}dD`}{{AAjc}dD`}{{ABdc}dD`}{{ABfc}dD`}{{ABhc}dD`}{Ef{{Bn{A`}}}}{AC`ABd}{ACbABd}{Lhd}`{{MbJh}Mb}0{ABdJh}`{{AFbIdAFd}{{Ah{AFfADh}}}}{{MhAf}Mh}{{MhIf}Mh}{ObJh}{ABdAFh}{{MjAd}Mj}{{NlIf}Nl}{ce{}{}}0000000000000000000000000000000000000000000000000000000{Lj{{En{{Cb{ElAFj}}Lj}}}}{{{Gn{Ob}}}{{Gn{Db}}}}{{{Ch{c}}}{{Ch{Db}}}{}}0000000000000000000000000000000000000000000000000000000{c{}{}}000000{Lhc{}}11{ADbAFl}{MfJh}{Nb}0{c{{AG`{{AFn{egd}}}}}{}{}{}}{c{{AGb{{AFn{egd}}i}}}{}{}{}{}}{Nb{{AGd{Od}}}}{c{{AFn{egd}}}{}{}{}}<<`{AC`Ad}{AD`Ad}{EfAd}{NbAd}0{{ce}{{AGf{g}}}{}AGhJf}00000000{{Mh{Bn{If}}}Mh}{{MjAd}Mj}{{Mj{H`{f}}}Mj}```{Bl{{Bn{If}}}}```{NbDd}{El{{Bn{Jj}}}}{Lh{{Bn{Jj}}}}{Lj{{Bn{Jj}}}}```{{Hn{H`{{H`{Ff}}}}{Ch{Mh}}Ad}{{En{Mb}}}}{{Md{Bn{If}}}Md}{{MhMf}Mh}0`{El{{Bn{Dd}}}}{{Mh{Bn{AGj}}}Mh}{{MbDd}Mb}```{{cg}{{Ej{ei}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}0{{MbAd}Mb}{{MhAf}Mh}{{NlAf}Nl}{{Mh{Bn{Nl}}}Mh}{Efd}{AD`Ad}{{}Nb}{{{Ch{AFb}}{Ch{Nd}}}Mb}{{AFhABlJh}ABd}``{Ef{{En{f}}}}{EfDn}```{El{{AGl{{Bn{An}}}}}}`{{ObO`O`JhAdAGn}d}{{ObO`O`AdJh}d}{{ObO`JhAd{Bn{Jh}}}d}{{ObAf}d}{{ObO`JhJh}d}{{Nf{C`{Ff}}{C`{Ff}}}{{Ah{{C`{Ff}}ADf}}}}{ElAH`}{ElAHb}{{MhId}Mh}{{NbDh}{{Bn{Ab}}}}{{Nbc}{{Bn{Ab}}}ACh}{{Nb{H`{Ff}}}{{Bn{Ab}}}}{{NbNb}{{Bn{Ab}}}}{{NbCn}{{Bn{Ab}}}}{{Nb{C`{Ff}}}{{Bn{Ab}}}}{{MfMf}{{Bn{Ab}}}}{{ABdABd}{{Bn{Ab}}}}{{ABfABf}{{Bn{Ab}}}}{{ABhABh}{{Bn{Ab}}}}```{El{{Bn{{Gn{Db}}}}}};`{{{F`{AFj}}Fb}Fd}{{{F`{AHb}}Fb}Fd}{{{F`{AH`}}Fb}Fd}{{{F`{M`}}Fb}Fd}{{{F`{Ln}}Fb}Fd}{{{F`{AHd}}Fb}Fd}{{{F`{Lf}}Fb}{{Fd{c}}}{}}{{{F`{ADd}}Fb}{{Fd{c}}}{}}{{{F`{Lj}}Fb}{{Fd{c}}}{}}{{{F`{ACb}}Fb}{{Fd{{Ah{dAHf}}}}}}{{{F`{ABj}}Fb}{{Fd{{Bn{c}}}}}{}}{{{F`{ABn}}Fb}{{Fd{{Bn{c}}}}}{}}{{AC`Fb{C`{Ff}}}{{Fd{{Ah{DdOl}}}}}}{{{F`{AC`}}FbAHh}{{Fd{{Ah{dAHf}}}}}}4{{{F`{ACb}}Fb{C`{Ff}}}{{Fd{{Ah{DdA@b}}}}}}{{{F`{ACb}}Fb{C`{Ff}}}{{Fd{{Ah{DdAHf}}}}}}{{Mb{Bn{Nh}}}Mb}{{Mb{Bn{Nj}}}Mb}{ACb{{Ah{AHjAAb}}}}{MjMj}{{MjCd}Mj}{{cg}{{AHl{ei}}}{}{}{{AGh{}{{Jd{e}}}}}{{Jf{}{{Jd{e}}}}}}00000000{{c{Fj{Fhegi}}}{{Fl{kegi}}}{}FnG`Gb{}}0{{c{Fj{Fhegi}}Gd}{{Fl{kegi}}}{}FnG`Gb{}}0{{AC`{C`{Ff}}}{{Ah{{Bn{Dd}}Ol}}}}{{AC`DdAd}{{Ah{{Bn{ACl}}Ol}}}}{{AC`{C`{Nb}}}{{Ah{{Bn{Dd}}Ol}}}}{ElAHd}{{AC`{C`{Ff}}}{{Ah{dA@`}}}}{{AC`Dd}{{Ah{{H`{Ff}}Oj}}}}```{{MhAd}Mh}{{MhMf}Mh}{AC`{{Ah{{Bn{Mf}}On}}}}{Lhd}{AA`l}{{MjAA`}Mj}``{NbDd}{ElAn}{LhAn}{LjAn}{LhAd}{{EfDn}{{Bn{Bl}}}}{Ef{{`{{B`{}{{Al{Bl}}}}}}}}{{MdMf}Md}{{ACbMf}{{Ah{dAAb}}}}``{Lh{{En{dADb}}}}{{AFbIdAFd{C`{Ff}}}{{AHn{Ff}}}}{{MbIf}Mb}{ElIf}`{{Mfc}Mf{{Cj{Mf}}}}{{Nf{H`{Ff}}{C`{Ff}}}{{Ah{dADf}}}}{{MjHn}Mj}{EfHn}{{ElNb}{{Ah{dOh}}}}{{ElNb}AI`}{{MhAd}Mh}{{MhJh}Mh}``{{AAdc}AhDf}{{AAfc}AhDf}{{Blc}AhDf}{{AAhc}AhDf}{{AAjc}AhDf}{{Ef{H`{{H`{Ff}}}}}{{En{d}}}}{{ElMf}d}0{{ACbAHj}{{Ah{dAAb}}}}1{{Nbc}Nb{{AIb{Dd}}}}{{Nb{C`{Ff}}}Nb}{Oh{{Bn{AId}}}}{Oj{{Bn{AId}}}}{Ol{{Bn{AId}}}}{On{{Bn{AId}}}}{A@`{{Bn{AId}}}}{A@b{{Bn{AId}}}}{A@d{{Bn{AId}}}}{Ll{{Bn{AId}}}}{Bl{{H`{{Cb{AAjIf}}}}}}`{{NbDd}Nb}0{ElDd}{{{Ch{AFb}}IdAIf}{{Gn{AIh}}}}{ElA@l}{{AC`Mf}{{Ah{dAAb}}}}`{ACb{{Ah{{Bn{Mf}}A@d}}}}``{{MhMf}Mh}``{{MhAIj}Mh}{ce{}{}}000000000000000000000000000000000{cDh{}}0000000000000000000{{Mb{Ch{Nd}}}Mb}`{{MjMh}Mj}{{Mb{Ch{Mh}}}Mb}{{NbDd}d}{c{{Ah{e}}}{}{}}0000000000000000000{Jh{{Ah{MfAF`}}}}1{AIl{{Ah{MfAF`}}}}{Dd{{Ah{MfAF`}}}}3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333{Nb{{Ah{ACjNb}}}}{{{F`{c}}Fb}Fd{}}000000`{cDj{}}0000000000000000000000000000000000000000000000000000000``{{NlAf}Nl}========================================================{Ef{{`{{Ed{}{{Al{A`}}}}}}}}{ElAD`}{ObJh}{{{Ch{AFb}}}Mb}{{{H`{AIn}}AJ`}{{Ah{MbAJb}}}}{{ACb{C`{Ff}}}{{Ah{DdA@b}}}}{{ACb{C`{Ff}}}{{Ah{dA@b}}}}{{ACb{C`{Nb}}}{{Ah{dA@b}}}}{{ACbNb}{{Ah{dA@b}}}}{{ACb{C`{Nb}}}{{Ah{A@nA@b}}}}{{cg}{{Gf{i}}}{}{}{{Eb{}{{Al{e}}}}}{{Ed{}{{Al{e}}}}}}0````````{{cb}d{}}00{AJd{{AHn{Ff}}}}{{}}0{AJd{{C`{Ff}}}}02{ce{}{}}00000{AJdAJd}{AJfAJf}{AJhAJh}{{ce}d{}{}}00{{AJdAJd}Ab}{{AJfAJf}Ab}{{AJhAJh}Ab}{{ce}Ab{}{}}{{{C`{Ff}}{C`{Ff}}}Ab}11{{}AJf}{c{{Ah{AJd}}}Aj}{c{{Ah{AJf}}}Aj}{c{{Ah{AJh}}}Aj}{ce{}{{ACf{ACd}}}}0{{AJdAJd}Ad}{{AJfAJf}Ad}{{AJhAJh}Ad}{{ce}Ad{}{}}00000000{{}{{Bn{Dd}}}}0{{AJdBb}{{Ah{dBd}}}}0{{AJfBb}{{Ah{dBd}}}}0{{AJhBb}{{Ah{dBd}}}}0{AJdDh}`{cc{}}{{{AHn{Ff}}}AJd}0{AJjAJd}221{{{C`{Ff}}}}0333{Cn{{Ah{AJd}}}}{Cn{{Ah{AJh}}}}{{AJdc}dD`}{{AJfc}dD`}{{AJhc}dD`}`{AJdAJh}{ce{}{}}00{{{Ch{c}}}{{Ch{Db}}}{}}00{AJfAd}0{cAJd{{AEn{{C`{Ff}}}}}}{{AJdAJf}AJh}{{AJdAJd}{{Bn{Ab}}}}{{AJfAJf}{{Bn{Ab}}}}{{AJhAJh}{{Bn{Ab}}}}8{{AJdc}AhDf}{{AJfc}AhDf}{{AJhc}AhDf}{AJdDh};;;{cDh{}}00{c{{Ah{e}}}{}{}}00000{cDj{}}00{{}AJl}0???``````````{{cb}d{}}00{Bj{{AHn{Ff}}}}{Bj{{C`{Ff}}}}{ce{}{}}000000000{AJnAJn}{BjBj}{HnHn}{{ce}d{}{}}00{{BjBj}Ab}{{ce}Ab{}{}}{c{{Ah{AJn}}}Aj}{c{{Ah{Bj}}}Aj}{c{{Ah{Hn}}}Aj}{ce{}{{ACf{ACd}}}}0{{AJnAJn}Ad}{{BjBj}Ad}{{ce}Ad{}{}}00000{{AJnBb}{{Ah{dBd}}}}000{{AK`Bb}{{Ah{dBd}}}}{{BjBb}{{Ah{dBd}}}}0{{AKbBb}{{Ah{dBd}}}}0{{HnBb}{{Ah{dBd}}}}0{BjDh}{AKdAJn}{cc{}}{{{AHn{Ff}}}AJn}011{AKfBj}{AKhAKb}3{AKjAKb}4{AKlHn}{{{AHn{Ff}}}Hn}5{{{AHn{Ff}}}{{Ah{BjAKh}}}}1{{{AHn{Ff}}{AHn{Ff}}}AJn}888{{{C`{Ff}}}{{Ah{AJnAKh}}}}{Cn{{Ah{AJnAKh}}}}{Cn{{Ah{Bj}}}}{Cn{{Ah{Hn}}}}{{}Hn}{cHn{AKnACh}}{{Bjc}dD`}{ce{}{}}0000{{{Ch{c}}}{{Ch{Db}}}{}}0000{{AK`AL`}{{Ah{dCf}}}}{{BjBj}{{Bn{Ab}}}}{HnBj}{AJn{{AHn{Ff}}}}0{{AK`AL`}d}{{AJnc}AhDf}{{Bjc}AhDf}{{Hnc}AhDf}{{HnBj}AK`}{{Hn{C`{Ff}}}AJn}{AKb{{Bn{AId}}}}77{Hn{{AHn{Ff}}}}{Hn{{Ah{{ALb{Dh}}ALd}}}}>>>{cDh{}}000{AJn{{H`{Ff}}}}{c{{Ah{e}}}{}{}}{{{C`{Ff}}}{{Ah{AJnAKh}}}}{ALf{{Ah{AJnALd}}}}022{{{AHn{Ff}}}{{Ah{Bj}}}}{{{C`{Ff}}}{{Ah{Bj}}}}44{{{C`{Ff}}}{{Ah{Hn}}}}{c{{Ah{HnCf}}}{{AEn{{C`{Ff}}}}}}66666{cDj{}}0000{{Bj{C`{Ff}}AJn}{{Ah{dAKh}}}}{ce{}{}}0000````{{cb}d{}}000`````````11111111``{ALhALh}{ALjALj}{ALlALl}{ALnALn}{{ce}d{}{}}000```{{}ALh}{{}ALj}{{}ALl}{{}ALn}``````{{ALhBb}{{Ah{dBd}}}}{{ALjBb}{{Ah{dBd}}}}{{ALlBb}{{Ah{dBd}}}}{{ALnBb}Eh}`{cc{}}0000000`????{{{Ch{c}}}{{Ch{Db}}}{}}000{ALh{{AM`{{Cb{CnDb}}}}}}{ALj{{AM`{{Cb{CnDb}}}}}}{ALl{{AM`{{Cb{CnDb}}}}}}{ALn{{AM`{{Cb{CnDb}}}}}}```{{}Cn}000```````````````````````````````````````````````````{ce{}{}}000{c{{Ah{e}}}{}{}}0000000{cDj{}}000```````2222``````{{cb}d{}}0{{{Ch{AMb}}Lj}{{AMd{{En{d}}}}}}{{AMfc{Ch{AMb}}}AMf{{AEn{{C`{Ff}}}}}}{AMh{{`{{B`{}{{Al{{H`{Ff}}}}}}}}}}666666{EfAMf}{AMjAMj}{AMhAMh}{{ce}d{}{}}0{{}AMh}{AMjEf}{AMfEf}{{AMjBb}Eh}{{AMfBb}Eh}{{AMhBb}Eh}{cc{}}0000{{AMh{C`{Ff}}}{{Bn{{Ch{AMb}}}}}}{{AMj{C`{Ff}}}{{Bn{{Ch{c}}}}}AMb}{{AMf{C`{Ff}}}{{Bn{{Ch{c}}}}}AMb}{{AMh{C`{Ff}}}{{Bn{{Ch{c}}}}}AMb}{{AMh{H`{Ff}}{Ch{AMb}}}d}{ce{}{}}00{{{Ch{AMl}}}{{Ch{Db}}}}{{{Ch{c}}}{{Ch{Db}}}{}}00{AMjAd}{EfAMf}{{{Ch{AMb}}}{{AMd{d}}}}{AMj{{En{d}}}}{AMhd}{AMf{{En{AMj}}}}88{c{{Ah{e}}}{}{}}00000{cDj{}}00:::``::::{An{{En{K`}}}}{{AMnHn}{{Gn{Gh}}}}{AMnJ`}{{AN`Bb}Eh}{{AMnBb}Eh}{cc{}}0{ce{}{}}0??``{{AMnDnIf}{{En{d}}}}`{{}{{En{AMn}}}}{{}{{En{{Cb{lA`ANb}}}}}}{{{Bn{ANd}}Ad}{{En{{Cb{lA`ANb}}}}}}1{Dh{{En{AMn}}}}====<<55`````````{{cb}d{}}0666666{ANfANf}{BfBf}{{ce}d{}{}}0{Cn{{Ah{ANhANj}}}}{c{{Ah{ANf}}}Aj}{c{{Ah{Bf}}}Aj}{{ANfANf}Ad}{{BfBf}Ad}{{ce}Ad{}{}}00000{{ANfBb}{{Ah{dBd}}}}0{{BfBb}{{Ah{dBd}}}}0{{ANjBb}{{Ah{dBd}}}}0{ANfAJf}{cc{}}0{fBf}{ANlANj}2{ANnANj}{{{C`{Ff}}}{{Ah{ANhANj}}}}{{{C`{Ff}}}{{Ah{ANfANj}}}}{{{C`{Ff}}}{{Ah{BfANj}}}}66{Cn{{Ah{ANf}}}}{Cn{{Ah{Bf}}}}{ANfAJd}{ce{}{}}00{{{Ch{c}}}{{Ch{Db}}}{}}00{ANf{{Cb{fAJdAJf}}}}{{fAJdAJf}{{Ah{ANfCf}}}}<{ANff}{Bff}{ANfAd}{ANhDh}{{ANfc}AhDf}{{Bfc}AhDf}{ANj{{Bn{AId}}}}{ANh{{H`{Ff}}}}{ANf{{H`{Ff}}}}{Bf{{H`{Ff}}}}=={cDh{}}00{c{{Ah{e}}}{}{}}00000{cDj{}}00{ce{}{}}00````00`{{AO`Bb}Eh}0{AObAO`}{AOdAO`}{cc{}}4{{{Ch{c}}}{{Ch{Db}}}{}}{{Hn{Bn{Bj}}{H`{{H`{Ff}}}}Ad}{{Ah{AOfAO`}}}}{{Hn{H`{{H`{Ff}}}}Ad}{{Ah{AOhAO`}}}}{AO`{{Bn{AId}}}};::98`````8888888888{{AOjBb}Eh}{{AOlBb}Eh}{{AObBb}Eh}0{{AOnBb}Eh}0{{B@`Bb}Eh}099{B@bAOb}:{B@dAOn};{B@dB@`}<{Hn{{Ah{{Cb{AInAJ`}}AOb}}}}{ce{}{}}0000====={AIn{{Ah{AOjAOn}}}}{AOjBj}{AOb{{Bn{AId}}}}{AOn{{Bn{AId}}}}{B@`{{Bn{AId}}}}{cDh{}}00{c{{Ah{e}}}{}{}}000000000{cDj{}}0000{{AOjB@f{C`{Ff}}{C`{Ff}}}{{Ah{dB@`}}}}99999","D":"GEl","p":[[5,"Private",2739],[1,"unit"],[5,"NodeAddr",0,2740],[6,"AddrInfoOptions",0,2740],[5,"AddrInfo",0,2740],[5,"RelayMap",0,2741],[5,"RelayNode",0,2741],[5,"RelayUrl",0,2742],[6,"Ordering",2743],[1,"bool"],[1,"u16"],[6,"Result",2744],[10,"Deserializer",2745],[17,"Item"],[6,"SocketAddr",2746],[10,"Iterator",2747],[5,"Formatter",2748],[5,"Error",2748],[5,"NodeTicket",2557,2749],[5,"NodeInfo",486],[5,"PublicKey",2152,2750],[5,"RemoteInfo",567,2751],[6,"Option",2752],[1,"slice"],[1,"tuple"],[5,"Url",2753],[5,"Error",2754],[5,"Arc",2755],[10,"Into",2756],[10,"IntoIterator",2757],[1,"str"],[10,"Hasher",2758],[10,"Any",2759],[1,"usize"],[10,"Serializer",2760],[5,"String",2761],[5,"TypeId",2759],[5,"Dialer",229],[8,"NodeId",0,2750],[5,"Chain2",2762],[10,"IntoStream",2763],[10,"Stream",2764],[5,"Endpoint",567],[8,"Result",2748],[5,"Merge2",2765],[5,"Connection",567,2766],[8,"Result",2754],[5,"Pin",2767],[5,"Context",2768],[6,"Poll",2769],[1,"u8"],[6,"NotKeyed",2770],[5,"RateLimiter",2771],[5,"RatelimitedStream",2772],[10,"DirectStateStore",2770],[10,"ReasonablyRealtime",2773],[10,"RateLimitingMiddleware",2774],[5,"Jitter",2775],[5,"Zip2",2776],[5,"ConcurrentDiscovery",254],[10,"Discovery",254],[5,"DiscoveryItem",254],[5,"Box",2777],[5,"Vec",2778],[8,"Boxed",2779],[5,"DnsDiscovery",301],[5,"LocalSwarmDiscovery",317],[5,"PkarrPublisher",333],[5,"PkarrResolver",333],[5,"PkarrRelayClient",333],[5,"SecretKey",2152,2750],[5,"SignedPacket",2780],[8,"BoxStream",2764],[1,"u32"],[5,"Duration",2781],[5,"Builder",398],[5,"DhtDiscovery",398],[5,"PkarrClient",2782],[5,"StaticProvider",440],[8,"DnsResolver",461],[10,"ResolverExt",461],[17,"Output"],[10,"Future",2783],[1,"u64"],[6,"IpAddr",2784],[10,"IntoName",2785],[10,"Clone",2786],[8,"TokioAsyncResolver",2787],[6,"IrohAttr",486],[5,"TxtAttrs",486],[5,"BTreeMap",2788],[10,"FromStr",2789],[10,"Display",2748],[10,"Hash",2758],[10,"Ord",2743],[10,"Debug",2748],[5,"Record",2790],[5,"BTreeSet",2791],[5,"Accept",567],[5,"Incoming",567],[5,"Connecting",567],[6,"ConnectionError",567,2792],[5,"AcceptBi",567,2766],[5,"AcceptUni",567,2766],[5,"ServerConfig",567,2793],[5,"AckFrequencyConfig",567,2793],[5,"VarInt",567,2794],[5,"TransportConfig",567,2793],[5,"Builder",567],[10,"FnOnce",2795],[10,"Send",2796],[10,"Sync",2796],[5,"Bytes",567,2797],[10,"HandshakeTokenKey",567,2798],[10,"AeadKey",567,2798],[5,"SocketAddrV4",2746],[5,"SocketAddrV6",2746],[5,"MtuDiscoveryConfig",567,2793],[10,"ControllerFactory",567,2799],[5,"Instant",2800],[10,"Controller",567,2799],[5,"Body",2801],[5,"Request",2802],[6,"SendDatagramError",567,2766],[6,"ReadToEndError",567,2803],[6,"ReadError",567,2803],[6,"ResetError",567,2803],[6,"ReadExactError",567,2803],[6,"WriteError",567,2804],[6,"StoppedError",567,2804],[5,"UdpStats",567,2805],[5,"FrameStats",567,2805],[5,"PathStats",567,2805],[5,"ConnectionStats",567,2805],[5,"Written",567,2806],[6,"RelayMode",567],[5,"ClosedStream",567,2807],[6,"ControlMsg",567,2751],[5,"DirectAddrInfo",567,2751],[6,"ConnectionType",567,2751],[6,"Source",567,2808],[5,"ConnectionClose",567,2809],[5,"ApplicationClose",567,2809],[5,"TransportError",567],[5,"TransportErrorCode",567],[5,"StreamId",567,2810],[5,"DirectAddr",567,2811],[6,"DirectAddrType",567,2811],[5,"ConnectionTypeStream",567,2808],[6,"Dir",2810],[5,"DirectAddrsStream",567,2811],[5,"RecvStream",567,2803],[5,"SendStream",567,2804],[1,"char"],[10,"FromIterator",2757],[10,"Sized",2796],[5,"BytesMut",2812],[5,"Chunk",567,2813],[5,"ExportKeyingMaterialError",567,2798],[5,"WeakConnectionHandle",567,2766],[5,"RetryError",567,2814],[5,"IncomingFuture",567],[5,"CryptoError",567,2798],[5,"UnsupportedVersion",567,2798],[5,"Custom",2815],[5,"ReasonPhrase",2816],[5,"ByteStr",2817],[5,"Custom",2815],[5,"ByteStr",2817],[6,"ReadableError",2818],[6,"Close",2809],[5,"Unspecified",2819],[6,"Error",2820],[5,"InvalidFrame",2809],[10,"AsRef",2756],[5,"VarIntBoundsExceeded",2794],[10,"CryptoServerConfig",567],[5,"ConnectionId",2821],[5,"Keys",2798],[6,"Side",2810],[5,"ZeroRttAccepted",567,2766],[5,"Incoming",2814],[5,"HandlerService",2822],[5,"IntoMakeService",2823],[5,"IntoMakeServiceWithConnectInfo",2824],[5,"Response",2825],[5,"Join2",2826],[10,"IntoFuture",2827],[5,"IdleTimeout",2793],[5,"Receiver",2828],[5,"RttEstimator",2829],[5,"OpenBi",567,2766],[5,"OpenUni",567,2766],[5,"ReadDatagram",567,2766],[5,"Error",2830],[5,"ReadBuf",2831],[1,"i32"],[5,"Race2",2832],[1,"array"],[5,"SendDatagram",2766],[10,"RangeBounds",2833],[10,"Error",2834],[5,"TransportParameters",2820],[10,"Session",2798],[1,"f32"],[1,"u128"],[5,"CertificateDer",2835],[6,"PrivateKeyDer",2835],[6,"Error",2836],[5,"Hash",2033,2837],[6,"BlobFormat",2033,2837],[5,"HashAndFormat",2033,2837],[5,"Hash",2838],[5,"TypeName",2839],[5,"Signature",2152,2840],[5,"SharedSecret",2152,2841],[6,"KeyParsingError",2152,2750],[5,"InternalSignature",2842],[5,"VerifyingKey",2843],[5,"Error",2844],[6,"HexOrBase32ParseError",2845],[5,"SigningKey",2846],[10,"CryptoRngCore",2847],[10,"Buffer",2848],[5,"Zeroizing",2849],[6,"Error",2850],[5,"Signature",2851],[5,"PortmapMetrics",2299],[5,"NetReportMetrics",2299],[5,"RelayMetrics",2299],[5,"MagicsockMetrics",2299],[5,"IntoIter",2852],[10,"ProtocolHandler",2459],[8,"Boxed",2853],[5,"RouterBuilder",2459],[5,"ProtocolMap",2459],[5,"Router",2459],[10,"IntoArcAny",2459],[5,"DnsPkarrServer",2523,2854],[5,"CleanupDropGuard",2523],[5,"Server",2855],[5,"StunConfig",2855],[5,"BlobTicket",2557,2856],[10,"Ticket",2557,2857],[6,"Error",2557,2857],[6,"Error",2858],[5,"DecodeError",2859],[6,"CreateConfigError",2647],[5,"GenError",2668],[5,"NoInitialCipherSuite",2860],[5,"QuicClientConfig",2860],[5,"QuicServerConfig",2860],[5,"P2pCertificate",2668],[5,"P2pExtension",2668],[5,"ParseError",2668],[5,"VerificationError",2668],[6,"Error",2861],[6,"Error",2862],[6,"SignatureScheme",2863],[15,"Discovery",2031],[15,"NamedApp",2031],[15,"Kind",2646]],"r":[[0,2740],[1,2740],[3,567],[5,2740],[6,2750],[9,2741],[10,567],[11,2741],[12,2742],[130,2864],[147,2864],[170,2864],[213,2741],[214,2741],[570,2766],[571,2766],[572,2793],[573,2740],[574,2740],[576,2798],[578,2809],[581,2797],[586,2813],[588,2807],[592,2766],[593,2809],[595,2792],[601,2805],[602,2751],[603,2808],[604,2751],[605,2799],[606,2799],[607,2798],[612,2811],[613,2751],[614,2811],[615,2811],[621,2798],[626,2805],[627,2798],[640,2793],[644,2740],[646,2766],[647,2766],[649,2805],[654,2766],[655,2803],[657,2803],[658,2803],[659,2803],[665,2751],[668,2803],[669,2814],[673,2766],[674,2804],[675,2793],[676,2808],[679,2804],[680,2810],[687,2793],[692,2805],[695,2798],[696,2794],[698,2766],[699,2804],[700,2806],[701,2766],[2033,2837],[2035,2837],[2036,2837],[2155,2750],[2156,2750],[2157,2865],[2158,2750],[2159,2750],[2160,2841],[2161,2840],[2524,2854],[2529,2866],[2557,2856],[2559,2857],[2562,2749],[2564,2857]],"b":[[97,"impl-Debug-for-AddrInfoOptions"],[98,"impl-Display-for-AddrInfoOptions"],[99,"impl-Display-for-RelayMap"],[100,"impl-Debug-for-RelayMap"],[101,"impl-Debug-for-RelayNode"],[102,"impl-Display-for-RelayNode"],[103,"impl-Debug-for-RelayUrl"],[104,"impl-Display-for-RelayUrl"],[105,"impl-From%3CNodeTicket%3E-for-NodeAddr"],[106,"impl-From%3CNodeInfo%3E-for-NodeAddr"],[108,"impl-From%3CPublicKey%3E-for-NodeAddr"],[109,"impl-From%3CRemoteInfo%3E-for-NodeAddr"],[110,"impl-From%3C(PublicKey,+Option%3CRelayUrl%3E,+%26%5BSocketAddr%5D)%3E-for-NodeAddr"],[514,"impl-Debug-for-IrohAttr"],[515,"impl-Display-for-IrohAttr"],[519,"impl-From%3CTxtAttrs%3CIrohAttr%3E%3E-for-NodeInfo"],[520,"impl-From%3C%26TxtAttrs%3CIrohAttr%3E%3E-for-NodeInfo"],[1032,"impl-PartialEq%3CVec%3Cu8%3E%3E-for-Bytes"],[1033,"impl-PartialEq%3C%26T%3E-for-Bytes"],[1034,"impl-PartialEq%3Cstr%3E-for-Bytes"],[1035,"impl-PartialEq%3CString%3E-for-Bytes"],[1036,"impl-PartialEq%3C%5Bu8%5D%3E-for-Bytes"],[1037,"impl-PartialEq%3CBytesMut%3E-for-Bytes"],[1038,"impl-PartialEq-for-Bytes"],[1150,"impl-LowerHex-for-Bytes"],[1151,"impl-UpperHex-for-Bytes"],[1152,"impl-Debug-for-Bytes"],[1155,"impl-Debug-for-SendDatagramError"],[1156,"impl-Display-for-SendDatagramError"],[1157,"impl-Debug-for-RetryError"],[1158,"impl-Display-for-RetryError"],[1160,"impl-Display-for-ReadToEndError"],[1161,"impl-Debug-for-ReadToEndError"],[1162,"impl-Display-for-ReadError"],[1163,"impl-Debug-for-ReadError"],[1164,"impl-Display-for-ResetError"],[1165,"impl-Debug-for-ResetError"],[1166,"impl-Display-for-ReadExactError"],[1167,"impl-Debug-for-ReadExactError"],[1169,"impl-Debug-for-WriteError"],[1170,"impl-Display-for-WriteError"],[1171,"impl-Display-for-StoppedError"],[1172,"impl-Debug-for-StoppedError"],[1174,"impl-Display-for-VarInt"],[1175,"impl-Debug-for-VarInt"],[1189,"impl-Debug-for-ClosedStream"],[1190,"impl-Display-for-ClosedStream"],[1191,"impl-Debug-for-ControlMsg"],[1192,"impl-Display-for-ControlMsg"],[1195,"impl-Debug-for-ConnectionType"],[1196,"impl-Display-for-ConnectionType"],[1197,"impl-Debug-for-ConnectionError"],[1198,"impl-Display-for-ConnectionError"],[1205,"impl-Debug-for-Source"],[1206,"impl-Display-for-Source"],[1207,"impl-Debug-for-ConnectionClose"],[1208,"impl-Display-for-ConnectionClose"],[1209,"impl-Display-for-ApplicationClose"],[1210,"impl-Debug-for-ApplicationClose"],[1212,"impl-Display-for-TransportError"],[1213,"impl-Debug-for-TransportError"],[1214,"impl-Display-for-TransportErrorCode"],[1215,"impl-Debug-for-TransportErrorCode"],[1216,"impl-Debug-for-StreamId"],[1217,"impl-Display-for-StreamId"],[1220,"impl-Display-for-DirectAddrType"],[1221,"impl-Debug-for-DirectAddrType"],[1228,"impl-From%3C%26str%3E-for-Bytes"],[1230,"impl-From%3CCustom%3E-for-Bytes"],[1231,"impl-From%3CReasonPhrase%3E-for-Bytes"],[1232,"impl-From%3CByteStr%3E-for-Bytes"],[1233,"impl-From%3CBytesMut%3E-for-Bytes"],[1234,"impl-From%3CBox%3C%5Bu8%5D%3E%3E-for-Bytes"],[1235,"impl-From%3CString%3E-for-Bytes"],[1236,"impl-From%3CVec%3Cu8%3E%3E-for-Bytes"],[1237,"impl-From%3CCustom%3E-for-Bytes"],[1238,"impl-From%3C%26%5Bu8%5D%3E-for-Bytes"],[1239,"impl-From%3CByteStr%3E-for-Bytes"],[1253,"impl-From%3CReadableError%3E-for-ReadError"],[1254,"impl-From%3CConnectionError%3E-for-ReadError"],[1256,"impl-From%3CResetError%3E-for-ReadError"],[1262,"impl-From%3CConnectionError%3E-for-WriteError"],[1264,"impl-From%3CClosedStream%3E-for-WriteError"],[1265,"impl-From%3CStoppedError%3E-for-WriteError"],[1269,"impl-From%3Cu8%3E-for-VarInt"],[1270,"impl-From%3Cu32%3E-for-VarInt"],[1271,"impl-From%3CStreamId%3E-for-VarInt"],[1273,"impl-From%3Cu16%3E-for-VarInt"],[1293,"impl-From%3CTransportError%3E-for-ConnectionError"],[1294,"impl-From%3CClose%3E-for-ConnectionError"],[1307,"impl-From%3CTransportErrorCode%3E-for-TransportError"],[1308,"impl-From%3CError%3E-for-TransportError"],[1310,"impl-From%3CInvalidFrame%3E-for-TransportError"],[1511,"impl-IntoIterator-for-%26Bytes"],[1512,"impl-IntoIterator-for-Bytes"],[1591,"impl-PartialOrd%3CString%3E-for-Bytes"],[1592,"impl-PartialOrd%3C%26T%3E-for-Bytes"],[1593,"impl-PartialOrd%3CVec%3Cu8%3E%3E-for-Bytes"],[1594,"impl-PartialOrd-for-Bytes"],[1595,"impl-PartialOrd%3Cstr%3E-for-Bytes"],[1596,"impl-PartialOrd%3C%5Bu8%5D%3E-for-Bytes"],[1619,"impl-RecvStream"],[1620,"impl-AsyncRead-for-RecvStream"],[1622,"impl-SendStream"],[1623,"impl-AsyncWrite-for-SendStream"],[1800,"impl-TryFrom%3Cu64%3E-for-VarInt"],[1802,"impl-TryFrom%3Cu128%3E-for-VarInt"],[1803,"impl-TryFrom%3Cusize%3E-for-VarInt"],[2042,"impl-Hash"],[2043,"impl-Value-for-Hash"],[2046,"impl-Borrow%3C%5Bu8%5D%3E-for-Hash"],[2047,"impl-Borrow%3C%5Bu8;+32%5D%3E-for-Hash"],[2087,"impl-Debug-for-Hash"],[2088,"impl-Display-for-Hash"],[2089,"impl-Debug-for-BlobFormat"],[2090,"impl-Display-for-BlobFormat"],[2091,"impl-Debug-for-HashAndFormat"],[2092,"impl-Display-for-HashAndFormat"],[2096,"impl-From%3C%26%5Bu8;+32%5D%3E-for-Hash"],[2097,"impl-From%3C%5Bu8;+32%5D%3E-for-Hash"],[2098,"impl-From%3CHash%3E-for-Hash"],[2101,"impl-Hash"],[2102,"impl-Value-for-Hash"],[2198,"impl-Debug-for-Signature"],[2199,"impl-UpperHex-for-Signature"],[2200,"impl-LowerHex-for-Signature"],[2201,"impl-Display-for-Signature"],[2203,"impl-Debug-for-PublicKey"],[2204,"impl-Display-for-PublicKey"],[2205,"impl-Debug-for-KeyParsingError"],[2206,"impl-Display-for-KeyParsingError"],[2207,"impl-Display-for-SecretKey"],[2208,"impl-Debug-for-SecretKey"],[2210,"impl-From%3CInternalSignature%3E-for-Signature"],[2212,"impl-From%3C%26%5Bu8;+ed25519::::SignatureBytes::%7Bconstant%230%7D%5D%3E-for-Signature"],[2213,"impl-From%3C%5Bu8;+ed25519::::SignatureBytes::%7Bconstant%230%7D%5D%3E-for-Signature"],[2217,"impl-From%3CError%3E-for-KeyParsingError"],[2219,"impl-From%3CHexOrBase32ParseError%3E-for-KeyParsingError"],[2221,"impl-From%3CSigningKey%3E-for-SecretKey"],[2222,"impl-From%3C%5Bu8;+32%5D%3E-for-SecretKey"],[2259,"impl-Signature"],[2260,"impl-SignatureEncoding-for-Signature"],[2272,"impl-TryFrom%3C%26%5Bu8%5D%3E-for-Signature"],[2273,"impl-TryFrom%3CSignature%3E-for-Signature"],[2274,"impl-TryFrom%3C%26Signature%3E-for-Signature"],[2277,"impl-TryFrom%3C%26%5Bu8;+32%5D%3E-for-PublicKey"],[2278,"impl-TryFrom%3C%26%5Bu8%5D%3E-for-PublicKey"],[2589,"impl-Debug-for-BlobTicket"],[2590,"impl-Display-for-BlobTicket"],[2591,"impl-Display-for-NodeTicket"],[2592,"impl-Debug-for-NodeTicket"],[2593,"impl-Debug-for-Error"],[2594,"impl-Display-for-Error"],[2599,"impl-From%3CError%3E-for-Error"],[2601,"impl-From%3CDecodeError%3E-for-Error"],[2653,"impl-Debug-for-CreateConfigError"],[2654,"impl-Display-for-CreateConfigError"],[2655,"impl-From%3CGenError%3E-for-CreateConfigError"],[2656,"impl-From%3CNoInitialCipherSuite%3E-for-CreateConfigError"],[2685,"impl-Debug-for-GenError"],[2686,"impl-Display-for-GenError"],[2687,"impl-Debug-for-ParseError"],[2688,"impl-Display-for-ParseError"],[2689,"impl-Debug-for-VerificationError"],[2690,"impl-Display-for-VerificationError"]],"c":"OjAAAAEAAAAAAAAAEAAAANcD","e":"OzAAAAEAAAUH2AAEAAAACwAAAA4ABQAWAB8ANwABADsABQBIACEAawAAAG0AAwB2AAAAeQAHAIQAAACMAAUAmgADAKAAAACjAAQAqwAAAK0AGwDLAAUA6AACAOwAAADvAAEA8gAAAPYAAAD4AAYAAgEAAAUBBgAOAQEAEQEAABMBAAAXAQEAHwEAACEBAAAkAQkAMQECADYBAAA5AQQAQAECAEUBAABHAQYAVQEOAGUBAwBsAQIAcgECAHoBAAB8AQAAfgELAIsBAgCRAQQAmQEDAJ4BAQCiAQAApwEBAKsBAACtAQAArwEEALUBAwC8AQMAxAEAAMYBAADIAQAAygEDANoBAADiAQAA7QEBAPABCQD7AQsACAIBAAsCAAASAgEAFgIAABoCAgAiAgAAJgIAACkCAAArAgwAwwIhAOsCAADtAgAA9AIAAPkCAAD/AnAAdgMDAH0DIQCgAyEAxgMEAMwDBADYAwAA2gMAANwDAADhAwEA5wMKAPMDBQADBAIABwRzAH8ERwDNBAAAzwQJAOAEAADkBAAA5gQBAOkEAQDtBAAA7wQAAPEEAgD2BAIA+gQAAA4FAQAUBQAAGAUAABwFAQAfBQAAIgUAACYFAAAoBSIAUgUAAFQFBQBeBQAApAVBAOgFBwD2BQgAFAYAABgGBAAmBgEALAYAADgGCQBDBgEARwYMAFUGAQBYBgAAXgYMAHwGAACFBgEAlgYEAKIGBwCyBgAAtAYBALcGAQC6BjUA9QYTAAoHAAANB1oAaQcGAHEHNwCsBzcA7gcBAPgHAgD8BzEAMQgCADcICQBGCAIATQgCAFEIAgBVCBMAcwgCAHcIKgCjCAAApQgBAKkIAQCsCAAArggBALQIAgC4CAIAvQgAAMMIBADJCAAAzggCANMIAADVCAAA2AgGAOAICgDsCAkA9wgEAAAJAwAFCQ8AFwkHACIJAwArCQQANQkDAD4JDgBWCQYAXgkHAGcJCABzCQYAewkUAJIJCAChCQEApgkFAK0JBAC0CQIAugkBAMUJAgDOCQ0A3gkDAOUJAQDrCQEA9gkHAAcKCwAUCg8AKAoAACoKAAAsCgUANgoCAEAKAgBEChMAWwoBAF4KAwBkCgAAZwoFAHIKEQCGCgAAiAoAAIoKAACSCgQAmQoUAK8KBAA="}],\ +["iroh_base",{"t":"CCCCCCPFGPGPPPPNNNNNNNNNNNNHNNNNNNHHNNNNNNNNOHHHONNNNNNNNNNNNNNNNNNGTFFPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTPPGISFFFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFGPPFPPFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNONNNNNNONNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNSSFFFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOONNOONNNNNNNNNNNNNNONNNNFPGTPFPKPNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNO","n":["base32","hash","key","node_addr","relay_map","ticket","Base32","DecodeError","DecodeKind","Hex","HexOrBase32ParseError","Length","Padding","Symbol","Trailing","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt_append","fmt_short","from","from","from","from","from","into","into","into","kind","parse_array","parse_array_hex_or_base32","parse_vec","position","source","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","BlobFormat","EMPTY","Hash","HashAndFormat","HashSeq","Raw","as_bytes","as_bytes","as_bytes","as_ref","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","cmp","cmp","cmp","compare","default","deserialize","deserialize","deserialize","encode_hex","encode_hex_upper","eq","eq","eq","fixed_width","fixed_width","fmt","fmt","fmt","fmt","fmt","fmt","fmt_short","format","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_str","from_str","hash","hash","hash","hash","hash_seq","into","into","into","is_hash_seq","is_raw","new","new","partial_cmp","partial_cmp","partial_cmp","raw","serialize","serialize","serialize","to_hex","to_owned","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","type_name","type_name","vzip","vzip","vzip","BYTE_SIZE","Base32","Key","KeyParsingError","NodeId","PUBLIC_KEY_LENGTH","PublicKey","SecretKey","SharedSecret","Signature","as_bytes","as_ref","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","cmp","deserialize","deserialize","deserialize","encode_hex","encode_hex_upper","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt_short","from","from","from","from","from","from","from","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_components","from_slice","from_str","from_str","from_str","generate","generate_with_rng","hash","into","into","into","into","into","open","partial_cmp","public","r_bytes","s_bytes","seal","serialize","serialize","serialize","shared","sign","source","to_bytes","to_bytes","to_bytes","to_openssh","to_owned","to_owned","to_owned","to_string","to_string","to_string","to_string","to_vec","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from_openssh","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","verify","vzip","vzip","vzip","vzip","vzip","AddrInfo","AddrInfoOptions","Addresses","Id","NodeAddr","Relay","RelayAndAddresses","RelayUrl","apply_options","apply_options","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","default","default","deref","deserialize","deserialize","deserialize","deserialize","direct_addresses","direct_addresses","eq","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from_parts","from_str","from_str","hash","info","into","into","into","into","is_empty","new","node_id","partial_cmp","partial_cmp","partial_cmp","relay_url","relay_url","serialize","serialize","serialize","serialize","to_owned","to_owned","to_owned","to_owned","to_string","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","with_direct_addresses","with_relay_url","DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT","QuicConfig","RelayMap","RelayNode","RelayUrl","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","cmp","cmp","contains_node","default","default_from_node","deserialize","deserialize","empty","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","from","from","from","from_nodes","from_url","get_node","into","into","into","is_empty","len","nodes","partial_cmp","partial_cmp","port","quic","serialize","serialize","stun_only","stun_port","to_owned","to_owned","to_owned","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","url","urls","vzip","vzip","vzip","BlobTicket","Encoding","Error","KIND","Kind","NodeTicket","Postcard","Ticket","Verify","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","deserialize","deserialize","deserialize","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","format","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_str","from_str","hash","into","into","into","into_parts","new","new","node_addr","node_addr","recursive","serialize","serialize","serialize","source","to_bytes","to_bytes","to_bytes","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","expected"],"q":[[0,"iroh_base"],[6,"iroh_base::base32"],[67,"iroh_base::hash"],[165,"iroh_base::key"],[294,"iroh_base::node_addr"],[395,"iroh_base::relay_map"],[468,"iroh_base::ticket"],[544,"iroh_base::ticket::Error"],[545,"data_encoding"],[546,"alloc::string"],[547,"core::convert"],[548,"core::fmt"],[549,"core::result"],[550,"hex::error"],[551,"alloc::vec"],[552,"core::error"],[553,"core::option"],[554,"core::any"],[555,"core::cmp"],[556,"serde::de"],[557,"core::iter::traits::collect"],[558,"iroh_blake3"],[559,"core::hash"],[560,"serde::ser"],[561,"redb::types"],[562,"ed25519"],[563,"iroh_base::key::encryption"],[564,"ed25519_dalek::signature"],[565,"ed25519_dalek::verifying"],[566,"ed25519_dalek::errors"],[567,"ed25519_dalek::signing"],[568,"signature::error"],[569,"rand_core"],[570,"core::marker"],[571,"aead"],[572,"anyhow"],[573,"zeroize"],[574,"ssh_key::error"],[575,"ssh_key::signature"],[576,"iroh_base::relay_url"],[577,"core::net::socket_addr"],[578,"core::iter::traits::iterator"],[579,"iroh_base::ticket::node"],[580,"url"],[581,"alloc::sync"],[582,"iroh_base::ticket::blob"],[583,"postcard::error"],[584,"ed25519_dalek::constants"]],"i":[0,0,0,0,0,0,12,0,0,12,0,1,1,1,1,1,2,12,1,2,12,1,2,1,2,1,2,0,1,1,2,2,12,12,0,0,1,2,12,12,12,1,2,12,2,0,0,0,2,12,1,2,1,2,12,1,2,12,1,2,12,1,2,12,1,2,12,0,21,0,0,22,22,21,21,23,21,21,21,21,22,23,21,22,23,21,22,23,21,22,23,21,22,23,21,22,21,22,23,21,21,21,22,23,21,23,21,21,22,22,23,23,21,23,21,21,21,21,22,23,21,21,23,21,23,21,22,23,23,23,21,22,23,22,22,21,23,21,22,23,23,21,22,23,21,21,22,23,21,22,23,21,22,23,21,22,23,21,22,23,21,23,21,22,23,34,37,37,0,0,0,0,0,0,0,33,33,34,36,33,37,35,34,36,33,37,35,34,33,35,34,33,35,33,34,33,35,33,33,34,33,34,34,34,34,36,33,33,37,37,35,35,33,34,34,34,34,36,33,33,37,37,37,35,35,35,34,33,35,34,34,34,33,35,35,35,33,34,36,33,37,35,36,33,35,34,34,36,34,33,35,35,35,37,34,34,35,35,34,33,35,34,33,37,35,34,34,34,34,34,36,33,33,33,37,35,35,35,34,36,33,37,35,34,36,33,37,35,33,34,36,33,37,35,0,0,52,52,0,52,52,0,51,53,51,53,52,54,51,53,52,54,51,53,52,54,51,53,52,54,51,53,54,53,52,54,51,53,52,54,51,53,51,53,52,54,51,53,52,52,54,54,51,51,51,51,53,52,54,54,51,52,54,54,51,51,53,52,54,53,51,51,51,53,54,51,53,51,53,52,54,51,53,52,54,52,54,51,53,52,54,51,53,52,54,51,53,52,54,51,53,52,54,51,51,0,0,0,0,0,0,63,64,65,63,64,65,63,64,65,63,64,65,64,65,63,65,63,64,65,63,63,64,65,63,63,64,64,65,63,64,65,63,63,63,63,64,65,63,63,63,64,65,65,64,64,65,64,64,63,64,65,63,64,63,64,65,63,64,65,63,64,65,64,63,63,64,65,0,71,0,70,71,0,71,0,71,69,60,71,69,60,71,69,60,69,60,70,69,60,69,60,69,69,60,60,71,71,69,69,60,60,71,71,71,70,69,60,69,60,69,69,60,71,69,69,60,69,60,69,70,69,60,71,70,69,60,69,60,69,60,71,69,60,71,69,60,71,69,60,71,69,60,71,73],"f":"```````````````{ce{}{}}00000{bb}{dd}{{ce}f{}{}}0{{bb}h}{{dd}h}{cj{{A`{{n{l}}}}}}{{bAb}{{Af{fAd}}}}0{{dAb}{{Af{fAd}}}}0{{AhAb}Aj}0{{cj}f{{A`{{n{l}}}}}}4{cc{}}00{AlAh}{dAh}===`{An{{Af{{B`{l}}d}}}}{An{{Af{{B`{l}}Ah}}}}{An{{Af{{Bb{l}}d}}}}`{Ah{{Bf{Bd}}}}{ce{}{}}0{cj{}}00{c{{Af{e}}}{}{}}00000{cBh{}}00333``````3{Bj{{B`{l}}}}4{Bj{{n{l}}}}10555555{BjBj}{BlBl}{BnBn}{{ce}f{}{}}00{{BjBj}C`}{{BlBl}C`}{{BnBn}C`}{{{n{l}}{n{l}}}C`}{{}Bl}{c{{Af{Bj}}}Cb}{c{{Af{Bl}}}Cb}{c{{Af{Bn}}}Cb}{ce{}{{Cf{Cd}}}}0{{BjBj}h}{{BlBl}h}{{BnBn}h}{{}{{Bf{Ch}}}}0{{BjAb}Aj}0{{BlAb}Aj}0{{BnAb}Aj}0{Bjj}`{CjBj}{cc{}}{{{B`{l}}}Bj}0110{{{n{l}}}c{}}0{An{{Af{Bjc}}}{}}{An{{Af{Bnc}}}{}}{{Bjc}fCl}{{Blc}fCl}{{Bnc}fCl}`{BjBn}{ce{}{}}00{Blh}0{cBj{{A`{{n{l}}}}}}{{BjBl}Bn}{{BjBj}{{Bf{C`}}}}{{BlBl}{{Bf{C`}}}}{{BnBn}{{Bf{C`}}}}7{{Bjc}AfCn}{{Blc}AfCn}{{Bnc}AfCn}{Bjj}:::{cj{}}00{c{{Af{e}}}{}{}}00000{cBh{}}00{{}D`}0>>>``````````{Db{{B`{l}}}}{Db{{n{l}}}}{ce{}{}}000000000{DdDd}{DbDb}{DfDf}{{ce}f{}{}}00{{DbDb}C`}{c{{Af{Dd}}}Cb}{c{{Af{Db}}}Cb}{c{{Af{Df}}}Cb}{ce{}{{Cf{Cd}}}}0{{DdDd}h}{{DbDb}h}{{DdAb}{{Af{fAd}}}}000{{DhAb}Aj}{{DbAb}Aj}0{{DjAb}Aj}0{{DfAb}Aj}0{Dbj}{DlDd}{{{B`{l}}}Dd}0{cc{}}00{DnDb}1{E`Dj}{AhDj}{EbDf}4{{{B`{l}}}Df}6{{{B`{l}}}{{Af{DbE`}}}}1{{{B`{l}}{B`{l}}}Dd}{{{n{l}}}{{Af{DdEd}}}}{An{{Af{DdEd}}}}{An{{Af{Dbc}}}{}}{An{{Af{Dfc}}}{}}{{}Df}{cDf{EfEh}}{{Dbc}fCl}{ce{}{}}0000{{DhEj}{{El{f}}}}{{DbDb}{{Bf{C`}}}}{DfDb}{Dd{{B`{l}}}}0{{DhEj}f}{{Ddc}AfCn}{{Dbc}AfCn}{{Dfc}AfCn}{{DfDb}Dh}{{Df{n{l}}}Dd}{Dj{{Bf{Bd}}}}77{Df{{B`{l}}}}{Df{{F`{{En{j}}}}}}==={cj{}}000{Dd{{Bb{l}}}}{c{{Af{e}}}{}{}}{{{n{l}}}{{Af{DdEd}}}}{Fb{{Af{DdFd}}}}02{{{B`{l}}}{{Af{Dbc}}}{}}3{{{n{l}}}{{Af{Dbc}}}{}}44{{{n{l}}}{{Af{Dfc}}}{}}{c{{El{Df}}}{{A`{{n{l}}}}}}66666{cBh{}}0000{{Db{n{l}}Dd}{{Af{fE`}}}}{ce{}{}}0000````````{{FfFh}f}{{FjFh}f}22222222{FfFf}{FjFj}{FhFh}{FlFl}{{ce}f{}{}}000{{FfFf}C`}{{FjFj}C`}{{FlFl}C`}{{}Fj}{{}Fh}{Flc{}}{c{{Af{Ff}}}Cb}{c{{Af{Fj}}}Cb}{c{{Af{Fh}}}Cb}{c{{Af{Fl}}}Cb}{Ff{{`{{Gb{}{{Fn{G`}}}}}}}}`{{FfFf}h}{{FjFj}h}{{FhFh}h}{{FlFl}h}{{FfAb}Aj}{{FjAb}Aj}{{FhAb}Aj}0{{FlAb}Aj}0{GdFf}{{{Gf{Db{Bf{Fl}}{n{G`}}}}}Ff}{GhFf}{cc{}}000{GjFl}{{Db{Bf{Fl}}c}Ff{{Gl{}{{Fn{G`}}}}}}{An{{Af{Fhc}}}{}}{An{{Af{Flc}}}{}}{{Flc}fCl}`{ce{}{}}000{Fjh}{DbFf}`{{FfFf}{{Bf{C`}}}}{{FjFj}{{Bf{C`}}}}{{FlFl}{{Bf{C`}}}}{Ff{{Bf{Fl}}}}`{{Ffc}AfCn}{{Fjc}AfCn}{{Fhc}AfCn}{{Flc}AfCn}::::{cj{}}0{c{{Af{e}}}{}{}}0000000{cBh{}}000===={{Ffc}Ff{{Gl{}{{Fn{G`}}}}}}{{FfFl}Ff}``````??????{GnGn}{H`H`}{HbHb}{{ce}f{}{}}00{{H`H`}C`}{{HbHb}C`}{{GnFl}h}{{}Hb}{{FlHd}Gn}{c{{Af{H`}}}Cb}{c{{Af{Hb}}}Cb}{{}Gn}{{GnGn}h}{{H`H`}h}{{HbHb}h}{{GnAb}Aj}0{{H`Ab}Aj}0{{HbAb}Aj}{cc{}}00{e{{El{Gn}}}{{Hh{{Hf{H`}}}}}{{Gl{}{{Fn{c}}}}}}{FlGn}{{GnFl}{{Bf{{Hf{H`}}}}}}{ce{}{}}00{Gnh}{GnCh}{Gn{{`{{Gb{}{{Fn{{Hf{H`}}}}}}}}}}{{H`H`}{{Bf{C`}}}}{{HbHb}{{Bf{C`}}}}``{{H`c}AfCn}{{Hbc}AfCn}``777{cj{}}0{c{{Af{e}}}{}{}}00000{cBh{}}00`{Gn{{`{{Gb{}{{Fn{Fl}}}}}}}};;;`````````;;;;;;{HjHj}{GhGh}{{ce}f{}{}}0{An{{Af{HlHn}}}}{c{{El{Hj}}}Cb}{c{{El{Gh}}}Cb}{{HjHj}h}{{GhGh}h}{{HjAb}Aj}0{{GhAb}Aj}0{{HnAb}Aj}0{HjBl}{cc{}}0{FfGh}1{I`Hn}{dHn}{{{n{l}}}{{Af{HlHn}}}}{{{n{l}}}{{Af{HjHn}}}}{{{n{l}}}{{Af{GhHn}}}}{An{{El{Hjc}}}{}}{An{{El{Ghc}}}{}}{HjBj}{ce{}{}}00{Hj{{Gf{FfBjBl}}}}{{FfBjBl}{{El{Hj}}}};{HjFf}{GhFf}{Hjh}{Hlj}{{Hjc}ElCn}{{Ghc}ElCn}{Hn{{Bf{Bd}}}}{Hl{{Bb{l}}}}{Hj{{Bb{l}}}}{Gh{{Bb{l}}}}<<{cj{}}00{c{{Af{e}}}{}{}}00000{cBh{}}00???`","D":"AFd","p":[[6,"DecodeKind",6,545],[5,"DecodeError",6,545],[1,"unit"],[1,"bool"],[5,"String",546],[1,"u8"],[1,"slice"],[10,"AsRef",547],[5,"Formatter",548],[5,"Error",548],[6,"Result",549],[6,"HexOrBase32ParseError",6],[8,"Result",548],[6,"FromHexError",550],[1,"str"],[1,"array"],[5,"Vec",551],[10,"Error",552],[6,"Option",553],[5,"TypeId",554],[5,"Hash",67],[6,"BlobFormat",67],[5,"HashAndFormat",67],[6,"Ordering",555],[10,"Deserializer",556],[1,"char"],[10,"FromIterator",557],[1,"usize"],[5,"Hash",558],[10,"Hasher",559],[10,"Serializer",560],[5,"TypeName",561],[5,"PublicKey",165],[5,"Signature",165,562],[5,"SecretKey",165],[5,"SharedSecret",165,563],[6,"KeyParsingError",165],[5,"InternalSignature",564],[5,"VerifyingKey",565],[8,"SignatureError",566],[5,"SigningKey",567],[5,"Error",568],[10,"CryptoRngCore",569],[10,"Sized",570],[10,"Buffer",571],[8,"Result",572],[5,"Zeroizing",573],[8,"Result",574],[5,"Signature",575],[6,"Error",574],[5,"NodeAddr",294],[6,"AddrInfoOptions",294],[5,"AddrInfo",294],[5,"RelayUrl",294,576],[17,"Item"],[6,"SocketAddr",577],[10,"Iterator",578],[8,"NodeId",165],[1,"tuple"],[5,"NodeTicket",468,579],[5,"Url",580],[10,"IntoIterator",557],[5,"RelayMap",395],[5,"RelayNode",395],[5,"QuicConfig",395],[1,"u16"],[5,"Arc",581],[10,"Into",547],[5,"BlobTicket",468,582],[10,"Ticket",468],[6,"Error",468],[6,"Error",583],[15,"Kind",544]],"r":[[7,545],[8,545],[170,584],[173,563],[174,562],[301,576],[400,576],[468,582],[473,579]],"b":[[28,"impl-Display-for-DecodeKind"],[29,"impl-Debug-for-DecodeKind"],[30,"impl-Display-for-DecodeError"],[31,"impl-Debug-for-DecodeError"],[32,"impl-Debug-for-HexOrBase32ParseError"],[33,"impl-Display-for-HexOrBase32ParseError"],[39,"impl-From%3CFromHexError%3E-for-HexOrBase32ParseError"],[40,"impl-From%3CDecodeError%3E-for-HexOrBase32ParseError"],[73,"impl-Value-for-Hash"],[74,"impl-Hash"],[77,"impl-Borrow%3C%5Bu8;+32%5D%3E-for-Hash"],[78,"impl-Borrow%3C%5Bu8%5D%3E-for-Hash"],[106,"impl-Display-for-Hash"],[107,"impl-Debug-for-Hash"],[108,"impl-Debug-for-BlobFormat"],[109,"impl-Display-for-BlobFormat"],[110,"impl-Display-for-HashAndFormat"],[111,"impl-Debug-for-HashAndFormat"],[114,"impl-From%3CHash%3E-for-Hash"],[116,"impl-From%3C%26%5Bu8;+32%5D%3E-for-Hash"],[117,"impl-From%3C%5Bu8;+32%5D%3E-for-Hash"],[120,"impl-Hash"],[121,"impl-Value-for-Hash"],[201,"impl-UpperHex-for-Signature"],[202,"impl-LowerHex-for-Signature"],[203,"impl-Debug-for-Signature"],[204,"impl-Display-for-Signature"],[206,"impl-Debug-for-PublicKey"],[207,"impl-Display-for-PublicKey"],[208,"impl-Debug-for-KeyParsingError"],[209,"impl-Display-for-KeyParsingError"],[210,"impl-Debug-for-SecretKey"],[211,"impl-Display-for-SecretKey"],[213,"impl-From%3CInternalSignature%3E-for-Signature"],[214,"impl-From%3C%5Bu8;+ed25519::::SignatureBytes::%7Bconstant%230%7D%5D%3E-for-Signature"],[215,"impl-From%3C%26%5Bu8;+ed25519::::SignatureBytes::%7Bconstant%230%7D%5D%3E-for-Signature"],[221,"impl-From%3CError%3E-for-KeyParsingError"],[222,"impl-From%3CHexOrBase32ParseError%3E-for-KeyParsingError"],[223,"impl-From%3CSigningKey%3E-for-SecretKey"],[225,"impl-From%3C%5Bu8;+32%5D%3E-for-SecretKey"],[254,"impl-Signature"],[255,"impl-SignatureEncoding-for-Signature"],[267,"impl-TryFrom%3C%26%5Bu8%5D%3E-for-Signature"],[268,"impl-TryFrom%3CSignature%3E-for-Signature"],[269,"impl-TryFrom%3C%26Signature%3E-for-Signature"],[271,"impl-TryFrom%3C%26%5Bu8;+32%5D%3E-for-PublicKey"],[273,"impl-TryFrom%3C%26%5Bu8%5D%3E-for-PublicKey"],[338,"impl-Debug-for-AddrInfoOptions"],[339,"impl-Display-for-AddrInfoOptions"],[340,"impl-Debug-for-RelayUrl"],[341,"impl-Display-for-RelayUrl"],[342,"impl-From%3CPublicKey%3E-for-NodeAddr"],[343,"impl-From%3C(PublicKey,+Option%3CRelayUrl%3E,+%26%5BSocketAddr%5D)%3E-for-NodeAddr"],[344,"impl-From%3CNodeTicket%3E-for-NodeAddr"],[424,"impl-Debug-for-RelayMap"],[425,"impl-Display-for-RelayMap"],[426,"impl-Display-for-RelayNode"],[427,"impl-Debug-for-RelayNode"],[492,"impl-Debug-for-BlobTicket"],[493,"impl-Display-for-BlobTicket"],[494,"impl-Debug-for-NodeTicket"],[495,"impl-Display-for-NodeTicket"],[496,"impl-Debug-for-Error"],[497,"impl-Display-for-Error"],[503,"impl-From%3CError%3E-for-Error"],[504,"impl-From%3CDecodeError%3E-for-Error"]],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAG8BMQABAAAABgAAABAACwAdAAUAKAABADIAEQBKAAAATAAkAHMAAAB1AAEAegAGAIoAAgCOAAIAkgATALEAIwDWAAIA3AAAAN4AAgDiAAAA6AACAO0AAAD0AAAA+QACAP4AAAAAAQAAAwEGAAsBCgAXAQkAIgEEADEBGQBNAQsAXgEAAGABAgBrAQIAcAEZAJIBDQChAQAAowEBAKYBBwC6AQIAvgEBAMIBDQDSAQIA3gEJAOkBCQD4AQEA+wEDAAoCAgAOAhMA"}],\ +["iroh_dns_server",{"t":"CCCCCCGFPPFFOONNNNNNNNNNNNNNNNNOOONNNNNNNNOONNNNNOOONNNNNNNNNNNNNNNNNNNNNFFFFNNNNONNNNNNNNNNNNNNOONNNNNNNNNNNNNNNNNNOOOOONNNNNNNNNNNNNNNNNNNNNNNNGPFFFPPGPPPNNNNOONNNNNNNNNNONNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFNNNNNNOOOOOONNNOOOOHNNNOOOOONNNNNFNNNNNHNNNNNNFNNNNNONNNONNNNN","n":["config","dns","http","metrics","server","state","BootstrapOption","Config","Custom","Default","MainlineConfig","MetricsConfig","bind_addr","bootstrap","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","data_dir","default","default","default","deserialize","deserialize","deserialize","deserialize","disabled","disabled","dns","enabled","fmt","fmt","fmt","fmt","from","from","from","from","http","https","into","into","into","into","load","mainline","metrics","pkarr_put_rate_limit","serialize","serialize","serialize","serialize","signed_packet_store_path","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","DnsConfig","DnsHandler","DnsServer","Handle","__clone_box","__clone_box","__clone_box","answer_request","bind_addr","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","default_soa","default_ttl","deserialize","fmt","fmt","fmt","from","from","from","from","from_ref","from_ref","from_ref","handle_request","into","into","into","into","local_addr","new","origins","port","rr_a","rr_aaaa","rr_ns","run_until_done","send_response","serialize","shutdown","spawn","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","CertMode","Disabled","HttpConfig","HttpServer","HttpsConfig","LetsEncrypt","Manual","RateLimitConfig","SelfSigned","Simple","Smart","__clone_box","__clone_box","__clone_box","__clone_box","bind_addr","bind_addr","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","cert_mode","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","default","default","deserialize","deserialize","deserialize","deserialize","domains","eq","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from_ref","from_ref","from_ref","from_ref","http_addr","https_addr","into","into","into","into","into","letsencrypt_contact","letsencrypt_prod","port","port","run_until_done","serialize","serialize","serialize","serialize","shutdown","spawn","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","Metrics","__clone_box","borrow","borrow_mut","clone","clone_into","default","dns_lookup_error","dns_lookup_notfound","dns_lookup_success","dns_requests","dns_requests_https","dns_requests_udp","fmt","from","from_ref","http_requests","http_requests_duration_ms","http_requests_error","http_requests_success","init_metrics","into","iter","name","pkarr_publish_noop","pkarr_publish_update","store_packets_inserted","store_packets_removed","store_packets_updated","to_owned","try_from","try_into","type_id","vzip","Server","borrow","borrow_mut","from","into","run_until_error","run_with_config_until_ctrl_c","shutdown","spawn","try_from","try_into","type_id","vzip","AppState","__clone_box","borrow","borrow_mut","clone","clone_into","dns_handler","from","from_ref","into","store","to_owned","try_from","try_into","type_id","vzip"],"q":[[0,"iroh_dns_server"],[6,"iroh_dns_server::config"],[73,"iroh_dns_server::dns"],[145,"iroh_dns_server::http"],[249,"iroh_dns_server::metrics"],[283,"iroh_dns_server::server"],[296,"iroh_dns_server::state"],[312,"std::path"],[313,"anyhow"],[314,"core::result"],[315,"serde::de"],[316,"core::fmt"],[317,"core::convert"],[318,"serde::ser"],[319,"core::any"],[320,"dyn_clone::sealed"],[321,"hickory_server::server::request_handler"],[322,"bytes::bytes"],[323,"core::future::future"],[324,"alloc::boxed"],[325,"core::pin"],[326,"hickory_server::server::response_handler"],[327,"core::net::socket_addr"],[328,"hickory_server::authority::message_response"],[329,"hickory_proto::rr::resource"],[330,"core::iter::traits::iterator"],[331,"core::marker"],[332,"iroh_dns_server::http::rate_limiting"],[333,"iroh_dns_server::http::tls"],[334,"core::option"],[335,"alloc::string"],[336,"alloc::vec::into_iter"]],"i":[0,0,0,0,0,0,0,0,5,5,0,0,8,4,3,8,4,5,3,8,4,5,3,3,4,5,3,8,4,5,8,8,3,4,3,8,4,5,3,8,4,5,3,3,3,8,4,5,3,3,3,3,3,8,4,5,3,3,8,4,5,3,8,4,5,3,8,4,5,3,8,4,5,0,0,0,0,20,17,21,17,20,26,20,17,21,26,20,17,21,20,17,21,20,17,21,20,20,20,20,17,21,26,20,17,21,20,17,21,17,26,20,17,21,26,17,20,20,20,20,20,26,21,20,26,26,20,17,21,26,20,17,21,26,20,17,21,26,20,17,21,26,20,17,21,0,33,0,0,0,34,34,0,34,33,33,33,34,35,36,35,36,39,33,34,35,36,39,33,34,35,36,36,33,34,35,36,33,34,35,36,33,33,33,34,35,36,36,34,34,34,34,33,34,34,35,36,39,33,34,35,36,33,34,35,36,39,39,39,33,34,35,36,36,36,35,36,39,33,34,35,36,39,39,33,34,35,36,34,39,33,34,35,36,39,33,34,35,36,39,33,34,35,36,39,33,34,35,36,0,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,0,43,43,43,43,43,43,43,43,43,43,43,43,43,0,48,48,48,48,48,0,48,48,48,48,48,48,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41],"f":"``````````````{ce{}{}}0000000{{}{{d{b}}}}{{}f}{{}h}{{}j}{c{{l{f}}}n}{c{{l{A`}}}n}{c{{l{h}}}n}{c{{l{j}}}n}{{}A`}```{{fAb}Ad}{{A`Ab}Ad}{{hAb}Ad}{{jAb}Ad}{cc{}}000``>>>>{c{{d{f}}}{{Ah{Af}}}}```{{fc}lAj}{{A`c}lAj}{{hc}lAj}{{jc}lAj}{{}{{d{b}}}}{c{{l{e}}}{}{}}0000000{cAl{}}000{ce{}{}}000````{{cAn}B`{}}00{{BbBd}{{d{Bf}}}}`22222222{BhBh}{BbBb}{BjBj}{{ce}B`{}{}}00``{c{{l{Bh}}}n}{{BhAb}Ad}{{BbAb}Ad}{{BjAb}Ad}{cc{}}000000{{BbBdc}{{C`{{Bn{Bl}}}}}Cb}<<<<{CdCf}``````{Cd{{d{B`}}}}{{Bj{Ch{cegi}}}{{C`{{Bn{Bl}}}}}{{Cn{}{{Cj{Cl}}}}D`}{{Cn{}{{Cj{Cl}}}}D`}{{Cn{}{{Cj{Cl}}}}D`}{{Cn{}{{Cj{Cl}}}}D`}}{{Bhc}lAj}2{{BhBb}{{d{Cd}}}}{ce{}{}}00{c{{l{e}}}{}{}}0000000{cAl{}}0002222```````````{{cAn}B`{}}000``3333333333`{DbDb}{DdDd}{DfDf}{DhDh}{{ce}B`{}{}}000{{}Db}0{c{{l{Db}}}n}{c{{l{Dd}}}n}{c{{l{Df}}}n}{c{{l{Dh}}}n}`{{DdDd}Dj}{{ce}Dj{}{}}00{{DbAb}Ad}{{DdAb}{{l{B`Dl}}}}{{DdAb}Ad}{{DfAb}Ad}{{DhAb}Ad}{cc{}}00000000{Dn{{E`{Cf}}}}0{ce{}{}}0000````{Dn{{d{B`}}}}{{Dbc}lAj}{{Ddc}lAj}{{Dfc}lAj}{{Dhc}lAj}4{{{E`{Df}}{E`{Dh}}DbEb}{{d{Dn}}}}6666{cEd{}}{c{{l{e}}}{}{}}000000000{cAl{}}000099999`{{cAn}B`{}}::{EfEf}{{ce}B`{}{}}{{}Ef}``````{{EfAb}Ad}{cc{}}0````{{}B`}{ce{}{}}{Ef{{En{{El{EhEj}}}}}}{{}Eh}`````2;;:2`2242{F`{{d{B`}}}}{f{{d{B`}}}}1`==<4`;44{EbEb}:`775`5>>=5","D":"Mn","p":[[5,"PathBuf",312],[8,"Result",313],[5,"Config",6],[5,"MainlineConfig",6],[6,"BootstrapOption",6],[6,"Result",314],[10,"Deserializer",315],[5,"MetricsConfig",6],[5,"Formatter",316],[8,"Result",316],[5,"Path",312],[10,"AsRef",317],[10,"Serializer",318],[5,"TypeId",319],[5,"Private",320],[1,"unit"],[5,"DnsHandler",73],[5,"Request",321],[5,"Bytes",322],[5,"DnsConfig",73],[5,"Handle",73],[10,"Future",323],[5,"Box",324],[5,"Pin",325],[10,"ResponseHandler",326],[5,"DnsServer",73],[6,"SocketAddr",327],[5,"MessageResponse",328],[17,"Item"],[5,"Record",329],[10,"Iterator",330],[10,"Send",331],[6,"RateLimitConfig",145,332],[6,"CertMode",145,333],[5,"HttpConfig",145],[5,"HttpsConfig",145],[1,"bool"],[5,"Error",316],[5,"HttpServer",145],[6,"Option",334],[5,"AppState",296],[5,"String",335],[5,"Metrics",249],[1,"str"],[10,"Any",319],[1,"tuple"],[5,"IntoIter",336],[5,"Server",283]],"r":[[145,333],[152,332]],"b":[[181,"impl-Default-for-%26RateLimitConfig"],[182,"impl-Default-for-RateLimitConfig"],[193,"impl-Display-for-CertMode"],[194,"impl-Debug-for-CertMode"]],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAMkAGgAPAAcAGAAGACMAAwA1AAMAOgAPAE4AAgBTAA0AYwADAGsAAwB7AAEAfwASAJ0AAwCjAAkArgANAL0ACADLAAMA2wADAOEAGAD7AAwACQEEABABCwAdAQEAJQEDACoBBAAxAQAANAEEAA=="}],\ +["iroh_net_bench",{"t":"FGGGPPPFPPPPNNNNNNNNNNNNNNNNHONNNNNNNNNNHNONNNNNNNNNNNNNNNONNNNNNNNNNCOONCOHCCNOONNNNNNNNNNNNNNNNNNNNNONNNNNOSHHHHHHSHHHHHHFNNNNNNNNNNNNNNNNNNNNNNNNFFFONNNNNNOOOONNOONNNNNNNNNNNNNNONOOOHOOONNNNNNOONNNNNN","n":["ClientStats","Commands","ConnectionSelector","EndpointSelector","Iroh","Iroh","Iroh","Opt","Quinn","Quinn","Quinn","S2n","__clone_box","__clone_box","augment_args","augment_args_for_update","augment_subcommands","augment_subcommands_for_update","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","client_handler","clients","clone","clone","clone_into","clone_into","close","close","command","command","command_for_update","command_for_update","configure_tracing_subscriber","default","download_size","fmt","fmt","from","from","from","from","from","from_arg_matches","from_arg_matches","from_arg_matches_mut","from_arg_matches_mut","from_ref","from_ref","group_id","has_subcommand","initial_mtu","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","iroh","max_streams","metrics","print","quinn","read_unordered","rt","s2n","stats","stats","stats","streams","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","update_from_arg_matches","update_from_arg_matches","update_from_arg_matches_mut","update_from_arg_matches_mut","upload_size","vzip","vzip","vzip","vzip","vzip","with_relay","ALPN","client","connect_client","handle_client_stream","server","server_endpoint","transport_config","ALPN","client","connect_client","handle_client_stream","server","server_endpoint","transport_config","Opt","__clone_box","augment_args","augment_args_for_update","borrow","borrow_mut","clone","clone_into","command","command_for_update","fmt","from","from_arg_matches","from_arg_matches_mut","from_ref","group_id","into","into_arc_any","to_owned","try_from","try_into","type_id","update_from_arg_matches","update_from_arg_matches_mut","vzip","Stats","StreamStats","TransferResult","avg_chunk_size","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","chunk_size","chunk_time","chunks","chunks","default","default","duration","duration_hist","fmt","fmt","fmt","from","from","from","into","into","into","into_arc_any","into_arc_any","into_arc_any","new","print","size","stream_finished","stream_stats","streams","throughput","throughput_bps","throughput_hist","total_duration","total_size","try_from","try_from","try_from","try_into","try_into","try_into","ttfb","ttfb_hist","type_id","type_id","type_id","vzip","vzip","vzip"],"q":[[0,"iroh_net_bench"],[109,"iroh_net_bench::iroh"],[116,"iroh_net_bench::quinn"],[123,"iroh_net_bench::s2n"],[148,"iroh_net_bench::stats"],[203,"dyn_clone::sealed"],[204,"clap_builder::builder::command"],[205,"anyhow"],[206,"core::fmt"],[207,"clap_builder::parser::matches::arg_matches"],[208,"clap_builder"],[209,"core::result"],[210,"clap_builder::util::id"],[211,"core::option"],[212,"alloc::sync"],[213,"core::any"],[214,"tokio::runtime::runtime"],[215,"iroh_base::node_addr"],[216,"iroh_base::relay_url"],[217,"iroh::endpoint"],[218,"iroh_quinn::connection"],[219,"iroh_quinn_proto::config"],[220,"core::net::socket_addr"],[221,"iroh_quinn::endpoint"],[222,"core::time"]],"i":[0,0,0,0,4,5,9,0,4,5,9,9,9,6,6,6,9,9,4,5,9,6,7,4,5,9,6,7,0,6,9,6,9,6,4,5,9,6,9,6,0,7,6,9,6,4,5,9,6,7,9,6,9,6,9,6,6,9,6,4,5,9,6,7,4,5,9,6,7,0,6,6,7,0,6,0,0,0,5,6,6,9,6,4,5,9,6,7,4,5,9,6,7,4,5,9,6,7,9,6,9,6,6,4,5,9,6,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,0,0,0,33,39,40,33,39,40,33,40,40,40,33,39,40,33,40,39,40,33,39,40,33,39,40,33,39,40,33,33,39,33,39,39,39,33,0,40,39,39,39,40,33,39,40,33,33,40,39,40,33,39,40,33],"f":"````````````{{cb}d{}}0{ff}000{ce{}{}}000000000{{hjl}{{A`{n}}}}`{AbAb}{ll}{{ce}d{}{}}0{h{{A`{d}}}}{{jAd{Ah{Af}}}d}{{}f}000{{}d}{{}n}`{{AbAj}Al}{{lAj}Al}{cc{}}0000{An{{Bb{AbB`}}}}{An{{Bb{lB`}}}}1022{{}{{Bf{Bd}}}}{BhBj}`{ce{}{}}0000{{{Bl{c}}}{{Bl{Bn}}}{}}0000```{{nC`}d}``{{}Cb}``{jd}``44{c{{Bb{e}}}{}{}}000000000{cCd{}}0000{{AbAn}{{Bb{dB`}}}}{{lAn}{{Bb{dB`}}}}10`88888``{{Cf{Bf{Ch}}l}{{A`{n}}}}{{Cf{Bf{Ch}}l}{{A`{{Cn{CjCl}}}}}}{{ClD`Bj}{{A`{{Cn{DbDb}}}}}}{{Cjl}{{A`{d}}}}{{Cb{Bf{Ch}}l}{{Cn{CfCj}}}}{{C`Dd}Df}`{{Dhl}{{A`{n}}}}{{Dhl}{{A`{{Cn{DjCl}}}}}}5{{Djl}{{A`{d}}}}{{Cbl}{{Cn{DhDj}}}}4`{{cb}d{}}{ff}0{ce{}{}}0{DlDl}{{ce}d{}{}}{{}f}0{{DlAj}Al}{cc{}}{An{{Bb{DlB`}}}}01{{}{{Bf{Bd}}}}7{{{Bl{c}}}{{Bl{Bn}}}{}}8{c{{Bb{e}}}{}{}}0{cCd{}}{{DlAn}{{Bb{dB`}}}}0;````;;;;;;````{{}Dn}{{}E`}``{{DnAj}Al}{{E`Aj}Al}{{DbAj}Al};;;{ce{}{}}00999{{EbD`EbD`}Db}{{DnBh}d}`{{DnDb}d}```{{EbD`}Ed}```<<<<<<``;;;444","D":"Dj","p":[[5,"Private",203],[1,"unit"],[5,"Command",204],[6,"EndpointSelector",0],[6,"ConnectionSelector",0],[5,"Opt",0],[5,"ClientStats",0],[8,"Result",205],[6,"Commands",0],[1,"u32"],[1,"u8"],[1,"slice"],[5,"Formatter",206],[8,"Result",206],[5,"ArgMatches",207],[8,"Error",208],[6,"Result",209],[5,"Id",210],[6,"Option",211],[1,"str"],[1,"bool"],[5,"Arc",212],[10,"Any",213],[1,"usize"],[5,"Runtime",214],[5,"TypeId",213],[5,"NodeAddr",215],[5,"RelayUrl",216],[5,"Endpoint",217],[5,"Connection",218],[1,"tuple"],[1,"u64"],[5,"TransferResult",148],[1,"u16"],[5,"TransportConfig",219],[6,"SocketAddr",220],[5,"Endpoint",221],[5,"Opt",123],[5,"Stats",148],[5,"StreamStats",148],[5,"Duration",222],[1,"f64"]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAKYAEQAAABwAHwALACwAAQAzAAcAQQAFAEkAAQBMAAMAUgAUAGgABABuAAAAcQAAAHQAAQB4AAAAewALAIgAAwCNABwAsAAbAA=="}],\ +["iroh_net_report",{"t":"FFFFFNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOONNNNNOOOONNOONNHOOONOOOOOOOOOONNNNNNNNNNNNNNNNNNNNONNNNN","n":["Addr","Client","Metrics","RelayLatencies","Report","addr","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","captive_portal","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","default","default","default","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","get_report","get_report_channel","global_v4","global_v6","hair_pinning","icmpv4","icmpv6","into","into","into","into","into","ipv4","ipv4_can_send","ipv6","ipv6_can_send","iter","iter","mapping_varies_by_dest_ip","mapping_varies_by_dest_ipv6","name","new","os_has_ipv6","os_has_ipv6","portmap_probe","preferred_relay","receive_stun_packet","relay_latency","relay_v4_latency","relay_v6_latency","reports","reports_full","stun_packets_dropped","stun_packets_recv_ipv4","stun_packets_recv_ipv6","stun_packets_sent_ipv4","stun_packets_sent_ipv6","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","udp","vzip","vzip","vzip","vzip","vzip"],"q":[[0,"iroh_net_report"],[110,"iroh_net_report::metrics"],[111,"core::fmt"],[112,"iroh_base::relay_map"],[113,"netwatch::udp"],[114,"alloc::sync"],[115,"core::option"],[116,"anyhow"],[117,"tokio::sync::oneshot"],[118,"core::any"],[119,"alloc::vec::into_iter"],[120,"iroh_base::relay_url"],[121,"core::time"],[122,"core::iter::traits::iterator"],[123,"portmapper"],[124,"hickory_resolver::async_resolver"],[125,"bytes::bytes"],[126,"core::net::socket_addr"],[127,"alloc::string"],[128,"core::result"]],"i":[0,0,0,0,0,1,3,4,5,1,2,3,4,5,1,2,4,3,4,5,2,3,4,5,2,3,4,5,4,5,4,4,4,5,5,5,3,4,4,5,1,2,3,4,5,1,2,1,1,4,4,4,4,4,3,4,5,1,2,4,4,4,4,3,5,4,4,3,1,0,4,4,4,2,4,4,4,3,3,3,3,3,3,3,3,4,5,2,4,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,4,3,4,5,1,2],"f":"`````{bd}{ce{}{}}000000000`{ff}{hh}{jj}{dd}{{ce}l{}{}}000{{}f}{{}h}{{}j}{{hh}n}{{jj}n}{{ce}n{}{}}00000{{fA`}Ab}{{hA`}Ab}0{{jA`}Ab}{{bA`}Ab}{{dA`}Ab}{cc{}}0000{{bAd{Aj{{Ah{Af}}}}{Aj{{Ah{Af}}}}}{{Al{{Ah{h}}}}}}{{bAd{Aj{{Ah{Af}}}}{Aj{{Ah{Af}}}}}{{Al{{An{{Al{{Ah{h}}}}}}}}}}`````{ce{}{}}0000````{f{{Bf{{Bd{B`Bb}}}}}}{j{{`{{Bn{}{{Bh{{Bd{BjBl}}}}}}}}}}``{{}B`}{{{Aj{C`}}Cb}{{Al{b}}}}{{}n}```{{dCdCf}l}``````````6666{cCh{}}{c{{Cj{e}}}{}{}}000000000{cCl{}}0000`99999","D":"Ed","p":[[5,"Client",0],[5,"Addr",0],[5,"Metrics",0,110],[5,"Report",0],[5,"RelayLatencies",0],[1,"unit"],[1,"bool"],[5,"Formatter",111],[8,"Result",111],[5,"RelayMap",112],[5,"UdpSocket",113],[5,"Arc",114],[6,"Option",115],[8,"Result",116],[5,"Receiver",117],[1,"str"],[10,"Any",118],[1,"tuple"],[5,"IntoIter",119],[17,"Item"],[5,"RelayUrl",120],[5,"Duration",121],[10,"Iterator",122],[5,"Client",123],[8,"TokioAsyncResolver",124],[5,"Bytes",125],[6,"SocketAddr",126],[5,"String",127],[6,"Result",128],[5,"TypeId",118]],"r":[[2,110]],"b":[[37,"impl-Debug-for-Report"],[38,"impl-Display-for-Report"]],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAEQABgAHAAkAEgAYAEAAAABEAAAATgAaAGoABAA="}],\ +["iroh_node_util",{"t":"CCCHCCCCPPGPPPNNNNNNNNNNNNNNNNNNNNNNNOOOOGPPPNNNNNNNNNNNNNNNNNNNNNNNOHHHHPFFPPGNNNNNNNNNNNNNNNNNNNNNOHNNNNNNNNNNNNNNNNNNNNNNNHHNNNNNNOOONNNNNNNNNNNNNNNNNNNCCCCCFFNNONNNNNNNNNNNNNNNNNONNNNNONNNNNNNNONNFNNNNNNNNNNNNNNNNNNNPPPPGGFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNCCNNNNNNNNNNNNNNNPFPPFPPFFPPFPPFFPPFFGGPPPFNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOONNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNFGGPPFPPFFPPFNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNKMHNMN","n":["cli","config","fs","load_secret_key","logging","rpc","net","node","AddNodeAddr","HomeRelay","NetCommands","NodeAddr","Remote","RemoteList","__clone_box","augment_subcommands","augment_subcommands_for_update","borrow","borrow_mut","clone","clone_into","fmt","from","from_arg_matches","from_arg_matches_mut","from_ref","has_subcommand","into","into_arc_any","run","to_owned","try_from","try_into","type_id","update_from_arg_matches","update_from_arg_matches_mut","vzip","addresses","node_id","node_id","relay","NodeCommands","Shutdown","Stats","Status","__clone_box","augment_subcommands","augment_subcommands_for_update","borrow","borrow_mut","clone","clone_into","fmt","from","from_arg_matches","from_arg_matches_mut","from_ref","has_subcommand","into","into_arc_any","run","to_owned","try_from","try_into","type_id","update_from_arg_matches","update_from_arg_matches_mut","vzip","force","cache_root","config_root","data_root","load_secret_key","Daily","EnvFilter","FileLogging","Hourly","Never","Rotation","__clone_box","__clone_box","__clone_box","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","default","default","default","deserialize","deserialize","deserialize","dir","env_file_rust_log","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","from","from","from","from_ref","from_ref","from_ref","from_str","init_terminal_and_file_logging","init_terminal_logging","into","into","into","into_arc_any","into_arc_any","into_arc_any","max_files","rotation","rust_log","serialize","serialize","serialize","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","client","proto","server","net","node","Client","NodeStatus","__clone_box","add_node_addr","addr","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","deserialize","fmt","fmt","from","from","from_ref","home_relay","into","into","into_arc_any","into_arc_any","listen_addrs","new","node_addr","node_id","remote_info","remote_info_iter","rpc_addr","serialize","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","version","vzip","vzip","Client","__clone_box","borrow","borrow_mut","clone","clone_into","fmt","from","from_ref","into","into_arc_any","new","shutdown","stats","status","to_owned","try_from","try_into","type_id","vzip","Net","Net","Node","Node","Request","Response","RpcService","__clone_box","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","deserialize","deserialize","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_ref","into","into","into","into_arc_any","into_arc_any","into_arc_any","net","node","serialize","serialize","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","AddAddr","AddAddrRequest","Addr","Addr","AddrRequest","Id","Id","IdRequest","NodeWatchRequest","Relay","Relay","RelayRequest","RemoteInfo","RemoteInfo","RemoteInfoRequest","RemoteInfoResponse","RemoteInfosIter","RemoteInfosIter","RemoteInfosIterRequest","RemoteInfosIterResponse","Request","Response","Unit","Watch","Watch","WatchResponse","__clone_box","addr","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_ref","info","info","into","into","into","into","into","into","into","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","node_id","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","to_owned","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","version","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","CounterStats","Request","Response","Shutdown","Shutdown","ShutdownRequest","Stats","Stats","StatsRequest","StatsResponse","Status","Status","StatusRequest","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","description","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","force","from","from","from","from","from","from","from","from","from","from","from","from","from","into","into","into","into","into","into","into","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","into_arc_any","serialize","serialize","serialize","serialize","serialize","serialize","serialize","stats","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","value","vzip","vzip","vzip","vzip","vzip","vzip","vzip","AbstractNode","endpoint","handle_rpc_request","rpc_addr","shutdown","stats"],"q":[[0,"iroh_node_util"],[6,"iroh_node_util::cli"],[8,"iroh_node_util::cli::net"],[37,"iroh_node_util::cli::net::NetCommands"],[41,"iroh_node_util::cli::node"],[68,"iroh_node_util::cli::node::NodeCommands"],[69,"iroh_node_util::config"],[72,"iroh_node_util::fs"],[73,"iroh_node_util::logging"],[155,"iroh_node_util::rpc"],[158,"iroh_node_util::rpc::client"],[160,"iroh_node_util::rpc::client::net"],[200,"iroh_node_util::rpc::client::node"],[220,"iroh_node_util::rpc::proto"],[292,"iroh_node_util::rpc::proto::net"],[526,"iroh_node_util::rpc::proto::node"],[653,"iroh_node_util::rpc::server"],[659,"std::path"],[660,"iroh_base::key"],[661,"anyhow"],[662,"dyn_clone::sealed"],[663,"clap_builder::builder::command"],[664,"core::fmt"],[665,"clap_builder::parser::matches::arg_matches"],[666,"clap_builder"],[667,"core::result"],[668,"alloc::sync"],[669,"core::any"],[670,"serde::de"],[671,"core::option"],[672,"tracing_appender::non_blocking"],[673,"serde::ser"],[674,"alloc::string"],[675,"iroh_base::node_addr"],[676,"iroh_base::relay_url"],[677,"quic_rpc::client"],[678,"iroh::magicsock::node_map::node_state"],[679,"futures_core::stream"],[680,"alloc::collections::btree::map"],[681,"serde_error"],[682,"iroh::endpoint"],[683,"quic_rpc::server"],[684,"core::net::socket_addr"]],"i":[0,0,0,0,0,0,0,0,7,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,69,70,69,69,0,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,71,0,0,0,0,23,0,0,23,23,0,21,22,23,21,22,23,21,22,23,21,22,23,21,22,23,21,22,23,21,22,23,21,0,21,22,23,21,21,21,22,22,22,23,23,23,21,22,22,23,21,22,23,21,22,23,22,0,0,21,22,23,21,22,23,21,21,21,21,22,23,21,22,23,22,21,22,23,21,22,23,21,22,23,21,22,23,0,0,0,0,0,0,0,17,17,31,17,31,17,31,17,17,31,17,31,17,31,17,17,17,31,17,31,31,17,17,17,17,17,31,31,17,17,31,17,31,17,31,31,17,31,0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,41,42,41,42,0,0,0,33,41,42,33,41,42,33,33,33,41,42,41,42,33,41,41,41,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,33,33,41,42,33,41,42,33,0,0,41,42,33,41,42,33,41,42,33,41,42,33,41,42,33,49,0,49,60,0,49,60,0,0,49,60,0,49,60,0,0,49,60,0,0,0,0,60,49,60,0,47,43,49,60,46,61,47,55,51,50,43,53,45,58,49,60,46,61,47,55,51,50,43,53,45,58,47,47,49,60,46,61,47,55,51,50,43,53,45,58,49,49,60,60,46,61,47,55,51,50,43,53,45,58,49,49,49,49,49,49,49,49,60,60,60,60,60,60,60,60,46,61,47,55,51,50,43,53,45,58,47,61,55,49,60,46,61,47,55,51,50,43,53,45,58,49,60,46,61,47,55,51,50,43,53,45,58,47,49,60,46,61,47,55,51,50,43,53,45,58,47,49,60,49,49,49,60,60,60,46,46,46,46,46,61,47,47,47,47,47,55,51,51,51,51,51,50,50,50,50,50,43,43,43,43,43,53,53,53,53,53,45,45,45,45,45,58,58,58,58,58,49,60,46,61,47,55,51,50,43,53,45,58,49,60,46,61,47,55,51,50,43,53,45,58,58,49,60,46,61,47,55,51,50,43,53,45,58,0,0,0,44,59,0,44,59,0,0,44,59,0,44,59,48,54,52,39,57,44,59,48,54,52,39,57,39,44,59,48,54,52,39,57,44,44,59,59,48,54,52,39,57,48,44,44,44,44,59,59,59,59,48,54,52,39,57,44,59,48,54,52,39,57,44,59,48,54,52,39,57,44,59,48,54,52,39,57,57,44,59,44,44,44,59,59,59,48,48,48,48,48,54,54,54,54,54,52,52,52,52,52,39,57,44,59,48,54,52,39,57,44,59,48,54,52,39,57,39,44,59,48,54,52,39,57,0,63,0,63,63,63],"f":"```{b{{f{d}}}}``````````{{ch}j{}}{ll}0{ce{}{}}0{nn}{{ce}j{}{}}{{nA`}Ab}{cc{}}{Ad{{Ah{nAf}}}}01{AjAl}6{{{An{c}}}{{An{B`}}}{}}{{nBb}{{f{j}}}}8{c{{Ah{e}}}{}{}}0{cBd{}}{{nAd}{{Ah{jAf}}}}0;````````=<<;;{BfBf}:{{BfA`}Ab}9{Ad{{Ah{BfAf}}}}0:8>7{{BfBh}{{f{j}}}}?665{{BfAd}{{Ah{jAf}}}}0{ce{}{}}`{Aj{{f{b}}}}00{b{{f{d}}}}``````{{ch}j{}}00333333{BjBj}{BlBl}{BnBn}{{ce}j{}{}}00{{}Bj}{{}Bl}{{}Bn}{c{{Ah{Bj}}}C`}{c{{Ah{Bl}}}C`}{c{{Ah{Bn}}}C`}`{Aj{{Cb{{f{Bl}}}}}}{{BjBj}Al}{{BlBl}Al}{{BnBn}Al}{{ce}Al{}{}}00000000{{BjA`}Ab}{{BlA`}Ab}0{{BnA`}Ab}{cc{}}00000{Aj{{Ah{Blc}}}{}}{{BjCd}{{f{Cf}}}}{{}{{f{j}}}}{ce{}{}}00{{{An{c}}}{{An{B`}}}{}}00```{{Bjc}AhCh}{{Blc}AhCh}{{Bnc}AhCh}444{cCj{}}{c{{Ah{e}}}{}{}}00000{cBd{}}00777```````{{ch}j{}}{{BbCl}{{f{j}}}}`9999{BbBb}{{ce}j{}{}}{c{{Ah{Cn}}}C`}{{BbA`}Ab}{{CnA`}Ab}{cc{}}00{Bb{{f{{Cb{D`}}}}}}{ce{}{}}0{{{An{c}}}{{An{B`}}}{}}0`{{{Dd{Db}}}Bb}{Bb{{f{Cl}}}}{Bb{{f{Df}}}}{{BbDf}{{f{{Cb{Dh}}}}}}{Bb{{f{{`{{Dl{}{{Dj{{f{Dh}}}}}}}}}}}}`{{Cnc}AhCh}7{c{{Ah{e}}}{}{}}000{cBd{}}0`99`{{ch}j{}}::{BhBh}{{ce}j{}{}}{{BhA`}Ab}??=<{{{Dd{Db}}}Bh}{{BhAl}{{f{j}}}}{Bh{{f{{E`{CjDn}}}}}}{Bh{{f{Cn}}}}{ce{}{}}::90```````8000000{DbDb}7{c{{Ah{Eb}}}C`}{c{{Ah{Ed}}}C`}{{EbA`}Ab}{{EdA`}Ab}{{DbA`}Ab}{EfEb}{EhEb}{EjEb}{ElEb}{EnEb}{F`Eb}{FbEb}{FdEb}{FfEb}{FhEb}{FjEb}{cc{}}{FlEb}{{{Ah{FnG`}}}Ed}{{{Ah{ClG`}}}Ed}{{{Ah{GbG`}}}Ed}{GdEd}{jEd}6{{{Ah{jG`}}}Ed}{{{Ah{{Cb{D`}}G`}}}Ed}{GfEd}{GhEd}{{{Ah{DfG`}}}Ed}{{{Ah{GjG`}}}Ed}{{{Ah{CnG`}}}Ed}=={ce{}{}}00{{{An{c}}}{{An{B`}}}{}}00``{{Ebc}AhCh}{{Edc}AhCh}3{c{{Ah{e}}}{}{}}00000{cBd{}}00555``````````````````````````{{ch}j{}}`666666666666666666666666{EnEn}{{ce}j{}{}}{c{{Ah{Fb}}}C`}{c{{Ah{Gh}}}C`}{c{{Ah{El}}}C`}{c{{Ah{Gj}}}C`}{c{{Ah{En}}}C`}{c{{Ah{Fn}}}C`}{c{{Ah{Ff}}}C`}{c{{Ah{Fd}}}C`}{c{{Ah{Ef}}}C`}{c{{Ah{Fj}}}C`}{c{{Ah{Ej}}}C`}{c{{Ah{Gd}}}C`}{{FbA`}{{Ah{jGl}}}}{{FbA`}Ab}{{GhA`}{{Ah{jGl}}}}{{GhA`}Ab}{{ElA`}Ab}{{GjA`}Ab}{{EnA`}Ab}{{FnA`}Ab}{{FfA`}Ab}{{FdA`}Ab}{{EfA`}Ab}{{FjA`}Ab}{{EjA`}Ab}{{GdA`}Ab}{ElFb}{EnFb}{cc{}}{FfFb}{FjFb}{FdFb}{EjFb}{EfFb}{GdGh}{{{Ah{jG`}}}Gh}{{{Ah{ClG`}}}Gh}{{{Ah{FnG`}}}Gh}{{{Ah{{Cb{D`}}G`}}}Gh}{{{Ah{DfG`}}}Gh};{{{Ah{GjG`}}}Gh}<<<<<<<<<<<``{ce{}{}}00000000000{{{An{c}}}{{An{B`}}}{}}00000000000`{{Fbc}AhCh}{{Ghc}AhCh}{{Elc}AhCh}{{Gjc}AhCh}{{Enc}AhCh}{{Fnc}AhCh}{{Ffc}AhCh}{{Fdc}AhCh}{{Efc}AhCh}{{Fjc}AhCh}{{Ejc}AhCh}{{Gdc}AhCh}={cCj{}}0{Eb{{Ah{Fbc}}}{}}{c{{Ah{e}}}{}{}}1{Ed{{Ah{Ghc}}}{}}01{Eb{{Ah{Elc}}}{}}2{Fb{{Ah{Elc}}}{}}103{Eb{{Ah{Enc}}}{}}{Fb{{Ah{Enc}}}{}}0155{Fb{{Ah{Ffc}}}{}}{Eb{{Ah{Ffc}}}{}}071{Eb{{Ah{Fdc}}}{}}8{Fb{{Ah{Fdc}}}{}}10{Eb{{Ah{Efc}}}{}}:{Fb{{Ah{Efc}}}{}}10{Fb{{Ah{Fjc}}}{}}{Eb{{Ah{Fjc}}}{}}=10{Fb{{Ah{Ejc}}}{}}{Eb{{Ah{Ejc}}}{}}1?0{Gh{{Ah{Gdc}}}{}}{Ed{{Ah{Gdc}}}{}}{c{{Ah{e}}}{}{}}21000000000000{cBd{}}00000000000`{ce{}{}}00000000000`````````````00000000000000`{c{{Ah{Eh}}}C`}{c{{Ah{Gf}}}C`}{c{{Ah{F`}}}C`}{c{{Ah{Fl}}}C`}{c{{Ah{Fh}}}C`}{c{{Ah{Dn}}}C`}{c{{Ah{Gb}}}C`}{{EhA`}{{Ah{jGl}}}}{{EhA`}Ab}{{GfA`}Ab}{{GfA`}{{Ah{jGl}}}}{{F`A`}Ab}{{FlA`}Ab}{{FhA`}Ab}{{DnA`}Ab}{{GbA`}Ab}`{cc{}}{FhEh}{FlEh}{F`Eh}{{{Ah{GbG`}}}Gf}{{{Ah{CnG`}}}Gf}{jGf}666666{ce{}{}}000000{{{An{c}}}{{An{B`}}}{}}000000{{Ehc}AhCh}{{Gfc}AhCh}{{F`c}AhCh}{{Flc}AhCh}{{Fhc}AhCh}{{Dnc}AhCh}{{Gbc}AhCh}`{cCj{}}0{c{{Ah{e}}}{}{}}{Eb{{Ah{Ehc}}}{}}0{Ed{{Ah{Gfc}}}{}}022{Eh{{Ah{F`c}}}{}}{Eb{{Ah{F`c}}}{}}104{Eb{{Ah{Flc}}}{}}{Eh{{Ah{Flc}}}{}}01{Eh{{Ah{Fhc}}}{}}{Eb{{Ah{Fhc}}}{}}801888888888{cBd{}}000000`{ce{}{}}000000`{GnH`}{{{An{Gn}}Eb{Hb{Dbc}}}{{f{j{Hd{c}}}}}{{Hf{Db}}}}{Gn{{Cb{Hh}}}}{Gnj}{Gn{{f{{E`{CjDn}}}}}}","D":"ABl","p":[[5,"PathBuf",659],[5,"SecretKey",660],[8,"Result",661],[5,"Private",662],[1,"unit"],[5,"Command",663],[6,"NetCommands",8],[5,"Formatter",664],[8,"Result",664],[5,"ArgMatches",665],[8,"Error",666],[6,"Result",667],[1,"str"],[1,"bool"],[5,"Arc",668],[10,"Any",669],[5,"Client",160],[5,"TypeId",669],[6,"NodeCommands",41],[5,"Client",200],[5,"FileLogging",73],[5,"EnvFilter",73],[6,"Rotation",73],[10,"Deserializer",670],[6,"Option",671],[5,"Path",659],[5,"WorkerGuard",672],[10,"Serializer",673],[5,"String",674],[5,"NodeAddr",675],[5,"NodeStatus",160],[5,"RelayUrl",676],[5,"RpcService",220],[5,"RpcClient",677],[8,"NodeId",660],[5,"RemoteInfo",678],[17,"Item"],[10,"Stream",679],[5,"CounterStats",526],[5,"BTreeMap",680],[6,"Request",220],[6,"Response",220],[5,"AddAddrRequest",292],[6,"Request",526],[5,"NodeWatchRequest",292],[5,"RemoteInfosIterRequest",292],[5,"RemoteInfoRequest",292],[5,"ShutdownRequest",526],[6,"Request",292],[5,"AddrRequest",292],[5,"IdRequest",292],[5,"StatsRequest",526],[5,"RelayRequest",292],[5,"StatusRequest",526],[5,"RemoteInfoResponse",292],[5,"Error",681],[5,"StatsResponse",526],[5,"WatchResponse",292],[6,"Response",526],[6,"Response",292],[5,"RemoteInfosIterResponse",292],[5,"Error",664],[10,"AbstractNode",653],[5,"Endpoint",682],[5,"RpcChannel",683],[6,"RpcServerError",683],[10,"ChannelTypes",683],[6,"SocketAddr",684],[15,"AddNodeAddr",37],[15,"Remote",37],[15,"Shutdown",68]],"r":[],"b":[[115,"impl-Debug-for-EnvFilter"],[116,"impl-Display-for-EnvFilter"],[241,"impl-From%3CAddAddrRequest%3E-for-Request"],[242,"impl-From%3CRequest%3E-for-Request"],[243,"impl-From%3CNodeWatchRequest%3E-for-Request"],[244,"impl-From%3CRemoteInfosIterRequest%3E-for-Request"],[245,"impl-From%3CRemoteInfoRequest%3E-for-Request"],[246,"impl-From%3CShutdownRequest%3E-for-Request"],[247,"impl-From%3CRequest%3E-for-Request"],[248,"impl-From%3CAddrRequest%3E-for-Request"],[249,"impl-From%3CIdRequest%3E-for-Request"],[250,"impl-From%3CStatsRequest%3E-for-Request"],[251,"impl-From%3CRelayRequest%3E-for-Request"],[253,"impl-From%3CStatusRequest%3E-for-Request"],[254,"impl-From%3CResult%3CRemoteInfoResponse,+Error%3E%3E-for-Response"],[255,"impl-From%3CResult%3CNodeAddr,+Error%3E%3E-for-Response"],[256,"impl-From%3CResult%3CStatsResponse,+Error%3E%3E-for-Response"],[257,"impl-From%3CWatchResponse%3E-for-Response"],[258,"impl-From%3C()%3E-for-Response"],[260,"impl-From%3CResult%3C(),+Error%3E%3E-for-Response"],[261,"impl-From%3CResult%3COption%3CRelayUrl%3E,+Error%3E%3E-for-Response"],[262,"impl-From%3CResponse%3E-for-Response"],[263,"impl-From%3CResponse%3E-for-Response"],[264,"impl-From%3CResult%3CPublicKey,+Error%3E%3E-for-Response"],[265,"impl-From%3CResult%3CRemoteInfosIterResponse,+Error%3E%3E-for-Response"],[266,"impl-From%3CResult%3CNodeStatus,+Error%3E%3E-for-Response"],[358,"impl-Display-for-Request"],[359,"impl-Debug-for-Request"],[360,"impl-Display-for-Response"],[361,"impl-Debug-for-Response"],[372,"impl-From%3CRemoteInfosIterRequest%3E-for-Request"],[373,"impl-From%3CRemoteInfoRequest%3E-for-Request"],[375,"impl-From%3CIdRequest%3E-for-Request"],[376,"impl-From%3CRelayRequest%3E-for-Request"],[377,"impl-From%3CAddrRequest%3E-for-Request"],[378,"impl-From%3CNodeWatchRequest%3E-for-Request"],[379,"impl-From%3CAddAddrRequest%3E-for-Request"],[380,"impl-From%3CWatchResponse%3E-for-Response"],[381,"impl-From%3CResult%3C(),+Error%3E%3E-for-Response"],[382,"impl-From%3CResult%3CNodeAddr,+Error%3E%3E-for-Response"],[383,"impl-From%3CResult%3CRemoteInfoResponse,+Error%3E%3E-for-Response"],[384,"impl-From%3CResult%3COption%3CRelayUrl%3E,+Error%3E%3E-for-Response"],[385,"impl-From%3CResult%3CPublicKey,+Error%3E%3E-for-Response"],[387,"impl-From%3CResult%3CRemoteInfosIterResponse,+Error%3E%3E-for-Response"],[441,"impl-TryFrom%3CRequest%3E-for-Request"],[443,"impl-TryFrom%3C%26Request%3E-for-%26Request"],[444,"impl-TryFrom%3C%26Response%3E-for-%26Response"],[445,"impl-TryFrom%3CResponse%3E-for-Response"],[447,"impl-TryFrom%3C%26Request%3E-for-%26RemoteInfosIterRequest"],[449,"impl-TryFrom%3CRequest%3E-for-RemoteInfosIterRequest"],[450,"impl-TryFrom%3CRequest%3E-for-RemoteInfosIterRequest"],[451,"impl-TryFrom%3C%26Request%3E-for-%26RemoteInfosIterRequest"],[453,"impl-TryFrom%3CRequest%3E-for-RemoteInfoRequest"],[454,"impl-TryFrom%3C%26Request%3E-for-%26RemoteInfoRequest"],[455,"impl-TryFrom%3CRequest%3E-for-RemoteInfoRequest"],[456,"impl-TryFrom%3C%26Request%3E-for-%26RemoteInfoRequest"],[459,"impl-TryFrom%3CRequest%3E-for-IdRequest"],[460,"impl-TryFrom%3CRequest%3E-for-IdRequest"],[461,"impl-TryFrom%3C%26Request%3E-for-%26IdRequest"],[463,"impl-TryFrom%3C%26Request%3E-for-%26IdRequest"],[464,"impl-TryFrom%3CRequest%3E-for-AddrRequest"],[466,"impl-TryFrom%3C%26Request%3E-for-%26AddrRequest"],[467,"impl-TryFrom%3C%26Request%3E-for-%26AddrRequest"],[468,"impl-TryFrom%3CRequest%3E-for-AddrRequest"],[469,"impl-TryFrom%3CRequest%3E-for-AddAddrRequest"],[471,"impl-TryFrom%3CRequest%3E-for-AddAddrRequest"],[472,"impl-TryFrom%3C%26Request%3E-for-%26AddAddrRequest"],[473,"impl-TryFrom%3C%26Request%3E-for-%26AddAddrRequest"],[474,"impl-TryFrom%3C%26Request%3E-for-%26RelayRequest"],[475,"impl-TryFrom%3C%26Request%3E-for-%26RelayRequest"],[477,"impl-TryFrom%3CRequest%3E-for-RelayRequest"],[478,"impl-TryFrom%3CRequest%3E-for-RelayRequest"],[479,"impl-TryFrom%3C%26Request%3E-for-%26NodeWatchRequest"],[480,"impl-TryFrom%3CRequest%3E-for-NodeWatchRequest"],[481,"impl-TryFrom%3CRequest%3E-for-NodeWatchRequest"],[483,"impl-TryFrom%3C%26Request%3E-for-%26NodeWatchRequest"],[484,"impl-TryFrom%3CResponse%3E-for-WatchResponse"],[485,"impl-TryFrom%3C%26Response%3E-for-%26WatchResponse"],[487,"impl-TryFrom%3C%26Response%3E-for-%26WatchResponse"],[488,"impl-TryFrom%3CResponse%3E-for-WatchResponse"],[561,"impl-Display-for-Request"],[562,"impl-Debug-for-Request"],[563,"impl-Debug-for-Response"],[564,"impl-Display-for-Response"],[572,"impl-From%3CStatsRequest%3E-for-Request"],[573,"impl-From%3CStatusRequest%3E-for-Request"],[574,"impl-From%3CShutdownRequest%3E-for-Request"],[575,"impl-From%3CResult%3CStatsResponse,+Error%3E%3E-for-Response"],[576,"impl-From%3CResult%3CNodeStatus,+Error%3E%3E-for-Response"],[577,"impl-From%3C()%3E-for-Response"],[609,"impl-TryFrom%3C%26Request%3E-for-%26Request"],[610,"impl-TryFrom%3CRequest%3E-for-Request"],[611,"impl-TryFrom%3C%26Response%3E-for-%26Response"],[612,"impl-TryFrom%3CResponse%3E-for-Response"],[615,"impl-TryFrom%3CRequest%3E-for-ShutdownRequest"],[616,"impl-TryFrom%3C%26Request%3E-for-%26ShutdownRequest"],[617,"impl-TryFrom%3C%26Request%3E-for-%26ShutdownRequest"],[618,"impl-TryFrom%3CRequest%3E-for-ShutdownRequest"],[620,"impl-TryFrom%3CRequest%3E-for-StatusRequest"],[621,"impl-TryFrom%3C%26Request%3E-for-%26StatusRequest"],[622,"impl-TryFrom%3CRequest%3E-for-StatusRequest"],[623,"impl-TryFrom%3C%26Request%3E-for-%26StatusRequest"],[624,"impl-TryFrom%3C%26Request%3E-for-%26StatsRequest"],[625,"impl-TryFrom%3CRequest%3E-for-StatsRequest"],[627,"impl-TryFrom%3C%26Request%3E-for-%26StatsRequest"],[628,"impl-TryFrom%3CRequest%3E-for-StatsRequest"]],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAP0BMgAPAAcAGAADAB0AAAAfAAoALgAHADcAAwA8AAAAPgAGAEoAAABNAAEAUAAUAGcADwB6AAMAgwACAIkAEgCjAAAApgAIALEAAAC1AAEAvgAHAMcAAQDKAAUA0QAAANMAAADYAAgA5AAYAP4ABQAFAQYADQEAABEBAgAWARUALgEEADUBAQA5AQQAPwE3AHgBCgCEAQAAjwEAAJ4BCwCrAVYAAwILABACAwAVAgEAGQIBABwCDQArAg8APQIFAFACDQBfAiYAhwIGAA=="}],\ +["iroh_relay",{"t":"PEEEEPEPPPGPFFPNNNNNNCNNNNNNNNNCNNNNNNNNNNNNNNNNNNNNCNNNNNNNCCNNNNCNNNNNNNNNNNNNNNNOOOOOPPPFFGFPPPPPPPPPPPPPPPPPPPPPPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNSSSSSGSSPPNNNNNNNNNNNNNNNNNNCCCSHSPGPPPPPPPPGFPPPPPPPPPPPGFPFPPPPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNHNNNNNNNNNNNNNNNNCHHNHHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNSSSSSSFNNNNNNNNNNNGFPFPGFPFFFFFFPFOOOOOONNNNNNNNNNNNNNNNNNNNNNNNOOOONONNNNNNONNNNOOOOOONNNNNNNNNNNNONNNNNNNNNNNNONONNONNNNNNNNNNNNNOONNOOONNOOONNNNNONOOOOOOOOONNONNCONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOONNNNNNNNNNNNOOOHHHHHH","n":["Health","HttpClient","HttpClientBuilder","HttpClientError","HttpClientReceiver","KeepAlive","MAX_PACKET_SIZE","NodeGone","Ping","Pong","ReceivedMessage","ReceivedPacket","RelayConn","RelayUrl","ServerRestarting","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","client","clone","clone","clone","clone_into","clone_into","clone_into","close","cmp","compare","defaults","deref","deserialize","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","from","from","from","from","from_str","hash","http","into","into","into","is_closed","local_addr","note_preferred","partial_cmp","protos","quic","send","send_ping","send_pong","serialize","server","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","data","problem","reconnect_in","source","try_for","ActorGone","Build","CannotAckPings","Client","ClientBuilder","ClientError","ClientReceiver","Closed","ConnectTimeout","DialIO","DialTask","Dns","DnsTimeout","Http","Hyper","IPDisabled","InvalidUrl","NoClient","NoLocalAddr","NoNodeForTarget","PingAborted","PingTimeout","Proxy","Receive","RelayNodeNotAvail","Send","StunOnlyNodesFound","UnexpectedStatusCode","Upgrade","WebsocketError","address_family_selector","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","build","can_ack_pings","clone","clone_into","close","close_for_reconnect","connect","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","insecure_skip_cert_verify","into","into","into","into","is_connected","is_preferred","is_prober","local_addr","new","note_preferred","ping","protocol","proxy_url","public_key","recv","send","send_pong","server_public_key","server_url","source","to_owned","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","DEFAULT_HTTPS_PORT","DEFAULT_HTTP_PORT","DEFAULT_METRICS_PORT","DEFAULT_RELAY_QUIC_PORT","DEFAULT_STUN_PORT","Protocol","RELAY_PATH","RELAY_PROBE_PATH","Relay","Websocket","borrow","borrow_mut","clone","clone_into","eq","equivalent","equivalent","equivalent","fmt","from","into","parse_header","to_owned","try_from","try_into","type_id","upgrade_header","vzip","disco","relay","stun","MAGIC","looks_like_disco_wrapper","MAX_PACKET_SIZE","AlternateServer","Error","ErrorCode","ErrorResponse","Fingerprint","Indication","InvalidFingerprint","InvalidMessage","MalformedAttrs","MappedAddress","MessageClass","MessageDecoder","MessageIntegrity","MessageIntegritySha256","NoFingerprint","Nonce","NotBinding","NotSuccessResponse","PasswordAlgorithm","PasswordAlgorithms","Realm","Request","Software","StunAttribute","StunDecodeError","SuccessResponse","TransactionId","Unknown","UnknownAttributes","UserHash","UserName","XorMappedAddress","as_alternate_server","as_bytes","as_error_code","as_fingerprint","as_mapped_address","as_message_integrity","as_message_integrity_sha256","as_nonce","as_password_algorithm","as_password_algorithms","as_realm","as_ref","as_software","as_unknown","as_unknown_attributes","as_user_hash","as_user_name","as_xor_mapped_address","attribute_type","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","cmp","compare","decode","default","default","deref","encode_hex","encode_hex_upper","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","expect_alternate_server","expect_error_code","expect_fingerprint","expect_mapped_address","expect_message_integrity","expect_message_integrity_sha256","expect_nonce","expect_password_algorithm","expect_password_algorithms","expect_realm","expect_software","expect_unknown","expect_unknown_attributes","expect_user_hash","expect_user_name","expect_xor_mapped_address","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","get_context","hash","into","into","into","into","into","into","is","is_alternate_server","is_error_code","is_fingerprint","is_mapped_address","is_message_integrity","is_message_integrity_sha256","is_nonce","is_password_algorithm","is_password_algorithms","is_realm","is_software","is_unknown","is_unknown_attributes","is_user_hash","is_user_name","is_xor_mapped_address","methods","parse_binding_request","parse_response","partial_cmp","request","response","to_owned","to_owned","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","BINDING","RESERVED","SHARED_SECRET","ALPN_QUIC_ADDR_DISC","QUIC_ADDR_DISC_CLOSE_CODE","QUIC_ADDR_DISC_CLOSE_REASON","QuicClient","borrow","borrow_mut","fmt","from","get_addr_and_latency","into","new","try_from","try_into","type_id","vzip","CertConfig","ClientConnRateLimit","LetsEncrypt","Limits","Manual","MaybeTlsStreamServer","Metrics","Plain","QuicConfig","RelayConfig","Server","ServerConfig","StunConfig","StunMetrics","Tls","TlsConfig","accept_conn_burst","accept_conn_limit","accepts","bad_requests","bind_addr","bind_addr","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","bytes_per_second","bytes_recv","bytes_sent","cert","certificates","client_rx","clone","clone","clone","clone_into","clone_into","clone_into","conns_rx_ratelimited_total","default","default","default","default","derp_accepts","disco_packets_dropped","disco_packets_recv","disco_packets_sent","disconnects","failures","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","frames_rx_ratelimited_total","from","from","from","from","from","from","from","from","from","from","from","from","got_ping","http_addr","http_bind_addr","http_url","https_addr","https_bind_addr","https_url","into","into","into","into","into","into","into","into","into","into","into","into","ipv4_success","ipv6_success","iter","iter","limits","max_burst_bytes","metrics_addr","name","name","other_packets_dropped","other_packets_recv","other_packets_sent","poll_flush","poll_read","poll_shutdown","poll_write","poll_write_vectored","quic","quic_addr","quic_bind_addr","relay","requests","send_packets_dropped","send_packets_recv","send_packets_sent","sent_pong","server_config","server_config","shutdown","spawn","stun","stun_addr","task_handle","testing","tls","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","unique_client_keys","unknown_frames","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","websocket_accepts","certs","state","quic_config","relay_config","self_signed_tls_certs_and_config","server_config","stun_config","tls_config"],"q":[[0,"iroh_relay"],[83,"iroh_relay::ReceivedMessage"],[88,"iroh_relay::client"],[187,"iroh_relay::defaults"],[192,"iroh_relay::http"],[215,"iroh_relay::protos"],[218,"iroh_relay::protos::disco"],[220,"iroh_relay::protos::relay"],[221,"iroh_relay::protos::stun"],[420,"iroh_relay::protos::stun::methods"],[423,"iroh_relay::quic"],[438,"iroh_relay::server"],[640,"iroh_relay::server::CertConfig"],[642,"iroh_relay::server::testing"],[648,"iroh_base::relay_url"],[649,"iroh_relay::client::conn"],[650,"core::cmp"],[651,"core::result"],[652,"serde::de"],[653,"core::fmt"],[654,"url"],[655,"core::hash"],[656,"core::net::socket_addr"],[657,"core::option"],[658,"anyhow"],[659,"iroh_base::key"],[660,"bytes::bytes"],[661,"serde::ser"],[662,"alloc::string"],[663,"core::any"],[664,"futures_lite::future"],[665,"core::ops::function"],[666,"core::marker"],[667,"hickory_resolver::async_resolver"],[668,"tokio_tungstenite_wasm::error"],[669,"std::io::error"],[670,"hyper::error"],[671,"tokio::runtime::task::error"],[672,"http::error"],[673,"core::convert"],[674,"core::time"],[675,"core::error"],[676,"http::header::value"],[677,"stun_rs::attributes"],[678,"stun_rs::attributes::stun::alternate_server"],[679,"stun_rs::error"],[680,"stun_rs::types"],[681,"stun_rs::attributes::stun::error_code"],[682,"stun_rs::attributes::stun::fingerprint"],[683,"stun_rs::attributes::stun::mapped_address"],[684,"stun_rs::attributes::stun::message_integrity"],[685,"stun_rs::attributes::stun::message_integrity_sha256"],[686,"stun_rs::attributes::stun::nonce"],[687,"stun_rs::attributes::stun::password_algorithm"],[688,"stun_rs::attributes::stun::password_algorithms"],[689,"stun_rs::attributes::stun::realm"],[690,"stun_rs::attributes::stun::software"],[691,"stun_rs::attributes::unknown"],[692,"stun_rs::attributes::stun::unknown_attributes"],[693,"stun_rs::attributes::stun::user_hash"],[694,"stun_rs::attributes::stun::user_name"],[695,"stun_rs::attributes::stun::xor_mapped_address"],[696,"stun_rs::context"],[697,"stun_rs::message"],[698,"core::iter::traits::collect"],[699,"alloc::vec"],[700,"iroh_quinn::endpoint"],[701,"rustls::client::client_conn"],[702,"rustls_pki_types"],[703,"iroh_relay::server::metrics"],[704,"core::default"],[705,"alloc::vec::into_iter"],[706,"core::pin"],[707,"core::task::wake"],[708,"core::task::poll"],[709,"tokio::io::read_buf"],[710,"std::io"],[711,"tokio_util::task::abort_on_drop"],[712,"rustls::server::server_conn"],[713,"iroh_base::relay_map"],[714,"stun_rs"],[715,"stun_rs::methods"]],"i":[3,0,0,0,0,3,0,3,3,3,0,3,0,0,3,1,2,3,1,2,3,0,1,2,3,1,2,3,2,1,1,0,1,1,1,2,1,1,1,2,2,2,1,1,2,3,1,1,2,3,1,1,0,1,2,3,2,2,2,1,0,0,2,2,2,1,0,1,2,3,1,1,2,3,1,2,3,1,2,3,1,2,3,107,108,109,107,109,36,36,36,0,0,0,0,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,25,36,33,34,25,36,33,34,25,25,25,33,33,33,33,33,36,36,33,34,25,36,36,36,36,36,36,33,34,25,25,36,33,34,25,33,25,25,33,25,33,33,25,25,33,34,33,33,25,25,36,33,36,36,33,34,25,36,33,34,25,36,33,34,25,36,33,34,25,0,0,0,0,0,0,0,0,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,0,0,0,0,0,0,49,0,49,70,49,70,76,76,76,49,0,0,49,49,76,49,76,76,49,49,49,70,49,0,0,70,0,49,49,49,49,49,49,52,49,49,49,49,49,49,49,49,49,52,49,49,49,49,49,49,49,69,70,52,49,76,73,69,70,52,49,76,73,69,70,52,49,69,70,52,49,52,52,69,69,52,52,52,52,70,52,70,70,70,52,52,52,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,69,70,52,52,49,76,76,73,73,69,70,52,52,52,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,76,73,69,52,69,70,52,49,76,73,0,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,0,0,0,52,0,0,69,70,52,49,52,76,73,69,70,70,52,49,76,73,69,70,52,49,76,73,69,70,52,49,76,73,69,70,52,49,76,73,0,0,0,0,0,0,0,79,79,79,79,79,79,79,79,79,79,79,0,0,96,0,96,0,0,91,0,0,0,0,0,0,91,0,90,90,84,85,93,94,84,85,91,87,92,93,94,95,90,86,96,82,84,85,91,87,92,93,94,95,90,86,96,82,86,84,84,95,82,90,84,85,86,84,85,86,84,84,85,87,90,84,84,84,84,84,85,84,85,91,87,92,93,94,95,90,86,96,82,84,84,85,91,87,92,93,94,95,90,86,96,82,84,82,92,82,82,95,82,84,85,91,87,92,93,94,95,90,86,96,82,85,85,84,85,92,86,87,84,85,84,84,84,91,91,91,91,91,87,82,95,87,85,84,84,84,84,94,95,82,82,87,82,82,0,92,84,85,86,84,85,91,87,92,93,94,95,90,86,96,82,84,85,91,87,92,93,94,95,90,86,96,82,84,85,91,87,92,93,94,95,90,86,96,82,84,84,84,85,91,87,92,93,94,95,90,86,96,82,84,110,111,0,0,0,0,0,0],"f":"```````````````{ce{}{}}00000`{bb}{dd}{ff}{{ce}h{}{}}00{dh}{{bb}j}{{ce}j{}{}}`{b}{c{{l{b}}}n}{{bb}A`}{{dd}A`}{{ce}A`{}{}}00000{{bAb}{{l{hAd}}}}0{{dAb}Af}{{fAb}Af}{cc{}}{Ahb}11{Aj{{l{b}}}}{{bc}hAl}`{ce{}{}}00{dA`}{d{{B`{An}}}}{{dA`}{{Bb{h}}}}{{bb}{{B`{j}}}}``{{dBdBf}{{Bb{h}}}}{{d{Bj{Bh}}}{{Bb{h}}}}0{{bc}lBl}`777{cBn{}}{c{{l{e}}}{}{}}00000{cC`{}}00:::```````````````````````````````````{{Cbc}Cb{{Ch{}{{Cd{{Cf{A`}}}}}}CjCl}};;;;;;;;{{CbCnD`}{{Df{DbDd}}}}{{CbA`}Cb}{DbDb}{{ce}h{}{}}{Db{{l{hDh}}}}0{Db{{l{dDh}}}}{{DhAb}Af}0{{DbAb}Af}{{DdAb}Af}{{CbAb}Af}{cc{}}{DjDh}{DlDh}{DnDh}{E`Dh}{EbDh}555>{ce{}{}}000{Db{{l{A`Dh}}}}{{CbA`}Cb}0{Db{{B`{An}}}}{cCb{{Ed{b}}}}{{DbA`}h}{Db{{l{EfDh}}}}{{CbEh}Cb}{{CbAh}Cb}{DbEj}{Dd{{B`{{l{fDh}}}}}}{{DbEjBf}{{l{hDh}}}}{{Db{Bj{Bh}}}{{l{hDh}}}}{{CbEj}Cb}{{Cbc}Cb{{Ed{b}}}}{Dh{{B`{El}}}}?{cBn{}}{c{{l{e}}}{}{}}0000000{cC`{}}000{ce{}{}}000``````````00{EhEh}{{ce}h{}{}}{{EhEh}A`}{{ce}A`{}{}}00{{EhAb}Af}{cc{}}6{En{{B`{Eh}}}}7998{EhAj}8````{{{F`{Bh}}}A`}`````````````````````````````````{Fb{{l{FdFf}}}}{Fh{{Bj{Bh}}}}{Fb{{l{FjFf}}}}{Fb{{l{FlFf}}}}{Fb{{l{FnFf}}}}{Fb{{l{G`Ff}}}}{Fb{{l{GbFf}}}}{Fb{{l{GdFf}}}}{Fb{{l{GfFf}}}}{Fb{{l{GhFf}}}}{Fb{{l{GjFf}}}}{Fh{{F`{Bh}}}}{Fb{{l{GlFf}}}}{Fb{{l{GnFf}}}}{Fb{{l{H`Ff}}}}{Fb{{l{HbFf}}}}{Fb{{l{HdFf}}}}{Fb{{l{HfFf}}}}{FbHh}{ce{}{}}00000000000{HjHj}{HlHl}{FhFh}{FbFb}{{ce}h{}{}}000{{FhFh}j}{{ce}j{}{}}{{Hj{F`{Bh}}}{{l{{Df{HnI`}}Ib}}}}{{}Hj}{{}Fh}{Fh{{F`{Bh}}}}{ce{}{{If{Id}}}}0{{HlHl}A`}{{FhFh}A`}{{ce}A`{}{}}00000{FbFd}{FbFj}{FbFl}{FbFn}{FbG`}{FbGb}{FbGd}{FbGf}{FbGh}{FbGj}{FbGl}{FbGn}{FbH`}{FbHb}{FbHd}{FbHf}{{HjAb}{{l{hAd}}}}{{HlAb}{{l{hAd}}}}{{FhAb}{{l{hAd}}}}0{{FbAb}{{l{hAd}}}}{{IhAb}Af}0{{IbAb}{{l{hAd}}}}0{cc{}}0{{{Bj{Bh}}}Fh}10{GhFb}{H`Fb}{GfFb}{FnFb}{GdFb}{FdFb}{HbFb}{GnFb}{FjFb}{GjFb}{G`Fb}{GbFb}{GlFb}{FlFb}{HdFb}{HfFb}{cc{}}00{Hj{{B`{Ij}}}}{{Fhc}hAl}{ce{}{}}00000{{{F`{Bh}}}A`}{FbA`}000000000000000`{{{F`{Bh}}}{{l{FhIh}}}}{{{F`{Bh}}}{{l{{Df{FhAn}}Ih}}}}{{FhFh}{{B`{j}}}}{Fh{{Il{Bh}}}}{{FhAn}{{Il{Bh}}}}7777{cBn{}}00{c{{l{e}}}{}{}}{Bh{{l{Hl}}}}11111111111{cC`{}}00000;;;;;;```````;;{{InAb}Af}?{{InAnAj}{{Bb{{Df{AnEf}}}}}}={{J`Jb}{{Bb{In}}}}553>``````````````````````>>>>>>>>>>>>>>>>>>>>>>>>````{Jd{{B`{{Il{Jf}}}}}}`{JhJh}{JjJj}{JlJl}{{ce}h{}{}}00`{{}Jh}{{}Jj}{{}{{Jn{ce}}}{K`Kb}{K`Kb}}{{}Kd}``````{{JhAb}Af}{{JjAb}Af}{{KfAb}Af}{{{Jn{ce}}Ab}AfKbKb}{{{Kh{ce}}Ab}AfKbKb}{{KjAb}Af}{{KlAb}Af}{{{Kn{ce}}Ab}AfKbKb}{{KdAb}Af}{{JlAb}Af}{{{L`{ce}}Ab}AfKbKb}{{JdAb}Af}`{cc{}}00000000000`{Jd{{B`{An}}}}`{Jd{{B`{b}}}}1`0{ce{}{}}00000000000``{Jh{{Ld{{Df{AjLb}}}}}}{Jj{{Ld{{Df{AjLb}}}}}}```{{}Aj}0```{{{Lf{Kf}}Lh}{{Lj{{l{hDl}}}}}}{{{Lf{Kf}}LhLl}{{Lj{{Ln{h}}}}}}1{{{Lf{Kf}}Lh{F`{Bh}}}{{Lj{{l{I`Dl}}}}}}{{{Lf{Kf}}Lh{F`{M`}}}{{Lj{{l{I`Dl}}}}}}`9`````````{Jd{{Bb{h}}}}{{{Jn{ce}}}{{Bb{Jd}}}KbKb}`;{Jd{{Mb{{Bb{h}}}}}}``:::{c{{l{e}}}{}{}}00000000000000000000000{cC`{}}00000000000``<<<<<<<<<<<<```{{}Kl}{{}{{Kh{h}}}}{{}{{Df{{Il{Jf}}Md}}}}{{}{{Jn{h}}}}{{}Kj}{{}{{Kn{h}}}}","D":"BIj","p":[[5,"RelayUrl",0,648],[5,"RelayConn",0],[6,"ReceivedMessage",0,649],[1,"unit"],[6,"Ordering",650],[6,"Result",651],[10,"Deserializer",652],[1,"bool"],[5,"Formatter",653],[5,"Error",653],[8,"Result",653],[5,"Url",654],[1,"str"],[10,"Hasher",655],[6,"SocketAddr",656],[6,"Option",657],[8,"Result",658],[8,"NodeId",659],[5,"Bytes",660],[1,"u8"],[1,"array"],[10,"Serializer",661],[5,"String",662],[5,"TypeId",663],[5,"ClientBuilder",88],[17,"Output"],[8,"Boxed",664],[10,"Fn",665],[10,"Send",666],[10,"Sync",666],[5,"SecretKey",659],[8,"TokioAsyncResolver",667],[5,"Client",88],[5,"ClientReceiver",88],[1,"tuple"],[6,"ClientError",88],[6,"Error",668],[5,"Error",669],[5,"Error",670],[5,"JoinError",671],[5,"Error",672],[10,"Into",673],[5,"Duration",674],[6,"Protocol",192],[5,"PublicKey",659],[10,"Error",675],[5,"HeaderValue",676],[1,"slice"],[6,"StunAttribute",221,677],[5,"AlternateServer",678],[5,"StunError",679],[5,"TransactionId",221,680],[5,"ErrorCode",681],[6,"Fingerprint",682],[5,"MappedAddress",683],[6,"MessageIntegrity",684],[6,"MessageIntegritySha256",685],[5,"Nonce",686],[5,"PasswordAlgorithm",687],[5,"PasswordAlgorithms",688],[5,"Realm",689],[5,"Software",690],[5,"Unknown",691],[5,"UnknownAttributes",692],[5,"UserHash",693],[5,"UserName",694],[5,"XorMappedAddress",695],[5,"AttributeType",677],[5,"MessageDecoder",221,696],[6,"MessageClass",221,697],[5,"StunMessage",697],[1,"usize"],[5,"StunDecodeError",221,679],[1,"char"],[10,"FromIterator",698],[6,"Error",221],[5,"DecoderContext",696],[5,"Vec",699],[5,"QuicClient",423],[5,"Endpoint",700],[5,"ClientConfig",701],[5,"Server",438],[5,"CertificateDer",702],[5,"Metrics",438,703],[5,"StunMetrics",438,703],[5,"ClientConnRateLimit",438],[5,"ServerConfig",438],[10,"Default",704],[10,"Debug",653],[5,"Limits",438],[6,"MaybeTlsStreamServer",438],[5,"RelayConfig",438],[5,"StunConfig",438],[5,"QuicConfig",438],[5,"TlsConfig",438],[6,"CertConfig",438],[10,"Any",663],[5,"IntoIter",705],[5,"Pin",706],[5,"Context",707],[6,"Poll",708],[5,"ReadBuf",709],[8,"Result",669],[5,"IoSlice",710],[5,"AbortOnDropHandle",711],[5,"ServerConfig",712],[15,"ReceivedPacket",83],[15,"Health",83],[15,"ServerRestarting",83],[15,"Manual",640],[15,"LetsEncrypt",640]],"r":[[6,220],[10,649],[13,648],[190,713],[191,713],[231,697],[232,696],[244,677],[245,679],[247,680],[382,714],[420,715],[421,715],[422,715],[444,703],[451,703]],"b":[[42,"impl-Display-for-RelayUrl"],[43,"impl-Debug-for-RelayUrl"],[134,"impl-Debug-for-ClientError"],[135,"impl-Display-for-ClientError"],[140,"impl-From%3CError%3E-for-ClientError"],[141,"impl-From%3CError%3E-for-ClientError"],[142,"impl-From%3CError%3E-for-ClientError"],[143,"impl-From%3CJoinError%3E-for-ClientError"],[144,"impl-From%3CError%3E-for-ClientError"],[326,"impl-Debug-for-TransactionId"],[327,"impl-Display-for-TransactionId"],[329,"impl-Display-for-Error"],[330,"impl-Debug-for-Error"],[331,"impl-Debug-for-StunDecodeError"],[332,"impl-Display-for-StunDecodeError"],[335,"impl-From%3C%5Bu8;+stun_rs::::types::%7Bimpl%2314%7D::%7Bconstant%230%7D%5D%3E-for-TransactionId"],[337,"impl-From%3C%26%5Bu8;+stun_rs::::types::%7Bimpl%2313%7D::%7Bconstant%230%7D%5D%3E-for-TransactionId"],[338,"impl-From%3CPasswordAlgorithms%3E-for-StunAttribute"],[339,"impl-From%3CUnknownAttributes%3E-for-StunAttribute"],[340,"impl-From%3CPasswordAlgorithm%3E-for-StunAttribute"],[341,"impl-From%3CMappedAddress%3E-for-StunAttribute"],[342,"impl-From%3CNonce%3E-for-StunAttribute"],[343,"impl-From%3CAlternateServer%3E-for-StunAttribute"],[344,"impl-From%3CUserHash%3E-for-StunAttribute"],[345,"impl-From%3CUnknown%3E-for-StunAttribute"],[346,"impl-From%3CErrorCode%3E-for-StunAttribute"],[347,"impl-From%3CRealm%3E-for-StunAttribute"],[348,"impl-From%3CMessageIntegrity%3E-for-StunAttribute"],[349,"impl-From%3CMessageIntegritySha256%3E-for-StunAttribute"],[350,"impl-From%3CSoftware%3E-for-StunAttribute"],[351,"impl-From%3CFingerprint%3E-for-StunAttribute"],[352,"impl-From%3CUserName%3E-for-StunAttribute"],[353,"impl-From%3CXorMappedAddress%3E-for-StunAttribute"]],"c":"OjAAAAAAAAA=","e":"OzAAAAEAADsBKAACAAMABwAAABAABQAXAAUAHgABACEADQAwAAAAMwABADwAAABCAAAARAAPAHgABwCCAAEAhwAEAI0ABACpABIAxgAIANIAAwDXAAAACQEAABEBFQAoAQAAKgEKAEUBCABQAQAAUgEQAGcBAACCAQAAhQEfAKwBAgCzAQMAzQEXAOsBBQDyAQMA/AELACoCAQAvAgEANAIEAEsCJgB0AgsA"}],\ +["iroh_test",{"t":"FQNNNNCNCNNNNHHHHH","n":["CallOnDrop","assert_eq_hex","borrow","borrow_mut","drop","from","hexdump","into","logging","new","try_from","try_into","type_id","parse_hexdump","print_hexdump","setup","setup_multithreaded","testing_subscriber"],"q":[[0,"iroh_test"],[13,"iroh_test::hexdump"],[15,"iroh_test::logging"],[18,"core::ops::function"],[19,"core::result"],[20,"core::any"],[21,"alloc::vec"],[22,"anyhow"],[23,"alloc::string"],[24,"core::convert"],[25,"tracing_core::dispatcher"],[26,"tracing_core::subscriber"]],"i":[0,0,1,1,1,1,0,1,0,1,1,1,1,0,0,0,0,0],"f":"``{ce{}{}}0{bd}{cc{}}`2`{cbf}{c{{h{e}}}{}{}}0{cj{}}{l{{Ab{{A`{n}}}}}}{{ce}Ad{{Ah{{Af{n}}}}}{{Ah{{Af{Aj}}}}}}{{}Al}{{}d}{{}{{`{An}}}}","D":"Ad","p":[[5,"CallOnDrop",0],[1,"unit"],[10,"FnOnce",18],[6,"Result",19],[5,"TypeId",20],[1,"str"],[1,"u8"],[5,"Vec",21],[8,"Result",22],[5,"String",23],[1,"slice"],[10,"AsRef",24],[1,"usize"],[5,"DefaultGuard",25],[10,"Subscriber",26]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAAgABAABAAAAAwACAAcAAAAKAAMA"}]\ +]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex); diff --git a/pr/2992/docs/search.desc/bulk/bulk-desc-0-.js b/pr/2992/docs/search.desc/bulk/bulk-desc-0-.js new file mode 100644 index 0000000000..baa20fff49 --- /dev/null +++ b/pr/2992/docs/search.desc/bulk/bulk-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("bulk", 0, "") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh/iroh-desc-0-.js b/pr/2992/docs/search.desc/iroh/iroh-desc-0-.js new file mode 100644 index 0000000000..b71abc6f26 --- /dev/null +++ b/pr/2992/docs/search.desc/iroh/iroh-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh", 0, "Peer-to-peer QUIC connections.\nNetwork paths to contact an iroh node.\nOptions to configure what is included in a NodeAddr and …\nIncludes the Node ID and the direct addresses.\nOnly the Node ID is added.\nNetwork-level addressing information for an iroh node.\nThe identifier for a node in the (iroh) network.\nIncludes the Node ID and the relay URL.\nIncludes the Node ID and both the relay URL, and the …\nConfiguration of all the relay servers that can be used.\nInformation on a specific relay server.\nA URL identifying a relay server.\nApplies the options to self.\nApplies the options to self.\nIs this a known node?\nCreates a new RelayMap with a single relay server …\nDefault values used in iroh\nA dialer to conveniently dial many nodes.\nReturns the direct addresses of this peer.\nSocket addresses where the peer might be reached directly.\nNode address discovery.\nThis module exports a DNS resolver, which is also the …\nCreate an empty relay map.\nThe Endpoint allows establishing connections to other iroh …\nReturns the addressing info from given ticket.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nConstructs the RelayMap from an iterator of RelayNodes.\nCreates a new NodeAddr from its parts.\nReturns a RelayMap from a RelayUrl.\nGet the given node.\nThe blake3 hash used in Iroh.\nAddressing information to connect to Self::node_id.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nReturns whether this addressing information is empty.\nAre there any nodes in this map?\nCryptographic key handling for iroh.\nHow many nodes are known?\nCo-locating all of the iroh metrics structs\nCreates a new NodeAddr with empty AddrInfo.\nThe node’s identifier.\nReturns an Iterator over all known nodes.\nTools for spawning an accept loop that routes incoming …\nConfiguration to speak to the QUIC endpoint on the relay …\nReturns the relay url of this peer.\nThe node’s home relay url.\nWhether this relay server should only be used for STUN …\nThe stun port of the relay server.\nInternal utilities to support testing.\nTLS configuration based on libp2p TLS specs.\nThe RelayUrl where this relay server can be dialed.\nReturns the sorted relay URLs.\nAdds the given direct addresses to the peer’s AddrInfo.\nAdds a relay url to the node’s AddrInfo.\nThe default HTTPS port used by the Relay server.\nThe default HTTP port used by the Relay server.\nThe default metrics port used by the Relay server.\nThe default QUIC port used by the Relay server to accept …\nThe default STUN port used by the Relay server.\nProduction configuration.\nStaging configuration.\nHostname of the default Asia-Pacific relay.\nHostname of the default EU relay.\nHostname of the default NA relay.\nGet the default RelayNode for Asia-Pacific\nGet the default RelayNode for EU.\nGet the default RelayNode for NA.\nGet the default RelayMap.\nHostname of the default EU relay.\nHostname of the default NA relay.\nGet the default RelayNode for EU.\nGet the default RelayNode for NA.\nGet the default RelayMap.\nDials nodes and maintains a queue of pending dials.\nAborts a pending dial.\nReturns a reference to the endpoint used in this dialer.\nReturns the argument unchanged.\nCalls U::from(self).\nChecks if a node is currently being dialed.\nCreate a new dialer for a Endpoint\nWaits for the next dial operation to complete.\nNumber of pending connections to be opened.\nStarts to dial a node by NodeId.\nA discovery service that combines multiple discovery …\nNode discovery for super::Endpoint.\nThe results returned from Discovery::resolve.\nAdds a Discovery service.\nThe address info for the node being resolved.\nDNS node discovery for iroh\nCreates an empty ConcurrentDiscovery.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreates a new ConcurrentDiscovery.\nCalls U::from(self).\nCalls U::from(self).\nOptional timestamp when this node address info was last …\nA discovery service that uses an mdns-like service to …\nThe NodeId whose address we have discovered\nA discovery service which publishes and resolves node …\nA static string to identify the discovery source.\nPublishes the given AddrInfo to the discovery mechanism.\nResolves the AddrInfo for the given NodeId.\nA static discovery implementation that allows adding info …\nSubscribe to all addresses that get passively discovered.\nDNS node discovery\nThe n0 testing DNS node origin, for production.\nThe n0 testing DNS node origin, for testing.\nReturns the argument unchanged.\nCalls U::from(self).\nCreates a new DNS discovery using the iroh.link domain.\nCreates a new DNS discovery.\nDiscovery using swarm-discovery, a variation on mdns\nName of this discovery service.\nReturns the argument unchanged.\nCalls U::from(self).\nCreate a new LocalSwarmDiscovery Service.\nDefault TTL for the records in the pkarr signed packet.\nInterval in which to republish the node info even if …\nThe production pkarr relay run by number 0.\nThe testing pkarr relay run by number 0.\nPublisher of node discovery information to a pkarr relay.\nA pkarr client to publish pkarr::SignedPackets to a pkarr …\nResolver of node discovery information from a pkarr relay.\nPkarr based node discovery for iroh, supporting both relay …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCreates a pkarr publisher which uses the number 0 pkarr …\nCreates a pkarr resolver which uses the number 0 pkarr …\nCreates a new publisher for the SecretKey.\nCreates a new publisher using the pkarr relay server at …\nCreates a new client.\nPublishes a SignedPacket.\nResolves a SignedPacket for the given NodeId.\nPublishes AddrInfo about this node to a pkarr relay.\nCreates a new PkarrPublisher with a custom TTL and …\nBuilder for DhtDiscovery.\nPkarr Mainline DHT and relay server node discovery.\nBuilds the discovery mechanism.\nCreates a new builder for DhtDiscovery.\nExplicitly sets the pkarr client to use.\nSets whether to publish to the Mainline DHT.\nReturns the argument unchanged.\nReturns the argument unchanged.\nSets whether to include the direct addresses in the DNS …\nSets the initial delay before the first publish.\nCalls U::from(self).\nCalls U::from(self).\nUses the default number 0 pkarr relay URL.\nSets the pkarr relay URL to use.\nSets the republish delay for the DHT.\nSets the secret key to use for signing the DNS packets.\nSets the time-to-live value for the DNS packets.\nThe provenance string for this discovery implementation.\nA static discovery implementation that allows providing …\nAdd node info for the given node id, combining it with any …\nReturns the argument unchanged.\nCreates a static discovery instance from something that …\nGet node info for the given node id.\nCalls U::from(self).\nCreate a new static discovery instance.\nRemove node info for the given node id.\nAdd node info for the given node id.\nThe DNS resolver type used throughout iroh.\nExtension trait to DnsResolver.\nGet a reference to the default DNS resolver.\nLooks up node info by NodeId and origin domain name.\nLooks up node info by NodeId and origin domain name.\nLooks up node info by NodeId and origin domain name.\nLooks up node info by NodeId and origin domain name.\nLooks up node info by DNS name.\nLooks up node info by DNS name.\nLooks up node info by DNS name in a staggered fashion.\nLooks up node info by DNS name in a staggered fashion.\nPerform an ipv4 lookup with a timeout.\nRace an ipv4 and ipv6 lookup with a timeout.\nResolve IPv4 and IPv6 in parallel.\nRace an ipv4 and ipv6 lookup with a timeout in a staggered …\nRace an ipv4 and ipv6 lookup with a timeout in a staggered …\nPerform an ipv4 lookup with a timeout in a staggered …\nPerform an ipv4 lookup with a timeout in a staggered …\nPerform an ipv6 lookup with a timeout.\nPerform an ipv6 lookup with a timeout in a staggered …\nPerform an ipv6 lookup with a timeout in a staggered …\nSupport for handling DNS resource records for dialing by …\nGet the DNS resolver used within iroh.\nDirect address.\nThe DNS name for the iroh TXT record.\nThe attributes supported by iroh for IROH_TXT_NAME DNS …\nInformation about the iroh node contained in an …\nURL of home relay.\nAttributes parsed from IROH_TXT_NAME TXT records.\nReturns the parsed attributes.\nAny direct addresses.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nParses a NodeInfo from a set of DNS records.\nParses a set of DNS resource records.\nCreates TxtAttrs from a node id and an iterator of …\nParses a NodeInfo from a pkarr::SignedPacket.\nParses a pkarr::SignedPacket.\nCreates TxtAttrs from a node id and an iterator of “…\nParses a NodeId from [z-base-32] encoding.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nLooks up attributes by NodeId and origin domain.\nLooks up attributes by DNS name.\nCreates a new NodeInfo from its parts.\nReturns the node id.\nThe NodeId.\nThe advertised home relay server.\nConverts into a hickory_proto::rr::Record DNS record.\nConverts to a list of hickory_proto::rr::Record resource …\nCreates a pkarr::SignedPacket.\nCreates a pkarr::SignedPacket\nEncodes a NodeId in [z-base-32] encoding.\nthe endpoint has reached the confidentiality or integrity …\nthe application or application protocol caused the …\nFuture produced by Endpoint::accept.\nFuture produced by Connection::accept_bi\nFuture produced by Connection::accept_uni\nParameters for controlling the peer’s acknowledgement …\nNetwork paths to contact an iroh node.\nOptions to configure what is included in a NodeAddr and …\nIncludes the Node ID and the direct addresses.\nA key for sealing data with AEAD-based algorithms\nApplication layer added the address directly.\nReason given by an application for closing the connection\nThe peer closed the connection\nBuilder for Endpoint.\nA cheaply cloneable and sliceable chunk of contiguous …\nthe number of connection IDs provided by the peer exceeds …\nthe server refused to accept a new connection\nreceived more data in CRYPTO frames than can be buffered\nWe received a CallMeMaybe.\nA chunk of data from the receive stream\nThe connection could not be created because not enough of …\nError indicating that a stream has not been opened or has …\nThe stream has already been stopped, finished, or reset\nThe stream has already been finished or reset\nIn-progress connection attempt future\nA QUIC connection.\nReason given by the transport for closing the connection\nThe peer’s QUIC stack aborted the connection …\nReasons why a connection might be lost\nThe connection was lost\nThe connection was lost\nThe connection was lost\nThe connection was lost\nThe connection was lost\nConnection statistics\nThe type of connection we have to the endpoint.\nStream returning ConnectionTypes\nThe type of control message we have received.\nCommon interface for different congestion controllers\nConstructs controllers on demand\nGeneric crypto errors\nServer-side configuration for the crypto protocol\nUse a custom relay map.\nUse the default relay map, with production relay servers …\nDirect UDP connection\nA direct address on which an iroh-node might be …\nInformation about a direct address.\nThe type of direct address.\nStream returning local endpoints as they change.\nDatagram support is disabled locally\nDisable relay servers completely.\nThe address was discovered by a discovery service.\nEnvironment variable to force the use of staging relays.\nControls an iroh node, establishing connections with other …\nError returned by Session::export_keying_material.\nreceived a STREAM frame or a RESET_STREAM frame containing …\nreceived more data than permitted in advertised data limits\nreceived a frame that was badly formatted\nThe stream finished before all bytes were read\nNumber of frames transmitted of each frame type\nA pseudo random key for HKDF\nthe endpoint encountered an internal error and cannot …\nreceived an invalid Retry Token in a client Initial\nOnly the Node ID is added.\nAttempted an ordered read following an unordered read\nAn incoming connection for which the server has not yet …\nAdaptor to let Incoming be awaited like a Connecting.\nkey update error\nA locally bound socket address.\nThe local application closed the connection\nThe largest representable value\nThe largest encoded value length\nBoth a UDP and a relay connection are used.\nParameters governing MTU discovery.\nthe connection is being closed abruptly in the absence of …\nno viable network path exists\nApplication layer with a specific name added the node …\nNetwork-level addressing information for an iroh node.\nWe have no verified connection to this PublicKey\nFuture produced by Connection::open_bi\nFuture produced by Connection::open_uni\ndetected an error with protocol compliance that was not …\nStatistics related to a transmission path\nWe received a Ping from the node.\nWe received a Pong from the node.\nAn address assigned by the router using port mapping.\nAn error occurred during reading\nFuture produced by Connection::read_datagram\nErrors that arise from reading from a stream.\nA read error occurred\nErrors that arise from reading from a stream.\nErrors from RecvStream::read_to_end\nA stream that can only be used to receive data\nIncludes the Node ID and the relay URL.\nRelay connection over relay\nA node communicated with us first via relay.\nIncludes the Node ID and both the relay URL, and the …\nConfiguration of the relay servers for an Endpoint.\nDetails about a remote iroh node which is known to this …\nThe peer abandoned transmitting data on this stream\nThe peer is unable to continue processing this connection, …\nErrors that arise while waiting for a stream to be reset\nError for attempting to retry an Incoming which already …\nreceived a frame for a stream identifier that exceeded …\nreceived a frame for a stream that was not in a state that …\nAddress was loaded from the fs.\nErrors that can arise when sending a datagram\nA stream that can only be used to send data\nParameters governing incoming connections\nThe origin or source through which an address associated …\nUse the staging relay servers from n0.\nThe peer is no longer accepting data on this stream\nErrors that arise while monitoring for a send stream stop …\nIdentifier for a stream within a particular connection\nPublic internet address discovered via STUN.\nHard NAT: STUN’ed IPv4 address + local fixed port.\nreceived transport parameters that were badly formatted, …\nCommunication with the peer has lapsed for longer than the …\nThe datagram is larger than the connection can currently …\nThe stream is larger than the user-supplied limit\nParameters governing the core QUIC state machine\nTransport-level errors occur when a peer violates the …\nThe peer violated the QUIC specification as understood by …\nTransport-level error code\nA node communicated with us first via UDP.\nStatistics about UDP datagrams transmitted or received on …\nNot yet determined..\nThe peer does not support receiving datagram frames\nError indicating that the specified QUIC version is not …\nAn integer less than 2^62\nThe peer doesn’t implement any supported version\nA handle to some connection internals, use with care.\nErrors that arise from writing to a stream\nIndicates how many bytes and chunks had been transferred …\nFuture that completes when a connection is fully …\nThis was a 0-RTT stream and the server rejected it\nThis was a 0-RTT stream and the server rejected it\nThis was a 0-RTT stream and the server rejected it\nThis was a 0-RTT stream and the server rejected it\nAccepts an incoming connection on the endpoint.\nAttempts to accept this incoming connection (an error may …\nAccept the next incoming bidirectional stream\nAccept the next incoming uni-directional stream\nAccepts this incoming connection using a custom …\nThe ack-eliciting threshold we will request the peer to use\nSpecifies the ACK frequency config (see AckFrequencyConfig …\nAdds a discovery mechanism for this endpoint.\nInforms this Endpoint about addresses of the iroh node.\nInforms this Endpoint about addresses of the iroh node, …\nThe UDP address reported by the remote node.\nThe address.\nThe addresses at which this node might be reachable.\nDerive AEAD using hkdf\nWhether the implementation is permitted to set the spin …\nExtracts the ALPN protocol from the peer’s handshake …\nSets the ALPN protocols that this endpoint will accept on …\nBinds the magic endpoint.\nSets the IPv4 bind address.\nSets the IPv6 bind address.\nSpecifies the amount of time that MTU discovery should …\nThe number of times a black hole was detected in the path\nReturns the local socket addresses on which the underlying …\nConstruct a fresh Controller\nReturns the builder for an Endpoint, with a production …\nThe contents of the chunk\nThe total amount of bytes which have been transferred …\nThe amount of bytes which had been written\nThe amount of full chunks which had been written\nClears the buffer, removing all data.\nRemoves all discovery services from the builder.\nDuplicate the controller’s state\nClose the connection immediately.\nCloses the QUIC endpoint and the magic socket.\nIf the connection is closed, the reason why.\nWait for the connection to be closed for any reason\nType of error\nHow to construct new congestion::Controllers\nCongestion events on the connection\nCurrent state of the congestion control algorithm, for …\nThe type of connection we have to the node, either direct …\nReturns a stream that reports connection type changes for …\nConnects to a remote Endpoint.\nConnects to a remote endpoint, using just the nodes’s …\nCreates Bytes instance from slice, by copying it.\nCreate QUIC error code from TLS alert code\nTLS configuration used for incoming connections.\nMaximum quantity of out-of-order crypto layer data to …\nLargest UDP payload size the path currently supports\nCurrent congestion window of the connection\nMaximum number of incoming application datagram bytes to …\nMaximum number of outgoing application datagram bytes to …\nBytes available in the outgoing datagram buffer\nThe amount of UDP datagrams observed\nReturns the default relay mode.\nWhich directions data flows in\nReturns the direct addresses of this Endpoint.\nSocket addresses where the peer might be reached directly.\nOptionally sets a discovery mechanism for this endpoint.\nReturns the discovery mechanism, if configured.\nConfigures the endpoint to also use the mainline DHT with …\nConfigures the endpoint to also use local network …\nConfigures the endpoint to use the default n0 DNS …\nOptionally sets a custom DNS resolver to use for this …\nReturns the DNS resolver used in this Endpoint.\nWhether to use “Generic Segmentation Offload” to …\nClass of error as encoded in the specification\nApplication-specific reason code\nDerive keying material from this connection’s TLS …\nNotify the peer that no more data will ever be written to …\nReturns true if the use of staging relays is forced.\nFrame type that triggered the error\nStatistics about frames received on a connection\nStatistics about frames transmitted on a connection\nType of frame that caused the close\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreate Bytes with a buffer whose lifetime is controlled …\nCreates a new Bytes from a static slice.\nConstruct a VarInt infallibly\nSucceeds iff x < 2^62\nCreate a VarInt without ensuring it’s in range\nExtract the PublicKey from the peer’s TLS certificate.\nParameters negotiated during the handshake\nParameters negotiated during the handshake\nWhether there is a possible known network path to the …\nReturns the RelayUrl of the Relay server used as home …\nGet the identity of this stream\nGet the identity of this stream\nIgnores this incoming connection attempt, not sending any …\nMaximum number of received bytes to buffer for each …\nMaximum number of received bytes to buffer for all Incoming\nDistinguishes streams of the same initiator and …\nAddressing information to connect to Self::node_id.\nCreate the initial set of keys given the client’s …\nThe initial value to be used as the maximum UDP payload …\nThe RTT used before an RTT sample is taken\nInitial congestion window\nWhich side of a connection initiated the stream\nSkip verification of SSL certificates from relay servers\nSpecifies the time to wait after completing MTU discovery …\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nConvert into a 0-RTT or 0.5-RTT connection at the cost of …\nReturns Self for use in down-casting to extract …\nGet the Incoming\nExtract the integer value\nThe amount of I/O operations executed\nCheck if this stream has been opened during 0-RTT.\nReturns true if the Connection associated with this handle …\nCheck if this endpoint is still alive, or already closed.\nReturns true if the Bytes has a length of 0.\nReturns true if this is the only reference to the data and …\nPeriod of inactivity before sending a keep-alive packet\nEnables saving the TLS pre-master key for connections.\nOptionally set a list of known nodes.\nElapsed time since this network path was known to exist.\nLast control message received by this node about this …\nElapsed time since the last payload message was received …\nGet the duration since the last activity we received from …\nTime elapsed time since last we have sent to or received …\nThe latency to the remote node over this network path.\nThe latency of the current network path to the remote node.\nReturns the number of bytes contained in this Bytes.\nThe local IP address which was used when the peer …\nReturns the local IP address which was used when the peer …\nThe local IP address which was used when the peer …\nThe amount of bytes lost on this path\nThe amount of packets lost on this path\nThe amount of PLPMTUD probe packets lost on this path …\nCreates a ServerConfig with the given secret key and …\nThe max_ack_delay we will request the peer to use\nMaximum number of incoming bidirectional streams that may …\nVariant of max_concurrent_bidi_streams affecting …\nCompute the maximum size of datagrams that may be passed …\nMaximum duration of inactivity to accept before timing out …\nMaximum number of Incoming to allow to exist at a time\nWhether to allow clients to migrate to new addresses\nThe maximum UDP payload size guaranteed to be supported by …\nSpecifies the minimum MTU change to stop the MTU discovery …\nSpecifies the MTU discovery config (see MtuDiscoveryConfig …\nNotifies the system of potential network changes.\nResets path-specific state.\nCreates a new empty Bytes.\nCreate a default config with a particular handshake token …\nCreate a new StreamId\nReturns the current NodeAddr for this endpoint.\nReturns the node id of this endpoint.\nThe node’s identifier.\nThe globally unique identifier for this node.\nTrack changed on our external address as reported by the …\nThe offset in the stream\nPacket deliveries were confirmed\nPackets were deemed lost or marked congested\nPackets are acked in batches, all with the same now …\nThe known MTU for the current network path has been updated\nOne or more packets were just sent\nMethod for opening a sealed message data\nInitiate a new outgoing bidirectional stream.\nInitiate a new outgoing unidirectional stream.\nMaximum reordering in packet number space before FACK …\nStatistics related to the current transmission path\nCryptographic identity of the peer\nNumber of consecutive PTOs after which network is …\nAttempts to read from the stream into buf.\nAttempt to write bytes from buf into the stream.\nThe preferred IPv4 address that will be communicated to …\nThe preferred IPv6 address that will be communicated to …\nGet the priority of the send stream\nSets the proxy url from the environment, in this order:\nSets an explicit proxy url to proxy all HTTP(S) traffic …\nRead data contiguously from the stream.\nRead the next segment of data\nRead the next segments of data\nReceive an application datagram\nRead an exact number of bytes contiguously from the stream.\nConvenience method to read all remaining data into a buffer\nHuman-readable reason for the close\nHuman-readable reason for the close\nHuman-readable explanation of the reason\nWhether to receive observed address reports from other …\nMaximum number of bytes the peer may transmit across all …\nCompletes when the stream has been reset by the peer or …\nRejects this incoming connection attempt.\nReturns the relay map for this mode.\nSets the relay servers to assist in establishing …\nThe node’s home relay url.\nRelay server information, if available.\nThe peer’s UDP address\nReturns the peer’s UDP address.\nThe peer’s UDP address.\nWhether the socket address that is initiating this …\nReturns information about the remote node identified by a …\nReturns information about all the remote nodes this …\nThe reordering threshold we will request the peer to use\nClose the send stream immediately.\nResponds with a retry packet.\nGenerate the integrity tag for a retry packet\nDuration after a stateless retry token was issued for …\nCurrent best estimate of this connection’s latency …\nCurrent best estimate of this connection’s latency …\nSaturating integer addition. Computes self + rhs, …\nMethod for sealing message data\nSets a secret key to authenticate with other peers.\nReturns the secret_key of this endpoint.\nTransmit data as an unreliable, unordered application …\nTransmit data as an unreliable, unordered application …\nWhether to send observed address reports to peers.\nMaximum number of bytes to transmit to a peer without …\nThe amount of packets sent on this path\nThe amount of PLPMTUD probe packets sent on this path …\nSets the list of accepted ALPN protocols.\nModify the number of remotely initiated bidirectional …\nModify the number of remotely initiated unidirectional …\nSet the priority of the send stream\nSee proto::TransportConfig::receive_window()\nReturns a slice of self for the provided range.\nReturns a slice of self that is equivalent to the given …\nReturns a deduplicated list of Sources merged from all …\nA HashMap of Sources to Durations.\nSplits the bytes into two at the given index.\nSplits the bytes into two at the given index.\nA stable identifier for this connection\nStart a server session with this configuration\nReturns connection statistics\nStop accepting data\nCompletes when the peer stops the stream or reads the …\nMaximum number of bytes the peer may transmit without …\nMaximum reordering in time space before time based loss …\nPrivate key used to authenticate data included in …\nTransport configuration to use for incoming connections\nSets a custom quinn::TransportConfig for this endpoint.\nSet a custom TransportConfig\nShortens the buffer, keeping the first len bytes and …\nSucceeds iff x < 2^62\nSucceeds iff x < 2^62\nSucceeds iff x < 2^62\nTry to convert self into BytesMut.\nThe origin of this direct address.\nStatistics about UDP datagrams received on a connection\nStatistics about UDP datagrams transmitted on a connection\nSpecifies the upper bound to the max UDP payload size that …\nWatches for changes to the home relay.\nReturns a weak reference to the inner connection struct.\nNumber of ack-eliciting bytes that may be in flight\nCreate a server config with the given crypto::ServerConfig\nCreate a server config with the given certificate chain to …\nWrite bytes to the stream\nConvenience method to write an entire buffer to the stream\nConvenience method to write an entire list of chunks to …\nConvenience method to write a single chunk in its entirety …\nWrite chunks to the stream\nThe name of the discovery service that discovered the …\nThe name of the application that added the node\nA format identifier\nThe hash for the empty byte range (b"").\nHash type used throughout.\nA hash and format pair\nA sequence of BLAKE3 hashes\nRaw blob\nBytes of the hash.\nConvert to a base32 string limited to the first 10 bytes …\nThe format\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreate a Hash from its raw bytes representation.\nThe hash\nCreate a new hash and format pair, using the collection …\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nIs hash seq format\nIs raw format\nCalculate the hash of the provided bytes.\nCreate a new hash and format pair.\nCreate a new hash and format pair, using the default (raw) …\nConvert the hash to a hex string.\nSize of an encoded Ed25519 signature in bytes.\nError when decoding the base32.\nError when decoding the public key.\nError when deserialising a PublicKey or a SecretKey.\nThe identifier for a node in the (iroh) network.\nThe length of an ed25519 PublicKey, in bytes.\nA public key.\nA secret key.\nShared Secret.\nEd25519 signature.\nGet this public key as a byte array.\nConvert to a base32 string limited to the first 10 bytes …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nParse an Ed25519 signature from a byte slice.\nConstruct a PublicKey from a slice of bytes.\nCreate a secret key from its byte representation.\nParse an Ed25519 signature from its R and s components.\nParse an Ed25519 signature from a byte slice.\nGenerate a new SecretKey with the default randomness …\nGenerate a new SecretKey with a randomness generator.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nOpens the ciphertext, which must have been created using …\nThe public key of this SecretKey.\nBytes for the R component of a signature.\nBytes for the s component of a signature.\nSeals the provided cleartext.\nReturns the shared key for communication between this key …\nSign the given message and return a digital signature\nReturn the inner byte array.\nConvert this to the bytes representing the secret part. …\nSerialise this key to OpenSSH format.\nConvert this signature into a byte vector.\nDeserialise this key from OpenSSH format.\nVerify a signature on a message with this secret key’s …\nEnum of metrics for the module\nEnum of metrics for the module\nEnum of metrics for the module\nMetrics tracked for the relay server\nNumber of connections we have accepted\nBytes received from a FrameType::SendPacket\nBytes sent from a FrameType::SendPacket\nNumber of connections with a successful handshake that …\nNumber of connections with a successful handshake.\nNumber of client connections which have had any frames …\nNumber of accepted ‘iroh derp http’ connection upgrades\nFrameType::SendPacket dropped that are disco messages\nFrameType::SendPacket received that are disco messages\nFrameType::SendPacket sent that are disco messages\nNumber of connections we have removed because of an error\nNumber of frames received from client connection which …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nNumber of FrameType::Pings received\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nNumber of nodes we have attempted to contact.\nNumber of nodes we have managed to contact directly.\nThe number of direct connections we have made to peers.\nThe number of direct connections we have lost to peers.\nThe number of connections to peers we have added over …\nThe number of connections to peers we have removed over …\nPackets of other FrameTypes dropped\nPackets of other FrameTypes received\nPackets of other FrameTypes sent\nNumber of QUIC datagrams received.\nNumber of datagrams received using GRO\nFrameType::SendPacket dropped, that are not disco messages\nFrameType::SendPacket received, that are not disco messages\nFrameType::SendPacket sent, that are not disco messages\nNumber of FrameType::Pongs sent\nNumber of unique client keys per day\nNumber of FrameType::Unknown received\nNumber of accepted websocket connections\nHelper trait to facilite casting from Arc<dyn T> to …\nHandler for incoming connections.\nA typed map of protocol handlers, mapping them from ALPNs.\nThe built router.\nBuilder for creating a Router for accepting protocols.\nHandle an incoming connection.\nConfigures the router to accept the ProtocolHandler when …\nReturns an iterator of all registered ALPN protocol …\nCreates a new Router using given Endpoint.\nReturns the Endpoint stored in this router.\nReturns the Endpoint of the node.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the registered protocol handler for an ALPN as a …\nReturns a protocol handler for an ALPN.\nReturns a protocol handler for an ALPN.\nReturns the registered protocol handler for an ALPN as a …\nInserts a protocol handler.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCasts Arc<Self> into Arc<dyn Any + Send + Sync>.\nChecks if the router is already shutdown.\nCreates a new router builder using given Endpoint.\nCalled when the node shuts down.\nShuts down the accept loop cleanly.\nShuts down all protocol handlers.\nSpawns an accept loop and returns a handle to it …\nA drop guard to clean up test infrastructure.\nHandle and drop guard for test DNS and Pkarr servers.\nCreate a DNS resolver with a single nameserver.\nCreate a ConcurrentDiscovery with DnsDiscovery and …\nCreate a DnsResolver configured to use the test DNS server.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nThe socket address of the DNS server.\nThe node origin domain.\nWait until a Pkarr announce for a node is published to the …\nThe HTTP URL of the Pkarr server.\nRun DNS and Pkarr servers on localhost.\nRuns a relay server with STUN and QUIC enabled suitable …\nRuns a relay server.\nRuns a relay server with STUN enabled suitable for tests.\nRun DNS and Pkarr servers on localhost with the specified …\nA token containing everything to get a file from the …\nThis looks like a ticket, but base32 decoding failed.\nAn error deserializing an iroh ticket.\nString prefix describing the kind of iroh ticket.\nFound a ticket of with the wrong prefix, indicating the …\nA token containing information for establishing a …\nThis looks like a ticket, but postcard deserialization …\nA ticket is a serializable object combining information …\nVerification of the deserialized bytes failed.\nDeserialize from a string.\nThe BlobFormat for this ticket.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreates a ticket from given addressing info.\nReturns the argument unchanged.\nDeserialize from the base32 string representation bytes.\nThe hash of the item this ticket can retrieve.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nGet the contents of the ticket, consuming it.\nCreates a new ticket.\nCreates a new ticket.\nThe NodeAddr of the provider for this ticket.\nThe NodeAddr of the provider for this ticket.\nTrue if the ticket is for a collection and should retrieve …\nSerialize to string.\nSerialize to bytes used in the base32 string …\nError generating the certificate.\nError creating QUIC config.\nError for generating iroh p2p TLS configs.\nX.509 certificate handling.\nReturns the argument unchanged.\nCalls U::from(self).\nCreate a TLS client configuration.\nCreate a TLS server configuration.\nAn error that occurs during certificate generation.\nAn X.509 certificate with a libp2p-specific extension is …\nThe contents of the specific libp2p extension, containing …\nAn error that occurs during certificate parsing.\nAn error that occurs during signature verification.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nGenerates a self-signed TLS certificate that includes a …\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nAttempts to parse the provided bytes as a P2pCertificate.\nThe PublicKey of the remote peer.\nVerify the signature of the message signed by the secret …") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_base/iroh_base-desc-0-.js b/pr/2992/docs/search.desc/iroh_base/iroh_base-desc-0-.js new file mode 100644 index 0000000000..852a4a10b1 --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_base/iroh_base-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_base", 0, "Base types and utilities for Iroh\nThe blake3 hash used in Iroh.\nCryptographic key handling for iroh.\nAddressing for iroh nodes.\nbased on tailscale/tailcfg/derpmap.go\nError when decoding the base32.\nDecoding error\nDecoding error kind\nError when decoding the public key.\nError when parsing a hex or base32 string.\nInvalid length\nInvalid padding length\nInvalid symbol\nNon-zero trailing bits\nConvert to a base32 string\nConvert to a base32 string and append out out\nConvert to a base32 string limited to the first 10 bytes\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nError kind\nParse from a base32 string into a byte array\nParse a fixed length hex or base32 string into a byte array\nDecode form a base32 string to a vector of bytes\nError position\nA format identifier\nThe hash for the empty byte range (b"").\nHash type used throughout.\nA hash and format pair\nA sequence of BLAKE3 hashes\nRaw blob\nBytes of the hash.\nConvert to a base32 string limited to the first 10 bytes …\nThe format\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreate a Hash from its raw bytes representation.\nThe hash\nCreate a new hash and format pair, using the collection …\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nIs hash seq format\nIs raw format\nCalculate the hash of the provided bytes.\nCreate a new hash and format pair.\nCreate a new hash and format pair, using the default (raw) …\nConvert the hash to a hex string.\nSize of an encoded Ed25519 signature in bytes.\nError when decoding the base32.\nError when decoding the public key.\nError when deserialising a PublicKey or a SecretKey.\nThe identifier for a node in the (iroh) network.\nThe length of an ed25519 PublicKey, in bytes.\nA public key.\nA secret key.\nShared Secret.\nEd25519 signature.\nGet this public key as a byte array.\nConvert to a base32 string limited to the first 10 bytes …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nParse an Ed25519 signature from a byte slice.\nConstruct a PublicKey from a slice of bytes.\nCreate a secret key from its byte representation.\nParse an Ed25519 signature from its R and s components.\nParse an Ed25519 signature from a byte slice.\nGenerate a new SecretKey with the default randomness …\nGenerate a new SecretKey with a randomness generator.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nOpens the ciphertext, which must have been created using …\nThe public key of this SecretKey.\nBytes for the R component of a signature.\nBytes for the s component of a signature.\nSeals the provided cleartext.\nReturns the shared key for communication between this key …\nSign the given message and return a digital signature\nReturn the inner byte array.\nConvert this to the bytes representing the secret part. …\nSerialise this key to OpenSSH format.\nConvert this signature into a byte vector.\nDeserialise this key from OpenSSH format.\nVerify a signature on a message with this secret key’s …\nNetwork paths to contact an iroh node.\nOptions to configure what is included in a NodeAddr and …\nIncludes the Node ID and the direct addresses.\nOnly the Node ID is added.\nNetwork-level addressing information for an iroh node.\nIncludes the Node ID and the relay URL.\nIncludes the Node ID and both the relay URL, and the …\nA URL identifying a relay server.\nApplies the options to self.\nApplies the options to self.\nReturns the direct addresses of this peer.\nSocket addresses where the peer might be reached directly.\nReturns the addressing info from given ticket.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreates a new NodeAddr from its parts.\nAddressing information to connect to Self::node_id.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nReturns whether this addressing information is empty.\nCreates a new NodeAddr with empty AddrInfo.\nThe node’s identifier.\nReturns the relay url of this peer.\nThe node’s home relay url.\nAdds the given direct addresses to the peer’s AddrInfo.\nAdds a relay url to the node’s AddrInfo.\nThe default QUIC port used by the Relay server to accept …\nThe default STUN port used by the Relay server.\nConfiguration for speaking to the QUIC endpoint on the …\nConfiguration of all the relay servers that can be used.\nInformation on a specific relay server.\nA URL identifying a relay server.\nIs this a known node?\nCreates a new RelayMap with a single relay server …\nCreate an empty relay map.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nConstructs the RelayMap from an iterator of RelayNodes.\nReturns a RelayMap from a RelayUrl.\nGet the given node.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nAre there any nodes in this map?\nHow many nodes are known?\nReturns an Iterator over all known nodes.\nConfiguration to speak to the QUIC endpoint on the relay …\nWhether this relay server should only be used for STUN …\nThe stun port of the relay server.\nThe RelayUrl where this relay server can be dialed.\nReturns the sorted relay URLs.\nA token containing everything to get a file from the …\nThis looks like a ticket, but base32 decoding failed.\nAn error deserializing an iroh ticket.\nString prefix describing the kind of iroh ticket.\nFound a ticket of with the wrong prefix, indicating the …\nA token containing information for establishing a …\nThis looks like a ticket, but postcard deserialization …\nA ticket is a serializable object combining information …\nVerification of the deserialized bytes failed.\nDeserialize from a string.\nThe BlobFormat for this ticket.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCreates a ticket from given addressing info.\nReturns the argument unchanged.\nDeserialize from the base32 string representation bytes.\nThe hash of the item this ticket can retrieve.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nGet the contents of the ticket, consuming it.\nCreates a new ticket.\nCreates a new ticket.\nThe NodeAddr of the provider for this ticket.\nThe NodeAddr of the provider for this ticket.\nTrue if the ticket is for a collection and should retrieve …\nSerialize to string.\nSerialize to bytes used in the base32 string …") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_dns_server/iroh_dns_server-desc-0-.js b/pr/2992/docs/search.desc/iroh_dns_server/iroh_dns_server-desc-0-.js new file mode 100644 index 0000000000..6d40bf5e82 --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_dns_server/iroh_dns_server-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_dns_server", 0, "A DNS server and pkarr relay\nConfiguration for the server\nImplementation of a DNS name server for iroh node announces\nHTTP server part of iroh-dns-server\nMetrics support for the server\nThe main server which combines the DNS and HTTP(S) servers.\nShared state and store for the iroh-dns-server\nConfigure the bootstrap servers for mainline DHT …\nServer configuration\nUse custom bootstrap servers.\nUse the default bootstrap servers.\nThe config for the metrics server.\nThe config for the metrics server.\nOptionally set a custom address to bind to.\nSet custom bootstrap nodes.\nGet the data directory.\nDisable the metrics server.\nSet to true to disable the metrics server.\nConfig for the DNS server.\nSet to true to enable the mainline lookup.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nConfig for the HTTP server\nConfig for the HTTPS server\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nLoad the config from a file.\nConfig for the mainline lookup.\nConfig for the metrics server.\nConfig for pkarr rate limit\nGet the path to the store database file.\nDNS server settings\nState for serving DNS\nA DNS server that serves pkarr signed packets.\nA handle to the channel over which the response to a DNS …\nHandle a DNS request\nThe IPv4 or IPv6 address to bind the UDP DNS server. Uses …\nSOA record data for any authoritative DNS records\nDefault time to live for returned DNS records (TXT & SOA)\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nGet the local address of the UDP/TCP socket.\nCreate a DNS server given some settings, a connection to …\nDomain used for serving the _iroh_node.<nodeid>.<origin> …\nThe port to serve a local UDP DNS server at\nA record to set for all origins\nAAAA record to set for all origins\nNS record to set for all origins\nWait for all tasks to complete.\nShutdown the server an wait for all tasks to complete.\nSpawn the server.\nThe mode how SSL certificates should be created.\nDisable rate limit.\nConfig for the HTTP server\nThe HTTP(S) server part of iroh-dns-server\nConfig for the HTTPS server\nACME with LetsEncrypt servers\nCerts are loaded from a the cert_cache path\nConfig for http server rate limit.\nCreate self-signed certificates and store them in the …\nEnable rate limit based on the connection’s peer IP …\nEnable rate limit based on headers commonly used by …\nOptionally set a custom bind address (will use 0.0.0.0 if …\nOptionally set a custom bind address (will use 0.0.0.0 if …\nThe mode of SSL certificate creation\nThe list of domains for which SSL certificates should be …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nGet the bound address of the HTTP socket.\nGet the bound address of the HTTPS socket.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nLetsencrypt contact email address (required if using …\nWhether to use the letsenrypt production servers (only …\nPort to bind to\nPort to bind to\nWait for all tasks to complete.\nShutdown the server and wait for all tasks to complete.\nSpawn the server\nMetrics for iroh-dns-server\nReturns the argument unchanged.\nInit the metrics collection core.\nCalls U::from(self).\nThe iroh-dns server.\nReturns the argument unchanged.\nCalls U::from(self).\nWait for all tasks to complete.\nSpawn the server and run until the Ctrl-C signal is …\nCancel the server tasks and wait for all tasks to complete.\nSpawn the server.\nThe shared app state.\nHandler for DNS requests\nReturns the argument unchanged.\nCalls U::from(self).\nThe pkarr DNS store") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_net_bench/iroh_net_bench-desc-0-.js b/pr/2992/docs/search.desc/iroh_net_bench/iroh_net_bench-desc-0-.js new file mode 100644 index 0000000000..56306d3ea2 --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_net_bench/iroh_net_bench-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_net_bench", 0, "Take the provided endpoint and run the client benchmark\nThe total number of clients which should be created\nNumber of bytes to transmit from server to client\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nStarting guess for maximum UDP payload size\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nThe amount of concurrent streams which should be used\nShow iroh library counter metrics at the end of the …\nWhether to use the unordered read API\nShow connection stats the at the end of the benchmark\nThe total number of streams which should be created\nNumber of bytes to transmit from client to server\nWhether to run a local relay and have the server and …\nCreate and run a client\nCreate a client endpoint and client connection\nTake the provided endpoint and run the server\nCreates a server endpoint which runs on the given runtime\nCreate and run a client\nCreate a client endpoint and client connection\nTake the provided endpoint and run the server\nCreates a server endpoint which runs on the given runtime\nReturns the argument unchanged.\nCalls U::from(self).\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_net_report/iroh_net_report-desc-0-.js b/pr/2992/docs/search.desc/iroh_net_report/iroh_net_report-desc-0-.js new file mode 100644 index 0000000000..bec251e28f --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_net_report/iroh_net_report-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_net_report", 0, "Checks the network conditions from the current host.\nSender to the main service.\nClient to run net_reports.\nEnum of metrics for the module\nLatencies per relay node.\nA net_report report.\nReturns a new address to send messages to this actor.\nCaptivePortal is set when we think there’s a captive …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nRuns a net_report, returning the report.\nGet report with channel\nip:port of global IPv4\n[ip]:port of global IPv6\nWhether the router supports communicating between two …\nAn ICMPv4 round trip completed, None if not checked.\nAn ICMPv6 round trip completed, None if not checked.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nAn IPv4 STUN round trip completed.\nan IPv4 packet was able to be sent\nAn IPv6 STUN round trip completed.\nAn IPv6 packet was able to be sent\nReturns an iterator over all the relays and their …\nWhether STUN results depend on which STUN server you’re …\nWhether STUN results depend on which STUN server you’re …\nCreates a new net_report client.\nTest if IPv6 works at all, or if it’s been hard disabled …\ncould bind a socket to ::1\nProbe indicating the presence of port mapping protocols on …\nNone for unknown\nPass a received STUN packet to the net_reporter.\nkeyed by relay Url\nkeyed by relay Url\nkeyed by relay Url\nA UDP STUN round trip completed.") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_node_util/iroh_node_util-desc-0-.js b/pr/2992/docs/search.desc/iroh_node_util/iroh_node_util-desc-0-.js new file mode 100644 index 0000000000..8543fb60b5 --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_node_util/iroh_node_util-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_node_util", 0, "Utilities for building iroh nodes.\nCli commands.\nUtilities to get default paths for configuration, data, …\nUtilities for filesystem operations.\nLoads a SecretKey from the provided file, or stores a …\nUtilities for logging\nRPC client, server and protocol to control iroh endpoints …\nDefine the net subcommands.\nNode commands\nAdd this node addr to the known nodes.\nGet the relay server we are connected to.\nCommands to manage the iroh network.\nGet the node addr of this node.\nGet information about a particular remote node.\nGet information about the different remote nodes.\nReturns the argument unchanged.\nCalls U::from(self).\nRuns the net command given the iroh client.\nCommands to manage the iroh RPC.\nShutdown the running node.\nGet statistics and metrics from the running node.\nGet status of the running node.\nReturns the argument unchanged.\nCalls U::from(self).\nRun the RPC command given the iroh client and the console …\nShutdown mode.\nReturns the path to the user’s cache directory for the …\nReturns the path to the user’s config directory for the …\nReturns the path to the user’s data directory for the …\nLoads a SecretKey from the provided file, or stores a …\nWrapper to obtain a tracing_subscriber::EnvFilter that …\nConfiguration for the logfiles.\nHow often should a new file be created for file logs.\nWhere to store log files.\nParse <bin>_FILE_RUST_LOG as tracing_subscriber::EnvFilter…\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nInitialize logging both in the terminal and file based.\nInitialize logging in the terminal.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nMaximum number of files to keep.\nHow often should a new log file be produced.\nRUST_LOG directive to filter file logs.\nClient to interact with iroh nodes and endpoints.\nRPC protocol definitions for controlling iroh endpoints …\nServer implementation to handle node and net rpc requests\nAPI to manage the iroh networking stack.\nClient to interact with an iroh node.\nIroh net Client.\nThe response to a version request\nAdds a known node address to this node.\nThe node id and socket addresses of this node.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the relay server we are connected to.\nCalls U::from(self).\nCalls U::from(self).\nThe bound listening addresses of the node\nCreates a new net client\nFetches the NodeAddr for this node.\nFetches the node id of this node.\nFetches node information about a remote iroh node …\nFetches information about currently known remote nodes.\nRPC address, if currently listening.\nThe version of the node\nClient to interact with an iroh node.\nReturns the argument unchanged.\nCalls U::from(self).\nCreates a new node client\nShuts down the node.\nFetches statistics of the running node.\nFetches status information about this node.\nRequest, either net or node\nResponse, either net or node\nThe RPC service\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nRPC calls to control an iroh endpoint.\nRPC calls to control a generic node.\nA request to get information the identity of the node.\nA request to watch for the node status\nGet information about a specific remote node.\nA response to a Request::RemoteInfo request\nList network path information about all the remote nodes …\nA response to a Request::RemoteInfosIter.\nThe response to a watch request\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nInformation about a node.\nInformation about a node\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nThe node identifier\nThe version of the node\nCounter stats\nA request to shutdown the node\nGet stats for the running Iroh node\nResponse to StatsRequest\nA request to get information about the status of the node.\nThe counter description\nForce shutdown\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nMap of statistics\nThe counter value\nTrait that provides fields used by the rpc handler for the …\nGet the endpoint of the node\nHandle rpc requests for the node and net services\nRpc address of the node, used by the node status rpc call\nShutdown the node, used by the node shutdown rpc call\nStats for the node stats rpc call") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_relay/iroh_relay-desc-0-.js b/pr/2992/docs/search.desc/iroh_relay/iroh_relay-desc-0-.js new file mode 100644 index 0000000000..4f8d11865f --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_relay/iroh_relay-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_relay", 0, "Iroh’s relay is a feature within iroh, a peer-to-peer …\nA one-way message from server to client, declaring the …\nA one-way empty message from server to client, just to …\nIndicates that the client identified by the underlying …\nRequest from a client or server to reply to the other side …\nReply to a ReceivedMessage::Ping from a client or server …\nThe type of message received by the Conn from a relay …\nRepresents an incoming packet.\nA connection to a relay server.\nA URL identifying a relay server.\nA one-way message from server to client, advertising that …\nExposes Client, which allows to establish connections to a …\nClose the connection\nDefault values used in the relay.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nHTTP-specific constants for the relay server and client.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nWhether or not this Conn is closed.\nThe local address that the Conn is listening on.\nSends a packet that tells the server whether this …\nProtocols used by the iroh-relay\nCreate a QUIC server that accepts connections for QUIC …\nSends a packet to the node identified by dstkey\nSend a ping with 8 bytes of random data.\nRespond to a ping request. The data field should be filled …\nA fully-fledged iroh-relay server over HTTP or HTTPS.\nThe received packet bytes.\nIf set, is a description of why the connection is …\nAn advisory duration that the client should wait before …\nThe NodeId of the packet sender.\nAn advisory duration for how long the client should …\nThe inner actor is gone, likely means things are shutdown.\nThe relay super::client::Client failed to build\nThis Client cannot acknowledge pings\nAn HTTP Relay client.\nBuild a Client.\nPossible connection errors on the Client\nReceiving end of a Client.\nThe client is closed\nThere was a connection timeout error\nThere was an error dialing\nThere was an error from the task doing the dialing\nThere was an error with DNS resolution\nThere was a timeout resolving DNS.\nThere was an http error http::Error.\nThere was http server hyper::Error\nBoth IPv4 and IPv6 are disabled for this relay node\nThe given Url is invalid\nThere no underlying relay super::client::Client client …\nNo local addresses exist\nNo relay nodes are available with that name\nThe ping request was aborted\nThe ping request timed out\nThe connection failed to proxy\nThere was an error receiving a packet\nNo relay nodes are available\nThere was an error sending a packet\nThe relay node specified only allows STUN requests\nThere was an unexpected status code\nThe connection failed to upgrade\nAn error related to websockets, either errors with parsing …\nReturns if we should prefer ipv6 it replaces the …\nBuild the Client\nEnable this Client to acknowledge pings.\nClose the http relay connection.\nDisconnect the http relay connection.\nConnects to a relay Server and returns the underlying …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nSkip the verification of the relay server’s SSL …\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nReturns true if the underlying relay connection is …\nIndicate this client is the preferred way to communicate …\nIndicates this client is a prober\nGet the local addr of the connection. If there is no …\nCreate a new ClientBuilder\nLet the server know that this client is the preferred …\nSend a ping to the server. Return once we get an expected …\nSets whether to connect to the relay via websockets or not.\nSet an explicit proxy url to proxy all HTTP(S) traffic …\nThe public key for this client\nReads a message from the server.\nSend a packet to the server.\nSend a pong back to the server.\nThe expected PublicKey of the relay server we are …\nSets the server url\nThe default HTTPS port used by the Relay server.\nThe default HTTP port used by the Relay server.\nThe default metrics port used by the Relay server.\nThe default QUIC port used by the Relay server to accept …\nThe default STUN port used by the Relay server.\nThe HTTP upgrade protocol used for relaying.\nThe HTTP path under which the relay accepts relaying …\nThe HTTP path under which the relay allows doing latency …\nRelays over the custom relaying protocol with a custom …\nRelays over websockets.\nReturns the argument unchanged.\nCalls U::from(self).\nTries to match the value of an HTTP upgrade header to …\nThe HTTP upgrade header used or expected.\nThis module exports looks_like_disco_wrapper as the only …\nThis module implements the relaying protocol used the …\nSTUN packets sending and receiving.\nThe 6 byte header of all discovery messages.\nReports whether p looks like it’s a packet containing an …\nThe maximum size of a packet sent over relay. (This only …\nThe AlternateServeratribute\nErrors that can occur when handling a STUN packet.\nThe ErrorCodeatribute\nerror response\nThe Fingerprintatribute\nindication\nSTUN request had bogus fingerprint.\nThe STUN message could not be parsed or is otherwise …\nSTUN response has malformed attributes.\nThe MappedAddressatribute\nThe STUN message class. Although there are four message …\nClass used to decode STUN messages\nThe MessageIntegrityatribute\nThe MessageIntegritySha256atribute\nSTUN request didn’t end in fingerprint.\nThe Nonceatribute\nSTUN request is not a binding request when it should be.\nSTUN packet is not a response when it should be.\nThe PasswordAlgorithmatribute\nThe PasswordAlgorithmsatribute\nThe Realmatribute\nrequest\nThe Softwareatribute\nSTUN Attributes that can be attached to a StunMessage\nDescribes an error decoding a StunMessage\nsuccess response\nThe transaction ID is a 96-bit identifier, used to …\nThe Unknownatribute\nThe UnknownAttributesatribute\nThe UserHashatribute\nThe UserNameatribute\nThe XorMappedAddressatribute\nReturns a reference to the internal attribute value or an …\nReturns a reference to the bytes that represents the …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns a reference to the internal attribute value or an …\nReturns the STUN attribute type of this instance.\nDecodes the STUN raw buffer\nCreates a cryptographically random transaction ID chosen …\nReturns a reference to the AlternateServer attribute.\nReturns a reference to the ErrorCode attribute.\nReturns a reference to the Fingerprint attribute.\nReturns a reference to the MappedAddress attribute.\nReturns a reference to the MessageIntegrity attribute.\nReturns a reference to the MessageIntegritySha256 …\nReturns a reference to the Nonce attribute.\nReturns a reference to the PasswordAlgorithm attribute.\nReturns a reference to the PasswordAlgorithms attribute.\nReturns a reference to the Realm attribute.\nReturns a reference to the Software attribute.\nReturns a reference to the Unknown attribute.\nReturns a reference to the UnknownAttributes attribute.\nReturns a reference to the UserHash attribute.\nReturns a reference to the UserName attribute.\nReturns a reference to the XorMappedAddress attribute.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nGets the context associated to this decoder\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nReports whether b is a STUN message.\nReturns true if this StunAttribute is AlternateServer\nReturns true if this StunAttribute is ErrorCode\nReturns true if this StunAttribute is Fingerprint\nReturns true if this StunAttribute is MappedAddress\nReturns true if this StunAttribute is MessageIntegrity\nReturns true if this StunAttribute is …\nReturns true if this StunAttribute is Nonce\nReturns true if this StunAttribute is PasswordAlgorithm\nReturns true if this StunAttribute is PasswordAlgorithms\nReturns true if this StunAttribute is Realm\nReturns true if this StunAttribute is Software\nReturns true if this StunAttribute is Unknown\nReturns true if this StunAttribute is UnknownAttributes\nReturns true if this StunAttribute is UserHash\nReturns true if this StunAttribute is UserName\nReturns true if this StunAttribute is XorMappedAddress\nSTUN Methods Registry\nParses a STUN binding request.\nParses a successful binding response STUN packet. The IP …\nGenerates a binding request STUN packet.\nGenerates a binding response.\nBinding\nReserved\nShared secret\nALPN for our quic addr discovery\nEndpoint close error code\nEndpoint close reason\nHandles the client side of QUIC address discovery.\nReturns the argument unchanged.\nClient side of QUIC address discovery.\nCalls U::from(self).\nCreate a new QuicClient to handle the client side of QUIC …\nTLS certificate configuration.\nPer-client rate limit configuration.\nUse Let’s Encrypt.\nRate limits.\nUse a static TLS key and certificate chain.\nThe main underlying IO stream type used for the relay …\nMetrics tracked for the relay server\nA plain non-Tls tokio::net::TcpStream\nConfiguration for the QUIC server.\nConfiguration for the Relay HTTP and HTTPS server.\nA running Relay + STUN server.\nConfiguration for the full Relay & STUN server.\nConfiguration for the STUN server.\nStunMetrics tracked for the DERPER\nA Tls wrapped tokio::net::TcpStream\nTLS configuration for Relay server.\nBurst limit for accepting new connection. Unlimited if not …\nRate limit for accepting new connection. Unlimited if not …\nNumber of connections we have accepted\nNumber of bad requests, either non-stun packets or …\nThe socket address on which the STUN server should bind.\nThe socket address on which the QUIC server should bind.\nMax number of bytes per second to read from the client …\nBytes received from a FrameType::SendPacket\nBytes sent from a FrameType::SendPacket\nMode for getting a cert.\nThe certificates chain if configured with manual TLS …\nRate limits for incoming traffic from a client connection.\nNumber of client connections which have had any frames …\nNumber of accepted ‘iroh derp http’ connection upgrades\nFrameType::SendPacket dropped that are disco messages\nFrameType::SendPacket received that are disco messages\nFrameType::SendPacket sent that are disco messages\nNumber of connections we have removed because of an error\nNumber of failures\nNumber of frames received from client connection which …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nNumber of FrameType::Pings received\nThe socket address the HTTP server is listening on.\nThe socket address on which the Relay HTTP server should …\nGet the server’s http RelayUrl.\nThe socket address the HTTPS server is listening on.\nThe socket address on which to serve the HTTPS server.\nGet the server’s https RelayUrl.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nNumber of successful requests over ipv4\nNumber of successful requests over ipv6\nRate limits.\nMax number of bytes to read in a single burst.\nSocket to serve metrics on.\nPackets of other FrameTypes dropped\nPackets of other FrameTypes received\nPackets of other FrameTypes sent\nConfiguration for the QUIC server, disabled if None.\nThe socket address the QUIC server is listening on.\nThe socket address on which to server the QUIC server is …\nConfiguration for the Relay server, disabled if None.\nNumber of stun requests made\nFrameType::SendPacket dropped, that are not disco messages\nFrameType::SendPacket received, that are not disco messages\nFrameType::SendPacket sent, that are not disco messages\nNumber of FrameType::Pongs sent\nThe TLS server configuration for the QUIC server.\nThe server configuration.\nRequests graceful shutdown.\nStarts the server.\nConfiguration for the STUN server, disabled if None.\nThe socket address the STUN server is listening on.\nReturns the handle for the task.\nExposes functions to quickly configure a server suitable …\nTLS configuration for the HTTPS server.\nNumber of unique client keys per day\nNumber of FrameType::Unknown received\nNumber of accepted websocket connections\nThe TLS certificate chain.\nState for Let’s Encrypt certificates.\nCreates a QuicConfig suitable for testing.\nCreates a RelayConfig suitable for testing.\nCreates a rustls::ServerConfig and certificates suitable …\nCreates a ServerConfig suitable for testing.\nCreates a StunConfig suitable for testing.\nCreates a TlsConfig suitable for testing.") \ No newline at end of file diff --git a/pr/2992/docs/search.desc/iroh_test/iroh_test-desc-0-.js b/pr/2992/docs/search.desc/iroh_test/iroh_test-desc-0-.js new file mode 100644 index 0000000000..06bc64079d --- /dev/null +++ b/pr/2992/docs/search.desc/iroh_test/iroh_test-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("iroh_test", 0, "Internal utilities to support testing.\nThis is a macro to assert that two byte slices are equal.\nReturns the argument unchanged.\nCalls U::from(self).\nLogging during tests.\nParses a commented multi line hexdump into a vector of …\nReturns a hexdump of the given bytes in multiple lines as …\nConfigures logging for the current test, single-threaded …\nThe first call to this function will install a global …\nReturns the a tracing::Subscriber configured for our tests.") \ No newline at end of file diff --git a/pr/2992/docs/settings.html b/pr/2992/docs/settings.html new file mode 100644 index 0000000000..ba10cf9e76 --- /dev/null +++ b/pr/2992/docs/settings.html @@ -0,0 +1 @@ +Settings

Rustdoc settings

Back
\ No newline at end of file diff --git a/pr/2992/docs/src-files.js b/pr/2992/docs/src-files.js new file mode 100644 index 0000000000..e5f96c3a2c --- /dev/null +++ b/pr/2992/docs/src-files.js @@ -0,0 +1,12 @@ +var srcIndex = new Map(JSON.parse('[\ +["bulk",["",[],["bulk.rs"]]],\ +["iroh",["",[["discovery",[["pkarr",[],["dht.rs"]]],["dns.rs","local_swarm_discovery.rs","pkarr.rs","static_provider.rs"]],["dns",[],["node_info.rs"]],["endpoint",[],["rtt_actor.rs"]],["magicsock",[["node_map",[],["best_addr.rs","node_state.rs","path_state.rs","udp_paths.rs"]]],["metrics.rs","node_map.rs","relay_actor.rs","timer.rs","udp_conn.rs"]],["tls",[],["certificate.rs","verifier.rs"]]],["defaults.rs","dialer.rs","disco.rs","discovery.rs","dns.rs","endpoint.rs","lib.rs","magicsock.rs","metrics.rs","protocol.rs","test_utils.rs","tls.rs","util.rs"]]],\ +["iroh_base",["",[["key",[],["encryption.rs"]],["ticket",[],["blob.rs","node.rs"]]],["base32.rs","hash.rs","key.rs","lib.rs","node_addr.rs","relay_map.rs","relay_url.rs","ticket.rs"]]],\ +["iroh_dns_server",["",[["dns",[],["node_authority.rs"]],["http",[["doh",[],["extract.rs","response.rs"]]],["doh.rs","error.rs","pkarr.rs","rate_limiting.rs","tls.rs"]],["store",[],["signed_packets.rs"]]],["config.rs","dns.rs","http.rs","lib.rs","metrics.rs","server.rs","state.rs","store.rs","util.rs"]]],\ +["iroh_net_bench",["",[],["iroh.rs","lib.rs","quinn.rs","s2n.rs","stats.rs"]]],\ +["iroh_net_report",["",[["reportgen",[],["hairpin.rs","probes.rs"]]],["defaults.rs","dns.rs","lib.rs","metrics.rs","ping.rs","reportgen.rs"]]],\ +["iroh_node_util",["",[["cli",[],["net.rs","node.rs"]],["rpc",[["client",[],["net.rs","node.rs"]],["proto",[],["net.rs","node.rs"]]],["client.rs","proto.rs","server.rs"]]],["cli.rs","config.rs","fs.rs","lib.rs","logging.rs","rpc.rs"]]],\ +["iroh_relay",["",[["client",[],["conn.rs","streams.rs","util.rs"]],["protos",[],["disco.rs","relay.rs","stun.rs"]],["server",[],["actor.rs","client_conn.rs","clients.rs","http_server.rs","metrics.rs","streams.rs","testing.rs"]]],["client.rs","defaults.rs","http.rs","lib.rs","protos.rs","quic.rs","server.rs"]]],\ +["iroh_test",["",[],["hexdump.rs","lib.rs","logging.rs"]]]\ +]')); +createSrcSidebar(); diff --git a/pr/2992/docs/src/bulk/bulk.rs.html b/pr/2992/docs/src/bulk/bulk.rs.html new file mode 100644 index 0000000000..ab6a7f1e03 --- /dev/null +++ b/pr/2992/docs/src/bulk/bulk.rs.html @@ -0,0 +1,397 @@ +bulk.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+
use std::collections::BTreeMap;
+
+use anyhow::Result;
+use clap::Parser;
+#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+use iroh_net_bench::quinn;
+use iroh_net_bench::{configure_tracing_subscriber, iroh, rt, s2n, Commands, Opt};
+
+fn main() {
+    let cmd = Commands::parse();
+    configure_tracing_subscriber();
+
+    match cmd {
+        Commands::Iroh(opt) => {
+            if let Err(e) = run_iroh(opt) {
+                eprintln!("failed: {e:#}");
+            }
+        }
+        #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+        Commands::Quinn(opt) => {
+            if let Err(e) = run_quinn(opt) {
+                eprintln!("failed: {e:#}");
+            }
+        }
+        Commands::S2n(opt) => {
+            if let Err(e) = run_s2n(opt) {
+                eprintln!("failed: {e:#}");
+            }
+        }
+    }
+}
+
+pub fn run_iroh(opt: Opt) -> Result<()> {
+    if opt.metrics {
+        // enable recording metrics
+        iroh_metrics::core::Core::try_init(|reg, metrics| {
+            use iroh_metrics::core::Metric;
+            metrics.insert(::iroh::metrics::MagicsockMetrics::new(reg));
+            metrics.insert(::iroh::metrics::NetReportMetrics::new(reg));
+            metrics.insert(::iroh::metrics::PortmapMetrics::new(reg));
+            #[cfg(feature = "local-relay")]
+            if opt.with_relay {
+                metrics.insert(::iroh::metrics::RelayMetrics::new(reg));
+            }
+        })?;
+    }
+
+    #[cfg(not(feature = "local-relay"))]
+    if opt.with_relay {
+        anyhow::bail!(
+            "Must compile the benchmark with the `local-relay` feature flag to use this option"
+        );
+    }
+
+    let server_span = tracing::error_span!("server");
+    let runtime = rt();
+
+    #[cfg(feature = "local-relay")]
+    let (relay_url, _guard) = if opt.with_relay {
+        let (_, relay_url, _guard) = runtime.block_on(::iroh::test_utils::run_relay_server())?;
+
+        (Some(relay_url), Some(_guard))
+    } else {
+        (None, None)
+    };
+    #[cfg(not(feature = "local-relay"))]
+    let relay_url = None;
+
+    let (server_addr, endpoint) = {
+        let _guard = server_span.enter();
+        iroh::server_endpoint(&runtime, &relay_url, &opt)
+    };
+
+    let server_thread = std::thread::spawn(move || {
+        let _guard = server_span.entered();
+        if let Err(e) = runtime.block_on(iroh::server(endpoint, opt)) {
+            eprintln!("server failed: {e:#}");
+        }
+    });
+
+    let mut handles = Vec::new();
+    for id in 0..opt.clients {
+        let server_addr = server_addr.clone();
+        let relay_url = relay_url.clone();
+        handles.push(std::thread::spawn(move || {
+            let _guard = tracing::error_span!("client", id).entered();
+            let runtime = rt();
+            match runtime.block_on(iroh::client(server_addr, relay_url.clone(), opt)) {
+                Ok(stats) => Ok(stats),
+                Err(e) => {
+                    eprintln!("client failed: {e:#}");
+                    Err(e)
+                }
+            }
+        }));
+    }
+
+    for (id, handle) in handles.into_iter().enumerate() {
+        // We print all stats at the end of the test sequentially to avoid
+        // them being garbled due to being printed concurrently
+        if let Ok(stats) = handle.join().expect("client thread") {
+            stats.print(id);
+        }
+    }
+
+    if opt.metrics {
+        // print metrics
+        let core =
+            iroh_metrics::core::Core::get().ok_or_else(|| anyhow::anyhow!("Missing metrics"))?;
+        println!("\nMetrics:");
+        collect_and_print(
+            "MagicsockMetrics",
+            core.get_collector::<::iroh::metrics::MagicsockMetrics>(),
+        );
+        collect_and_print(
+            "NetReportMetrics",
+            core.get_collector::<::iroh::metrics::NetReportMetrics>(),
+        );
+        collect_and_print(
+            "PortmapMetrics",
+            core.get_collector::<::iroh::metrics::PortmapMetrics>(),
+        );
+        // if None, (this is the case if opt.with_relay is false), then this is skipped internally:
+        #[cfg(feature = "local-relay")]
+        collect_and_print(
+            "RelayMetrics",
+            core.get_collector::<::iroh::metrics::RelayMetrics>(),
+        );
+    }
+
+    server_thread.join().expect("server thread");
+
+    Ok(())
+}
+
+#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+pub fn run_quinn(opt: Opt) -> Result<()> {
+    let server_span = tracing::error_span!("server");
+    let runtime = rt();
+    let (server_addr, endpoint) = {
+        let _guard = server_span.enter();
+        quinn::server_endpoint(&runtime, &opt)
+    };
+
+    let server_thread = std::thread::spawn(move || {
+        let _guard = server_span.entered();
+        if let Err(e) = runtime.block_on(quinn::server(endpoint, opt)) {
+            eprintln!("server failed: {e:#}");
+        }
+    });
+
+    let mut handles = Vec::new();
+    for id in 0..opt.clients {
+        handles.push(std::thread::spawn(move || {
+            let _guard = tracing::error_span!("client", id).entered();
+            let runtime = rt();
+            match runtime.block_on(quinn::client(server_addr, opt)) {
+                Ok(stats) => Ok(stats),
+                Err(e) => {
+                    eprintln!("client failed: {e:#}");
+                    Err(e)
+                }
+            }
+        }));
+    }
+
+    for (id, handle) in handles.into_iter().enumerate() {
+        // We print all stats at the end of the test sequentially to avoid
+        // them being garbled due to being printed concurrently
+        if let Ok(stats) = handle.join().expect("client thread") {
+            stats.print(id);
+        }
+    }
+
+    server_thread.join().expect("server thread");
+
+    Ok(())
+}
+
+pub fn run_s2n(_opt: s2n::Opt) -> Result<()> {
+    unimplemented!()
+}
+
+fn collect_and_print(
+    category: &'static str,
+    metrics: Option<&impl iroh_metrics::struct_iterable::Iterable>,
+) {
+    let Some(metrics) = metrics else {
+        return;
+    };
+    let mut map = BTreeMap::new();
+    for (name, counter) in metrics.iter() {
+        if let Some(counter) = counter.downcast_ref::<iroh_metrics::core::Counter>() {
+            map.insert(name.to_string(), counter.get());
+        }
+    }
+    println!("{category}: {map:#?}");
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/defaults.rs.html b/pr/2992/docs/src/iroh/defaults.rs.html new file mode 100644 index 0000000000..1fcbd6bb14 --- /dev/null +++ b/pr/2992/docs/src/iroh/defaults.rs.html @@ -0,0 +1,299 @@ +defaults.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+
//! Default values used in [`iroh`][`crate`]
+
+use iroh_base::relay_map::QuicConfig;
+/// The default QUIC port used by the Relay server to accept QUIC connections
+/// for QUIC address discovery
+///
+/// The port is "QUIC" typed on a phone keypad.
+pub use iroh_base::relay_map::DEFAULT_RELAY_QUIC_PORT;
+/// The default STUN port used by the Relay server.
+///
+/// The STUN port as defined by [RFC
+/// 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
+pub use iroh_base::relay_map::DEFAULT_STUN_PORT;
+use url::Url;
+
+use crate::{RelayMap, RelayNode};
+
+/// The default HTTP port used by the Relay server.
+pub const DEFAULT_HTTP_PORT: u16 = 80;
+
+/// The default HTTPS port used by the Relay server.
+pub const DEFAULT_HTTPS_PORT: u16 = 443;
+
+/// The default metrics port used by the Relay server.
+pub const DEFAULT_METRICS_PORT: u16 = 9090;
+
+/// Production configuration.
+pub mod prod {
+    use iroh_base::relay_map::QuicConfig;
+
+    use super::*;
+
+    /// Hostname of the default NA relay.
+    pub const NA_RELAY_HOSTNAME: &str = "use1-1.relay.iroh.network.";
+    /// Hostname of the default EU relay.
+    pub const EU_RELAY_HOSTNAME: &str = "euw1-1.relay.iroh.network.";
+    /// Hostname of the default Asia-Pacific relay.
+    pub const AP_RELAY_HOSTNAME: &str = "aps1-1.relay.iroh.network.";
+
+    /// Get the default [`RelayMap`].
+    pub fn default_relay_map() -> RelayMap {
+        RelayMap::from_nodes([
+            default_na_relay_node(),
+            default_eu_relay_node(),
+            default_ap_relay_node(),
+        ])
+        .expect("default nodes invalid")
+    }
+
+    /// Get the default [`RelayNode`] for NA.
+    pub fn default_na_relay_node() -> RelayNode {
+        // The default NA relay server run by number0.
+        let url: Url = format!("https://{NA_RELAY_HOSTNAME}")
+            .parse()
+            .expect("default url");
+        RelayNode {
+            url: url.into(),
+            stun_only: false,
+            stun_port: DEFAULT_STUN_PORT,
+            quic: Some(QuicConfig::default()),
+        }
+    }
+
+    /// Get the default [`RelayNode`] for EU.
+    pub fn default_eu_relay_node() -> RelayNode {
+        // The default EU relay server run by number0.
+        let url: Url = format!("https://{EU_RELAY_HOSTNAME}")
+            .parse()
+            .expect("default_url");
+        RelayNode {
+            url: url.into(),
+            stun_only: false,
+            stun_port: DEFAULT_STUN_PORT,
+            quic: Some(QuicConfig::default()),
+        }
+    }
+
+    /// Get the default [`RelayNode`] for Asia-Pacific
+    pub fn default_ap_relay_node() -> RelayNode {
+        // The default Asia-Pacific relay server run by number0.
+        let url: Url = format!("https://{AP_RELAY_HOSTNAME}")
+            .parse()
+            .expect("default_url");
+        RelayNode {
+            url: url.into(),
+            stun_only: false,
+            stun_port: DEFAULT_STUN_PORT,
+            quic: Some(QuicConfig::default()),
+        }
+    }
+}
+
+/// Staging configuration.
+///
+/// Used by tests and might have incompatible changes deployed
+///
+/// Note: we have staging servers in EU and NA, but no corresponding staging server for AP at this time.
+pub mod staging {
+    use super::*;
+
+    /// Hostname of the default NA relay.
+    pub const NA_RELAY_HOSTNAME: &str = "staging-use1-1.relay.iroh.network.";
+    /// Hostname of the default EU relay.
+    pub const EU_RELAY_HOSTNAME: &str = "staging-euw1-1.relay.iroh.network.";
+
+    /// Get the default [`RelayMap`].
+    pub fn default_relay_map() -> RelayMap {
+        RelayMap::from_nodes([default_na_relay_node(), default_eu_relay_node()])
+            .expect("default nodes invalid")
+    }
+
+    /// Get the default [`RelayNode`] for NA.
+    pub fn default_na_relay_node() -> RelayNode {
+        // The default NA relay server run by number0.
+        let url: Url = format!("https://{NA_RELAY_HOSTNAME}")
+            .parse()
+            .expect("default url");
+        RelayNode {
+            url: url.into(),
+            stun_only: false,
+            stun_port: DEFAULT_STUN_PORT,
+            quic: Some(QuicConfig::default()),
+        }
+    }
+
+    /// Get the default [`RelayNode`] for EU.
+    pub fn default_eu_relay_node() -> RelayNode {
+        // The default EU relay server run by number0.
+        let url: Url = format!("https://{EU_RELAY_HOSTNAME}")
+            .parse()
+            .expect("default_url");
+        RelayNode {
+            url: url.into(),
+            stun_only: false,
+            stun_port: DEFAULT_STUN_PORT,
+            quic: Some(QuicConfig::default()),
+        }
+    }
+}
+
+/// Contains all timeouts that we use in `iroh`.
+pub(crate) mod timeouts {
+    use std::time::Duration;
+
+    // Timeouts for net_report
+
+    /// Maximum duration to wait for a net_report.
+    pub(crate) const NET_REPORT_TIMEOUT: Duration = Duration::from_secs(10);
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/dialer.rs.html b/pr/2992/docs/src/iroh/dialer.rs.html new file mode 100644 index 0000000000..fe0be38c54 --- /dev/null +++ b/pr/2992/docs/src/iroh/dialer.rs.html @@ -0,0 +1,257 @@ +dialer.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+
//! A dialer to conveniently dial many nodes.
+
+use std::{collections::HashMap, pin::Pin, task::Poll};
+
+use anyhow::anyhow;
+use futures_lite::Stream;
+use tokio::task::JoinSet;
+use tokio_util::sync::CancellationToken;
+use tracing::error;
+
+use crate::{Endpoint, NodeId};
+
+/// Dials nodes and maintains a queue of pending dials.
+///
+/// The [`Dialer`] wraps an [`Endpoint`], connects to nodes through the endpoint, stores the
+/// pending connect futures and emits finished connect results.
+///
+/// The [`Dialer`] also implements [`Stream`] to retrieve the dialled connections.
+#[derive(Debug)]
+pub struct Dialer {
+    endpoint: Endpoint,
+    pending: JoinSet<(NodeId, anyhow::Result<quinn::Connection>)>,
+    pending_dials: HashMap<NodeId, CancellationToken>,
+}
+
+impl Dialer {
+    /// Create a new dialer for a [`Endpoint`]
+    pub fn new(endpoint: Endpoint) -> Self {
+        Self {
+            endpoint,
+            pending: Default::default(),
+            pending_dials: Default::default(),
+        }
+    }
+
+    /// Starts to dial a node by [`NodeId`].
+    ///
+    /// Since this dials by [`NodeId`] the [`Endpoint`] must know how to contact the node by
+    /// [`NodeId`] only.  This relies on addressing information being provided by either the
+    /// [discovery service] or manually by calling [`Endpoint::add_node_addr`].
+    ///
+    /// [discovery service]: crate::discovery::Discovery
+    pub fn queue_dial(&mut self, node_id: NodeId, alpn: &'static [u8]) {
+        if self.is_pending(node_id) {
+            return;
+        }
+        let cancel = CancellationToken::new();
+        self.pending_dials.insert(node_id, cancel.clone());
+        let endpoint = self.endpoint.clone();
+        self.pending.spawn(async move {
+            let res = tokio::select! {
+                biased;
+                _ = cancel.cancelled() => Err(anyhow!("Cancelled")),
+                res = endpoint.connect(node_id, alpn) => res
+            };
+            (node_id, res)
+        });
+    }
+
+    /// Aborts a pending dial.
+    pub fn abort_dial(&mut self, node_id: NodeId) {
+        if let Some(cancel) = self.pending_dials.remove(&node_id) {
+            cancel.cancel();
+        }
+    }
+
+    /// Checks if a node is currently being dialed.
+    pub fn is_pending(&self, node: NodeId) -> bool {
+        self.pending_dials.contains_key(&node)
+    }
+
+    /// Waits for the next dial operation to complete.
+    pub async fn next_conn(&mut self) -> (NodeId, anyhow::Result<quinn::Connection>) {
+        match self.pending_dials.is_empty() {
+            false => {
+                let (node_id, res) = loop {
+                    match self.pending.join_next().await {
+                        Some(Ok((node_id, res))) => {
+                            self.pending_dials.remove(&node_id);
+                            break (node_id, res);
+                        }
+                        Some(Err(e)) => {
+                            error!("next conn error: {:?}", e);
+                        }
+                        None => {
+                            error!("no more pending conns available");
+                            std::future::pending().await
+                        }
+                    }
+                };
+
+                (node_id, res)
+            }
+            true => std::future::pending().await,
+        }
+    }
+
+    /// Number of pending connections to be opened.
+    pub fn pending_count(&self) -> usize {
+        self.pending_dials.len()
+    }
+
+    /// Returns a reference to the endpoint used in this dialer.
+    pub fn endpoint(&self) -> &Endpoint {
+        &self.endpoint
+    }
+}
+
+impl Stream for Dialer {
+    type Item = (NodeId, anyhow::Result<quinn::Connection>);
+
+    fn poll_next(
+        mut self: Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> Poll<Option<Self::Item>> {
+        match self.pending.poll_join_next(cx) {
+            Poll::Ready(Some(Ok((node_id, result)))) => {
+                self.pending_dials.remove(&node_id);
+                Poll::Ready(Some((node_id, result)))
+            }
+            Poll::Ready(Some(Err(e))) => {
+                error!("dialer error: {:?}", e);
+                Poll::Pending
+            }
+            _ => Poll::Pending,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/disco.rs.html b/pr/2992/docs/src/iroh/disco.rs.html new file mode 100644 index 0000000000..04171bf2e5 --- /dev/null +++ b/pr/2992/docs/src/iroh/disco.rs.html @@ -0,0 +1,1011 @@ +disco.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+
//! Contains the discovery message types.
+//!
+//! A discovery message is:
+//!
+//! Header:
+//!
+//! ```ignore
+//! magic:            [u8; 6]  // “TS💬” (0x54 53 f0 9f 92 ac)
+//! sender_disco_pub: [u8; 32] // nacl public key
+//! nonce:            [u8; 24]
+//! ````
+//! The recipient then decrypts the bytes following (the nacl secretbox)
+//! and then the inner payload structure is:
+//!
+//! ```ignore
+//! message_type:    u8   // (the MessageType constants below)
+//! message_version: u8   // (0 for now; but always ignore bytes at the end)
+//! message_payload: &[u8]
+//! ```
+
+use std::{
+    fmt::Display,
+    net::{IpAddr, SocketAddr},
+};
+
+use anyhow::{anyhow, bail, ensure, Context, Result};
+use iroh_relay::RelayUrl;
+use serde::{Deserialize, Serialize};
+use url::Url;
+
+use super::key::PublicKey;
+use crate::key;
+
+// TODO: custom magicn
+/// The 6 byte header of all discovery messages.
+pub const MAGIC: &str = "TS💬"; // 6 bytes: 0x54 53 f0 9f 92 ac
+pub const MAGIC_LEN: usize = MAGIC.as_bytes().len();
+
+/// Current Version.
+const V0: u8 = 0;
+
+pub(crate) const KEY_LEN: usize = 32;
+const TX_LEN: usize = 12;
+
+// Sizes for the inner message structure.
+
+/// Header: Type | Version
+const HEADER_LEN: usize = 2;
+
+const PING_LEN: usize = TX_LEN + key::PUBLIC_KEY_LENGTH;
+const EP_LENGTH: usize = 16 + 2; // 16 byte IP address + 2 byte port
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[repr(u8)]
+pub enum MessageType {
+    Ping = 0x01,
+    Pong = 0x02,
+    CallMeMaybe = 0x03,
+}
+
+impl TryFrom<u8> for MessageType {
+    type Error = u8;
+
+    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+        match value {
+            0x01 => Ok(MessageType::Ping),
+            0x02 => Ok(MessageType::Pong),
+            0x03 => Ok(MessageType::CallMeMaybe),
+            _ => Err(value),
+        }
+    }
+}
+
+const MESSAGE_HEADER_LEN: usize = MAGIC_LEN + KEY_LEN;
+
+pub fn encode_message(sender: &PublicKey, seal: Vec<u8>) -> Vec<u8> {
+    let mut out = Vec::with_capacity(MESSAGE_HEADER_LEN);
+    out.extend_from_slice(MAGIC.as_bytes());
+    out.extend_from_slice(sender.as_bytes());
+    out.extend(seal);
+
+    out
+}
+
+/// Reports whether p looks like it's a packet containing an encrypted disco message.
+pub fn looks_like_disco_wrapper(p: &[u8]) -> bool {
+    if p.len() < MESSAGE_HEADER_LEN {
+        return false;
+    }
+
+    &p[..MAGIC_LEN] == MAGIC.as_bytes()
+}
+
+/// If `p` looks like a disco message it returns the slice of `p` that represents the disco public key source,
+/// and the part that is the box.
+pub fn source_and_box(p: &[u8]) -> Option<(PublicKey, &[u8])> {
+    if !looks_like_disco_wrapper(p) {
+        return None;
+    }
+
+    let source = &p[MAGIC_LEN..MAGIC_LEN + KEY_LEN];
+    let sender = PublicKey::try_from(source).ok()?;
+    let sealed_box = &p[MAGIC_LEN + KEY_LEN..];
+    Some((sender, sealed_box))
+}
+
+/// A discovery message.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Message {
+    Ping(Ping),
+    Pong(Pong),
+    CallMeMaybe(CallMeMaybe),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Ping {
+    /// Random client-generated per-ping transaction ID.
+    pub tx_id: stun_rs::TransactionId,
+
+    /// Allegedly the ping sender's wireguard public key.
+    /// It shouldn't be trusted by itself, but can be combined with
+    /// netmap data to reduce the discokey:nodekey relation from 1:N to 1:1.
+    pub node_key: PublicKey,
+}
+
+/// A response a Ping.
+///
+/// It includes the sender's source IP + port, so it's effectively a STUN response.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Pong {
+    pub tx_id: stun_rs::TransactionId,
+    /// The observed address off the ping sender.
+    ///
+    /// 18 bytes (16+2) on the wire; v4-mapped ipv6 for IPv4.
+    pub ping_observed_addr: SendAddr,
+}
+
+/// Addresses to which we can send. This is either a UDP or a relay address.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum SendAddr {
+    /// UDP, the ip addr.
+    Udp(SocketAddr),
+    /// Relay Url.
+    Relay(RelayUrl),
+}
+
+impl SendAddr {
+    /// Returns if this is a `relay` addr.
+    pub fn is_relay(&self) -> bool {
+        matches!(self, Self::Relay(_))
+    }
+
+    /// Returns the `Some(Url)` if it is a relay addr.
+    pub fn relay_url(&self) -> Option<RelayUrl> {
+        match self {
+            Self::Relay(url) => Some(url.clone()),
+            Self::Udp(_) => None,
+        }
+    }
+}
+
+impl From<SocketAddr> for SendAddr {
+    fn from(source: SocketAddr) -> Self {
+        SendAddr::Udp(source)
+    }
+}
+
+impl From<RelayUrl> for SendAddr {
+    fn from(source: RelayUrl) -> Self {
+        SendAddr::Relay(source)
+    }
+}
+
+impl PartialEq<SocketAddr> for SendAddr {
+    fn eq(&self, other: &SocketAddr) -> bool {
+        match self {
+            Self::Relay(_) => false,
+            Self::Udp(addr) => addr.eq(other),
+        }
+    }
+}
+
+impl Display for SendAddr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            SendAddr::Relay(id) => write!(f, "Relay({})", id),
+            SendAddr::Udp(addr) => write!(f, "UDP({})", addr),
+        }
+    }
+}
+
+/// Message sent only over the relay to request that the recipient try
+/// to open up a magicsock path back to the sender.
+///
+/// The sender should've already sent UDP packets to the peer to open
+/// up the stateful firewall mappings inbound.
+///
+/// The recipient may choose to not open a path back, if it's already happy with its path.
+/// But usually it will.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct CallMeMaybe {
+    /// What the peer believes its endpoints are.
+    pub my_numbers: Vec<SocketAddr>,
+}
+
+impl Ping {
+    fn from_bytes(ver: u8, p: &[u8]) -> Result<Self> {
+        ensure!(ver == V0, "invalid version");
+        // Deliberately lax on longer-than-expected messages, for future compatibility.
+        ensure!(p.len() >= PING_LEN, "message too short");
+        let tx_id: [u8; TX_LEN] = p[..TX_LEN].try_into().expect("length checked");
+        let raw_key = &p[TX_LEN..TX_LEN + key::PUBLIC_KEY_LENGTH];
+        let node_key = PublicKey::try_from(raw_key)?;
+        let tx_id = stun_rs::TransactionId::from(tx_id);
+
+        Ok(Ping { tx_id, node_key })
+    }
+
+    fn as_bytes(&self) -> Vec<u8> {
+        let header = msg_header(MessageType::Ping, V0);
+        let mut out = vec![0u8; PING_LEN + HEADER_LEN];
+
+        out[..HEADER_LEN].copy_from_slice(&header);
+        out[HEADER_LEN..HEADER_LEN + TX_LEN].copy_from_slice(&self.tx_id);
+        out[HEADER_LEN + TX_LEN..].copy_from_slice(self.node_key.as_ref());
+
+        out
+    }
+}
+
+fn send_addr_from_bytes(p: &[u8]) -> Result<SendAddr> {
+    ensure!(p.len() > 2, "too short");
+    match p[0] {
+        0u8 => {
+            let bytes: [u8; EP_LENGTH] = p[1..].try_into().context("invalid length")?;
+            let addr = socket_addr_from_bytes(bytes);
+            Ok(SendAddr::Udp(addr))
+        }
+        1u8 => {
+            let s = std::str::from_utf8(&p[1..])?;
+            let u: Url = s.parse()?;
+            Ok(SendAddr::Relay(u.into()))
+        }
+        _ => {
+            bail!("invalid addr type {}", p[0]);
+        }
+    }
+}
+
+fn send_addr_to_vec(addr: &SendAddr) -> Vec<u8> {
+    match addr {
+        SendAddr::Relay(url) => {
+            let mut out = vec![1u8];
+            out.extend_from_slice(url.to_string().as_bytes());
+            out
+        }
+        SendAddr::Udp(ip) => {
+            let mut out = vec![0u8];
+            out.extend_from_slice(&socket_addr_as_bytes(ip));
+            out
+        }
+    }
+}
+
+// Assumes p.len() == EP_LENGTH
+fn socket_addr_from_bytes(p: [u8; EP_LENGTH]) -> SocketAddr {
+    debug_assert_eq!(EP_LENGTH, 16 + 2);
+
+    let raw_src_ip: [u8; 16] = p[..16].try_into().expect("array long enough");
+    let raw_port: [u8; 2] = p[16..].try_into().expect("array long enough");
+
+    let src_ip = IpAddr::from(raw_src_ip).to_canonical();
+    let src_port = u16::from_le_bytes(raw_port);
+
+    SocketAddr::new(src_ip, src_port)
+}
+
+fn socket_addr_as_bytes(addr: &SocketAddr) -> [u8; EP_LENGTH] {
+    let mut out = [0u8; EP_LENGTH];
+    let ipv6 = match addr.ip() {
+        IpAddr::V4(v4) => v4.to_ipv6_mapped(),
+        IpAddr::V6(v6) => v6,
+    };
+    out[..16].copy_from_slice(&ipv6.octets());
+    out[16..].copy_from_slice(&addr.port().to_le_bytes());
+
+    out
+}
+
+impl Pong {
+    fn from_bytes(ver: u8, p: &[u8]) -> Result<Self> {
+        ensure!(ver == V0, "invalid version");
+        let tx_id: [u8; TX_LEN] = p[..TX_LEN].try_into().context("message too short")?;
+        let tx_id = stun_rs::TransactionId::from(tx_id);
+        let src = send_addr_from_bytes(&p[TX_LEN..])?;
+
+        Ok(Pong {
+            tx_id,
+            ping_observed_addr: src,
+        })
+    }
+
+    fn as_bytes(&self) -> Vec<u8> {
+        let header = msg_header(MessageType::Pong, V0);
+        let mut out = header.to_vec();
+        out.extend_from_slice(&self.tx_id);
+
+        let src_bytes = send_addr_to_vec(&self.ping_observed_addr);
+        out.extend(src_bytes);
+        out
+    }
+}
+
+impl CallMeMaybe {
+    fn from_bytes(ver: u8, p: &[u8]) -> Result<Self> {
+        ensure!(ver == V0, "invalid version");
+        ensure!(p.len() % EP_LENGTH == 0, "invalid entries");
+
+        let num_entries = p.len() / EP_LENGTH;
+        let mut m = CallMeMaybe {
+            my_numbers: Vec::with_capacity(num_entries),
+        };
+
+        for chunk in p.chunks_exact(EP_LENGTH) {
+            let bytes: [u8; EP_LENGTH] = chunk.try_into().context("chunk must match")?;
+            let src = socket_addr_from_bytes(bytes);
+            m.my_numbers.push(src);
+        }
+
+        Ok(m)
+    }
+
+    fn as_bytes(&self) -> Vec<u8> {
+        let header = msg_header(MessageType::CallMeMaybe, V0);
+        let mut out = vec![0u8; HEADER_LEN + self.my_numbers.len() * EP_LENGTH];
+        out[..HEADER_LEN].copy_from_slice(&header);
+
+        for (m, chunk) in self
+            .my_numbers
+            .iter()
+            .zip(out[HEADER_LEN..].chunks_exact_mut(EP_LENGTH))
+        {
+            let raw = socket_addr_as_bytes(m);
+            chunk.copy_from_slice(&raw);
+        }
+
+        out
+    }
+}
+
+impl Message {
+    /// Parses the encrypted part of the message from inside the nacl secretbox.
+    pub fn from_bytes(p: &[u8]) -> Result<Self> {
+        ensure!(p.len() >= 2, "message too short");
+
+        let t = MessageType::try_from(p[0]).map_err(|v| anyhow!("unknown message type: {}", v))?;
+        let ver = p[1];
+        let p = &p[2..];
+        match t {
+            MessageType::Ping => {
+                let ping = Ping::from_bytes(ver, p)?;
+                Ok(Message::Ping(ping))
+            }
+            MessageType::Pong => {
+                let pong = Pong::from_bytes(ver, p)?;
+                Ok(Message::Pong(pong))
+            }
+            MessageType::CallMeMaybe => {
+                let cm = CallMeMaybe::from_bytes(ver, p)?;
+                Ok(Message::CallMeMaybe(cm))
+            }
+        }
+    }
+
+    /// Serialize this message to bytes.
+    pub fn as_bytes(&self) -> Vec<u8> {
+        match self {
+            Message::Ping(ping) => ping.as_bytes(),
+            Message::Pong(pong) => pong.as_bytes(),
+            Message::CallMeMaybe(cm) => cm.as_bytes(),
+        }
+    }
+}
+
+impl Display for Message {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Message::Ping(ping) => {
+                write!(f, "Ping(tx={})", hex::encode(ping.tx_id))
+            }
+            Message::Pong(pong) => {
+                write!(f, "Pong(tx={})", hex::encode(pong.tx_id))
+            }
+            Message::CallMeMaybe(_) => {
+                write!(f, "CallMeMaybe")
+            }
+        }
+    }
+}
+
+const fn msg_header(t: MessageType, ver: u8) -> [u8; HEADER_LEN] {
+    [t as u8, ver]
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::key::SecretKey;
+
+    #[test]
+    fn test_to_from_bytes() {
+        struct Test {
+            name: &'static str,
+            m: Message,
+            want: &'static str,
+        }
+        let tests = [
+            Test {
+                name: "ping_with_nodekey_src",
+                m: Message::Ping(Ping {
+                    tx_id: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].into(),
+                    node_key: PublicKey::try_from(&[
+                        190, 243, 65, 104, 37, 102, 175, 75, 243, 22, 69, 200, 167, 107, 24, 63, 216, 140, 120, 43, 4, 112, 16, 62, 117, 155, 45, 215, 72, 175, 40, 189][..]).unwrap(),
+                }),
+                want: "01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c be f3 41 68 25 66 af 4b f3 16 45 c8 a7 6b 18 3f d8 8c 78 2b 04 70 10 3e 75 9b 2d d7 48 af 28 bd",
+            },
+            Test {
+                name: "pong",
+                m: Message::Pong(Pong{
+                    tx_id: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].into(),
+                    ping_observed_addr:  SendAddr::Udp("2.3.4.5:1234".parse().unwrap()),
+                }),
+                want: "02 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 00 00 00 00 00 00 00 00 00 00 00 ff ff 02 03 04 05 d2 04",
+            },
+            Test {
+                name: "pongv6",
+                m: Message::Pong(Pong {
+                    tx_id: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].into(),
+                    ping_observed_addr: SendAddr::Udp("[fed0::12]:6666".parse().unwrap()),
+                }),
+                want: "02 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 00 fe d0 00 00 00 00 00 00 00 00 00 00 00 00 00 12 0a 1a",
+            },
+            Test {
+                name: "call_me_maybe",
+                m: Message::CallMeMaybe(CallMeMaybe { my_numbers: Vec::new() }),
+                want: "03 00",
+            },
+            Test {
+                name: "call_me_maybe_endpoints",
+                m: Message::CallMeMaybe(CallMeMaybe {
+                    my_numbers: vec![
+                        "1.2.3.4:567".parse().unwrap(),
+                        "[2001::3456]:789".parse().unwrap(),
+                    ],
+                }),
+                want: "03 00 00 00 00 00 00 00 00 00 00 00 ff ff 01 02 03 04 37 02 20 01 00 00 00 00 00 00 00 00 00 00 00 00 34 56 15 03",
+            },
+        ];
+        for test in tests {
+            println!("{}", test.name);
+
+            let got = test.m.as_bytes();
+            assert_eq!(
+                got,
+                hex::decode(test.want.replace(' ', "")).unwrap(),
+                "wrong as_bytes"
+            );
+
+            let back = Message::from_bytes(&got).expect("failed to parse");
+            assert_eq!(test.m, back, "wrong from_bytes");
+        }
+    }
+
+    #[test]
+    fn test_extraction() {
+        let sender_key = SecretKey::generate();
+        let recv_key = SecretKey::generate();
+
+        let msg = Message::Ping(Ping {
+            tx_id: stun_rs::TransactionId::default(),
+            node_key: sender_key.public(),
+        });
+
+        let shared = sender_key.shared(&recv_key.public());
+        let mut seal = msg.as_bytes();
+        shared.seal(&mut seal);
+
+        let bytes = encode_message(&sender_key.public(), seal.clone());
+
+        assert!(looks_like_disco_wrapper(&bytes));
+        assert_eq!(source_and_box(&bytes).unwrap().0, sender_key.public());
+
+        let (raw_key, seal_back) = source_and_box(&bytes).unwrap();
+        assert_eq!(raw_key, sender_key.public());
+        assert_eq!(seal_back, seal);
+
+        let shared_recv = recv_key.shared(&sender_key.public());
+        let mut open_seal = seal_back.to_vec();
+        shared_recv
+            .open(&mut open_seal)
+            .expect("failed to open seal_back");
+        let msg_back = Message::from_bytes(&open_seal).unwrap();
+        assert_eq!(msg_back, msg);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery.rs.html b/pr/2992/docs/src/iroh/discovery.rs.html new file mode 100644 index 0000000000..e289173db2 --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery.rs.html @@ -0,0 +1,1791 @@ +discovery.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+
//! Node address discovery.
+//!
+//! To connect to an iroh node a [`NodeAddr`] is needed, which may contain a
+//! [`RelayUrl`] or one or more *direct addresses* in addition to the [`NodeId`].
+//!
+//! Since there is a conversion from [`NodeId`] to [`NodeAddr`], you can also use
+//! connect directly with a [`NodeId`].
+//!
+//! For this to work however, the endpoint has to get the addressing  information by
+//! other means.  This can be done by manually calling [`Endpoint::add_node_addr`],
+//! but that still requires knowing the other addressing information.
+//!
+//! Node discovery is an automated system for an [`Endpoint`] to retrieve this addressing
+//! information.  Each iroh node will automatically publish their own addressing
+//! information.  Usually this means publishing which [`RelayUrl`] to use for their
+//! [`NodeId`], but they could also publish their direct addresses.
+//!
+//! The [`Discovery`] trait is used to define node discovery.  This allows multiple
+//! implementations to co-exist because there are many possible ways to implement this.
+//! Each [`Endpoint`] can use the discovery mechanisms most suitable to the application.
+//! The [`Builder::discovery`] method is used to add a discovery mechanism to an
+//! [`Endpoint`].
+//!
+//! Some generally useful discovery implementations are provided:
+//!
+//! - The [`DnsDiscovery`] which performs lookups via the standard DNS systems.  To publish
+//!   to this DNS server a [`PkarrPublisher`] is needed.  [Number 0] runs a public instance
+//!   of a [`PkarrPublisher`] with attached DNS server which is globally available and a
+//!   reliable default choice.
+//!
+//! - The [`PkarrResolver`] which can perform lookups from designated [pkarr relay servers]
+//!   using HTTP.
+#![cfg_attr(
+    feature = "discovery-local-network",
+    doc = "- [`LocalSwarmDiscovery`]: local_swarm_discovery::LocalSwarmDiscovery
+             very similar to mDNS."
+)]
+//!
+//! - The [`DhtDiscovery`] also uses the [`pkarr`] system but can also publish and lookup
+//!   records to/from the Mainline DHT.
+//!
+//! To use multiple discovery systems simultaneously use [`ConcurrentDiscovery`] which will
+//! perform lookups to all discovery systems at the same time.
+//!
+//! # Examples
+//!
+//! A very common setup is to enable DNS discovery, which needs to be done in two parts as a
+//! [`PkarrPublisher`] and [`DnsDiscovery`]:
+//!
+//! ```no_run
+//! use iroh::{
+//!     discovery::{dns::DnsDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery},
+//!     key::SecretKey,
+//!     Endpoint,
+//! };
+//!
+//! # async fn wrapper() -> anyhow::Result<()> {
+//! let secret_key = SecretKey::generate();
+//! let discovery = ConcurrentDiscovery::from_services(vec![
+//!     Box::new(PkarrPublisher::n0_dns(secret_key.clone())),
+//!     Box::new(DnsDiscovery::n0_dns()),
+//! ]);
+//! let ep = Endpoint::builder()
+//!     .secret_key(secret_key)
+//!     .discovery(Box::new(discovery))
+//!     .bind()
+//!     .await?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! To also enable
+#![cfg_attr(feature = "discovery-local-network", doc = "[`LocalSwarmDiscovery`]")]
+#![cfg_attr(
+    not(feature = "discovery-local-network"),
+    doc = "`LocalSwarmDiscovery`"
+)]
+//! it can be added as another service in the
+//! [`ConcurrentDiscovery`]:
+//!
+//! ```no_run
+//! # #[cfg(feature = "discovery-local-network")]
+//! # {
+//! # use iroh::discovery::dns::DnsDiscovery;
+//! # use iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery;
+//! # use iroh::discovery::pkarr::PkarrPublisher;
+//! # use iroh::discovery::ConcurrentDiscovery;
+//! # use iroh::key::SecretKey;
+//! #
+//! # async fn wrapper() -> anyhow::Result<()> {
+//! # let secret_key = SecretKey::generate();
+//! let discovery = ConcurrentDiscovery::from_services(vec![
+//!     Box::new(PkarrPublisher::n0_dns(secret_key.clone())),
+//!     Box::new(DnsDiscovery::n0_dns()),
+//!     Box::new(LocalSwarmDiscovery::new(secret_key.public())?),
+//! ]);
+//! # Ok(())
+//! # }
+//! # }
+//! ```
+//!
+//! [`RelayUrl`]: crate::relay::RelayUrl
+//! [`Builder::discovery`]: crate::endpoint::Builder::discovery
+//! [`DnsDiscovery`]: dns::DnsDiscovery
+//! [Number 0]: https://n0.computer
+//! [`PkarrResolver`]: pkarr::PkarrResolver
+//! [`PkarrPublisher`]: pkarr::PkarrPublisher
+//! [`DhtDiscovery`]: pkarr::dht::DhtDiscovery
+//! [pkarr relay servers]: https://pkarr.org/#servers
+#![cfg_attr(
+    feature = "discovery-local-network",
+    doc = "[`LocalSwarmDiscovery`]: local_swarm_discovery::LocalSwarmDiscovery"
+)]
+
+use std::time::Duration;
+
+use anyhow::{anyhow, ensure, Result};
+use futures_lite::stream::{Boxed as BoxStream, StreamExt};
+use iroh_base::node_addr::NodeAddr;
+use tokio::{sync::oneshot, task::JoinHandle};
+use tracing::{debug, error_span, warn, Instrument};
+
+use crate::{AddrInfo, Endpoint, NodeId};
+
+pub mod dns;
+
+#[cfg(feature = "discovery-local-network")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "discovery-local-network")))]
+pub mod local_swarm_discovery;
+pub mod pkarr;
+pub mod static_provider;
+
+/// Node discovery for [`super::Endpoint`].
+///
+/// This trait defines publishing and resolving addressing information for a [`NodeId`].
+/// This enables connecting to other nodes with only knowing the [`NodeId`], by using this
+/// [`Discovery`] system to look up the actual addressing information.  It is common for
+/// implementations to require each node to publish their own information before it can be
+/// looked up by other nodes.
+///
+/// The published addressing information can include both a [`RelayUrl`] and/or direct
+/// addresses.
+///
+/// To allow for discovery, the [`super::Endpoint`] will call `publish` whenever
+/// discovery information changes. If a discovery mechanism requires a periodic
+/// refresh, it should start its own task.
+///
+/// [`RelayUrl`]: crate::relay::RelayUrl
+pub trait Discovery: std::fmt::Debug + Send + Sync {
+    /// Publishes the given [`AddrInfo`] to the discovery mechanism.
+    ///
+    /// This is fire and forget, since the [`Endpoint`] can not wait for successful
+    /// publishing. If publishing is async, the implementation should start it's own task.
+    ///
+    /// This will be called from a tokio task, so it is safe to spawn new tasks.
+    /// These tasks will be run on the runtime of the [`super::Endpoint`].
+    fn publish(&self, _info: &AddrInfo) {}
+
+    /// Resolves the [`AddrInfo`] for the given [`NodeId`].
+    ///
+    /// Once the returned [`BoxStream`] is dropped, the service should stop any pending
+    /// work.
+    fn resolve(
+        &self,
+        _endpoint: Endpoint,
+        _node_id: NodeId,
+    ) -> Option<BoxStream<Result<DiscoveryItem>>> {
+        None
+    }
+
+    /// Subscribe to all addresses that get *passively* discovered.
+    ///
+    /// An implementation may choose to defer emitting passively discovered nodes
+    /// until the stream is actually polled. To avoid missing discovered nodes,
+    /// poll the stream as soon as possible.
+    ///
+    /// If you do not regularly poll the stream, you may miss discovered nodes.
+    ///
+    /// Any discovery systems that only discover when explicitly resolving a
+    /// specific [`NodeId`] do not need to implement this method. Any nodes or
+    /// addresses that are discovered by calling `resolve` should NOT be added
+    /// to the `subscribe` stream.
+    ///
+    /// Discovery systems that are capable of receiving information about [`NodeId`]s
+    /// and their [`AddrInfo`]s without explicitly calling `resolve`, i.e.,
+    /// systems that do "passive" discovery, should implement this method. If
+    /// `subscribe` is called multiple times, the passively discovered addresses
+    /// should be sent on all streams.
+    ///
+    /// The [`crate::endpoint::Endpoint`] will `subscribe` to the discovery system
+    /// and add the discovered addresses to the internal address book as they arrive
+    /// on this stream.
+    fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>> {
+        None
+    }
+}
+
+/// The results returned from [`Discovery::resolve`].
+#[derive(Debug, Clone)]
+pub struct DiscoveryItem {
+    /// The [`NodeId`] whose address we have discovered
+    pub node_id: NodeId,
+    /// A static string to identify the discovery source.
+    ///
+    /// Should be uniform per discovery service.
+    pub provenance: &'static str,
+    /// Optional timestamp when this node address info was last updated.
+    ///
+    /// Must be microseconds since the unix epoch.
+    // TODO(ramfox): this is currently unused. As we develop more `DiscoveryService`s, we may discover that we do not need this. It is only truly relevant when comparing `relay_urls`, since we can attempt to dial any number of socket addresses, but expect each node to have one "home relay" that we will attempt to contact them on. This means we would need some way to determine which relay url to choose between, if more than one relay url is reported.
+    pub last_updated: Option<u64>,
+    /// The address info for the node being resolved.
+    pub addr_info: AddrInfo,
+}
+
+/// A discovery service that combines multiple discovery sources.
+///
+/// The discovery services will resolve concurrently.
+#[derive(Debug, Default)]
+pub struct ConcurrentDiscovery {
+    services: Vec<Box<dyn Discovery>>,
+}
+
+impl ConcurrentDiscovery {
+    /// Creates an empty [`ConcurrentDiscovery`].
+    pub fn empty() -> Self {
+        Self::default()
+    }
+
+    /// Creates a new [`ConcurrentDiscovery`].
+    pub fn from_services(services: Vec<Box<dyn Discovery>>) -> Self {
+        Self { services }
+    }
+
+    /// Adds a [`Discovery`] service.
+    pub fn add(&mut self, service: impl Discovery + 'static) {
+        self.services.push(Box::new(service));
+    }
+}
+
+impl<T> From<T> for ConcurrentDiscovery
+where
+    T: IntoIterator<Item = Box<dyn Discovery>>,
+{
+    fn from(iter: T) -> Self {
+        let services = iter.into_iter().collect::<Vec<_>>();
+        Self { services }
+    }
+}
+
+impl Discovery for ConcurrentDiscovery {
+    fn publish(&self, info: &AddrInfo) {
+        for service in &self.services {
+            service.publish(info);
+        }
+    }
+
+    fn resolve(
+        &self,
+        endpoint: Endpoint,
+        node_id: NodeId,
+    ) -> Option<BoxStream<Result<DiscoveryItem>>> {
+        let streams = self
+            .services
+            .iter()
+            .filter_map(|service| service.resolve(endpoint.clone(), node_id));
+
+        let streams = futures_buffered::MergeBounded::from_iter(streams);
+        Some(Box::pin(streams))
+    }
+
+    fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>> {
+        let mut streams = vec![];
+        for service in self.services.iter() {
+            if let Some(stream) = service.subscribe() {
+                streams.push(stream)
+            }
+        }
+
+        let streams = futures_buffered::MergeBounded::from_iter(streams);
+        Some(Box::pin(streams))
+    }
+}
+
+/// Maximum duration since the last control or data message received from an endpoint to make us
+/// start a discovery task.
+const MAX_AGE: Duration = Duration::from_secs(10);
+
+/// A wrapper around a tokio task which runs a node discovery.
+pub(super) struct DiscoveryTask {
+    on_first_rx: oneshot::Receiver<Result<()>>,
+    task: JoinHandle<()>,
+}
+
+impl DiscoveryTask {
+    /// Starts a discovery task.
+    pub(super) fn start(ep: Endpoint, node_id: NodeId) -> Result<Self> {
+        ensure!(ep.discovery().is_some(), "No discovery services configured");
+        let (on_first_tx, on_first_rx) = oneshot::channel();
+        let me = ep.node_id();
+        let task = tokio::task::spawn(
+            async move { Self::run(ep, node_id, on_first_tx).await }.instrument(
+                error_span!("discovery", me = %me.fmt_short(), node = %node_id.fmt_short()),
+            ),
+        );
+        Ok(Self { task, on_first_rx })
+    }
+
+    /// Starts a discovery task after a delay and only if no path to the node was recently active.
+    ///
+    /// This returns `None` if we received data or control messages from the remote endpoint
+    /// recently enough. If not it returns a [`DiscoveryTask`].
+    ///
+    /// If `delay` is set, the [`DiscoveryTask`] will first wait for `delay` and then check again
+    /// if we recently received messages from remote endpoint. If true, the task will abort.
+    /// Otherwise, or if no `delay` is set, the discovery will be started.
+    pub(super) fn maybe_start_after_delay(
+        ep: &Endpoint,
+        node_id: NodeId,
+        delay: Option<Duration>,
+    ) -> Result<Option<Self>> {
+        // If discovery is not needed, don't even spawn a task.
+        if !Self::needs_discovery(ep, node_id) {
+            return Ok(None);
+        }
+        ensure!(ep.discovery().is_some(), "No discovery services configured");
+        let (on_first_tx, on_first_rx) = oneshot::channel();
+        let ep = ep.clone();
+        let me = ep.node_id();
+        let task = tokio::task::spawn(
+            async move {
+                // If delay is set, wait and recheck if discovery is needed. If not, early-exit.
+                if let Some(delay) = delay {
+                    tokio::time::sleep(delay).await;
+                    if !Self::needs_discovery(&ep, node_id) {
+                        debug!("no discovery needed, abort");
+                        on_first_tx.send(Ok(())).ok();
+                        return;
+                    }
+                }
+                Self::run(ep, node_id, on_first_tx).await
+            }
+            .instrument(
+                error_span!("discovery", me = %me.fmt_short(), node = %node_id.fmt_short()),
+            ),
+        );
+        Ok(Some(Self { task, on_first_rx }))
+    }
+
+    /// Waits until the discovery task produced at least one result.
+    pub(super) async fn first_arrived(&mut self) -> Result<()> {
+        let fut = &mut self.on_first_rx;
+        fut.await??;
+        Ok(())
+    }
+
+    /// Cancels the discovery task.
+    pub(super) fn cancel(&self) {
+        self.task.abort();
+    }
+
+    fn create_stream(ep: &Endpoint, node_id: NodeId) -> Result<BoxStream<Result<DiscoveryItem>>> {
+        let discovery = ep
+            .discovery()
+            .ok_or_else(|| anyhow!("No discovery service configured"))?;
+        let stream = discovery
+            .resolve(ep.clone(), node_id)
+            .ok_or_else(|| anyhow!("No discovery service can resolve node {node_id}",))?;
+        Ok(stream)
+    }
+
+    /// We need discovery if we have no paths to the node, or if the paths we do have
+    /// have timed out.
+    fn needs_discovery(ep: &Endpoint, node_id: NodeId) -> bool {
+        match ep.remote_info(node_id) {
+            // No info means no path to node -> start discovery.
+            None => true,
+            Some(info) => {
+                match (
+                    info.last_received(),
+                    info.relay_url.as_ref().and_then(|r| r.last_alive),
+                ) {
+                    // No path to node -> start discovery.
+                    (None, None) => true,
+                    // If we haven't received on direct addresses or the relay for MAX_AGE,
+                    // start discovery.
+                    (Some(elapsed), Some(elapsed_relay)) => {
+                        elapsed > MAX_AGE && elapsed_relay > MAX_AGE
+                    }
+                    (Some(elapsed), _) | (_, Some(elapsed)) => elapsed > MAX_AGE,
+                }
+            }
+        }
+    }
+
+    async fn run(ep: Endpoint, node_id: NodeId, on_first_tx: oneshot::Sender<Result<()>>) {
+        let mut stream = match Self::create_stream(&ep, node_id) {
+            Ok(stream) => stream,
+            Err(err) => {
+                on_first_tx.send(Err(err)).ok();
+                return;
+            }
+        };
+        let mut on_first_tx = Some(on_first_tx);
+        debug!("discovery: start");
+        loop {
+            let next = tokio::select! {
+                _ = ep.cancel_token().cancelled() => break,
+                next = stream.next() => next
+            };
+            match next {
+                Some(Ok(r)) => {
+                    if r.addr_info.is_empty() {
+                        debug!(provenance = %r.provenance, addr = ?r.addr_info, "discovery: empty address found");
+                        continue;
+                    }
+                    debug!(provenance = %r.provenance, addr = ?r.addr_info, "discovery: new address found");
+                    let addr = NodeAddr {
+                        info: r.addr_info,
+                        node_id,
+                    };
+                    ep.add_node_addr_with_source(addr, r.provenance).ok();
+                    if let Some(tx) = on_first_tx.take() {
+                        tx.send(Ok(())).ok();
+                    }
+                }
+                Some(Err(err)) => {
+                    warn!(?err, "discovery service produced error");
+                    break;
+                }
+                None => break,
+            }
+        }
+        if let Some(tx) = on_first_tx.take() {
+            let err = anyhow!("Discovery produced no results for {}", node_id.fmt_short());
+            tx.send(Err(err)).ok();
+        }
+    }
+}
+
+impl Drop for DiscoveryTask {
+    fn drop(&mut self) {
+        self.task.abort();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::{
+        collections::{BTreeSet, HashMap},
+        net::SocketAddr,
+        sync::Arc,
+        time::SystemTime,
+    };
+
+    use parking_lot::Mutex;
+    use rand::Rng;
+    use tokio_util::task::AbortOnDropHandle;
+
+    use super::*;
+    use crate::{key::SecretKey, RelayMode};
+
+    #[derive(Debug, Clone, Default)]
+    struct TestDiscoveryShared {
+        nodes: Arc<Mutex<HashMap<NodeId, (AddrInfo, u64)>>>,
+    }
+    impl TestDiscoveryShared {
+        pub fn create_discovery(&self, node_id: NodeId) -> TestDiscovery {
+            TestDiscovery {
+                node_id,
+                shared: self.clone(),
+                publish: true,
+                resolve_wrong: false,
+                delay: Duration::from_millis(200),
+            }
+        }
+
+        pub fn create_lying_discovery(&self, node_id: NodeId) -> TestDiscovery {
+            TestDiscovery {
+                node_id,
+                shared: self.clone(),
+                publish: false,
+                resolve_wrong: true,
+                delay: Duration::from_millis(100),
+            }
+        }
+    }
+    #[derive(Debug)]
+    struct TestDiscovery {
+        node_id: NodeId,
+        shared: TestDiscoveryShared,
+        publish: bool,
+        resolve_wrong: bool,
+        delay: Duration,
+    }
+
+    impl Discovery for TestDiscovery {
+        fn publish(&self, info: &AddrInfo) {
+            if !self.publish {
+                return;
+            }
+            let now = system_time_now();
+            self.shared
+                .nodes
+                .lock()
+                .insert(self.node_id, (info.clone(), now));
+        }
+
+        fn resolve(
+            &self,
+            endpoint: Endpoint,
+            node_id: NodeId,
+        ) -> Option<BoxStream<Result<DiscoveryItem>>> {
+            let addr_info = match self.resolve_wrong {
+                false => self.shared.nodes.lock().get(&node_id).cloned(),
+                true => {
+                    let ts = system_time_now() - 100_000;
+                    let port: u16 = rand::thread_rng().gen_range(10_000..20_000);
+                    // "240.0.0.0/4" is reserved and unreachable
+                    let addr: SocketAddr = format!("240.0.0.1:{port}").parse().unwrap();
+                    let addr_info = AddrInfo {
+                        relay_url: None,
+                        direct_addresses: BTreeSet::from([addr]),
+                    };
+                    Some((addr_info, ts))
+                }
+            };
+            let stream = match addr_info {
+                Some((addr_info, ts)) => {
+                    let item = DiscoveryItem {
+                        node_id,
+                        provenance: "test-disco",
+                        last_updated: Some(ts),
+                        addr_info,
+                    };
+                    let delay = self.delay;
+                    let fut = async move {
+                        tokio::time::sleep(delay).await;
+                        tracing::debug!(
+                            "resolve on {}: {} = {item:?}",
+                            endpoint.node_id().fmt_short(),
+                            node_id.fmt_short()
+                        );
+                        Ok(item)
+                    };
+                    futures_lite::stream::once_future(fut).boxed()
+                }
+                None => futures_lite::stream::empty().boxed(),
+            };
+            Some(stream)
+        }
+    }
+
+    #[derive(Debug)]
+    struct EmptyDiscovery;
+    impl Discovery for EmptyDiscovery {
+        fn publish(&self, _info: &AddrInfo) {}
+
+        fn resolve(
+            &self,
+            _endpoint: Endpoint,
+            _node_id: NodeId,
+        ) -> Option<BoxStream<Result<DiscoveryItem>>> {
+            Some(futures_lite::stream::empty().boxed())
+        }
+    }
+
+    const TEST_ALPN: &[u8] = b"n0/iroh/test";
+
+    /// This is a smoke test for our discovery mechanism.
+    #[tokio::test]
+    async fn endpoint_discovery_simple_shared() -> anyhow::Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let disco_shared = TestDiscoveryShared::default();
+        let (ep1, _guard1) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let (ep2, _guard2) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let ep1_addr = NodeAddr::new(ep1.node_id());
+        // wait for out address to be updated and thus published at least once
+        ep1.node_addr().await?;
+        let _conn = ep2.connect(ep1_addr, TEST_ALPN).await?;
+        Ok(())
+    }
+
+    /// This test adds an empty discovery which provides no addresses.
+    #[tokio::test]
+    async fn endpoint_discovery_combined_with_empty() -> anyhow::Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let disco_shared = TestDiscoveryShared::default();
+        let (ep1, _guard1) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let (ep2, _guard2) = {
+            let secret = SecretKey::generate();
+            let disco1 = EmptyDiscovery;
+            let disco2 = disco_shared.create_discovery(secret.public());
+            let mut disco = ConcurrentDiscovery::empty();
+            disco.add(disco1);
+            disco.add(disco2);
+            new_endpoint(secret, disco).await
+        };
+        let ep1_addr = NodeAddr::new(ep1.node_id());
+        // wait for out address to be updated and thus published at least once
+        ep1.node_addr().await?;
+        let _conn = ep2.connect(ep1_addr, TEST_ALPN).await?;
+        Ok(())
+    }
+
+    /// This test adds a "lying" discovery which provides a wrong address.
+    /// This is to make sure that as long as one of the discoveries returns a working address, we
+    /// will connect successfully.
+    #[tokio::test]
+    async fn endpoint_discovery_combined_with_empty_and_wrong() -> anyhow::Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let disco_shared = TestDiscoveryShared::default();
+        let (ep1, _guard1) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let (ep2, _guard2) = {
+            let secret = SecretKey::generate();
+            let disco1 = EmptyDiscovery;
+            let disco2 = disco_shared.create_lying_discovery(secret.public());
+            let disco3 = disco_shared.create_discovery(secret.public());
+            let mut disco = ConcurrentDiscovery::empty();
+            disco.add(disco1);
+            disco.add(disco2);
+            disco.add(disco3);
+            new_endpoint(secret, disco).await
+        };
+        let ep1_addr = NodeAddr::new(ep1.node_id());
+        // wait for out address to be updated and thus published at least once
+        ep1.node_addr().await?;
+        let _conn = ep2.connect(ep1_addr, TEST_ALPN).await?;
+        Ok(())
+    }
+
+    /// This test only has the "lying" discovery. It is here to make sure that this actually fails.
+    #[tokio::test]
+    async fn endpoint_discovery_combined_wrong_only() -> anyhow::Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let disco_shared = TestDiscoveryShared::default();
+        let (ep1, _guard1) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let (ep2, _guard2) = {
+            let secret = SecretKey::generate();
+            let disco1 = disco_shared.create_lying_discovery(secret.public());
+            let disco = ConcurrentDiscovery::from_services(vec![Box::new(disco1)]);
+            new_endpoint(secret, disco).await
+        };
+        let ep1_addr = NodeAddr::new(ep1.node_id());
+        // wait for out address to be updated and thus published at least once
+        ep1.node_addr().await?;
+        let res = ep2.connect(ep1_addr, TEST_ALPN).await;
+        assert!(res.is_err());
+        Ok(())
+    }
+
+    /// This test first adds a wrong address manually (e.g. from an outdated&node_id ticket).
+    /// Connect should still succeed because the discovery service will be invoked (after a delay).
+    #[tokio::test]
+    async fn endpoint_discovery_with_wrong_existing_addr() -> anyhow::Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let disco_shared = TestDiscoveryShared::default();
+        let (ep1, _guard1) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        let (ep2, _guard2) = {
+            let secret = SecretKey::generate();
+            let disco = disco_shared.create_discovery(secret.public());
+            new_endpoint(secret, disco).await
+        };
+        // wait for out address to be updated and thus published at least once
+        ep1.node_addr().await?;
+        let ep1_wrong_addr = NodeAddr {
+            node_id: ep1.node_id(),
+            info: AddrInfo {
+                relay_url: None,
+                direct_addresses: BTreeSet::from(["240.0.0.1:1000".parse().unwrap()]),
+            },
+        };
+        let _conn = ep2.connect(ep1_wrong_addr, TEST_ALPN).await?;
+        Ok(())
+    }
+
+    async fn new_endpoint(
+        secret: SecretKey,
+        disco: impl Discovery + 'static,
+    ) -> (Endpoint, AbortOnDropHandle<anyhow::Result<()>>) {
+        let ep = Endpoint::builder()
+            .secret_key(secret)
+            .discovery(Box::new(disco))
+            .relay_mode(RelayMode::Disabled)
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .bind()
+            .await
+            .unwrap();
+
+        let handle = tokio::spawn({
+            let ep = ep.clone();
+            async move {
+                // we skip accept() errors, they can be caused by retransmits
+                while let Some(connecting) = ep.accept().await.and_then(|inc| inc.accept().ok()) {
+                    let _conn = connecting.await?;
+                    // Just accept incoming connections, but don't do anything with them.
+                }
+
+                anyhow::Ok(())
+            }
+        });
+
+        (ep, AbortOnDropHandle::new(handle))
+    }
+
+    fn system_time_now() -> u64 {
+        SystemTime::now()
+            .duration_since(SystemTime::UNIX_EPOCH)
+            .expect("time drift")
+            .as_micros() as u64
+    }
+}
+
+/// This module contains end-to-end tests for DNS node discovery.
+///
+/// The tests run a minimal test DNS server to resolve against, and a minimal pkarr relay to
+/// publish to. The DNS and pkarr servers share their state.
+#[cfg(test)]
+mod test_dns_pkarr {
+    use std::time::Duration;
+
+    use anyhow::Result;
+    use iroh_base::key::SecretKey;
+    use tokio_util::task::AbortOnDropHandle;
+
+    use crate::{
+        discovery::pkarr::PkarrPublisher,
+        dns::{node_info::NodeInfo, ResolverExt},
+        test_utils::{
+            dns_server::{create_dns_resolver, run_dns_server},
+            pkarr_dns_state::State,
+            run_relay_server, DnsPkarrServer,
+        },
+        AddrInfo, Endpoint, NodeAddr, RelayMap, RelayMode,
+    };
+
+    const PUBLISH_TIMEOUT: Duration = Duration::from_secs(10);
+
+    #[tokio::test]
+    async fn dns_resolve() -> Result<()> {
+        let _logging_guard = iroh_test::logging::setup();
+
+        let origin = "testdns.example".to_string();
+        let state = State::new(origin.clone());
+        let (nameserver, _dns_drop_guard) = run_dns_server(state.clone()).await?;
+
+        let secret_key = SecretKey::generate();
+        let node_info = NodeInfo::new(
+            secret_key.public(),
+            Some("https://relay.example".parse().unwrap()),
+            Default::default(),
+        );
+        let signed_packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;
+        state.upsert(signed_packet)?;
+
+        let resolver = create_dns_resolver(nameserver)?;
+        let resolved = resolver.lookup_by_id(&node_info.node_id, &origin).await?;
+
+        assert_eq!(resolved, node_info.into());
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn pkarr_publish_dns_resolve() -> Result<()> {
+        let _logging_guard = iroh_test::logging::setup();
+
+        let origin = "testdns.example".to_string();
+
+        let dns_pkarr_server = DnsPkarrServer::run_with_origin(origin.clone()).await?;
+
+        let secret_key = SecretKey::generate();
+        let node_id = secret_key.public();
+
+        let addr_info = AddrInfo {
+            relay_url: Some("https://relay.example".parse().unwrap()),
+            ..Default::default()
+        };
+
+        let resolver = create_dns_resolver(dns_pkarr_server.nameserver)?;
+        let publisher = PkarrPublisher::new(secret_key, dns_pkarr_server.pkarr_url.clone());
+        // does not block, update happens in background task
+        publisher.update_addr_info(&addr_info);
+        // wait until our shared state received the update from pkarr publishing
+        dns_pkarr_server.on_node(&node_id, PUBLISH_TIMEOUT).await?;
+        let resolved = resolver.lookup_by_id(&node_id, &origin).await?;
+
+        let expected = NodeAddr {
+            info: addr_info,
+            node_id,
+        };
+
+        assert_eq!(resolved, expected);
+        Ok(())
+    }
+
+    const TEST_ALPN: &[u8] = b"TEST";
+
+    #[tokio::test]
+    async fn pkarr_publish_dns_discover() -> Result<()> {
+        let _logging_guard = iroh_test::logging::setup();
+
+        let dns_pkarr_server = DnsPkarrServer::run().await?;
+        let (relay_map, _relay_url, _relay_guard) = run_relay_server().await?;
+
+        let (ep1, _guard1) = ep_with_discovery(&relay_map, &dns_pkarr_server).await?;
+        let (ep2, _guard2) = ep_with_discovery(&relay_map, &dns_pkarr_server).await?;
+
+        // wait until our shared state received the update from pkarr publishing
+        dns_pkarr_server
+            .on_node(&ep1.node_id(), PUBLISH_TIMEOUT)
+            .await?;
+
+        // we connect only by node id!
+        let res = ep2.connect(ep1.node_id(), TEST_ALPN).await;
+        assert!(res.is_ok(), "connection established");
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn pkarr_publish_dns_discover_empty_node_addr() -> Result<()> {
+        let _logging_guard = iroh_test::logging::setup();
+
+        let dns_pkarr_server = DnsPkarrServer::run().await?;
+        let (relay_map, _relay_url, _relay_guard) = run_relay_server().await?;
+
+        let (ep1, _guard1) = ep_with_discovery(&relay_map, &dns_pkarr_server).await?;
+        let (ep2, _guard2) = ep_with_discovery(&relay_map, &dns_pkarr_server).await?;
+
+        // wait until our shared state received the update from pkarr publishing
+        dns_pkarr_server
+            .on_node(&ep1.node_id(), PUBLISH_TIMEOUT)
+            .await?;
+
+        // we connect only by node id!
+        let res = ep2.connect(ep1.node_id(), TEST_ALPN).await;
+        assert!(res.is_ok(), "connection established");
+        Ok(())
+    }
+
+    async fn ep_with_discovery(
+        relay_map: &RelayMap,
+        dns_pkarr_server: &DnsPkarrServer,
+    ) -> Result<(Endpoint, AbortOnDropHandle<Result<()>>)> {
+        let secret_key = SecretKey::generate();
+        let ep = Endpoint::builder()
+            .relay_mode(RelayMode::Custom(relay_map.clone()))
+            .insecure_skip_relay_cert_verify(true)
+            .secret_key(secret_key.clone())
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .dns_resolver(dns_pkarr_server.dns_resolver())
+            .discovery(dns_pkarr_server.discovery(secret_key))
+            .bind()
+            .await?;
+
+        let handle = tokio::spawn({
+            let ep = ep.clone();
+            async move {
+                // we skip accept() errors, they can be caused by retransmits
+                while let Some(connecting) = ep.accept().await.and_then(|inc| inc.accept().ok()) {
+                    let _conn = connecting.await?;
+                    // Just accept incoming connections, but don't do anything with them.
+                }
+
+                anyhow::Ok(())
+            }
+        });
+
+        Ok((ep, AbortOnDropHandle::new(handle)))
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery/dns.rs.html b/pr/2992/docs/src/iroh/discovery/dns.rs.html new file mode 100644 index 0000000000..6f27a5d156 --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery/dns.rs.html @@ -0,0 +1,175 @@ +dns.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+
//! DNS node discovery for iroh
+
+use anyhow::Result;
+use futures_lite::stream::Boxed as BoxStream;
+
+use crate::{
+    discovery::{Discovery, DiscoveryItem},
+    dns::ResolverExt,
+    endpoint::force_staging_infra,
+    Endpoint, NodeId,
+};
+
+/// The n0 testing DNS node origin, for production.
+pub const N0_DNS_NODE_ORIGIN_PROD: &str = "dns.iroh.link";
+/// The n0 testing DNS node origin, for testing.
+pub const N0_DNS_NODE_ORIGIN_STAGING: &str = "staging-dns.iroh.link";
+
+const DNS_STAGGERING_MS: &[u64] = &[200, 300];
+
+/// DNS node discovery
+///
+/// When asked to resolve a [`NodeId`], this service performs a lookup in the Domain Name System (DNS).
+///
+/// It uses the [`Endpoint`]'s DNS resolver to query for `TXT` records under the domain
+/// `_iroh.<z32-node-id>.<origin-domain>`:
+///
+/// * `_iroh`: is the record name
+/// * `<z32-node-id>` is the [`NodeId`] encoded in [`z-base-32`] format
+/// * `<origin-domain>` is the node origin domain as set in [`DnsDiscovery::new`].
+///
+/// Each TXT record returned from the query is expected to contain a string in the format `<name>=<value>`.
+/// If a TXT record contains multiple character strings, they are concatenated first.
+/// The supported attributes are:
+/// * `relay=<url>`: The URL of the home relay server of the node
+///
+/// The DNS resolver defaults to using the nameservers configured on the host system, but can be changed
+/// with [`crate::endpoint::Builder::dns_resolver`].
+///
+/// [z-base-32]: https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
+#[derive(Debug)]
+pub struct DnsDiscovery {
+    origin_domain: String,
+}
+
+impl DnsDiscovery {
+    /// Creates a new DNS discovery.
+    pub fn new(origin_domain: String) -> Self {
+        Self { origin_domain }
+    }
+
+    /// Creates a new DNS discovery using the `iroh.link` domain.
+    ///
+    /// This uses the [`N0_DNS_NODE_ORIGIN_PROD`] domain.
+    ///
+    /// # Usage during tests
+    ///
+    /// For testing it is possible to use the [`N0_DNS_NODE_ORIGIN_STAGING`] domain
+    /// with [`DnsDiscovery::new`].  This would then use a hosted staging discovery
+    /// service for testing purposes.
+    pub fn n0_dns() -> Self {
+        if force_staging_infra() {
+            Self::new(N0_DNS_NODE_ORIGIN_STAGING.to_string())
+        } else {
+            Self::new(N0_DNS_NODE_ORIGIN_PROD.to_string())
+        }
+    }
+}
+
+impl Discovery for DnsDiscovery {
+    fn resolve(&self, ep: Endpoint, node_id: NodeId) -> Option<BoxStream<Result<DiscoveryItem>>> {
+        let resolver = ep.dns_resolver().clone();
+        let origin_domain = self.origin_domain.clone();
+        let fut = async move {
+            let node_addr = resolver
+                .lookup_by_id_staggered(&node_id, &origin_domain, DNS_STAGGERING_MS)
+                .await?;
+            Ok(DiscoveryItem {
+                node_id,
+                provenance: "dns",
+                last_updated: None,
+                addr_info: node_addr.info,
+            })
+        };
+        let stream = futures_lite::stream::once_future(fut);
+        Some(Box::pin(stream))
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery/local_swarm_discovery.rs.html b/pr/2992/docs/src/iroh/discovery/local_swarm_discovery.rs.html new file mode 100644 index 0000000000..e6801e408f --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery/local_swarm_discovery.rs.html @@ -0,0 +1,977 @@ +local_swarm_discovery.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+
//! A discovery service that uses an mdns-like service to discover local nodes.
+//!
+//! This allows you to use an mdns-like swarm discovery service to find address information about nodes that are on your local network, no relay or outside internet needed.
+//! See the [`swarm-discovery`](https://crates.io/crates/swarm-discovery) crate for more details.
+//!
+//! When [`LocalSwarmDiscovery`] is enabled, it's possible to get a list of the locally discovered nodes by filtering a list of `RemoteInfo`s.
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! use iroh::endpoint::{Endpoint, Source};
+//!
+//! #[tokio::main]
+//! async fn main() {
+//!     let recent = Duration::from_secs(600); // 10 minutes in seconds
+//!
+//!     let endpoint = Endpoint::builder().bind().await.unwrap();
+//!     let remotes = endpoint.remote_info_iter();
+//!     let locally_discovered: Vec<_> = remotes
+//!         .filter(|remote| {
+//!             remote.sources().iter().any(|(source, duration)| {
+//!                 if let Source::Discovery { name } = source {
+//!                     name == iroh::discovery::local_swarm_discovery::NAME && *duration <= recent
+//!                 } else {
+//!                     false
+//!                 }
+//!             })
+//!         })
+//!         .collect();
+//!     println!("locally discovered nodes: {locally_discovered:?}");
+//! }
+//! ```
+use std::{
+    collections::{BTreeSet, HashMap},
+    net::{IpAddr, SocketAddr},
+    time::Duration,
+};
+
+use anyhow::Result;
+use derive_more::FromStr;
+use futures_lite::stream::Boxed as BoxStream;
+use futures_util::FutureExt;
+use iroh_base::key::PublicKey;
+use swarm_discovery::{Discoverer, DropGuard, IpClass, Peer};
+use tokio::{
+    sync::mpsc::{
+        error::TrySendError,
+        {self},
+    },
+    task::JoinSet,
+};
+use tokio_util::task::AbortOnDropHandle;
+use tracing::{debug, error, info_span, trace, warn, Instrument};
+use watchable::Watchable;
+
+use crate::{
+    discovery::{Discovery, DiscoveryItem},
+    AddrInfo, Endpoint, NodeId,
+};
+
+/// The n0 local swarm node discovery name
+const N0_LOCAL_SWARM: &str = "iroh.local.swarm";
+
+/// Name of this discovery service.
+///
+/// Used as the `provenance` field in [`DiscoveryItem`]s.
+///
+/// Used in the [`crate::endpoint::Source::Discovery`] enum variant as the `name`.
+pub const NAME: &str = "local.swarm.discovery";
+
+/// How long we will wait before we stop sending discovery items
+const DISCOVERY_DURATION: Duration = Duration::from_secs(10);
+
+/// Discovery using `swarm-discovery`, a variation on mdns
+#[derive(Debug)]
+pub struct LocalSwarmDiscovery {
+    #[allow(dead_code)]
+    handle: AbortOnDropHandle<()>,
+    sender: mpsc::Sender<Message>,
+    /// When `local_addrs` changes, we re-publish our [`AddrInfo`]
+    local_addrs: Watchable<Option<AddrInfo>>,
+}
+
+#[derive(Debug)]
+enum Message {
+    Discovery(String, Peer),
+    Resolve(NodeId, mpsc::Sender<Result<DiscoveryItem>>),
+    Timeout(NodeId, usize),
+    Subscribe(mpsc::Sender<DiscoveryItem>),
+}
+
+/// Manages the list of subscribers that are subscribed to this discovery service.
+#[derive(Debug)]
+struct Subscribers(Vec<mpsc::Sender<DiscoveryItem>>);
+
+impl Subscribers {
+    fn new() -> Self {
+        Self(vec![])
+    }
+
+    /// Add the subscriber to the list of subscribers
+    fn push(&mut self, subscriber: mpsc::Sender<DiscoveryItem>) {
+        self.0.push(subscriber);
+    }
+
+    /// Sends the `node_id` and `item` to each subscriber.
+    ///
+    /// Cleans up any subscribers that have been dropped.
+    fn send(&mut self, item: DiscoveryItem) {
+        let mut clean_up = vec![];
+        for (i, subscriber) in self.0.iter().enumerate() {
+            // assume subscriber was dropped
+            if let Err(err) = subscriber.try_send(item.clone()) {
+                match err {
+                    TrySendError::Full(_) => {
+                        warn!(
+                            ?item,
+                            idx = i,
+                            "local swarm discovery subscriber is blocked, dropping item"
+                        )
+                    }
+                    TrySendError::Closed(_) => clean_up.push(i),
+                }
+            }
+        }
+        for i in clean_up.into_iter().rev() {
+            self.0.swap_remove(i);
+        }
+    }
+}
+
+impl LocalSwarmDiscovery {
+    /// Create a new [`LocalSwarmDiscovery`] Service.
+    ///
+    /// This starts a [`Discoverer`] that broadcasts your addresses and receives addresses from other nodes in your local network.
+    ///
+    /// # Errors
+    /// Returns an error if the network does not allow ipv4 OR ipv6.
+    ///
+    /// # Panics
+    /// This relies on [`tokio::runtime::Handle::current`] and will panic if called outside of the context of a tokio runtime.
+    pub fn new(node_id: NodeId) -> Result<Self> {
+        debug!("Creating new LocalSwarmDiscovery service");
+        let (send, mut recv) = mpsc::channel(64);
+        let task_sender = send.clone();
+        let rt = tokio::runtime::Handle::current();
+        let discovery = LocalSwarmDiscovery::spawn_discoverer(
+            node_id,
+            task_sender.clone(),
+            BTreeSet::new(),
+            &rt,
+        )?;
+
+        let local_addrs: Watchable<Option<AddrInfo>> = Watchable::new(None);
+        let addrs_change = local_addrs.watch();
+        let discovery_fut = async move {
+            let mut node_addrs: HashMap<PublicKey, Peer> = HashMap::default();
+            let mut subscribers = Subscribers::new();
+            let mut last_id = 0;
+            let mut senders: HashMap<
+                PublicKey,
+                HashMap<usize, mpsc::Sender<Result<DiscoveryItem>>>,
+            > = HashMap::default();
+            let mut timeouts = JoinSet::new();
+            loop {
+                trace!(?node_addrs, "LocalSwarmDiscovery Service loop tick");
+                let msg = tokio::select! {
+                    msg = recv.recv() => {
+                        msg
+                    }
+                    Ok(Some(addrs))= addrs_change.next_value_async() => {
+                        tracing::trace!(?addrs, "LocalSwarmDiscovery address changed");
+                        discovery.remove_all();
+                        let addrs =
+                            LocalSwarmDiscovery::socketaddrs_to_addrs(addrs.direct_addresses);
+                        for addr in addrs {
+                            discovery.add(addr.0, addr.1)
+                        }
+                        continue;
+                    }
+                };
+                let msg = match msg {
+                    None => {
+                        error!("LocalSwarmDiscovery channel closed");
+                        error!("closing LocalSwarmDiscovery");
+                        timeouts.abort_all();
+                        return;
+                    }
+                    Some(msg) => msg,
+                };
+                match msg {
+                    Message::Discovery(discovered_node_id, peer_info) => {
+                        trace!(
+                            ?discovered_node_id,
+                            ?peer_info,
+                            "LocalSwarmDiscovery Message::Discovery"
+                        );
+                        let discovered_node_id = match PublicKey::from_str(&discovered_node_id) {
+                            Ok(node_id) => node_id,
+                            Err(e) => {
+                                warn!(
+                                    discovered_node_id,
+                                    "couldn't parse node_id from mdns discovery service: {e:?}"
+                                );
+                                continue;
+                            }
+                        };
+
+                        if discovered_node_id == node_id {
+                            continue;
+                        }
+
+                        if peer_info.is_expiry() {
+                            trace!(
+                                ?discovered_node_id,
+                                "removing node from LocalSwarmDiscovery address book"
+                            );
+                            node_addrs.remove(&discovered_node_id);
+                            continue;
+                        }
+
+                        let entry = node_addrs.entry(discovered_node_id);
+                        if let std::collections::hash_map::Entry::Occupied(ref entry) = entry {
+                            if entry.get() == &peer_info {
+                                // this is a republish we already know about
+                                continue;
+                            }
+                        }
+
+                        debug!(
+                            ?discovered_node_id,
+                            ?peer_info,
+                            "adding node to LocalSwarmDiscovery address book"
+                        );
+
+                        let mut resolved = false;
+                        let item = peer_to_discovery_item(&peer_info, &discovered_node_id);
+                        if let Some(senders) = senders.get(&discovered_node_id) {
+                            trace!(?item, senders = senders.len(), "sending DiscoveryItem");
+                            resolved = true;
+                            for sender in senders.values() {
+                                sender.send(Ok(item.clone())).await.ok();
+                            }
+                        }
+                        entry.or_insert(peer_info);
+
+                        // only send nodes to the `subscriber` if they weren't explicitly resolved
+                        // in other words, nodes sent to the `subscribers` should only be the ones that
+                        // have been "passively" discovered
+                        if !resolved {
+                            subscribers.send(item);
+                        }
+                    }
+                    Message::Resolve(node_id, sender) => {
+                        let id = last_id + 1;
+                        last_id = id;
+                        trace!(?node_id, "LocalSwarmDiscovery Message::SendAddrs");
+                        if let Some(peer_info) = node_addrs.get(&node_id) {
+                            let item = peer_to_discovery_item(peer_info, &node_id);
+                            debug!(?item, "sending DiscoveryItem");
+                            sender.send(Ok(item)).await.ok();
+                        }
+                        if let Some(senders_for_node_id) = senders.get_mut(&node_id) {
+                            senders_for_node_id.insert(id, sender);
+                        } else {
+                            let mut senders_for_node_id = HashMap::new();
+                            senders_for_node_id.insert(id, sender);
+                            senders.insert(node_id, senders_for_node_id);
+                        }
+                        let timeout_sender = task_sender.clone();
+                        timeouts.spawn(async move {
+                            tokio::time::sleep(DISCOVERY_DURATION).await;
+                            trace!(?node_id, "discovery timeout");
+                            timeout_sender
+                                .send(Message::Timeout(node_id, id))
+                                .await
+                                .ok();
+                        });
+                    }
+                    Message::Timeout(node_id, id) => {
+                        trace!(?node_id, "LocalSwarmDiscovery Message::Timeout");
+                        if let Some(senders_for_node_id) = senders.get_mut(&node_id) {
+                            senders_for_node_id.remove(&id);
+                            if senders_for_node_id.is_empty() {
+                                senders.remove(&node_id);
+                            }
+                        }
+                    }
+                    Message::Subscribe(subscriber) => {
+                        trace!("LocalSwarmDiscovery Message::Subscribe");
+                        subscribers.push(subscriber);
+                    }
+                }
+            }
+        };
+        let handle = tokio::spawn(discovery_fut.instrument(info_span!("swarm-discovery.actor")));
+        Ok(Self {
+            handle: AbortOnDropHandle::new(handle),
+            sender: send,
+            local_addrs,
+        })
+    }
+
+    fn spawn_discoverer(
+        node_id: PublicKey,
+        sender: mpsc::Sender<Message>,
+        socketaddrs: BTreeSet<SocketAddr>,
+        rt: &tokio::runtime::Handle,
+    ) -> Result<DropGuard> {
+        let spawn_rt = rt.clone();
+        let callback = move |node_id: &str, peer: &Peer| {
+            trace!(
+                node_id,
+                ?peer,
+                "Received peer information from LocalSwarmDiscovery"
+            );
+
+            let sender = sender.clone();
+            let node_id = node_id.to_string();
+            let peer = peer.clone();
+            spawn_rt.spawn(async move {
+                sender.send(Message::Discovery(node_id, peer)).await.ok();
+            });
+        };
+        let addrs = LocalSwarmDiscovery::socketaddrs_to_addrs(socketaddrs);
+        let mut discoverer =
+            Discoverer::new_interactive(N0_LOCAL_SWARM.to_string(), node_id.to_string())
+                .with_callback(callback)
+                .with_ip_class(IpClass::Auto);
+        for addr in addrs {
+            discoverer = discoverer.with_addrs(addr.0, addr.1);
+        }
+        discoverer.spawn(rt)
+    }
+
+    fn socketaddrs_to_addrs(socketaddrs: BTreeSet<SocketAddr>) -> HashMap<u16, Vec<IpAddr>> {
+        let mut addrs: HashMap<u16, Vec<IpAddr>> = HashMap::default();
+        for socketaddr in socketaddrs {
+            addrs
+                .entry(socketaddr.port())
+                .and_modify(|a| a.push(socketaddr.ip()))
+                .or_insert(vec![socketaddr.ip()]);
+        }
+        addrs
+    }
+}
+
+fn peer_to_discovery_item(peer: &Peer, node_id: &NodeId) -> DiscoveryItem {
+    let direct_addresses: BTreeSet<SocketAddr> = peer
+        .addrs()
+        .iter()
+        .map(|(ip, port)| SocketAddr::new(*ip, *port))
+        .collect();
+    DiscoveryItem {
+        node_id: *node_id,
+        provenance: NAME,
+        last_updated: None,
+        addr_info: AddrInfo {
+            relay_url: None,
+            direct_addresses,
+        },
+    }
+}
+
+impl Discovery for LocalSwarmDiscovery {
+    fn resolve(&self, _ep: Endpoint, node_id: NodeId) -> Option<BoxStream<Result<DiscoveryItem>>> {
+        let (send, recv) = mpsc::channel(20);
+        let discovery_sender = self.sender.clone();
+        let stream = async move {
+            discovery_sender
+                .send(Message::Resolve(node_id, send))
+                .await
+                .ok();
+            tokio_stream::wrappers::ReceiverStream::new(recv)
+        };
+        Some(Box::pin(stream.flatten_stream()))
+    }
+
+    fn publish(&self, info: &AddrInfo) {
+        self.local_addrs.replace(Some(info.clone()));
+    }
+
+    fn subscribe(&self) -> Option<BoxStream<DiscoveryItem>> {
+        let (sender, recv) = mpsc::channel(20);
+        let discovery_sender = self.sender.clone();
+        let stream = async move {
+            discovery_sender.send(Message::Subscribe(sender)).await.ok();
+            tokio_stream::wrappers::ReceiverStream::new(recv)
+        };
+        Some(Box::pin(stream.flatten_stream()))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    /// This module's name signals nextest to run test in a single thread (no other concurrent
+    /// tests)
+    mod run_in_isolation {
+        use futures_lite::StreamExt;
+        use testresult::TestResult;
+
+        use super::super::*;
+
+        #[tokio::test]
+        async fn local_swarm_discovery_publish_resolve() -> TestResult {
+            let _guard = iroh_test::logging::setup();
+            let (_, discovery_a) = make_discoverer()?;
+            let (node_id_b, discovery_b) = make_discoverer()?;
+
+            // make addr info for discoverer b
+            let addr_info = AddrInfo {
+                relay_url: None,
+                direct_addresses: BTreeSet::from(["0.0.0.0:11111".parse()?]),
+            };
+
+            // pass in endpoint, this is never used
+            let ep = crate::endpoint::Builder::default().bind().await?;
+
+            // resolve twice to ensure we can create separate streams for the same node_id
+            let mut s1 = discovery_a.resolve(ep.clone(), node_id_b).unwrap();
+            let mut s2 = discovery_a.resolve(ep, node_id_b).unwrap();
+
+            tracing::debug!(?node_id_b, "Discovering node id b");
+            // publish discovery_b's address
+            discovery_b.publish(&addr_info);
+            let s1_res = tokio::time::timeout(Duration::from_secs(5), s1.next())
+                .await?
+                .unwrap()?;
+            let s2_res = tokio::time::timeout(Duration::from_secs(5), s2.next())
+                .await?
+                .unwrap()?;
+            assert_eq!(s1_res.addr_info, addr_info);
+            assert_eq!(s2_res.addr_info, addr_info);
+
+            Ok(())
+        }
+
+        #[tokio::test]
+        async fn local_swarm_discovery_subscribe() -> TestResult {
+            let _guard = iroh_test::logging::setup();
+
+            let num_nodes = 5;
+            let mut node_ids = BTreeSet::new();
+            let mut discoverers = vec![];
+
+            let (_, discovery) = make_discoverer()?;
+            let addr_info = AddrInfo {
+                relay_url: None,
+                direct_addresses: BTreeSet::from(["0.0.0.0:11111".parse()?]),
+            };
+
+            for _ in 0..num_nodes {
+                let (node_id, discovery) = make_discoverer()?;
+                node_ids.insert(node_id);
+                discovery.publish(&addr_info);
+                discoverers.push(discovery);
+            }
+
+            let mut events = discovery.subscribe().unwrap();
+
+            let test = async move {
+                let mut got_ids = BTreeSet::new();
+                while got_ids.len() != num_nodes {
+                    if let Some(item) = events.next().await {
+                        if node_ids.contains(&item.node_id) {
+                            got_ids.insert(item.node_id);
+                        }
+                    } else {
+                        anyhow::bail!(
+                            "no more events, only got {} ids, expected {num_nodes}\n",
+                            got_ids.len()
+                        );
+                    }
+                }
+                assert_eq!(got_ids, node_ids);
+                anyhow::Ok(())
+            };
+            tokio::time::timeout(Duration::from_secs(5), test).await??;
+            Ok(())
+        }
+
+        fn make_discoverer() -> Result<(PublicKey, LocalSwarmDiscovery)> {
+            let node_id = crate::key::SecretKey::generate().public();
+            Ok((node_id, LocalSwarmDiscovery::new(node_id)?))
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery/pkarr.rs.html b/pr/2992/docs/src/iroh/discovery/pkarr.rs.html new file mode 100644 index 0000000000..27e092a916 --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery/pkarr.rs.html @@ -0,0 +1,843 @@ +pkarr.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+
//! A discovery service which publishes and resolves node information using a [pkarr] relay.
+//!
+//! Public-Key Addressable Resource Records, [pkarr], is a system which allows publishing
+//! [DNS Resource Records] owned by a particular [`SecretKey`] under a name derived from its
+//! corresponding [`PublicKey`], also known as the [`NodeId`].  Additionally this pkarr
+//! Resource Record is signed using the same [`SecretKey`], ensuring authenticity of the
+//! record.
+//!
+//! Pkarr normally stores these records on the [Mainline DHT], but also provides two bridges
+//! that do not require clients to directly interact with the DHT:
+//!
+//! - Resolvers are servers which expose the pkarr Resource Record under a domain name,
+//!   e.g. `o3dks..6uyy.dns.iroh.link`.  This allows looking up the pkarr Resource Records
+//!   using normal DNS clients.  These resolvers would normally perform lookups on the
+//!   Mainline DHT augmented with a local cache to improve performance.
+//!
+//! - Relays are servers which allow both publishing and looking up of the pkarr Resource
+//!   Records using HTTP PUT and GET requests.  They will usually perform the publishing to
+//!   the Mainline DHT on behalf on the client as well as cache lookups performed on the DHT
+//!   to improve performance.
+//!
+//! For node discovery in iroh the pkarr Resource Records contain the [`AddrInfo`]
+//! information, providing nodes which retrieve the pkarr Resource Record with enough detail
+//! to contact the iroh node.
+//!
+//! There are several node discovery services built on top of pkarr, which can be composed
+//! to the application's needs:
+//!
+//! - [`PkarrPublisher`], which publishes to a pkarr relay server using HTTP.
+//!
+//! - [`PkarrResolver`], which resolves from a pkarr relay server using HTTP.
+//!
+//! - [`DnsDiscovery`], which resolves from a DNS server.
+//!
+//! - [`DhtDiscovery`], which resolves and publishes from both pkarr relay servers and well
+//!   as the Mainline DHT.
+//!
+//! [pkarr]: https://pkarr.org
+//! [DNS Resource Records]: https://en.wikipedia.org/wiki/Domain_Name_System#Resource_records
+//! [Mainline DHT]: https://en.wikipedia.org/wiki/Mainline_DHT
+//! [`SecretKey`]: crate::key::SecretKey
+//! [`PublicKey`]: crate::key::PublicKey
+//! [`NodeId`]: crate::key::NodeId
+//! [`DnsDiscovery`]: crate::discovery::dns::DnsDiscovery
+//! [`DhtDiscovery`]: dht::DhtDiscovery
+
+use std::sync::Arc;
+
+use anyhow::{anyhow, bail, Result};
+use futures_util::stream::BoxStream;
+use pkarr::SignedPacket;
+use tokio::{
+    task::JoinHandle,
+    time::{Duration, Instant},
+};
+use tracing::{debug, error_span, info, warn, Instrument};
+use url::Url;
+use watchable::{Watchable, Watcher};
+
+use crate::{
+    discovery::{Discovery, DiscoveryItem},
+    dns::node_info::NodeInfo,
+    endpoint::force_staging_infra,
+    key::SecretKey,
+    AddrInfo, Endpoint, NodeId,
+};
+
+#[cfg(feature = "discovery-pkarr-dht")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "discovery-pkarr-dht")))]
+pub mod dht;
+
+/// The production pkarr relay run by [number 0].
+///
+/// This server is both a pkarr relay server as well as a DNS resolver, see the [module
+/// documentation].  However it does not interact with the Mainline DHT, so is a more
+/// central service.  It is a reliable service to use for node discovery.
+///
+/// [number 0]: https://n0.computer
+/// [module documentation]: crate::discovery::pkarr
+pub const N0_DNS_PKARR_RELAY_PROD: &str = "https://dns.iroh.link/pkarr";
+/// The testing pkarr relay run by [number 0].
+///
+/// This server operates similarly to [`N0_DNS_PKARR_RELAY_PROD`] but is not as reliable.
+/// It is meant for more experimental use and testing purposes.
+///
+/// [number 0]: https://n0.computer
+pub const N0_DNS_PKARR_RELAY_STAGING: &str = "https://staging-dns.iroh.link/pkarr";
+
+/// Default TTL for the records in the pkarr signed packet.
+///
+/// The Time To Live (TTL) tells DNS caches how long to store a record. It is ignored by the
+/// `iroh-dns-server`, e.g. as running on [`N0_DNS_PKARR_RELAY_PROD`], as the home server
+/// keeps the records for the domain. When using the pkarr relay no DNS is involved and the
+/// setting is ignored.
+// TODO(flub): huh?
+pub const DEFAULT_PKARR_TTL: u32 = 30;
+
+/// Interval in which to republish the node info even if unchanged: 5 minutes.
+pub const DEFAULT_REPUBLISH_INTERVAL: Duration = Duration::from_secs(60 * 5);
+
+/// Publisher of node discovery information to a [pkarr] relay.
+///
+/// This publisher uses HTTP to publish node discovery information to a pkarr relay
+/// server, see the [module docs] for details.
+///
+/// This implements the [`Discovery`] trait to be used as a node discovery service.  Note
+/// that it only publishes node discovery information, for the corresponding resolver use
+/// the [`PkarrResolver`] together with [`ConcurrentDiscovery`].
+///
+/// This publisher will **only** publish the [`RelayUrl`] if the [`AddrInfo`] contains a
+/// [`RelayUrl`].  If the [`AddrInfo`] does not contain a [`RelayUrl`] the *direct
+/// addresses* are published instead.
+///
+/// [pkarr]: https://pkarr.org
+/// [module docs]: crate::discovery::pkarr
+/// [`RelayUrl`]: crate::relay::RelayUrl
+/// [`ConcurrentDiscovery`]: super::ConcurrentDiscovery
+#[derive(derive_more::Debug, Clone)]
+pub struct PkarrPublisher {
+    node_id: NodeId,
+    watchable: Watchable<Option<NodeInfo>>,
+    join_handle: Arc<JoinHandle<()>>,
+}
+
+impl PkarrPublisher {
+    /// Creates a new publisher for the [`SecretKey`].
+    ///
+    /// This publisher will be able to publish [pkarr] records for [`SecretKey`].  It will
+    /// use [`DEFAULT_PKARR_TTL`] as the time-to-live value for the published packets.  Will
+    /// republish discovery information every [`DEFAULT_REPUBLISH_INTERVAL`], even if the
+    /// information is unchanged.
+    ///
+    /// [pkarr]: https://pkarr.org
+    pub fn new(secret_key: SecretKey, pkarr_relay: Url) -> Self {
+        Self::with_options(
+            secret_key,
+            pkarr_relay,
+            DEFAULT_PKARR_TTL,
+            DEFAULT_REPUBLISH_INTERVAL,
+        )
+    }
+
+    /// Creates a new [`PkarrPublisher`] with a custom TTL and republish intervals.
+    ///
+    /// This allows creating the publisher with custom time-to-live values of the
+    /// [`pkarr::SignedPacket`]s and well as a custom republish interval.
+    pub fn with_options(
+        secret_key: SecretKey,
+        pkarr_relay: Url,
+        ttl: u32,
+        republish_interval: std::time::Duration,
+    ) -> Self {
+        debug!("creating pkarr publisher that publishes to {pkarr_relay}");
+        let node_id = secret_key.public();
+        let pkarr_client = PkarrRelayClient::new(pkarr_relay);
+        let watchable = Watchable::default();
+        let service = PublisherService {
+            ttl,
+            watcher: watchable.watch(),
+            secret_key,
+            pkarr_client,
+            republish_interval,
+        };
+        let join_handle = tokio::task::spawn(
+            service
+                .run()
+                .instrument(error_span!("pkarr_publish", me=%node_id.fmt_short())),
+        );
+        Self {
+            watchable,
+            node_id,
+            join_handle: Arc::new(join_handle),
+        }
+    }
+
+    /// Creates a pkarr publisher which uses the [number 0] pkarr relay server.
+    ///
+    /// This uses the pkarr relay server operated by [number 0], at
+    /// [`N0_DNS_PKARR_RELAY_PROD`].
+    ///
+    /// When running with the environment variable
+    /// `IROH_FORCE_STAGING_RELAYS` set to any non empty value [`N0_DNS_PKARR_RELAY_STAGING`]
+    /// server is used instead.
+    ///
+    /// [number 0]: https://n0.computer
+    pub fn n0_dns(secret_key: SecretKey) -> Self {
+        let pkarr_relay = match force_staging_infra() {
+            true => N0_DNS_PKARR_RELAY_STAGING,
+            false => N0_DNS_PKARR_RELAY_PROD,
+        };
+
+        let pkarr_relay: Url = pkarr_relay.parse().expect("url is valid");
+        Self::new(secret_key, pkarr_relay)
+    }
+
+    /// Publishes [`AddrInfo`] about this node to a pkarr relay.
+    ///
+    /// This is a nonblocking function, the actual update is performed in the background.
+    pub fn update_addr_info(&self, info: &AddrInfo) {
+        let (relay_url, direct_addresses) = if let Some(relay_url) = info.relay_url.as_ref() {
+            (Some(relay_url.clone().into()), Default::default())
+        } else {
+            (None, info.direct_addresses.clone())
+        };
+        let info = NodeInfo::new(self.node_id, relay_url, direct_addresses);
+        self.watchable.update(Some(info)).ok();
+    }
+}
+
+impl Discovery for PkarrPublisher {
+    fn publish(&self, info: &AddrInfo) {
+        self.update_addr_info(info);
+    }
+}
+
+impl Drop for PkarrPublisher {
+    fn drop(&mut self) {
+        // this means we're dropping the last reference
+        if let Some(handle) = Arc::get_mut(&mut self.join_handle) {
+            handle.abort();
+        }
+    }
+}
+
+/// Publish node info to a pkarr relay.
+#[derive(derive_more::Debug, Clone)]
+struct PublisherService {
+    #[debug("SecretKey")]
+    secret_key: SecretKey,
+    #[debug("PkarrClient")]
+    pkarr_client: PkarrRelayClient,
+    watcher: Watcher<Option<NodeInfo>>,
+    ttl: u32,
+    republish_interval: Duration,
+}
+
+impl PublisherService {
+    async fn run(self) {
+        let mut failed_attempts = 0;
+        let republish = tokio::time::sleep(Duration::MAX);
+        tokio::pin!(republish);
+        loop {
+            if let Some(info) = self.watcher.get() {
+                if let Err(err) = self.publish_current(info).await {
+                    failed_attempts += 1;
+                    // Retry after increasing timeout
+                    let retry_after = Duration::from_secs(failed_attempts);
+                    republish.as_mut().reset(Instant::now() + retry_after);
+                    warn!(
+                        err = %format!("{err:#}"),
+                        url = %self.pkarr_client.pkarr_relay_url ,
+                        ?retry_after,
+                        %failed_attempts,
+                        "Failed to publish to pkarr",
+                    );
+                } else {
+                    failed_attempts = 0;
+                    // Republish after fixed interval
+                    republish
+                        .as_mut()
+                        .reset(Instant::now() + self.republish_interval);
+                }
+            }
+            // Wait until either the retry/republish timeout is reached, or the node info changed.
+            tokio::select! {
+                res = self.watcher.watch_async() => match res {
+                    Ok(()) => debug!("Publish node info to pkarr (info changed)"),
+                    Err(_disconnected) => break,
+                },
+                _ = &mut republish => debug!("Publish node info to pkarr (interval elapsed)"),
+            }
+        }
+    }
+
+    async fn publish_current(&self, info: NodeInfo) -> Result<()> {
+        info!(
+            relay_url = ?info
+                .relay_url
+                .as_ref()
+                .map(|s| s.as_str()),
+            pkarr_relay = %self.pkarr_client.pkarr_relay_url,
+            "Publish node info to pkarr"
+        );
+        let signed_packet = info.to_pkarr_signed_packet(&self.secret_key, self.ttl)?;
+        self.pkarr_client.publish(&signed_packet).await?;
+        Ok(())
+    }
+}
+
+/// Resolver of node discovery information from a [pkarr] relay.
+///
+/// The resolver uses HTTP to query node discovery information from a pkarr relay server,
+/// see the [module docs] for details.
+///
+/// This implements the [`Discovery`] trait to be used as a node discovery service.  Note
+/// that it only resolves node discovery information, for the corresponding publisher use
+/// the [`PkarrPublisher`] together with [`ConcurrentDiscovery`].
+///
+/// [pkarr]: https://pkarr.org
+/// [module docs]: crate::discovery::pkarr
+/// [`ConcurrentDiscovery`]: super::ConcurrentDiscovery
+#[derive(derive_more::Debug, Clone)]
+pub struct PkarrResolver {
+    pkarr_client: PkarrRelayClient,
+}
+
+impl PkarrResolver {
+    /// Creates a new publisher using the pkarr relay server at the URL.
+    pub fn new(pkarr_relay: Url) -> Self {
+        Self {
+            pkarr_client: PkarrRelayClient::new(pkarr_relay),
+        }
+    }
+
+    /// Creates a pkarr resolver which uses the [number 0] pkarr relay server.
+    ///
+    /// This uses the pkarr relay server operated by [number 0] at
+    /// [`N0_DNS_PKARR_RELAY_PROD`].
+    ///
+    /// When running with the environment variable `IROH_FORCE_STAGING_RELAYS`
+    /// set to any non empty value [`N0_DNS_PKARR_RELAY_STAGING`]
+    /// server is used instead.
+    ///
+    /// [number 0]: https://n0.computer
+    pub fn n0_dns() -> Self {
+        let pkarr_relay = match force_staging_infra() {
+            true => N0_DNS_PKARR_RELAY_STAGING,
+            false => N0_DNS_PKARR_RELAY_PROD,
+        };
+
+        let pkarr_relay: Url = pkarr_relay.parse().expect("url is valid");
+        Self::new(pkarr_relay)
+    }
+}
+
+impl Discovery for PkarrResolver {
+    fn resolve(
+        &self,
+        _ep: Endpoint,
+        node_id: NodeId,
+    ) -> Option<BoxStream<'static, Result<DiscoveryItem>>> {
+        let pkarr_client = self.pkarr_client.clone();
+        let fut = async move {
+            let signed_packet = pkarr_client.resolve(node_id).await?;
+            let info = NodeInfo::from_pkarr_signed_packet(&signed_packet)?;
+            let item = DiscoveryItem {
+                node_id,
+                provenance: "pkarr",
+                last_updated: None,
+                addr_info: info.into(),
+            };
+            Ok(item)
+        };
+        let stream = futures_lite::stream::once_future(fut);
+        Some(Box::pin(stream))
+    }
+}
+
+/// A [pkarr] client to publish [`pkarr::SignedPacket`]s to a pkarr relay.
+///
+/// [pkarr]: https://pkarr.org
+#[derive(Debug, Clone)]
+pub struct PkarrRelayClient {
+    http_client: reqwest::Client,
+    pkarr_relay_url: Url,
+}
+
+impl PkarrRelayClient {
+    /// Creates a new client.
+    pub fn new(pkarr_relay_url: Url) -> Self {
+        Self {
+            http_client: reqwest::Client::new(),
+            pkarr_relay_url,
+        }
+    }
+
+    /// Resolves a [`SignedPacket`] for the given [`NodeId`].
+    pub async fn resolve(&self, node_id: NodeId) -> anyhow::Result<SignedPacket> {
+        let public_key = pkarr::PublicKey::try_from(node_id.as_bytes())?;
+        let mut url = self.pkarr_relay_url.clone();
+        url.path_segments_mut()
+            .map_err(|_| anyhow!("Failed to resolve: Invalid relay URL"))?
+            .push(&public_key.to_z32());
+
+        let response = self.http_client.get(url).send().await?;
+
+        if !response.status().is_success() {
+            bail!(format!(
+                "Resolve request failed with status {}",
+                response.status()
+            ))
+        }
+
+        let payload = response.bytes().await?;
+        Ok(SignedPacket::from_relay_payload(&public_key, &payload)?)
+    }
+
+    /// Publishes a [`SignedPacket`].
+    pub async fn publish(&self, signed_packet: &SignedPacket) -> anyhow::Result<()> {
+        let mut url = self.pkarr_relay_url.clone();
+        url.path_segments_mut()
+            .map_err(|_| anyhow!("Failed to publish: Invalid relay URL"))?
+            .push(&signed_packet.public_key().to_z32());
+
+        let response = self
+            .http_client
+            .put(url)
+            .body(signed_packet.to_relay_payload())
+            .send()
+            .await?;
+
+        if !response.status().is_success() {
+            bail!(format!(
+                "Publish request failed with status {}",
+                response.status()
+            ))
+        }
+
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery/pkarr/dht.rs.html b/pr/2992/docs/src/iroh/discovery/pkarr/dht.rs.html new file mode 100644 index 0000000000..d152728064 --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery/pkarr/dht.rs.html @@ -0,0 +1,929 @@ +dht.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+
//! Pkarr based node discovery for iroh, supporting both relay servers and the DHT.
+//!
+//! This module contains pkarr-based node discovery for iroh which can use both pkarr
+//! relay servers as well as the Mainline DHT directly.  See the [pkarr module] for an
+//! overview of pkarr.
+//!
+//! [pkarr module]: super
+use std::{
+    sync::{Arc, Mutex},
+    time::Duration,
+};
+
+use futures_lite::{stream::Boxed, StreamExt};
+use genawaiter::sync::{Co, Gen};
+use pkarr::{
+    PkarrClient, PkarrClientAsync, PkarrRelayClient, PkarrRelayClientAsync, PublicKey,
+    RelaySettings, SignedPacket,
+};
+use tokio_util::task::AbortOnDropHandle;
+use url::Url;
+
+use crate::{
+    discovery::{
+        pkarr::{DEFAULT_PKARR_TTL, N0_DNS_PKARR_RELAY_PROD},
+        Discovery, DiscoveryItem,
+    },
+    dns::node_info::NodeInfo,
+    key::SecretKey,
+    AddrInfo, Endpoint, NodeId,
+};
+
+/// Republish delay for the DHT.
+///
+/// This is only for when the info does not change.  If the info changes, it will be
+/// published immediately.
+const REPUBLISH_DELAY: Duration = Duration::from_secs(60 * 60);
+/// Initial publish delay.
+///
+/// This is to avoid spamming the DHT when there are frequent network changes at startup.
+const INITIAL_PUBLISH_DELAY: Duration = Duration::from_millis(500);
+
+/// Pkarr Mainline DHT and relay server node discovery.
+///
+/// It stores node addresses in DNS records, signed by the node's private key, and publishes
+/// them to the BitTorrent Mainline DHT.  See the [pkarr module] for more details.
+///
+/// This implements the [`Discovery`] trait to be used as a node discovery service which can
+/// be used as both a publisher and resolver.  Calling [`DhtDiscovery::publish`] will start
+/// a background task that periodically publishes the node address.
+///
+/// [pkarr module]: super
+#[derive(Debug, Clone)]
+pub struct DhtDiscovery(Arc<Inner>);
+
+impl Default for DhtDiscovery {
+    fn default() -> Self {
+        Self::builder().build().expect("valid builder")
+    }
+}
+
+#[derive(derive_more::Debug)]
+struct Inner {
+    /// Pkarr client for interacting with the DHT.
+    pkarr: PkarrClientAsync,
+    /// Pkarr client for interacting with a pkarr relay
+    #[debug("Option<PkarrRelayClientAsync>")]
+    pkarr_relay: Option<PkarrRelayClientAsync>,
+    /// The background task that periodically publishes the node address.
+    ///
+    /// Due to [`AbortOnDropHandle`], this will be aborted when the discovery is dropped.
+    task: Mutex<Option<AbortOnDropHandle<()>>>,
+    /// Optional keypair for signing the DNS packets.
+    ///
+    /// If this is None, the node will not publish its address to the DHT.
+    secret_key: Option<SecretKey>,
+    /// Optional pkarr relay URL to use.
+    relay_url: Option<Url>,
+    /// Whether to publish to the mainline DHT.
+    dht: bool,
+    /// Time-to-live value for the DNS packets.
+    ttl: u32,
+    /// True to include the direct addresses in the DNS packet.
+    include_direct_addresses: bool,
+    /// Initial delay before the first publish.
+    initial_publish_delay: Duration,
+    /// Republish delay for the DHT.
+    republish_delay: Duration,
+}
+
+/// Builder for [`DhtDiscovery`].
+///
+/// By default, publishing to the DHT is enabled, and relay publishing is disabled.
+#[derive(Debug)]
+pub struct Builder {
+    client: Option<PkarrClient>,
+    secret_key: Option<SecretKey>,
+    ttl: Option<u32>,
+    pkarr_relay: Option<Url>,
+    dht: bool,
+    include_direct_addresses: bool,
+    initial_publish_delay: Duration,
+    republish_delay: Duration,
+}
+
+impl Default for Builder {
+    fn default() -> Self {
+        Self {
+            client: None,
+            secret_key: None,
+            ttl: None,
+            pkarr_relay: None,
+            dht: true,
+            include_direct_addresses: false,
+            initial_publish_delay: INITIAL_PUBLISH_DELAY,
+            republish_delay: REPUBLISH_DELAY,
+        }
+    }
+}
+
+impl Builder {
+    /// Explicitly sets the pkarr client to use.
+    pub fn client(mut self, client: PkarrClient) -> Self {
+        self.client = Some(client);
+        self
+    }
+
+    /// Sets the secret key to use for signing the DNS packets.
+    ///
+    /// Without a secret key, the node will not publish its address to the DHT.
+    pub fn secret_key(mut self, secret_key: SecretKey) -> Self {
+        self.secret_key = Some(secret_key);
+        self
+    }
+
+    /// Sets the time-to-live value for the DNS packets.
+    pub fn ttl(mut self, ttl: u32) -> Self {
+        self.ttl = Some(ttl);
+        self
+    }
+
+    /// Sets the pkarr relay URL to use.
+    pub fn pkarr_relay(mut self, pkarr_relay: Url) -> Self {
+        self.pkarr_relay = Some(pkarr_relay);
+        self
+    }
+
+    /// Uses the default [number 0] pkarr relay URL.
+    ///
+    /// [number 0]: https://n0.computer
+    pub fn n0_dns_pkarr_relay(mut self) -> Self {
+        self.pkarr_relay = Some(N0_DNS_PKARR_RELAY_PROD.parse().expect("valid URL"));
+        self
+    }
+
+    /// Sets whether to publish to the Mainline DHT.
+    pub fn dht(mut self, dht: bool) -> Self {
+        self.dht = dht;
+        self
+    }
+
+    /// Sets whether to include the direct addresses in the DNS packet.
+    pub fn include_direct_addresses(mut self, include_direct_addresses: bool) -> Self {
+        self.include_direct_addresses = include_direct_addresses;
+        self
+    }
+
+    /// Sets the initial delay before the first publish.
+    pub fn initial_publish_delay(mut self, initial_publish_delay: Duration) -> Self {
+        self.initial_publish_delay = initial_publish_delay;
+        self
+    }
+
+    /// Sets the republish delay for the DHT.
+    pub fn republish_delay(mut self, republish_delay: Duration) -> Self {
+        self.republish_delay = republish_delay;
+        self
+    }
+
+    /// Builds the discovery mechanism.
+    pub fn build(self) -> anyhow::Result<DhtDiscovery> {
+        let pkarr = self
+            .client
+            .unwrap_or_else(|| PkarrClient::new(Default::default()).unwrap())
+            .as_async();
+        let ttl = self.ttl.unwrap_or(DEFAULT_PKARR_TTL);
+        let relay_url = self.pkarr_relay;
+        let dht = self.dht;
+        let include_direct_addresses = self.include_direct_addresses;
+        anyhow::ensure!(
+            dht || relay_url.is_some(),
+            "at least one of DHT or relay must be enabled"
+        );
+
+        let pkarr_relay = match relay_url.clone() {
+            Some(url) => Some(
+                PkarrRelayClient::new(RelaySettings {
+                    relays: vec![url.to_string()],
+                    ..RelaySettings::default()
+                })?
+                .as_async(),
+            ),
+            None => None,
+        };
+
+        Ok(DhtDiscovery(Arc::new(Inner {
+            pkarr,
+            pkarr_relay,
+            ttl,
+            relay_url,
+            dht,
+            include_direct_addresses,
+            secret_key: self.secret_key,
+            initial_publish_delay: self.initial_publish_delay,
+            republish_delay: self.republish_delay,
+            task: Default::default(),
+        })))
+    }
+}
+
+impl DhtDiscovery {
+    /// Creates a new builder for [`DhtDiscovery`].
+    pub fn builder() -> Builder {
+        Builder::default()
+    }
+
+    /// Periodically publishes the node address to the DHT and/or relay.
+    async fn publish_loop(self, keypair: SecretKey, signed_packet: SignedPacket) {
+        let this = self;
+        let z32 = pkarr::PublicKey::try_from(keypair.public().as_bytes())
+            .expect("valid public key")
+            .to_z32();
+        // initial delay. If the task gets aborted before this delay is over,
+        // we have not published anything to the DHT yet.
+        tokio::time::sleep(this.0.initial_publish_delay).await;
+        loop {
+            // publish to the DHT if enabled
+            let dht_publish = async {
+                if this.0.dht {
+                    let res = this.0.pkarr.publish(&signed_packet).await;
+                    match res {
+                        Ok(()) => {
+                            tracing::debug!("pkarr publish success. published under {z32}",);
+                        }
+                        Err(e) => {
+                            // we could do a smaller delay here, but in general DHT publish
+                            // not working is due to a network issue, and if the network changes
+                            // the task will be restarted anyway.
+                            //
+                            // Being unable to publish to the DHT is something that is expected
+                            // to happen from time to time, so this does not warrant a error log.
+                            tracing::warn!("pkarr publish error: {}", e);
+                        }
+                    }
+                }
+            };
+            // publish to the relay if enabled
+            let relay_publish = async {
+                if let Some(relay) = this.0.pkarr_relay.as_ref() {
+                    tracing::info!(
+                        "publishing to relay: {}",
+                        this.0.relay_url.as_ref().unwrap().to_string()
+                    );
+                    match relay.publish(&signed_packet).await {
+                        Ok(_) => {
+                            tracing::debug!("pkarr publish to relay success");
+                        }
+                        Err(e) => {
+                            tracing::warn!("pkarr publish to relay error: {}", e);
+                        }
+                    }
+                }
+            };
+            // do both at the same time
+            tokio::join!(relay_publish, dht_publish);
+            tokio::time::sleep(this.0.republish_delay).await;
+        }
+    }
+
+    async fn resolve_relay(
+        &self,
+        pkarr_public_key: PublicKey,
+        co: &Co<anyhow::Result<DiscoveryItem>>,
+    ) {
+        let Some(relay) = &self.0.pkarr_relay else {
+            return;
+        };
+        let url = self.0.relay_url.as_ref().unwrap();
+        tracing::info!("resolving {} from relay {}", pkarr_public_key.to_z32(), url);
+        let response = relay.resolve(&pkarr_public_key).await;
+        match response {
+            Ok(Some(signed_packet)) => {
+                if let Ok(node_info) = NodeInfo::from_pkarr_signed_packet(&signed_packet) {
+                    let node_id = node_info.node_id;
+                    let addr_info = node_info.into();
+                    tracing::info!("discovered node info from relay {:?}", addr_info);
+                    co.yield_(Ok(DiscoveryItem {
+                        node_id,
+                        provenance: "relay",
+                        last_updated: None,
+                        addr_info,
+                    }))
+                    .await;
+                } else {
+                    tracing::debug!("failed to parse signed packet as node info");
+                }
+            }
+            Ok(None) => {
+                tracing::debug!("no signed packet found in relay");
+            }
+            Err(e) => {
+                tracing::debug!("failed to get signed packet from relay: {}", e);
+                co.yield_(Err(e.into())).await;
+            }
+        }
+    }
+
+    /// Resolves a node id from the DHT.
+    async fn resolve_dht(
+        &self,
+        pkarr_public_key: PublicKey,
+        co: &Co<anyhow::Result<DiscoveryItem>>,
+    ) {
+        if !self.0.dht {
+            return;
+        };
+        tracing::info!("resolving {} from DHT", pkarr_public_key.to_z32());
+        let response = match self.0.pkarr.resolve(&pkarr_public_key).await {
+            Ok(r) => r,
+            Err(e) => {
+                co.yield_(Err(e.into())).await;
+                return;
+            }
+        };
+        let Some(signed_packet) = response else {
+            tracing::debug!("no signed packet found in DHT");
+            return;
+        };
+        if let Ok(node_info) = NodeInfo::from_pkarr_signed_packet(&signed_packet) {
+            let node_id = node_info.node_id;
+            let addr_info = node_info.into();
+            tracing::info!("discovered node info from DHT {:?}", addr_info);
+            co.yield_(Ok(DiscoveryItem {
+                node_id,
+                provenance: "mainline",
+                last_updated: None,
+                addr_info,
+            }))
+            .await;
+        } else {
+            tracing::debug!("failed to parse signed packet as node info");
+        }
+    }
+
+    async fn gen_resolve(self, node_id: NodeId, co: Co<anyhow::Result<DiscoveryItem>>) {
+        let pkarr_public_key =
+            pkarr::PublicKey::try_from(node_id.as_bytes()).expect("valid public key");
+        tokio::join!(
+            self.resolve_dht(pkarr_public_key.clone(), &co),
+            self.resolve_relay(pkarr_public_key, &co)
+        );
+    }
+}
+
+impl Discovery for DhtDiscovery {
+    fn publish(&self, info: &AddrInfo) {
+        let Some(keypair) = &self.0.secret_key else {
+            tracing::debug!("no keypair set, not publishing");
+            return;
+        };
+        tracing::debug!("publishing {:?}", info);
+        let info = NodeInfo {
+            node_id: keypair.public(),
+            relay_url: info.relay_url.clone().map(Url::from),
+            direct_addresses: if self.0.include_direct_addresses {
+                info.direct_addresses.clone()
+            } else {
+                Default::default()
+            },
+        };
+        let Ok(signed_packet) = info.to_pkarr_signed_packet(keypair, self.0.ttl) else {
+            tracing::warn!("failed to create signed packet");
+            return;
+        };
+        let this = self.clone();
+        let curr = tokio::spawn(this.publish_loop(keypair.clone(), signed_packet));
+        let mut task = self.0.task.lock().unwrap();
+        *task = Some(AbortOnDropHandle::new(curr));
+    }
+
+    fn resolve(
+        &self,
+        _endpoint: Endpoint,
+        node_id: NodeId,
+    ) -> Option<Boxed<anyhow::Result<DiscoveryItem>>> {
+        let this = self.clone();
+        let pkarr_public_key =
+            pkarr::PublicKey::try_from(node_id.as_bytes()).expect("valid public key");
+        tracing::info!("resolving {} as {}", node_id, pkarr_public_key.to_z32());
+        Some(Gen::new(|co| async move { this.gen_resolve(node_id, co).await }).boxed())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::collections::BTreeSet;
+
+    use iroh_base::node_addr::RelayUrl;
+    use pkarr::mainline::dht::DhtSettings;
+    use testresult::TestResult;
+
+    use super::*;
+
+    #[tokio::test]
+    #[ignore = "flaky"]
+    async fn dht_discovery_smoke() -> TestResult {
+        let _logging_guard = iroh_test::logging::setup();
+        let ep = crate::Endpoint::builder().bind().await?;
+        let secret = ep.secret_key().clone();
+        let testnet = pkarr::mainline::dht::Testnet::new(2);
+        let settings = pkarr::Settings {
+            dht: DhtSettings {
+                bootstrap: Some(testnet.bootstrap.clone()),
+                ..Default::default()
+            },
+            ..Default::default()
+        };
+        let client = PkarrClient::new(settings)?;
+        let discovery = DhtDiscovery::builder()
+            .secret_key(secret.clone())
+            .initial_publish_delay(Duration::ZERO)
+            .client(client)
+            .build()?;
+        let relay_url: RelayUrl = Url::parse("https://example.com")?.into();
+
+        discovery.publish(&AddrInfo {
+            relay_url: Some(relay_url.clone()),
+            direct_addresses: Default::default(),
+        });
+
+        // publish is fire and forget, so we have no way to wait until it is done.
+        tokio::time::timeout(Duration::from_secs(30), async move {
+            loop {
+                tokio::time::sleep(Duration::from_millis(200)).await;
+                let mut found_relay_urls = BTreeSet::new();
+                let items = discovery
+                    .resolve(ep.clone(), secret.public())
+                    .unwrap()
+                    .collect::<Vec<_>>()
+                    .await;
+                for item in items.into_iter().flatten() {
+                    if let Some(url) = item.addr_info.relay_url {
+                        found_relay_urls.insert(url);
+                    }
+                }
+                if found_relay_urls.contains(&relay_url) {
+                    break;
+                }
+            }
+        })
+        .await
+        .expect("timeout, relay_url not found on DHT");
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/discovery/static_provider.rs.html b/pr/2992/docs/src/iroh/discovery/static_provider.rs.html new file mode 100644 index 0000000000..bd00bb82fb --- /dev/null +++ b/pr/2992/docs/src/iroh/discovery/static_provider.rs.html @@ -0,0 +1,325 @@ +static_provider.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+
//! A static discovery implementation that allows adding info for nodes manually.
+use std::{
+    collections::{btree_map::Entry, BTreeMap},
+    sync::{Arc, RwLock},
+    time::SystemTime,
+};
+
+use futures_lite::stream::{self, StreamExt};
+use iroh_base::{
+    key::NodeId,
+    node_addr::{AddrInfo, NodeAddr},
+};
+
+use super::{Discovery, DiscoveryItem};
+
+/// A static discovery implementation that allows providing info for nodes manually.
+#[derive(Debug, Default)]
+#[repr(transparent)]
+pub struct StaticProvider {
+    nodes: Arc<RwLock<BTreeMap<NodeId, NodeInfo>>>,
+}
+
+#[derive(Debug)]
+struct NodeInfo {
+    info: AddrInfo,
+    last_updated: SystemTime,
+}
+
+impl StaticProvider {
+    /// The provenance string for this discovery implementation.
+    pub const PROVENANCE: &'static str = "static_discovery";
+
+    /// Create a new static discovery instance.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Creates a static discovery instance from something that can be converted into node addresses.
+    ///
+    /// Example:
+    /// ```rust
+    /// use std::str::FromStr;
+    ///
+    /// use iroh_base::ticket::NodeTicket;
+    /// use iroh::{Endpoint, discovery::static_provider::StaticProvider};
+    ///
+    /// # async fn example() -> anyhow::Result<()> {
+    /// # #[derive(Default)] struct Args { tickets: Vec<NodeTicket> }
+    /// # let args = Args::default();
+    /// // get tickets from command line args
+    /// let tickets: Vec<NodeTicket> = args.tickets;
+    /// // create a StaticProvider from the tickets. Ticket info will be combined if multiple tickets refer to the same node.
+    /// let discovery = StaticProvider::from_node_addrs(tickets);
+    /// // create an endpoint with the discovery
+    /// let endpoint = Endpoint::builder()
+    ///     .add_discovery(|_| Some(discovery))
+    ///     .bind().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn from_node_addrs(infos: impl IntoIterator<Item = impl Into<NodeAddr>>) -> Self {
+        let res = Self::default();
+        for info in infos {
+            res.add_node_addr(info);
+        }
+        res
+    }
+
+    /// Add node info for the given node id.
+    ///
+    /// This will completely overwrite any existing info for the node.
+    pub fn set_node_addr(&self, info: impl Into<NodeAddr>) -> Option<NodeAddr> {
+        let last_updated = SystemTime::now();
+        let info: NodeAddr = info.into();
+        let mut guard = self.nodes.write().unwrap();
+        let previous = guard.insert(
+            info.node_id,
+            NodeInfo {
+                info: info.info,
+                last_updated,
+            },
+        );
+        previous.map(|x| NodeAddr {
+            node_id: info.node_id,
+            info: x.info,
+        })
+    }
+
+    /// Add node info for the given node id, combining it with any existing info.
+    ///
+    /// This will add any new direct addresses and overwrite the relay url.
+    pub fn add_node_addr(&self, info: impl Into<NodeAddr>) {
+        let info: NodeAddr = info.into();
+        let last_updated = SystemTime::now();
+        let mut guard = self.nodes.write().unwrap();
+        match guard.entry(info.node_id) {
+            Entry::Occupied(mut entry) => {
+                let existing = entry.get_mut();
+                existing
+                    .info
+                    .direct_addresses
+                    .extend(info.info.direct_addresses);
+                existing.info.relay_url = info.info.relay_url;
+                existing.last_updated = last_updated;
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(NodeInfo {
+                    info: info.info,
+                    last_updated,
+                });
+            }
+        }
+    }
+
+    /// Get node info for the given node id.
+    pub fn get_node_addr(&self, node_id: NodeId) -> Option<NodeAddr> {
+        let guard = self.nodes.read().unwrap();
+        let info = guard.get(&node_id).map(|x| x.info.clone())?;
+        Some(NodeAddr { node_id, info })
+    }
+
+    /// Remove node info for the given node id.
+    pub fn remove_node_addr(&self, node_id: NodeId) -> Option<NodeAddr> {
+        let mut guard = self.nodes.write().unwrap();
+        let res = guard.remove(&node_id)?;
+        Some(NodeAddr {
+            node_id,
+            info: res.info,
+        })
+    }
+}
+
+impl Discovery for StaticProvider {
+    fn publish(&self, _info: &AddrInfo) {}
+
+    fn resolve(
+        &self,
+        _endpoint: crate::Endpoint,
+        node_id: NodeId,
+    ) -> Option<futures_lite::stream::Boxed<anyhow::Result<super::DiscoveryItem>>> {
+        let guard = self.nodes.read().unwrap();
+        let info = guard.get(&node_id);
+        match info {
+            Some(addr_info) => {
+                let item = DiscoveryItem {
+                    node_id,
+                    provenance: Self::PROVENANCE,
+                    last_updated: Some(
+                        addr_info
+                            .last_updated
+                            .duration_since(SystemTime::UNIX_EPOCH)
+                            .expect("time drift")
+                            .as_micros() as u64,
+                    ),
+                    addr_info: addr_info.info.clone(),
+                };
+                Some(stream::iter(Some(Ok(item))).boxed())
+            }
+            None => None,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/dns.rs.html b/pr/2992/docs/src/iroh/dns.rs.html new file mode 100644 index 0000000000..2c7a952342 --- /dev/null +++ b/pr/2992/docs/src/iroh/dns.rs.html @@ -0,0 +1,841 @@ +dns.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+
//! This module exports a DNS resolver, which is also the default resolver used in the
+//! [`crate::Endpoint`] if no custom resolver is configured.
+//!
+//! It also exports [`ResolverExt`]: A extension trait over [`DnsResolver`] to perform DNS queries
+//! by ipv4, ipv6, name and node_id. See the [`node_info`] module documentation for details on how
+//! iroh node records are structured.
+
+use std::{
+    fmt::Write,
+    net::{IpAddr, Ipv6Addr},
+    time::Duration,
+};
+
+use anyhow::Result;
+use futures_lite::{Future, StreamExt};
+use hickory_resolver::{AsyncResolver, IntoName, TokioAsyncResolver};
+use iroh_base::{key::NodeId, node_addr::NodeAddr};
+use once_cell::sync::Lazy;
+
+pub mod node_info;
+
+/// The DNS resolver type used throughout `iroh`.
+pub type DnsResolver = TokioAsyncResolver;
+
+static DNS_RESOLVER: Lazy<TokioAsyncResolver> =
+    Lazy::new(|| create_default_resolver().expect("unable to create DNS resolver"));
+
+/// Get a reference to the default DNS resolver.
+///
+/// The default resolver can be cheaply cloned and is shared throughout the running process.
+/// It is configured to use the system's DNS configuration.
+pub fn default_resolver() -> &'static DnsResolver {
+    &DNS_RESOLVER
+}
+
+/// Get the DNS resolver used within iroh.
+pub fn resolver() -> &'static TokioAsyncResolver {
+    Lazy::force(&DNS_RESOLVER)
+}
+
+/// Deprecated IPv6 site-local anycast addresses still configured by windows.
+///
+/// Windows still configures these site-local addresses as soon even as an IPv6 loopback
+/// interface is configured.  We do not want to use these DNS servers, the chances of them
+/// being usable are almost always close to zero, while the chance of DNS configuration
+/// **only** relying on these servers and not also being configured normally are also almost
+/// zero.  The chance of the DNS resolver accidentally trying one of these and taking a
+/// bunch of timeouts to figure out they're no good are on the other hand very high.
+const WINDOWS_BAD_SITE_LOCAL_DNS_SERVERS: [IpAddr; 3] = [
+    IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 1)),
+    IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 2)),
+    IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 3)),
+];
+
+/// Get resolver to query MX records.
+///
+/// We first try to read the system's resolver from `/etc/resolv.conf`.
+/// This does not work at least on some Androids, therefore we fallback
+/// to the default `ResolverConfig` which uses eg. to google's `8.8.8.8` or `8.8.4.4`.
+fn create_default_resolver() -> Result<TokioAsyncResolver> {
+    let (system_config, mut options) =
+        hickory_resolver::system_conf::read_system_conf().unwrap_or_default();
+
+    // Copy all of the system config, but strip the bad windows nameservers.  Unfortunately
+    // there is no easy way to do this.
+    let mut config = hickory_resolver::config::ResolverConfig::new();
+    if let Some(name) = system_config.domain() {
+        config.set_domain(name.clone());
+    }
+    for name in system_config.search() {
+        config.add_search(name.clone());
+    }
+    for nameserver_cfg in system_config.name_servers() {
+        if !WINDOWS_BAD_SITE_LOCAL_DNS_SERVERS.contains(&nameserver_cfg.socket_addr.ip()) {
+            config.add_name_server(nameserver_cfg.clone());
+        }
+    }
+
+    // see [`ResolverExt::lookup_ipv4_ipv6`] for info on why we avoid `LookupIpStrategy::Ipv4AndIpv6`
+    options.ip_strategy = hickory_resolver::config::LookupIpStrategy::Ipv4thenIpv6;
+
+    let resolver = AsyncResolver::tokio(config, options);
+    Ok(resolver)
+}
+
+/// Extension trait to [`DnsResolver`].
+pub trait ResolverExt {
+    /// Perform an ipv4 lookup with a timeout.
+    fn lookup_ipv4<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Perform an ipv6 lookup with a timeout.
+    fn lookup_ipv6<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Race an ipv4 and ipv6 lookup with a timeout.
+    fn lookup_ipv4_ipv6<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Looks up node info by DNS name.
+    fn lookup_by_name(&self, name: &str) -> impl Future<Output = Result<NodeAddr>>;
+
+    /// Looks up node info by [`NodeId`] and origin domain name.
+    fn lookup_by_id(
+        &self,
+        node_id: &NodeId,
+        origin: &str,
+    ) -> impl Future<Output = Result<NodeAddr>>;
+
+    /// Perform an ipv4 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually. The
+    /// result of the first successful call is returned, or a summary of all errors otherwise.
+    fn lookup_ipv4_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Perform an ipv6 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually. The
+    /// result of the first successful call is returned, or a summary of all errors otherwise.
+    fn lookup_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied as stated in
+    /// [`Self::lookup_ipv4_ipv6`]. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Looks up node info by DNS name in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    fn lookup_by_name_staggered(
+        &self,
+        name: &str,
+        delays_ms: &[u64],
+    ) -> impl Future<Output = Result<NodeAddr>>;
+
+    /// Looks up node info by [`NodeId`] and origin domain name.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    fn lookup_by_id_staggered(
+        &self,
+        node_id: &NodeId,
+        origin: &str,
+        delays_ms: &[u64],
+    ) -> impl Future<Output = Result<NodeAddr>>;
+}
+
+impl ResolverExt for DnsResolver {
+    async fn lookup_ipv4<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let addrs = tokio::time::timeout(timeout, self.ipv4_lookup(host)).await??;
+        Ok(addrs.into_iter().map(|ip| IpAddr::V4(ip.0)))
+    }
+
+    async fn lookup_ipv6<N: IntoName>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let addrs = tokio::time::timeout(timeout, self.ipv6_lookup(host)).await??;
+        Ok(addrs.into_iter().map(|ip| IpAddr::V6(ip.0)))
+    }
+
+    /// Resolve IPv4 and IPv6 in parallel.
+    ///
+    /// `LookupIpStrategy::Ipv4AndIpv6` will wait for ipv6 resolution timeout, even if it is
+    /// not usable on the stack, so we manually query both lookups concurrently and time them out
+    /// individually.
+    async fn lookup_ipv4_ipv6<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let res = tokio::join!(
+            self.lookup_ipv4(host.clone(), timeout),
+            self.lookup_ipv6(host, timeout)
+        );
+
+        match res {
+            (Ok(ipv4), Ok(ipv6)) => Ok(LookupIter::Both(ipv4.chain(ipv6))),
+            (Ok(ipv4), Err(_)) => Ok(LookupIter::Ipv4(ipv4)),
+            (Err(_), Ok(ipv6)) => Ok(LookupIter::Ipv6(ipv6)),
+            (Err(ipv4_err), Err(ipv6_err)) => {
+                anyhow::bail!("Ipv4: {:?}, Ipv6: {:?}", ipv4_err, ipv6_err)
+            }
+        }
+    }
+
+    /// Looks up node info by DNS name.
+    ///
+    /// The resource records returned for `name` must either contain an [`node_info::IROH_TXT_NAME`] TXT
+    /// record or be a CNAME record that leads to an [`node_info::IROH_TXT_NAME`] TXT record.
+    async fn lookup_by_name(&self, name: &str) -> Result<NodeAddr> {
+        let attrs = node_info::TxtAttrs::<node_info::IrohAttr>::lookup_by_name(self, name).await?;
+        let info: node_info::NodeInfo = attrs.into();
+        Ok(info.into())
+    }
+
+    /// Looks up node info by [`NodeId`] and origin domain name.
+    async fn lookup_by_id(&self, node_id: &NodeId, origin: &str) -> Result<NodeAddr> {
+        let attrs =
+            node_info::TxtAttrs::<node_info::IrohAttr>::lookup_by_id(self, node_id, origin).await?;
+        let info: node_info::NodeInfo = attrs.into();
+        Ok(info.into())
+    }
+
+    /// Perform an ipv4 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually. The
+    /// result of the first successful call is returned, or a summary of all errors otherwise.
+    async fn lookup_ipv4_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv4(host.clone(), timeout);
+        stagger_call(f, delays_ms).await
+    }
+
+    /// Perform an ipv6 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually. The
+    /// result of the first successful call is returned, or a summary of all errors otherwise.
+    async fn lookup_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv6(host.clone(), timeout);
+        stagger_call(f, delays_ms).await
+    }
+
+    /// Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The `timeout` is applied as stated in
+    /// [`Self::lookup_ipv4_ipv6`]. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    async fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+        timeout: Duration,
+        delays_ms: &[u64],
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv4_ipv6(host.clone(), timeout);
+        stagger_call(f, delays_ms).await
+    }
+
+    /// Looks up node info by DNS name in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    async fn lookup_by_name_staggered(&self, name: &str, delays_ms: &[u64]) -> Result<NodeAddr> {
+        let f = || self.lookup_by_name(name);
+        stagger_call(f, delays_ms).await
+    }
+
+    /// Looks up node info by [`NodeId`] and origin domain name.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
+    /// at T+0ms, T+200ms and T+300ms. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    async fn lookup_by_id_staggered(
+        &self,
+        node_id: &NodeId,
+        origin: &str,
+        delays_ms: &[u64],
+    ) -> Result<NodeAddr> {
+        let f = || self.lookup_by_id(node_id, origin);
+        stagger_call(f, delays_ms).await
+    }
+}
+
+/// Helper enum to give a unified type to the iterators of [`ResolverExt::lookup_ipv4_ipv6`].
+enum LookupIter<A, B> {
+    Ipv4(A),
+    Ipv6(B),
+    Both(std::iter::Chain<A, B>),
+}
+
+impl<A: Iterator<Item = IpAddr>, B: Iterator<Item = IpAddr>> Iterator for LookupIter<A, B> {
+    type Item = IpAddr;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            LookupIter::Ipv4(iter) => iter.next(),
+            LookupIter::Ipv6(iter) => iter.next(),
+            LookupIter::Both(iter) => iter.next(),
+        }
+    }
+}
+
+/// Staggers calls to the future F with the given delays.
+///
+/// The first call is performed immediately. The first call to succeed generates an Ok result
+/// ignoring any previous error. If all calls fail, an error summarizing all errors is returned.
+async fn stagger_call<T, F: Fn() -> Fut, Fut: Future<Output = Result<T>>>(
+    f: F,
+    delays_ms: &[u64],
+) -> Result<T> {
+    let mut calls = futures_buffered::FuturesUnorderedBounded::new(delays_ms.len() + 1);
+    // NOTE: we add the 0 delay here to have a uniform set of futures. This is more performant than
+    // using alternatives that allow futures of different types.
+    for delay in std::iter::once(&0u64).chain(delays_ms) {
+        let delay = std::time::Duration::from_millis(*delay);
+        let fut = f();
+        let staggered_fut = async move {
+            tokio::time::sleep(delay).await;
+            fut.await
+        };
+        calls.push(staggered_fut)
+    }
+
+    let mut errors = vec![];
+    while let Some(call_result) = calls.next().await {
+        match call_result {
+            Ok(t) => return Ok(t),
+            Err(e) => errors.push(e),
+        }
+    }
+
+    anyhow::bail!(
+        "no calls succeed: [ {}]",
+        errors.into_iter().fold(String::new(), |mut summary, e| {
+            write!(summary, "{e} ").expect("infallible");
+            summary
+        })
+    )
+}
+
+#[cfg(test)]
+pub(crate) mod tests {
+    use std::sync::atomic::AtomicUsize;
+
+    use super::*;
+    use crate::defaults::staging::NA_RELAY_HOSTNAME;
+    const TIMEOUT: Duration = Duration::from_secs(5);
+    const STAGGERING_DELAYS: &[u64] = &[200, 300];
+
+    #[tokio::test]
+    async fn test_dns_lookup_ipv4_ipv6() {
+        let _logging = iroh_test::logging::setup();
+        let resolver = default_resolver();
+        let res: Vec<_> = resolver
+            .lookup_ipv4_ipv6_staggered(NA_RELAY_HOSTNAME, TIMEOUT, STAGGERING_DELAYS)
+            .await
+            .unwrap()
+            .collect();
+        assert!(!res.is_empty());
+        dbg!(res);
+    }
+
+    #[tokio::test]
+    async fn stagger_basic() {
+        let _logging = iroh_test::logging::setup();
+        const CALL_RESULTS: &[Result<u8, u8>] = &[Err(2), Ok(3), Ok(5), Ok(7)];
+        static DONE_CALL: AtomicUsize = AtomicUsize::new(0);
+        let f = || {
+            let r_pos = DONE_CALL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
+            async move {
+                tracing::info!(r_pos, "call");
+                CALL_RESULTS[r_pos].map_err(|e| anyhow::anyhow!("{e}"))
+            }
+        };
+
+        let delays = [1000, 15];
+        let result = stagger_call(f, &delays).await.unwrap();
+        assert_eq!(result, 5)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/dns/node_info.rs.html b/pr/2992/docs/src/iroh/dns/node_info.rs.html new file mode 100644 index 0000000000..46083c6a6d --- /dev/null +++ b/pr/2992/docs/src/iroh/dns/node_info.rs.html @@ -0,0 +1,899 @@ +node_info.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+
//! Support for handling DNS resource records for dialing by [`NodeId`].
+//!
+//! Dialing by [`NodeId`] is supported by iroh nodes publishing [Pkarr] records to DNS
+//! servers or the Mainline DHT.  This module supports creating and parsing these records.
+//!
+//! DNS records are published under the following names:
+//!
+//! `_iroh.<z32-node-id>.<origin-domain> TXT`
+//!
+//! - `_iroh` is the record name as defined by [`IROH_TXT_NAME`].
+//!
+//! - `<z32-node-id>` is the [z-base-32] encoding of the [`NodeId`].
+//!
+//! - `<origin-domain>` is the domain name of the publishing DNS server,
+//!   [`N0_DNS_NODE_ORIGIN_PROD`] is the server operated by number0 for production.
+//!   [`N0_DNS_NODE_ORIGIN_STAGING`] is the server operated by number0 for testing.
+//!
+//! - `TXT` is the DNS record type.
+//!
+//! The returned TXT records must contain a string value of the form `key=value` as defined
+//! in [RFC1464].  The following attributes are defined:
+//!
+//! - `relay=<url>`: The home [`RelayUrl`] of this node.
+//!
+//! - `addr=<addr> <addr>`: A space-separated list of sockets addresses for this iroh node.
+//!   Each address is an IPv4 or IPv6 address with a port.
+//!
+//! [Pkarr]: https://app.pkarr.org
+//! [z-base-32]: https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
+//! [RFC1464]: https://www.rfc-editor.org/rfc/rfc1464
+//! [`RelayUrl`]: iroh_base::node_addr::RelayUrl
+//! [`N0_DNS_NODE_ORIGIN_PROD`]: crate::discovery::dns::N0_DNS_NODE_ORIGIN_PROD
+//! [`N0_DNS_NODE_ORIGIN_STAGING`]: crate::discovery::dns::N0_DNS_NODE_ORIGIN_STAGING
+
+use std::{
+    collections::{BTreeMap, BTreeSet},
+    fmt::Display,
+    hash::Hash,
+    net::SocketAddr,
+    str::FromStr,
+};
+
+use anyhow::{anyhow, ensure, Result};
+use hickory_proto::error::ProtoError;
+use hickory_resolver::{Name, TokioAsyncResolver};
+use url::Url;
+
+use crate::{key::SecretKey, AddrInfo, NodeAddr, NodeId};
+
+/// The DNS name for the iroh TXT record.
+pub const IROH_TXT_NAME: &str = "_iroh";
+
+/// The attributes supported by iroh for [`IROH_TXT_NAME`] DNS resource records.
+///
+/// The resource record uses the lower-case names.
+#[derive(
+    Debug, strum::Display, strum::AsRefStr, strum::EnumString, Hash, Eq, PartialEq, Ord, PartialOrd,
+)]
+#[strum(serialize_all = "kebab-case")]
+pub enum IrohAttr {
+    /// URL of home relay.
+    Relay,
+    /// Direct address.
+    Addr,
+}
+
+/// Encodes a [`NodeId`] in [`z-base-32`] encoding.
+///
+/// [z-base-32]: https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
+pub fn to_z32(node_id: &NodeId) -> String {
+    z32::encode(node_id.as_bytes())
+}
+
+/// Parses a [`NodeId`] from [`z-base-32`] encoding.
+///
+/// [z-base-32]: https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
+pub fn from_z32(s: &str) -> Result<NodeId> {
+    let bytes = z32::decode(s.as_bytes()).map_err(|_| anyhow!("invalid z32"))?;
+    let bytes: &[u8; 32] = &bytes.try_into().map_err(|_| anyhow!("not 32 bytes long"))?;
+    let node_id = NodeId::from_bytes(bytes)?;
+    Ok(node_id)
+}
+
+/// Information about the iroh node contained in an [`IROH_TXT_NAME`] TXT resource record.
+#[derive(derive_more::Debug, Clone, Eq, PartialEq)]
+pub struct NodeInfo {
+    /// The [`NodeId`].
+    pub node_id: NodeId,
+    /// The advertised home relay server.
+    #[debug("{:?}", self.relay_url.as_ref().map(|s| s.to_string()))]
+    pub relay_url: Option<Url>,
+    /// Any direct addresses.
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
+
+impl From<TxtAttrs<IrohAttr>> for NodeInfo {
+    fn from(attrs: TxtAttrs<IrohAttr>) -> Self {
+        (&attrs).into()
+    }
+}
+
+impl From<&TxtAttrs<IrohAttr>> for NodeInfo {
+    fn from(attrs: &TxtAttrs<IrohAttr>) -> Self {
+        let node_id = attrs.node_id();
+        let attrs = attrs.attrs();
+        let relay_url = attrs
+            .get(&IrohAttr::Relay)
+            .into_iter()
+            .flatten()
+            .next()
+            .and_then(|s| Url::parse(s).ok());
+        let direct_addresses = attrs
+            .get(&IrohAttr::Addr)
+            .into_iter()
+            .flatten()
+            .filter_map(|s| SocketAddr::from_str(s).ok())
+            .collect();
+        Self {
+            node_id,
+            relay_url,
+            direct_addresses,
+        }
+    }
+}
+
+impl From<&NodeInfo> for TxtAttrs<IrohAttr> {
+    fn from(info: &NodeInfo) -> Self {
+        let mut attrs = vec![];
+        if let Some(relay_url) = &info.relay_url {
+            attrs.push((IrohAttr::Relay, relay_url.to_string()));
+        }
+        for addr in &info.direct_addresses {
+            attrs.push((IrohAttr::Addr, addr.to_string()));
+        }
+        Self::from_parts(info.node_id, attrs.into_iter())
+    }
+}
+
+impl From<NodeInfo> for NodeAddr {
+    fn from(value: NodeInfo) -> Self {
+        NodeAddr {
+            node_id: value.node_id,
+            info: value.into(),
+        }
+    }
+}
+
+impl From<NodeInfo> for AddrInfo {
+    fn from(value: NodeInfo) -> Self {
+        AddrInfo {
+            relay_url: value.relay_url.map(|u| u.into()),
+            direct_addresses: value.direct_addresses,
+        }
+    }
+}
+
+impl NodeInfo {
+    /// Creates a new [`NodeInfo`] from its parts.
+    pub fn new(
+        node_id: NodeId,
+        relay_url: Option<Url>,
+        direct_addresses: BTreeSet<SocketAddr>,
+    ) -> Self {
+        Self {
+            node_id,
+            relay_url,
+            direct_addresses,
+        }
+    }
+
+    fn to_attrs(&self) -> TxtAttrs<IrohAttr> {
+        self.into()
+    }
+
+    /// Parses a [`NodeInfo`] from a set of DNS records.
+    pub fn from_hickory_records(records: &[hickory_proto::rr::Record]) -> Result<Self> {
+        let attrs = TxtAttrs::from_hickory_records(records)?;
+        Ok(attrs.into())
+    }
+
+    /// Parses a [`NodeInfo`] from a [`pkarr::SignedPacket`].
+    pub fn from_pkarr_signed_packet(packet: &pkarr::SignedPacket) -> Result<Self> {
+        let attrs = TxtAttrs::from_pkarr_signed_packet(packet)?;
+        Ok(attrs.into())
+    }
+
+    /// Creates a [`pkarr::SignedPacket`].
+    ///
+    /// This constructs a DNS packet and signs it with a [`SecretKey`].
+    pub fn to_pkarr_signed_packet(
+        &self,
+        secret_key: &SecretKey,
+        ttl: u32,
+    ) -> Result<pkarr::SignedPacket> {
+        self.to_attrs().to_pkarr_signed_packet(secret_key, ttl)
+    }
+
+    /// Converts into a [`hickory_proto::rr::Record`] DNS record.
+    pub fn to_hickory_records(
+        &self,
+        origin: &str,
+        ttl: u32,
+    ) -> Result<impl Iterator<Item = hickory_proto::rr::Record> + 'static> {
+        let attrs = self.to_attrs();
+        let records = attrs.to_hickory_records(origin, ttl)?;
+        Ok(records.collect::<Vec<_>>().into_iter())
+    }
+}
+
+/// Parses a [`NodeId`] from iroh DNS name.
+///
+/// Takes a [`hickory_proto::rr::Name`] DNS name and expects the first label to be
+/// [`IROH_TXT_NAME`] and the second label to be a z32 encoded [`NodeId`]. Ignores
+/// subsequent labels.
+pub(crate) fn node_id_from_hickory_name(name: &hickory_proto::rr::Name) -> Option<NodeId> {
+    if name.num_labels() < 2 {
+        return None;
+    }
+    let mut labels = name.iter();
+    let label = std::str::from_utf8(labels.next().expect("num_labels checked")).ok()?;
+    if label != IROH_TXT_NAME {
+        return None;
+    }
+    let label = std::str::from_utf8(labels.next().expect("num_labels checked")).ok()?;
+    let node_id = from_z32(label).ok()?;
+    Some(node_id)
+}
+
+/// Attributes parsed from [`IROH_TXT_NAME`] TXT records.
+///
+/// This struct is generic over the key type. When using with [`String`], this will parse
+/// all attributes. Can also be used with an enum, if it implements [`FromStr`] and
+/// [`Display`].
+#[derive(Debug)]
+pub struct TxtAttrs<T> {
+    node_id: NodeId,
+    attrs: BTreeMap<T, Vec<String>>,
+}
+
+impl<T: FromStr + Display + Hash + Ord> TxtAttrs<T> {
+    /// Creates [`TxtAttrs`] from a node id and an iterator of key-value pairs.
+    pub fn from_parts(node_id: NodeId, pairs: impl Iterator<Item = (T, String)>) -> Self {
+        let mut attrs: BTreeMap<T, Vec<String>> = BTreeMap::new();
+        for (k, v) in pairs {
+            attrs.entry(k).or_default().push(v);
+        }
+        Self { attrs, node_id }
+    }
+
+    /// Creates [`TxtAttrs`] from a node id and an iterator of "{key}={value}" strings.
+    pub fn from_strings(node_id: NodeId, strings: impl Iterator<Item = String>) -> Result<Self> {
+        let mut attrs: BTreeMap<T, Vec<String>> = BTreeMap::new();
+        for s in strings {
+            let mut parts = s.split('=');
+            let (Some(key), Some(value)) = (parts.next(), parts.next()) else {
+                continue;
+            };
+            let Ok(attr) = T::from_str(key) else {
+                continue;
+            };
+            attrs.entry(attr).or_default().push(value.to_string());
+        }
+        Ok(Self { attrs, node_id })
+    }
+
+    async fn lookup(resolver: &TokioAsyncResolver, name: Name) -> Result<Self> {
+        let name = ensure_iroh_txt_label(name)?;
+        let lookup = resolver.txt_lookup(name).await?;
+        let attrs = Self::from_hickory_records(lookup.as_lookup().records())?;
+        Ok(attrs)
+    }
+
+    /// Looks up attributes by [`NodeId`] and origin domain.
+    pub async fn lookup_by_id(
+        resolver: &TokioAsyncResolver,
+        node_id: &NodeId,
+        origin: &str,
+    ) -> Result<Self> {
+        let name = node_domain(node_id, origin)?;
+        TxtAttrs::lookup(resolver, name).await
+    }
+
+    /// Looks up attributes by DNS name.
+    pub async fn lookup_by_name(resolver: &TokioAsyncResolver, name: &str) -> Result<Self> {
+        let name = Name::from_str(name)?;
+        TxtAttrs::lookup(resolver, name).await
+    }
+
+    /// Returns the parsed attributes.
+    pub fn attrs(&self) -> &BTreeMap<T, Vec<String>> {
+        &self.attrs
+    }
+
+    /// Returns the node id.
+    pub fn node_id(&self) -> NodeId {
+        self.node_id
+    }
+
+    /// Parses a [`pkarr::SignedPacket`].
+    pub fn from_pkarr_signed_packet(packet: &pkarr::SignedPacket) -> Result<Self> {
+        use pkarr::dns::{
+            rdata::RData,
+            {self},
+        };
+        let pubkey = packet.public_key();
+        let pubkey_z32 = pubkey.to_z32();
+        let node_id = NodeId::from(*pubkey.verifying_key());
+        let zone = dns::Name::new(&pubkey_z32)?;
+        let inner = packet.packet();
+        let txt_data = inner.answers.iter().filter_map(|rr| match &rr.rdata {
+            RData::TXT(txt) => match rr.name.without(&zone) {
+                Some(name) if name.to_string() == IROH_TXT_NAME => Some(txt),
+                Some(_) | None => None,
+            },
+            _ => None,
+        });
+
+        let txt_strs = txt_data.filter_map(|s| String::try_from(s.clone()).ok());
+        Self::from_strings(node_id, txt_strs)
+    }
+
+    /// Parses a set of DNS resource records.
+    pub fn from_hickory_records(records: &[hickory_proto::rr::Record]) -> Result<Self> {
+        use hickory_proto::rr;
+        let mut records = records.iter().filter_map(|rr| match rr.data() {
+            rr::RData::TXT(txt) => {
+                node_id_from_hickory_name(rr.name()).map(|node_id| (node_id, txt))
+            }
+            _ => None,
+        });
+        let (node_id, first) = records.next().ok_or_else(|| {
+            anyhow!("invalid DNS answer: no TXT record with name _iroh.z32encodedpubkey found")
+        })?;
+        ensure!(
+            &records.all(|(n, _)| n == node_id),
+            "invalid DNS answer: all _iroh txt records must belong to the same node domain"
+        );
+        let records = records.map(|(_, txt)| txt).chain(Some(first));
+        let strings = records.map(ToString::to_string);
+        Self::from_strings(node_id, strings)
+    }
+
+    fn to_txt_strings(&self) -> impl Iterator<Item = String> + '_ {
+        self.attrs
+            .iter()
+            .flat_map(move |(k, vs)| vs.iter().map(move |v| format!("{k}={v}")))
+    }
+
+    /// Converts to a list of [`hickory_proto::rr::Record`] resource records.
+    pub fn to_hickory_records(
+        &self,
+        origin: &str,
+        ttl: u32,
+    ) -> Result<impl Iterator<Item = hickory_proto::rr::Record> + '_> {
+        use hickory_proto::rr;
+        let name = format!("{}.{}.{}", IROH_TXT_NAME, to_z32(&self.node_id), origin);
+        let name = rr::Name::from_utf8(name)?;
+        let records = self.to_txt_strings().map(move |s| {
+            let txt = rr::rdata::TXT::new(vec![s]);
+            let rdata = rr::RData::TXT(txt);
+            rr::Record::from_rdata(name.clone(), ttl, rdata)
+        });
+        Ok(records)
+    }
+
+    /// Creates a [`pkarr::SignedPacket`]
+    ///
+    /// This constructs a DNS packet and signs it with a [`SecretKey`].
+    pub fn to_pkarr_signed_packet(
+        &self,
+        secret_key: &SecretKey,
+        ttl: u32,
+    ) -> Result<pkarr::SignedPacket> {
+        let packet = self.to_pkarr_dns_packet(ttl)?;
+        let keypair = pkarr::Keypair::from_secret_key(&secret_key.to_bytes());
+        let signed_packet = pkarr::SignedPacket::from_packet(&keypair, &packet)?;
+        Ok(signed_packet)
+    }
+
+    fn to_pkarr_dns_packet(&self, ttl: u32) -> Result<pkarr::dns::Packet<'static>> {
+        use pkarr::dns::{self, rdata};
+        let name = dns::Name::new(IROH_TXT_NAME)?.into_owned();
+
+        let mut packet = dns::Packet::new_reply(0);
+        for s in self.to_txt_strings() {
+            let mut txt = rdata::TXT::new();
+            txt.add_string(&s)?;
+            let rdata = rdata::RData::TXT(txt.into_owned());
+            packet.answers.push(dns::ResourceRecord::new(
+                name.clone(),
+                dns::CLASS::IN,
+                ttl,
+                rdata,
+            ));
+        }
+        Ok(packet)
+    }
+}
+
+fn ensure_iroh_txt_label(name: Name) -> Result<Name, ProtoError> {
+    if name.iter().next() == Some(IROH_TXT_NAME.as_bytes()) {
+        Ok(name)
+    } else {
+        Name::parse(IROH_TXT_NAME, Some(&name))
+    }
+}
+
+fn node_domain(node_id: &NodeId, origin: &str) -> Result<Name> {
+    let domain = format!("{}.{}", to_z32(node_id), origin);
+    let domain = Name::from_str(&domain)?;
+    Ok(domain)
+}
+
+#[cfg(test)]
+mod tests {
+    use std::str::FromStr;
+
+    use iroh_base::key::SecretKey;
+
+    use super::NodeInfo;
+
+    #[test]
+    fn txt_attr_roundtrip() {
+        let expected = NodeInfo {
+            node_id: "vpnk377obfvzlipnsfbqba7ywkkenc4xlpmovt5tsfujoa75zqia"
+                .parse()
+                .unwrap(),
+            relay_url: Some("https://example.com".parse().unwrap()),
+            direct_addresses: ["127.0.0.1:1234".parse().unwrap()].into_iter().collect(),
+        };
+        let attrs = expected.to_attrs();
+        let actual = NodeInfo::from(&attrs);
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn signed_packet_roundtrip() {
+        let secret_key =
+            SecretKey::from_str("vpnk377obfvzlipnsfbqba7ywkkenc4xlpmovt5tsfujoa75zqia").unwrap();
+        let expected = NodeInfo {
+            node_id: secret_key.public(),
+            relay_url: Some("https://example.com".parse().unwrap()),
+            direct_addresses: ["127.0.0.1:1234".parse().unwrap()].into_iter().collect(),
+        };
+        let packet = expected.to_pkarr_signed_packet(&secret_key, 30).unwrap();
+        let actual = NodeInfo::from_pkarr_signed_packet(&packet).unwrap();
+        assert_eq!(expected, actual);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/endpoint.rs.html b/pr/2992/docs/src/iroh/endpoint.rs.html new file mode 100644 index 0000000000..aa55a92240 --- /dev/null +++ b/pr/2992/docs/src/iroh/endpoint.rs.html @@ -0,0 +1,3841 @@ +endpoint.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+
//! The [`Endpoint`] allows establishing connections to other iroh nodes.
+//!
+//! The [`Endpoint`] is the main API interface to manage a local iroh node.  It allows
+//! connecting to and accepting connections from other nodes.  See the [module docs] for
+//! more details on how iroh connections work.
+//!
+//! The main items in this module are:
+//!
+//! - [`Endpoint`] to establish iroh connections with other nodes.
+//! - [`Builder`] to create an [`Endpoint`].
+//!
+//! [module docs]: crate
+
+use std::{
+    any::Any,
+    future::{Future, IntoFuture},
+    net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6},
+    pin::Pin,
+    sync::Arc,
+    task::Poll,
+    time::Duration,
+};
+
+use anyhow::{anyhow, bail, Context, Result};
+use derive_more::Debug;
+use futures_lite::{Stream, StreamExt};
+use iroh_base::relay_map::RelayMap;
+use pin_project::pin_project;
+use tokio_util::sync::CancellationToken;
+use tracing::{debug, instrument, trace, warn};
+use url::Url;
+
+use crate::{
+    discovery::{
+        dns::DnsDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery, Discovery, DiscoveryTask,
+    },
+    dns::{default_resolver, DnsResolver},
+    key::{PublicKey, SecretKey},
+    magicsock::{self, Handle, QuicMappedAddr},
+    tls, NodeId, RelayUrl,
+};
+
+mod rtt_actor;
+
+pub use bytes::Bytes;
+pub use iroh_base::node_addr::{AddrInfo, AddrInfoOptions, NodeAddr};
+// Missing still: SendDatagram and ConnectionClose::frame_type's Type.
+pub use quinn::{
+    AcceptBi, AcceptUni, AckFrequencyConfig, ApplicationClose, Chunk, ClosedStream, Connection,
+    ConnectionClose, ConnectionError, ConnectionStats, MtuDiscoveryConfig, OpenBi, OpenUni,
+    ReadDatagram, ReadError, ReadExactError, ReadToEndError, RecvStream, ResetError, RetryError,
+    SendDatagramError, SendStream, ServerConfig, StoppedError, StreamId, TransportConfig, VarInt,
+    WeakConnectionHandle, WriteError, ZeroRttAccepted,
+};
+pub use quinn_proto::{
+    congestion::{Controller, ControllerFactory},
+    crypto::{
+        AeadKey, CryptoError, ExportKeyingMaterialError, HandshakeTokenKey,
+        ServerConfig as CryptoServerConfig, UnsupportedVersion,
+    },
+    FrameStats, PathStats, TransportError, TransportErrorCode, UdpStats, Written,
+};
+
+use self::rtt_actor::RttMessage;
+pub use super::magicsock::{
+    ConnectionType, ConnectionTypeStream, ControlMsg, DirectAddr, DirectAddrInfo, DirectAddrType,
+    DirectAddrsStream, RemoteInfo, Source,
+};
+
+/// The delay to fall back to discovery when direct addresses fail.
+///
+/// When a connection is attempted with a [`NodeAddr`] containing direct addresses the
+/// [`Endpoint`] assumes one of those addresses probably works.  If after this delay there
+/// is still no connection the configured [`Discovery`] will be used however.
+const DISCOVERY_WAIT_PERIOD: Duration = Duration::from_millis(500);
+
+type DiscoveryBuilder = Box<dyn FnOnce(&SecretKey) -> Option<Box<dyn Discovery>> + Send + Sync>;
+
+/// Builder for [`Endpoint`].
+///
+/// By default the endpoint will generate a new random [`SecretKey`], which will result in a
+/// new [`NodeId`].
+///
+/// To create the [`Endpoint`] call [`Builder::bind`].
+#[derive(Debug)]
+pub struct Builder {
+    secret_key: Option<SecretKey>,
+    relay_mode: RelayMode,
+    alpn_protocols: Vec<Vec<u8>>,
+    transport_config: Option<quinn::TransportConfig>,
+    keylog: bool,
+    #[debug(skip)]
+    discovery: Vec<DiscoveryBuilder>,
+    proxy_url: Option<Url>,
+    /// List of known nodes. See [`Builder::known_nodes`].
+    node_map: Option<Vec<NodeAddr>>,
+    dns_resolver: Option<DnsResolver>,
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    insecure_skip_relay_cert_verify: bool,
+    addr_v4: Option<SocketAddrV4>,
+    addr_v6: Option<SocketAddrV6>,
+}
+
+impl Default for Builder {
+    fn default() -> Self {
+        Self {
+            secret_key: Default::default(),
+            relay_mode: default_relay_mode(),
+            alpn_protocols: Default::default(),
+            transport_config: Default::default(),
+            keylog: Default::default(),
+            discovery: Default::default(),
+            proxy_url: None,
+            node_map: None,
+            dns_resolver: None,
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_relay_cert_verify: false,
+            addr_v4: None,
+            addr_v6: None,
+        }
+    }
+}
+
+impl Builder {
+    // The ordering of public methods is reflected directly in the documentation.  This is
+    // roughly ordered by what is most commonly needed by users.
+
+    // # The final constructor that everyone needs.
+
+    /// Binds the magic endpoint.
+    pub async fn bind(self) -> Result<Endpoint> {
+        let relay_map = self.relay_mode.relay_map();
+        let secret_key = self.secret_key.unwrap_or_else(SecretKey::generate);
+        let static_config = StaticConfig {
+            transport_config: Arc::new(self.transport_config.unwrap_or_default()),
+            keylog: self.keylog,
+            secret_key: secret_key.clone(),
+        };
+        let dns_resolver = self
+            .dns_resolver
+            .unwrap_or_else(|| default_resolver().clone());
+        let discovery = self
+            .discovery
+            .into_iter()
+            .filter_map(|f| f(&secret_key))
+            .collect::<Vec<_>>();
+        let discovery: Option<Box<dyn Discovery>> = match discovery.len() {
+            0 => None,
+            1 => Some(discovery.into_iter().next().unwrap()),
+            _ => Some(Box::new(ConcurrentDiscovery::from_services(discovery))),
+        };
+        let msock_opts = magicsock::Options {
+            addr_v4: self.addr_v4,
+            addr_v6: self.addr_v6,
+            secret_key,
+            relay_map,
+            node_map: self.node_map,
+            discovery,
+            proxy_url: self.proxy_url,
+            dns_resolver,
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_relay_cert_verify: self.insecure_skip_relay_cert_verify,
+        };
+        Endpoint::bind(static_config, msock_opts, self.alpn_protocols).await
+    }
+
+    // # The very common methods everyone basically needs.
+
+    /// Sets the IPv4 bind address.
+    ///
+    /// Setting the port to `0` will use a random port.
+    /// If the port specified is already in use, it will fallback to choosing a random port.
+    ///
+    /// By default will use `0.0.0.0:0` to bind to.
+    pub fn bind_addr_v4(mut self, addr: SocketAddrV4) -> Self {
+        self.addr_v4.replace(addr);
+        self
+    }
+
+    /// Sets the IPv6 bind address.
+    ///
+    /// Setting the port to `0` will use a random port.
+    /// If the port specified is already in use, it will fallback to choosing a random port.
+    ///
+    /// By default will use `[::]:0` to bind to.
+    pub fn bind_addr_v6(mut self, addr: SocketAddrV6) -> Self {
+        self.addr_v6.replace(addr);
+        self
+    }
+
+    /// Sets a secret key to authenticate with other peers.
+    ///
+    /// This secret key's public key will be the [`PublicKey`] of this endpoint and thus
+    /// also its [`NodeId`]
+    ///
+    /// If not set, a new secret key will be generated.
+    pub fn secret_key(mut self, secret_key: SecretKey) -> Self {
+        self.secret_key = Some(secret_key);
+        self
+    }
+
+    /// Sets the [ALPN] protocols that this endpoint will accept on incoming connections.
+    ///
+    /// Not setting this will still allow creating connections, but to accept incoming
+    /// connections the [ALPN] must be set.
+    ///
+    /// [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
+    pub fn alpns(mut self, alpn_protocols: Vec<Vec<u8>>) -> Self {
+        self.alpn_protocols = alpn_protocols;
+        self
+    }
+
+    // # Methods for common customisation items.
+
+    /// Sets the relay servers to assist in establishing connectivity.
+    ///
+    /// Relay servers are used to establish initial connection with another iroh node.
+    /// They also perform various functions related to hole punching, see the [crate docs]
+    /// for more details.
+    ///
+    /// By default the [number 0] relay servers are used, see [`RelayMode::Default`].
+    ///
+    /// When using [RelayMode::Custom], the provided `relay_map` must contain at least one
+    /// configured relay node.  If an invalid RelayMap is provided [`bind`]
+    /// will result in an error.
+    ///
+    /// [`bind`]: Builder::bind
+    /// [crate docs]: crate
+    /// [number 0]: https://n0.computer
+    pub fn relay_mode(mut self, relay_mode: RelayMode) -> Self {
+        self.relay_mode = relay_mode;
+        self
+    }
+
+    /// Removes all discovery services from the builder.
+    pub fn clear_discovery(mut self) -> Self {
+        self.discovery.clear();
+        self
+    }
+
+    /// Optionally sets a discovery mechanism for this endpoint.
+    ///
+    /// If you want to combine multiple discovery services, you can use
+    /// [`Builder::add_discovery`] instead. This will internally create a
+    /// [`crate::discovery::ConcurrentDiscovery`].
+    ///
+    /// If no discovery service is set, connecting to a node without providing its
+    /// direct addresses or relay URLs will fail.
+    ///
+    /// See the documentation of the [`Discovery`] trait for details.
+    pub fn discovery(mut self, discovery: Box<dyn Discovery>) -> Self {
+        self.discovery.clear();
+        self.discovery.push(Box::new(move |_| Some(discovery)));
+        self
+    }
+
+    /// Adds a discovery mechanism for this endpoint.
+    ///
+    /// The function `discovery`
+    /// will be called on endpoint creation with the configured secret key of
+    /// the endpoint. Discovery services that need to publish information need
+    /// to use this secret key to sign the information.
+    ///
+    /// If you add multiple discovery services, they will be combined using a
+    /// [`crate::discovery::ConcurrentDiscovery`].
+    ///
+    /// If no discovery service is set, connecting to a node without providing its
+    /// direct addresses or relay URLs will fail.
+    ///
+    /// To clear all discovery services, use [`Builder::clear_discovery`].
+    ///
+    /// See the documentation of the [`Discovery`] trait for details.
+    pub fn add_discovery<F, D>(mut self, discovery: F) -> Self
+    where
+        F: FnOnce(&SecretKey) -> Option<D> + Send + Sync + 'static,
+        D: Discovery + 'static,
+    {
+        let discovery: DiscoveryBuilder =
+            Box::new(move |secret_key| discovery(secret_key).map(|x| Box::new(x) as _));
+        self.discovery.push(discovery);
+        self
+    }
+
+    /// Configures the endpoint to use the default n0 DNS discovery service.
+    ///
+    /// The default discovery service publishes to and resolves from the
+    /// n0.computer dns server `iroh.link`.
+    ///
+    /// This is equivalent to adding both a [`crate::discovery::pkarr::PkarrPublisher`]
+    /// and a [`crate::discovery::dns::DnsDiscovery`], both configured to use the
+    /// n0.computer dns server.
+    ///
+    /// This will by default use [`N0_DNS_PKARR_RELAY_PROD`].
+    /// When in tests, or when the `test-utils` feature is enabled, this will use the
+    /// [`N0_DNS_PKARR_RELAY_STAGING`].
+    ///
+    /// [`N0_DNS_PKARR_RELAY_PROD`]: crate::discovery::pkarr::N0_DNS_PKARR_RELAY_PROD
+    /// [`N0_DNS_PKARR_RELAY_STAGING`]: crate::discovery::pkarr::N0_DNS_PKARR_RELAY_STAGING
+    pub fn discovery_n0(mut self) -> Self {
+        self.discovery.push(Box::new(|secret_key| {
+            Some(Box::new(PkarrPublisher::n0_dns(secret_key.clone())))
+        }));
+        self.discovery
+            .push(Box::new(|_| Some(Box::new(DnsDiscovery::n0_dns()))));
+        self
+    }
+
+    #[cfg(feature = "discovery-pkarr-dht")]
+    /// Configures the endpoint to also use the mainline DHT with default settings.
+    ///
+    /// This is equivalent to adding a [`crate::discovery::pkarr::dht::DhtDiscovery`]
+    /// with default settings. Note that DhtDiscovery has various more advanced
+    /// configuration options. If you need any of those, you should manually
+    /// create a DhtDiscovery and add it with [`Builder::add_discovery`].
+    pub fn discovery_dht(mut self) -> Self {
+        use crate::discovery::pkarr::dht::DhtDiscovery;
+        self.discovery.push(Box::new(|secret_key| {
+            Some(Box::new(
+                DhtDiscovery::builder()
+                    .secret_key(secret_key.clone())
+                    .build()
+                    .unwrap(),
+            ))
+        }));
+        self
+    }
+
+    #[cfg(feature = "discovery-local-network")]
+    /// Configures the endpoint to also use local network discovery.
+    ///
+    /// This is equivalent to adding a [`crate::discovery::local_swarm_discovery::LocalSwarmDiscovery`]
+    /// with default settings. Note that LocalSwarmDiscovery has various more advanced
+    /// configuration options. If you need any of those, you should manually
+    /// create a LocalSwarmDiscovery and add it with [`Builder::add_discovery`].
+    pub fn discovery_local_network(mut self) -> Self {
+        use crate::discovery::local_swarm_discovery::LocalSwarmDiscovery;
+        self.discovery.push(Box::new(|secret_key| {
+            LocalSwarmDiscovery::new(secret_key.public())
+                .map(|x| Box::new(x) as _)
+                .ok()
+        }));
+        self
+    }
+
+    /// Optionally set a list of known nodes.
+    pub fn known_nodes(mut self, nodes: Vec<NodeAddr>) -> Self {
+        self.node_map = Some(nodes);
+        self
+    }
+
+    // # Methods for more specialist customisation.
+
+    /// Sets a custom [`quinn::TransportConfig`] for this endpoint.
+    ///
+    /// The transport config contains parameters governing the QUIC state machine.
+    ///
+    /// If unset, the default config is used. Default values should be suitable for most
+    /// internet applications. Applications protocols which forbid remotely-initiated
+    /// streams should set `max_concurrent_bidi_streams` and `max_concurrent_uni_streams` to
+    /// zero.
+    pub fn transport_config(mut self, transport_config: quinn::TransportConfig) -> Self {
+        self.transport_config = Some(transport_config);
+        self
+    }
+
+    /// Optionally sets a custom DNS resolver to use for this endpoint.
+    ///
+    /// The DNS resolver is used to resolve relay hostnames, and node addresses if
+    /// [`crate::discovery::dns::DnsDiscovery`] is configured.
+    ///
+    /// By default, all endpoints share a DNS resolver, which is configured to use the
+    /// host system's DNS configuration. You can pass a custom instance of [`DnsResolver`]
+    /// here to use a differently configured DNS resolver for this endpoint.
+    pub fn dns_resolver(mut self, dns_resolver: DnsResolver) -> Self {
+        self.dns_resolver = Some(dns_resolver);
+        self
+    }
+
+    /// Sets an explicit proxy url to proxy all HTTP(S) traffic through.
+    pub fn proxy_url(mut self, url: Url) -> Self {
+        self.proxy_url.replace(url);
+        self
+    }
+
+    /// Sets the proxy url from the environment, in this order:
+    ///
+    /// - `HTTP_PROXY`
+    /// - `http_proxy`
+    /// - `HTTPS_PROXY`
+    /// - `https_proxy`
+    pub fn proxy_from_env(mut self) -> Self {
+        self.proxy_url = proxy_url_from_env();
+        self
+    }
+
+    /// Enables saving the TLS pre-master key for connections.
+    ///
+    /// This key should normally remain secret but can be useful to debug networking issues
+    /// by decrypting captured traffic.
+    ///
+    /// If *keylog* is `true` then setting the `SSLKEYLOGFILE` environment variable to a
+    /// filename will result in this file being used to log the TLS pre-master keys.
+    pub fn keylog(mut self, keylog: bool) -> Self {
+        self.keylog = keylog;
+        self
+    }
+
+    /// Skip verification of SSL certificates from relay servers
+    ///
+    /// May only be used in tests.
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    pub fn insecure_skip_relay_cert_verify(mut self, skip_verify: bool) -> Self {
+        self.insecure_skip_relay_cert_verify = skip_verify;
+        self
+    }
+}
+
+/// Configuration for a [`quinn::Endpoint`] that cannot be changed at runtime.
+#[derive(Debug)]
+struct StaticConfig {
+    secret_key: SecretKey,
+    transport_config: Arc<quinn::TransportConfig>,
+    keylog: bool,
+}
+
+impl StaticConfig {
+    /// Create a [`quinn::ServerConfig`] with the specified ALPN protocols.
+    fn create_server_config(&self, alpn_protocols: Vec<Vec<u8>>) -> Result<ServerConfig> {
+        let server_config = make_server_config(
+            &self.secret_key,
+            alpn_protocols,
+            self.transport_config.clone(),
+            self.keylog,
+        )?;
+        Ok(server_config)
+    }
+}
+
+/// Creates a [`ServerConfig`] with the given secret key and limits.
+// This return type can not longer be used anywhere in our public API.  It is however still
+// used by iroh::node::Node (or rather iroh::node::Builder) to create a plain Quinn
+// endpoint.
+pub fn make_server_config(
+    secret_key: &SecretKey,
+    alpn_protocols: Vec<Vec<u8>>,
+    transport_config: Arc<TransportConfig>,
+    keylog: bool,
+) -> Result<ServerConfig> {
+    let quic_server_config = tls::make_server_config(secret_key, alpn_protocols, keylog)?;
+    let mut server_config = ServerConfig::with_crypto(Arc::new(quic_server_config));
+    server_config.transport_config(transport_config);
+
+    Ok(server_config)
+}
+
+/// 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.
+///
+/// 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.
+///
+/// [QUIC]: https://quicwg.org
+#[derive(Clone, Debug)]
+pub struct Endpoint {
+    msock: Handle,
+    endpoint: quinn::Endpoint,
+    rtt_actor: Arc<rtt_actor::RttHandle>,
+    cancel_token: CancellationToken,
+    static_config: Arc<StaticConfig>,
+}
+
+impl Endpoint {
+    // The ordering of public methods is reflected directly in the documentation.  This is
+    // roughly ordered by what is most commonly needed by users, but grouped in similar
+    // items.
+
+    // # Methods relating to construction.
+
+    /// Returns the builder for an [`Endpoint`], with a production configuration.
+    pub fn builder() -> Builder {
+        Builder::default()
+    }
+
+    /// Creates a quinn endpoint backed by a magicsock.
+    ///
+    /// This is for internal use, the public interface is the [`Builder`] obtained from
+    /// [Self::builder]. See the methods on the builder for documentation of the parameters.
+    #[instrument("ep", skip_all, fields(me = %static_config.secret_key.public().fmt_short()))]
+    async fn bind(
+        static_config: StaticConfig,
+        msock_opts: magicsock::Options,
+        initial_alpns: Vec<Vec<u8>>,
+    ) -> Result<Self> {
+        let msock = magicsock::MagicSock::spawn(msock_opts).await?;
+        trace!("created magicsock");
+
+        let server_config = static_config.create_server_config(initial_alpns)?;
+
+        let mut endpoint_config = quinn::EndpointConfig::default();
+        // Setting this to false means that quinn will ignore packets that have the QUIC fixed bit
+        // set to 0. The fixed bit is the 3rd bit of the first byte of a packet.
+        // For performance reasons and to not rewrite buffers we pass non-QUIC UDP packets straight
+        // through to quinn. We set the first byte of the packet to zero, which makes quinn ignore
+        // the packet if grease_quic_bit is set to false.
+        endpoint_config.grease_quic_bit(false);
+
+        let endpoint = quinn::Endpoint::new_with_abstract_socket(
+            endpoint_config,
+            Some(server_config),
+            Arc::new(msock.clone()),
+            Arc::new(quinn::TokioRuntime),
+        )?;
+        trace!("created quinn endpoint");
+        debug!(version = env!("CARGO_PKG_VERSION"), "iroh Endpoint created");
+        Ok(Self {
+            msock,
+            endpoint,
+            rtt_actor: Arc::new(rtt_actor::RttHandle::new()),
+            cancel_token: CancellationToken::new(),
+            static_config: Arc::new(static_config),
+        })
+    }
+
+    /// Sets the list of accepted ALPN protocols.
+    ///
+    /// This will only affect new incoming connections.
+    /// Note that this *overrides* the current list of ALPNs.
+    pub fn set_alpns(&self, alpns: Vec<Vec<u8>>) -> Result<()> {
+        let server_config = self.static_config.create_server_config(alpns)?;
+        self.endpoint.set_server_config(Some(server_config));
+        Ok(())
+    }
+
+    // # Methods for establishing connectivity.
+
+    /// 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.
+    #[instrument(skip_all, fields(me = %self.node_id().fmt_short(), alpn = ?String::from_utf8_lossy(alpn)))]
+    pub async fn connect(&self, node_addr: impl Into<NodeAddr>, alpn: &[u8]) -> Result<Connection> {
+        let node_addr = node_addr.into();
+        tracing::Span::current().record("remote", node_addr.node_id.fmt_short());
+        // Connecting to ourselves is not supported.
+        if node_addr.node_id == self.node_id() {
+            bail!(
+                "Connecting to ourself is not supported ({} is the node id of this node)",
+                node_addr.node_id.fmt_short()
+            );
+        }
+
+        if !node_addr.info.is_empty() {
+            self.add_node_addr(node_addr.clone())?;
+        }
+
+        let NodeAddr { node_id, info } = node_addr.clone();
+
+        // Get the mapped IPv6 address from the magic socket. Quinn will connect to this address.
+        // Start discovery for this node if it's enabled and we have no valid or verified
+        // address information for this node.
+        let (addr, discovery) = self
+            .get_mapping_addr_and_maybe_start_discovery(node_addr)
+            .await
+            .with_context(|| {
+                format!(
+                    "No addressing information for NodeId({}), unable to connect",
+                    node_id.fmt_short()
+                )
+            })?;
+
+        debug!(
+            "connecting to {}: (via {} - {:?})",
+            node_id, addr, info.direct_addresses
+        );
+
+        // Start connecting via quinn. This will time out after 10 seconds if no reachable address
+        // is available.
+        let conn = self.connect_quinn(node_id, alpn, addr).await;
+
+        // Cancel the node discovery task (if still running).
+        if let Some(discovery) = discovery {
+            discovery.cancel();
+        }
+
+        conn
+    }
+
+    /// Connects to a remote endpoint, using just the nodes's [`NodeId`].
+    ///
+    /// This is a convenience function for [`Endpoint::connect`].  It relies on addressing
+    /// information being provided by either the discovery service or using
+    /// [`Endpoint::add_node_addr`].  See [`Endpoint::connect`] for the details of how it
+    /// uses the discovery service to establish a connection to a remote node.
+    #[deprecated(
+        since = "0.27.0",
+        note = "Please use `connect` directly with a NodeId. This fn will be removed in 0.28.0."
+    )]
+    pub async fn connect_by_node_id(&self, node_id: NodeId, alpn: &[u8]) -> Result<Connection> {
+        let addr = NodeAddr::new(node_id);
+        self.connect(addr, alpn).await
+    }
+
+    #[instrument(
+        skip_all,
+        fields(remote_node = node_id.fmt_short(), alpn = %String::from_utf8_lossy(alpn))
+    )]
+    async fn connect_quinn(
+        &self,
+        node_id: NodeId,
+        alpn: &[u8],
+        addr: QuicMappedAddr,
+    ) -> Result<Connection> {
+        debug!("Attempting connection...");
+        let client_config = {
+            let alpn_protocols = vec![alpn.to_vec()];
+            let quic_client_config = tls::make_client_config(
+                &self.static_config.secret_key,
+                Some(node_id),
+                alpn_protocols,
+                self.static_config.keylog,
+            )?;
+            let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.keep_alive_interval(Some(Duration::from_secs(1)));
+            client_config.transport_config(Arc::new(transport_config));
+            client_config
+        };
+
+        // TODO: We'd eventually want to replace "localhost" with something that makes more sense.
+        let connect = self
+            .endpoint
+            .connect_with(client_config, addr.0, "localhost")?;
+
+        let connection = connect
+            .await
+            .context("failed connecting to remote endpoint")?;
+
+        let rtt_msg = RttMessage::NewConnection {
+            connection: connection.weak_handle(),
+            conn_type_changes: self.conn_type_stream(node_id)?,
+            node_id,
+        };
+        if let Err(err) = self.rtt_actor.msg_tx.send(rtt_msg).await {
+            // If this actor is dead, that's not great but we can still function.
+            warn!("rtt-actor not reachable: {err:#}");
+        }
+        debug!("Connection established");
+        Ok(connection)
+    }
+
+    /// 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`].
+    pub fn accept(&self) -> Accept<'_> {
+        Accept {
+            inner: self.endpoint.accept(),
+            ep: self.clone(),
+        }
+    }
+
+    // # Methods for manipulating the internal state about other nodes.
+
+    /// 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`].
+    ///
+    /// # Errors
+    ///
+    /// Will return an error if we attempt to add our own [`PublicKey`] to the node map or if the
+    /// direct addresses are a subset of ours.
+    pub fn add_node_addr(&self, node_addr: NodeAddr) -> Result<()> {
+        self.add_node_addr_inner(node_addr, magicsock::Source::App)
+    }
+
+    /// 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.
+    ///
+    /// # Errors
+    ///
+    /// Will return an error if we attempt to add our own [`PublicKey`] to the node map or if the
+    /// direct addresses are a subset of ours.
+    pub fn add_node_addr_with_source(
+        &self,
+        node_addr: NodeAddr,
+        source: &'static str,
+    ) -> Result<()> {
+        self.add_node_addr_inner(
+            node_addr,
+            magicsock::Source::NamedApp {
+                name: source.into(),
+            },
+        )
+    }
+
+    fn add_node_addr_inner(&self, node_addr: NodeAddr, source: magicsock::Source) -> Result<()> {
+        // Connecting to ourselves is not supported.
+        if node_addr.node_id == self.node_id() {
+            bail!(
+                "Adding our own address is not supported ({} is the node id of this node)",
+                node_addr.node_id.fmt_short()
+            );
+        }
+        self.msock.add_node_addr(node_addr, source)
+    }
+
+    // # Getter methods for properties of this Endpoint itself.
+
+    /// Returns the secret_key of this endpoint.
+    pub fn secret_key(&self) -> &SecretKey {
+        &self.static_config.secret_key
+    }
+
+    /// 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.
+    pub fn node_id(&self) -> NodeId {
+        self.static_config.secret_key.public()
+    }
+
+    /// Returns the current [`NodeAddr`] for this endpoint.
+    ///
+    /// The returned [`NodeAddr`] will have the current [`RelayUrl`] and local IP endpoints
+    /// as they would be returned by [`Endpoint::home_relay`] and
+    /// [`Endpoint::direct_addresses`].
+    pub async fn node_addr(&self) -> Result<NodeAddr> {
+        let addrs = self
+            .direct_addresses()
+            .next()
+            .await
+            .ok_or(anyhow!("No IP endpoints found"))?;
+        let relay = self.home_relay();
+        Ok(NodeAddr::from_parts(
+            self.node_id(),
+            relay,
+            addrs.into_iter().map(|x| x.addr),
+        ))
+    }
+
+    /// Returns 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.
+    ///
+    /// Returns `None` if we are not connected to any Relay server.
+    ///
+    /// Note that this will be `None` right after the [`Endpoint`] is created since it takes
+    /// some time to connect to find and connect to the home relay server.  Use
+    /// [`Endpoint::watch_home_relay`] to wait until the home relay server is available.
+    pub fn home_relay(&self) -> Option<RelayUrl> {
+        self.msock.my_relay()
+    }
+
+    /// Watches for changes to the home relay.
+    ///
+    /// If there is currently a home relay it will be yielded immediately as the first item
+    /// in the stream.  This makes it possible to use this function to wait for the initial
+    /// home relay to be known.
+    ///
+    /// Note that it is not guaranteed that a home relay will ever become available.  If no
+    /// servers are configured with [`Builder::relay_mode`] this stream will never yield an
+    /// item.
+    pub fn watch_home_relay(&self) -> impl Stream<Item = RelayUrl> {
+        self.msock.watch_home_relay()
+    }
+
+    /// Returns 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 first item of the returned stream will not be
+    /// immediately available.  Once this first set of local IP endpoints are discovered the
+    /// stream will always return the first set of IP endpoints immediately, which are the
+    /// most recently discovered IP endpoints.
+    ///
+    /// # Examples
+    ///
+    /// To get the current endpoints, drop the stream after the first item was received:
+    /// ```
+    /// use futures_lite::StreamExt;
+    /// use iroh::Endpoint;
+    ///
+    /// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
+    /// # rt.block_on(async move {
+    /// let mep = Endpoint::builder().bind().await.unwrap();
+    /// let _addrs = mep.direct_addresses().next().await;
+    /// # });
+    /// ```
+    ///
+    /// [STUN]: https://en.wikipedia.org/wiki/STUN
+    pub fn direct_addresses(&self) -> DirectAddrsStream {
+        self.msock.direct_addresses()
+    }
+
+    /// 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.
+    pub fn bound_sockets(&self) -> (SocketAddr, Option<SocketAddr>) {
+        self.msock.local_addr()
+    }
+
+    // # Getter methods for information about other nodes.
+
+    /// 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`].
+    pub fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo> {
+        self.msock.remote_info(node_id)
+    }
+
+    /// 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.
+    pub fn remote_info_iter(&self) -> impl Iterator<Item = RemoteInfo> {
+        self.msock.list_remote_infos().into_iter()
+    }
+
+    // # Methods for less common getters.
+    //
+    // Partially they return things passed into the builder.
+
+    /// Returns a stream that reports connection type changes for the remote node.
+    ///
+    /// This returns a stream of [`ConnectionType`] items, each time the underlying
+    /// connection to a remote node changes it yields an item.  These connection changes are
+    /// when the connection switches between using the Relay server and a direct connection.
+    ///
+    /// If there is currently a connection with the remote node the first item in the stream
+    /// will yield immediately returning the current connection type.
+    ///
+    /// 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.
+    ///
+    /// # Errors
+    ///
+    /// Will error if we do not have any address information for the given `node_id`.
+    pub fn conn_type_stream(&self, node_id: NodeId) -> Result<ConnectionTypeStream> {
+        self.msock.conn_type_stream(node_id)
+    }
+
+    /// Returns the DNS resolver used in this [`Endpoint`].
+    ///
+    /// See [`Builder::discovery`].
+    pub fn dns_resolver(&self) -> &DnsResolver {
+        self.msock.dns_resolver()
+    }
+
+    /// Returns the discovery mechanism, if configured.
+    ///
+    /// See [`Builder::dns_resolver`].
+    pub fn discovery(&self) -> Option<&dyn Discovery> {
+        self.msock.discovery()
+    }
+
+    // # Methods for less common state updates.
+
+    /// 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.
+    pub async fn network_change(&self) {
+        self.msock.network_change().await;
+    }
+
+    // # Methods for terminating the endpoint.
+
+    /// 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 magic socket is closed.
+    ///
+    /// Be aware however that the underlying UDP sockets are only closed
+    /// on [`Drop`], bearing in mind the [`Endpoint`] is only dropped once all the clones
+    /// are dropped.
+    ///
+    /// Returns an error if closing the magic socket failed.
+    /// TODO: Document error cases.
+    pub async fn close(&self) -> Result<()> {
+        if self.is_closed() {
+            return Ok(());
+        }
+
+        self.cancel_token.cancel();
+        tracing::debug!("Closing connections");
+        self.endpoint.close(0u16.into(), b"");
+        self.endpoint.wait_idle().await;
+
+        tracing::debug!("Connections closed");
+        self.msock.close().await?;
+        Ok(())
+    }
+
+    /// Check if this endpoint is still alive, or already closed.
+    pub fn is_closed(&self) -> bool {
+        self.cancel_token.is_cancelled() && self.msock.is_closed()
+    }
+
+    // # Remaining private methods
+
+    /// Expose the internal [`CancellationToken`] to link shutdowns.
+    pub(crate) fn cancel_token(&self) -> &CancellationToken {
+        &self.cancel_token
+    }
+
+    /// Return the quic mapped address for this `node_id` and possibly start discovery
+    /// services if discovery is enabled on this magic endpoint.
+    ///
+    /// This will launch discovery in all cases except if:
+    /// 1) we do not have discovery enabled
+    /// 2) we have discovery enabled, but already have at least one verified, unexpired
+    ///    addresses for this `node_id`
+    ///
+    /// # Errors
+    ///
+    /// This method may fail if we have no way of dialing the node. This can occur if
+    /// we were given no dialing information in the [`NodeAddr`] and no discovery
+    /// services were configured or if discovery failed to fetch any dialing information.
+    async fn get_mapping_addr_and_maybe_start_discovery(
+        &self,
+        node_addr: NodeAddr,
+    ) -> Result<(QuicMappedAddr, Option<DiscoveryTask>)> {
+        let node_id = node_addr.node_id;
+
+        // Only return a mapped addr if we have some way of dialing this node, in other
+        // words, we have either a relay URL or at least one direct address.
+        let addr = if self.msock.has_send_address(node_id) {
+            self.msock.get_mapping_addr(node_id)
+        } else {
+            None
+        };
+        match addr {
+            Some(addr) => {
+                // We have some way of dialing this node, but that doesn't actually mean
+                // we can actually connect to any of these addresses.
+                // Therefore, we will invoke the discovery service if we haven't received from the
+                // endpoint on any of the existing paths recently.
+                // If the user provided addresses in this connect call, we will add a delay
+                // followed by a recheck before starting the discovery, to give the magicsocket a
+                // chance to test the newly provided addresses.
+                let delay = (!node_addr.info.is_empty()).then_some(DISCOVERY_WAIT_PERIOD);
+                let discovery = DiscoveryTask::maybe_start_after_delay(self, node_id, delay)
+                    .ok()
+                    .flatten();
+                Ok((addr, discovery))
+            }
+
+            None => {
+                // We have no known addresses or relay URLs for this node.
+                // So, we start a discovery task and wait for the first result to arrive, and
+                // only then continue, because otherwise we wouldn't have any
+                // path to the remote endpoint.
+                let mut discovery = DiscoveryTask::start(self.clone(), node_id)
+                    .context("Discovery service required due to missing addressing information")?;
+                discovery
+                    .first_arrived()
+                    .await
+                    .context("Discovery service failed")?;
+                if let Some(addr) = self.msock.get_mapping_addr(node_id) {
+                    Ok((addr, Some(discovery)))
+                } else {
+                    bail!("Discovery did not find addressing information");
+                }
+            }
+        }
+    }
+
+    #[cfg(test)]
+    pub(crate) fn magic_sock(&self) -> Handle {
+        self.msock.clone()
+    }
+    #[cfg(test)]
+    pub(crate) fn endpoint(&self) -> &quinn::Endpoint {
+        &self.endpoint
+    }
+}
+
+/// Future produced by [`Endpoint::accept`].
+#[derive(Debug)]
+#[pin_project]
+pub struct Accept<'a> {
+    #[pin]
+    #[debug("quinn::Accept")]
+    inner: quinn::Accept<'a>,
+    ep: Endpoint,
+}
+
+impl Future for Accept<'_> {
+    type Output = Option<Incoming>;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+        let this = self.project();
+        match this.inner.poll(cx) {
+            Poll::Pending => Poll::Pending,
+            Poll::Ready(None) => Poll::Ready(None),
+            Poll::Ready(Some(inner)) => Poll::Ready(Some(Incoming {
+                inner,
+                ep: this.ep.clone(),
+            })),
+        }
+    }
+}
+
+/// An incoming connection for which the server has not yet begun its parts of the
+/// handshake.
+#[derive(Debug)]
+pub struct Incoming {
+    inner: quinn::Incoming,
+    ep: Endpoint,
+}
+
+impl Incoming {
+    /// Attempts to accept this incoming connection (an error may still occur).
+    ///
+    /// Errors occurring here are likely not caused by the application or remote.  The QUIC
+    /// connection listens on a normal UDP socket and any reachable network endpoint can
+    /// send datagrams to it, solicited or not.  Even if the first few bytes look like a
+    /// QUIC packet, it might not even be a QUIC packet that is being received.
+    ///
+    /// Thus it is common to simply log the errors here and accept them as something which
+    /// can happen.
+    pub fn accept(self) -> Result<Connecting, ConnectionError> {
+        self.inner.accept().map(|conn| Connecting {
+            inner: conn,
+            ep: self.ep,
+        })
+    }
+
+    /// Accepts this incoming connection using a custom configuration.
+    ///
+    /// See [`accept()`] for more details.
+    ///
+    /// [`accept()`]: Incoming::accept
+    pub fn accept_with(
+        self,
+        server_config: Arc<ServerConfig>,
+    ) -> Result<Connecting, ConnectionError> {
+        self.inner
+            .accept_with(server_config)
+            .map(|conn| Connecting {
+                inner: conn,
+                ep: self.ep,
+            })
+    }
+
+    /// Rejects this incoming connection attempt.
+    pub fn refuse(self) {
+        self.inner.refuse()
+    }
+
+    /// Responds with a retry packet.
+    ///
+    /// This requires the client to retry with address validation.
+    ///
+    /// Errors if `remote_address_validated()` is true.
+    pub fn retry(self) -> Result<(), RetryError> {
+        self.inner.retry()
+    }
+
+    /// Ignores this incoming connection attempt, not sending any packet in response.
+    pub fn ignore(self) {
+        self.inner.ignore()
+    }
+
+    /// Returns the local IP address which was used when the peer established the
+    /// connection.
+    pub fn local_ip(&self) -> Option<IpAddr> {
+        self.inner.local_ip()
+    }
+
+    /// Returns the peer's UDP address.
+    pub fn remote_address(&self) -> SocketAddr {
+        self.inner.remote_address()
+    }
+
+    /// Whether the socket address that is initiating this connection has been validated.
+    ///
+    /// This means that the sender of the initial packet has proved that they can receive
+    /// traffic sent to `self.remote_address()`.
+    pub fn remote_address_validated(&self) -> bool {
+        self.inner.remote_address_validated()
+    }
+}
+
+impl IntoFuture for Incoming {
+    type Output = Result<Connection, ConnectionError>;
+    type IntoFuture = IncomingFuture;
+
+    fn into_future(self) -> Self::IntoFuture {
+        IncomingFuture {
+            inner: self.inner.into_future(),
+            ep: self.ep,
+        }
+    }
+}
+
+/// Adaptor to let [`Incoming`] be `await`ed like a [`Connecting`].
+#[derive(Debug)]
+#[pin_project]
+pub struct IncomingFuture {
+    #[pin]
+    inner: quinn::IncomingFuture,
+    ep: Endpoint,
+}
+
+impl Future for IncomingFuture {
+    type Output = Result<quinn::Connection, ConnectionError>;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+        let this = self.project();
+        match this.inner.poll(cx) {
+            Poll::Pending => Poll::Pending,
+            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
+            Poll::Ready(Ok(conn)) => {
+                try_send_rtt_msg(&conn, this.ep);
+                Poll::Ready(Ok(conn))
+            }
+        }
+    }
+}
+
+/// In-progress connection attempt future
+#[derive(Debug)]
+#[pin_project]
+pub struct Connecting {
+    #[pin]
+    inner: quinn::Connecting,
+    ep: Endpoint,
+}
+
+impl Connecting {
+    /// Convert into a 0-RTT or 0.5-RTT connection at the cost of weakened security.
+    pub fn into_0rtt(self) -> Result<(Connection, ZeroRttAccepted), Self> {
+        match self.inner.into_0rtt() {
+            Ok((conn, zrtt_accepted)) => {
+                try_send_rtt_msg(&conn, &self.ep);
+                Ok((conn, zrtt_accepted))
+            }
+            Err(inner) => Err(Self { inner, ep: self.ep }),
+        }
+    }
+
+    /// Parameters negotiated during the handshake
+    pub async fn handshake_data(&mut self) -> Result<Box<dyn Any>, 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<IpAddr> {
+        self.inner.local_ip()
+    }
+
+    /// The peer's UDP address.
+    pub fn remote_address(&self) -> SocketAddr {
+        self.inner.remote_address()
+    }
+
+    /// 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<Vec<u8>> {
+        let data = self.handshake_data().await?;
+        match data.downcast::<quinn::crypto::rustls::HandshakeData>() {
+            Ok(data) => match data.protocol {
+                Some(protocol) => Ok(protocol),
+                None => bail!("no ALPN protocol available"),
+            },
+            Err(_) => bail!("unknown handshake type"),
+        }
+    }
+}
+
+impl Future for Connecting {
+    type Output = Result<Connection, ConnectionError>;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+        let this = self.project();
+        match this.inner.poll(cx) {
+            Poll::Pending => Poll::Pending,
+            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
+            Poll::Ready(Ok(conn)) => {
+                try_send_rtt_msg(&conn, this.ep);
+                Poll::Ready(Ok(conn))
+            }
+        }
+    }
+}
+
+/// Extract the [`PublicKey`] from the peer's TLS certificate.
+// TODO: make this a method now
+pub fn get_remote_node_id(connection: &Connection) -> Result<PublicKey> {
+    let data = connection.peer_identity();
+    match data {
+        None => bail!("no peer certificate found"),
+        Some(data) => match data.downcast::<Vec<rustls::pki_types::CertificateDer>>() {
+            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"),
+        },
+    }
+}
+
+/// Try send a message to the rtt-actor.
+///
+/// If we can't notify the actor that will impact performance a little, but we can still
+/// 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(peer_id) = get_remote_node_id(conn) else {
+        warn!(?conn, "failed to get remote node id");
+        return;
+    };
+    let Ok(conn_type_changes) = magic_ep.conn_type_stream(peer_id) else {
+        warn!(?conn, "failed to create conn_type_stream");
+        return;
+    };
+    let rtt_msg = RttMessage::NewConnection {
+        connection: conn.weak_handle(),
+        conn_type_changes,
+        node_id: peer_id,
+    };
+    if let Err(err) = magic_ep.rtt_actor.msg_tx.try_send(rtt_msg) {
+        warn!(?conn, "rtt-actor not reachable: {err:#}");
+    }
+}
+
+/// Read a proxy url from the environment, in this order
+///
+/// - `HTTP_PROXY`
+/// - `http_proxy`
+/// - `HTTPS_PROXY`
+/// - `https_proxy`
+fn proxy_url_from_env() -> Option<Url> {
+    if let Some(url) = std::env::var("HTTP_PROXY")
+        .ok()
+        .and_then(|s| s.parse::<Url>().ok())
+    {
+        if is_cgi() {
+            warn!("HTTP_PROXY environment variable ignored in CGI");
+        } else {
+            return Some(url);
+        }
+    }
+    if let Some(url) = std::env::var("http_proxy")
+        .ok()
+        .and_then(|s| s.parse::<Url>().ok())
+    {
+        return Some(url);
+    }
+    if let Some(url) = std::env::var("HTTPS_PROXY")
+        .ok()
+        .and_then(|s| s.parse::<Url>().ok())
+    {
+        return Some(url);
+    }
+    if let Some(url) = std::env::var("https_proxy")
+        .ok()
+        .and_then(|s| s.parse::<Url>().ok())
+    {
+        return Some(url);
+    }
+
+    None
+}
+
+/// Configuration of the relay servers for an [`Endpoint`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum RelayMode {
+    /// Disable relay servers completely.
+    Disabled,
+    /// Use the default relay map, with production relay servers from n0.
+    ///
+    /// See [`crate::defaults::prod`] for the severs used.
+    Default,
+    /// Use the staging relay servers from n0.
+    Staging,
+    /// Use a custom relay map.
+    Custom(RelayMap),
+}
+
+impl RelayMode {
+    /// Returns the relay map for this mode.
+    pub fn relay_map(&self) -> RelayMap {
+        match self {
+            RelayMode::Disabled => RelayMap::empty(),
+            RelayMode::Default => crate::defaults::prod::default_relay_map(),
+            RelayMode::Staging => crate::defaults::staging::default_relay_map(),
+            RelayMode::Custom(relay_map) => relay_map.clone(),
+        }
+    }
+}
+
+/// Environment variable to force the use of staging relays.
+#[cfg_attr(iroh_docsrs, doc(cfg(not(test))))]
+pub const ENV_FORCE_STAGING_RELAYS: &str = "IROH_FORCE_STAGING_RELAYS";
+
+/// Returns `true` if the use of staging relays is forced.
+pub fn force_staging_infra() -> bool {
+    matches!(std::env::var(ENV_FORCE_STAGING_RELAYS), Ok(value) if !value.is_empty())
+}
+
+/// Returns the default relay mode.
+///
+/// If the `IROH_FORCE_STAGING_RELAYS` environment variable is non empty, it will return `RelayMode::Staging`.
+/// Otherwise, it will return `RelayMode::Default`.
+pub fn default_relay_mode() -> RelayMode {
+    // Use staging in testing
+    match force_staging_infra() {
+        true => RelayMode::Staging,
+        false => RelayMode::Default,
+    }
+}
+
+/// Check if we are being executed in a CGI context.
+///
+/// If so, a malicious client can send the `Proxy:` header, and it will
+/// be in the `HTTP_PROXY` env var. So we don't use it :)
+fn is_cgi() -> bool {
+    std::env::var_os("REQUEST_METHOD").is_some()
+}
+
+// TODO: These tests could still be flaky, lets fix that:
+// https://github.com/n0-computer/iroh/issues/1183
+#[cfg(test)]
+mod tests {
+
+    use std::time::Instant;
+
+    use iroh_test::CallOnDrop;
+    use rand::SeedableRng;
+    use tracing::{error_span, info, info_span, Instrument};
+
+    use super::*;
+    use crate::test_utils::{run_relay_server, run_relay_server_with};
+
+    const TEST_ALPN: &[u8] = b"n0/iroh/test";
+
+    #[test]
+    fn test_addr_info_debug() {
+        let info = AddrInfo {
+            relay_url: Some("https://relay.example.com".parse().unwrap()),
+            direct_addresses: vec![SocketAddr::from(([1, 2, 3, 4], 1234))]
+                .into_iter()
+                .collect(),
+        };
+        assert_eq!(
+            format!("{:?}", info),
+            r#"AddrInfo { relay_url: Some(RelayUrl("https://relay.example.com./")), direct_addresses: {1.2.3.4:1234} }"#
+        );
+    }
+
+    #[tokio::test]
+    async fn test_connect_self() {
+        let _guard = iroh_test::logging::setup();
+        let ep = Endpoint::builder()
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .bind()
+            .await
+            .unwrap();
+        let my_addr = ep.node_addr().await.unwrap();
+        let res = ep.connect(my_addr.clone(), TEST_ALPN).await;
+        assert!(res.is_err());
+        let err = res.err().unwrap();
+        assert!(err.to_string().starts_with("Connecting to ourself"));
+
+        let res = ep.add_node_addr(my_addr);
+        assert!(res.is_err());
+        let err = res.err().unwrap();
+        assert!(err.to_string().starts_with("Adding our own address"));
+    }
+
+    #[tokio::test]
+    async fn endpoint_connect_close() {
+        let _guard = iroh_test::logging::setup();
+        let (relay_map, relay_url, _guard) = run_relay_server().await.unwrap();
+        let server_secret_key = SecretKey::generate();
+        let server_peer_id = server_secret_key.public();
+
+        let server = {
+            let relay_map = relay_map.clone();
+            tokio::spawn(
+                async move {
+                    let ep = Endpoint::builder()
+                        .secret_key(server_secret_key)
+                        .alpns(vec![TEST_ALPN.to_vec()])
+                        .relay_mode(RelayMode::Custom(relay_map))
+                        .insecure_skip_relay_cert_verify(true)
+                        .bind()
+                        .await
+                        .unwrap();
+                    info!("accepting connection");
+                    let incoming = ep.accept().await.unwrap();
+                    let conn = incoming.await.unwrap();
+                    let mut stream = conn.accept_uni().await.unwrap();
+                    let mut buf = [0u8; 5];
+                    stream.read_exact(&mut buf).await.unwrap();
+                    info!("Accepted 1 stream, received {buf:?}.  Closing now.");
+                    // close the connection
+                    conn.close(7u8.into(), b"bye");
+
+                    let res = conn.accept_uni().await;
+                    assert_eq!(res.unwrap_err(), quinn::ConnectionError::LocallyClosed);
+
+                    let res = stream.read_to_end(10).await;
+                    assert_eq!(
+                        res.unwrap_err(),
+                        quinn::ReadToEndError::Read(quinn::ReadError::ConnectionLost(
+                            quinn::ConnectionError::LocallyClosed
+                        ))
+                    );
+                    info!("server test completed");
+                }
+                .instrument(info_span!("test-server")),
+            )
+        };
+
+        let client = tokio::spawn(
+            async move {
+                let ep = Endpoint::builder()
+                    .alpns(vec![TEST_ALPN.to_vec()])
+                    .relay_mode(RelayMode::Custom(relay_map))
+                    .insecure_skip_relay_cert_verify(true)
+                    .bind()
+                    .await
+                    .unwrap();
+                info!("client connecting");
+                let node_addr = NodeAddr::new(server_peer_id).with_relay_url(relay_url);
+                let conn = ep.connect(node_addr, TEST_ALPN).await.unwrap();
+                let mut stream = conn.open_uni().await.unwrap();
+
+                // First write is accepted by server.  We need this bit of synchronisation
+                // because if the server closes after simply accepting the connection we can
+                // not be sure our .open_uni() call would succeed as it may already receive
+                // the error.
+                stream.write_all(b"hello").await.unwrap();
+
+                info!("waiting for closed");
+                // Remote now closes the connection, we should see an error sometime soon.
+                let err = conn.closed().await;
+                let expected_err =
+                    quinn::ConnectionError::ApplicationClosed(quinn::ApplicationClose {
+                        error_code: 7u8.into(),
+                        reason: b"bye".to_vec().into(),
+                    });
+                assert_eq!(err, expected_err);
+
+                info!("opening new - expect it to fail");
+                let res = conn.open_uni().await;
+                assert_eq!(res.unwrap_err(), expected_err);
+                info!("client test completed");
+            }
+            .instrument(info_span!("test-client")),
+        );
+
+        let (server, client) = tokio::time::timeout(
+            Duration::from_secs(30),
+            futures_lite::future::zip(server, client),
+        )
+        .await
+        .expect("timeout");
+        server.unwrap();
+        client.unwrap();
+    }
+
+    /// Test that peers are properly restored
+    #[tokio::test]
+    async fn restore_peers() {
+        let _guard = iroh_test::logging::setup();
+
+        let secret_key = SecretKey::generate();
+
+        /// Create an endpoint for the test.
+        async fn new_endpoint(secret_key: SecretKey, nodes: Option<Vec<NodeAddr>>) -> Endpoint {
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+
+            let mut builder = Endpoint::builder()
+                .secret_key(secret_key.clone())
+                .transport_config(transport_config);
+            if let Some(nodes) = nodes {
+                builder = builder.known_nodes(nodes);
+            }
+            builder
+                .alpns(vec![TEST_ALPN.to_vec()])
+                .bind()
+                .await
+                .unwrap()
+        }
+
+        // create the peer that will be added to the peer map
+        let peer_id = SecretKey::generate().public();
+        let direct_addr: SocketAddr =
+            (std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST), 8758u16).into();
+        let node_addr = NodeAddr::new(peer_id).with_direct_addresses([direct_addr]);
+
+        info!("setting up first endpoint");
+        // first time, create a magic endpoint without peers but a peers file and add addressing
+        // information for a peer
+        let endpoint = new_endpoint(secret_key.clone(), None).await;
+        assert_eq!(endpoint.remote_info_iter().count(), 0);
+        endpoint.add_node_addr(node_addr.clone()).unwrap();
+
+        // Grab the current addrs
+        let node_addrs: Vec<NodeAddr> = endpoint.remote_info_iter().map(Into::into).collect();
+        assert_eq!(node_addrs.len(), 1);
+        assert_eq!(node_addrs[0], node_addr);
+
+        info!("closing endpoint");
+        // close the endpoint and restart it
+        endpoint.close().await.unwrap();
+
+        info!("restarting endpoint");
+        // now restart it and check the addressing info of the peer
+        let endpoint = new_endpoint(secret_key, Some(node_addrs)).await;
+        let RemoteInfo { mut addrs, .. } = endpoint.remote_info(peer_id).unwrap();
+        let conn_addr = addrs.pop().unwrap().addr;
+        assert_eq!(conn_addr, direct_addr);
+    }
+
+    #[tokio::test]
+    async fn endpoint_relay_connect_loop() {
+        let _logging_guard = iroh_test::logging::setup();
+        let start = Instant::now();
+        let n_clients = 5;
+        let n_chunks_per_client = 2;
+        let chunk_size = 10;
+        let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42);
+        let (relay_map, relay_url, _relay_guard) = run_relay_server().await.unwrap();
+        let server_secret_key = SecretKey::generate_with_rng(&mut rng);
+        let server_node_id = server_secret_key.public();
+
+        // The server accepts the connections of the clients sequentially.
+        let server = {
+            let relay_map = relay_map.clone();
+            tokio::spawn(
+                async move {
+                    let ep = Endpoint::builder()
+                        .insecure_skip_relay_cert_verify(true)
+                        .secret_key(server_secret_key)
+                        .alpns(vec![TEST_ALPN.to_vec()])
+                        .relay_mode(RelayMode::Custom(relay_map))
+                        .bind()
+                        .await
+                        .unwrap();
+                    let eps = ep.bound_sockets();
+                    info!(me = %ep.node_id().fmt_short(), ipv4=%eps.0, ipv6=?eps.1, "server listening on");
+                    for i in 0..n_clients {
+                        let now = Instant::now();
+                        println!("[server] round {}", i + 1);
+                        let incoming = ep.accept().await.unwrap();
+                        let conn = incoming.await.unwrap();
+                        let peer_id = get_remote_node_id(&conn).unwrap();
+                        info!(%i, peer = %peer_id.fmt_short(), "accepted connection");
+                        let (mut send, mut recv) = conn.accept_bi().await.unwrap();
+                        let mut buf = vec![0u8; chunk_size];
+                        for _i in 0..n_chunks_per_client {
+                            recv.read_exact(&mut buf).await.unwrap();
+                            send.write_all(&buf).await.unwrap();
+                        }
+                        send.finish().unwrap();
+                        send.stopped().await.unwrap();
+                        recv.read_to_end(0).await.unwrap();
+                        info!(%i, peer = %peer_id.fmt_short(), "finished");
+                        println!("[server] round {} done in {:?}", i + 1, now.elapsed());
+                    }
+                }
+                .instrument(error_span!("server")),
+            )
+        };
+        let abort_handle = server.abort_handle();
+        let _server_guard = CallOnDrop::new(move || {
+            abort_handle.abort();
+        });
+
+        for i in 0..n_clients {
+            let now = Instant::now();
+            println!("[client] round {}", i + 1);
+            let relay_map = relay_map.clone();
+            let client_secret_key = SecretKey::generate_with_rng(&mut rng);
+            let relay_url = relay_url.clone();
+            async {
+                info!("client binding");
+                let ep = Endpoint::builder()
+                    .alpns(vec![TEST_ALPN.to_vec()])
+                    .insecure_skip_relay_cert_verify(true)
+                    .relay_mode(RelayMode::Custom(relay_map))
+                    .secret_key(client_secret_key)
+                    .bind()
+                    .await
+                    .unwrap();
+                let eps = ep.bound_sockets();
+                info!(me = %ep.node_id().fmt_short(), ipv4=%eps.0, ipv6=?eps.1, "client bound");
+                let node_addr = NodeAddr::new(server_node_id).with_relay_url(relay_url);
+                info!(to = ?node_addr, "client connecting");
+                let conn = ep.connect(node_addr, TEST_ALPN).await.unwrap();
+                info!("client connected");
+                let (mut send, mut recv) = conn.open_bi().await.unwrap();
+
+                for i in 0..n_chunks_per_client {
+                    let mut buf = vec![i; chunk_size];
+                    send.write_all(&buf).await.unwrap();
+                    recv.read_exact(&mut buf).await.unwrap();
+                    assert_eq!(buf, vec![i; chunk_size]);
+                }
+                send.finish().unwrap();
+                send.stopped().await.unwrap();
+                recv.read_to_end(0).await.unwrap();
+                info!("client finished");
+                ep.close().await.unwrap();
+                info!("client closed");
+            }
+            .instrument(error_span!("client", %i))
+            .await;
+            println!("[client] round {} done in {:?}", i + 1, now.elapsed());
+        }
+
+        server.await.unwrap();
+
+        // We appear to have seen this being very slow at times.  So ensure we fail if this
+        // test is too slow.  We're only making two connections transferring very little
+        // data, this really shouldn't take long.
+        if start.elapsed() > Duration::from_secs(15) {
+            panic!("Test too slow, something went wrong");
+        }
+    }
+
+    #[tokio::test]
+    async fn endpoint_bidi_send_recv() {
+        let _logging_guard = iroh_test::logging::setup();
+        let ep1 = Endpoint::builder()
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .relay_mode(RelayMode::Disabled)
+            .bind()
+            .await
+            .unwrap();
+        let ep2 = Endpoint::builder()
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .relay_mode(RelayMode::Disabled)
+            .bind()
+            .await
+            .unwrap();
+        let ep1_nodeaddr = ep1.node_addr().await.unwrap();
+        let ep2_nodeaddr = ep2.node_addr().await.unwrap();
+        ep1.add_node_addr(ep2_nodeaddr.clone()).unwrap();
+        ep2.add_node_addr(ep1_nodeaddr.clone()).unwrap();
+        let ep1_nodeid = ep1.node_id();
+        let ep2_nodeid = ep2.node_id();
+        eprintln!("node id 1 {ep1_nodeid}");
+        eprintln!("node id 2 {ep2_nodeid}");
+
+        async fn connect_hello(ep: Endpoint, dst: NodeAddr) {
+            let conn = ep.connect(dst, TEST_ALPN).await.unwrap();
+            let (mut send, mut recv) = conn.open_bi().await.unwrap();
+            info!("sending hello");
+            send.write_all(b"hello").await.unwrap();
+            send.finish().unwrap();
+            info!("receiving world");
+            let m = recv.read_to_end(100).await.unwrap();
+            assert_eq!(m, b"world");
+            conn.close(1u8.into(), b"done");
+        }
+
+        async fn accept_world(ep: Endpoint, src: NodeId) {
+            let incoming = ep.accept().await.unwrap();
+            let mut iconn = incoming.accept().unwrap();
+            let alpn = iconn.alpn().await.unwrap();
+            let conn = iconn.await.unwrap();
+            let node_id = get_remote_node_id(&conn).unwrap();
+            assert_eq!(node_id, src);
+            assert_eq!(alpn, TEST_ALPN);
+            let (mut send, mut recv) = conn.accept_bi().await.unwrap();
+            info!("receiving hello");
+            let m = recv.read_to_end(100).await.unwrap();
+            assert_eq!(m, b"hello");
+            info!("sending hello");
+            send.write_all(b"world").await.unwrap();
+            send.finish().unwrap();
+            match conn.closed().await {
+                ConnectionError::ApplicationClosed(closed) => {
+                    assert_eq!(closed.error_code, 1u8.into());
+                }
+                _ => panic!("wrong close error"),
+            }
+        }
+
+        let p1_accept = tokio::spawn(accept_world(ep1.clone(), ep2_nodeid).instrument(info_span!(
+            "p1_accept",
+            ep1 = %ep1.node_id().fmt_short(),
+            dst = %ep2_nodeid.fmt_short(),
+        )));
+        let p2_accept = tokio::spawn(accept_world(ep2.clone(), ep1_nodeid).instrument(info_span!(
+            "p2_accept",
+            ep2 = %ep2.node_id().fmt_short(),
+            dst = %ep1_nodeid.fmt_short(),
+        )));
+        let p1_connect = tokio::spawn(connect_hello(ep1.clone(), ep2_nodeaddr).instrument(
+            info_span!(
+                "p1_connect",
+                ep1 = %ep1.node_id().fmt_short(),
+                dst = %ep2_nodeid.fmt_short(),
+            ),
+        ));
+        let p2_connect = tokio::spawn(connect_hello(ep2.clone(), ep1_nodeaddr).instrument(
+            info_span!(
+                "p2_connect",
+                ep2 = %ep2.node_id().fmt_short(),
+                dst = %ep1_nodeid.fmt_short(),
+            ),
+        ));
+
+        p1_accept.await.unwrap();
+        p2_accept.await.unwrap();
+        p1_connect.await.unwrap();
+        p2_connect.await.unwrap();
+    }
+
+    #[tokio::test]
+    async fn endpoint_conn_type_stream() {
+        const TIMEOUT: Duration = std::time::Duration::from_secs(15);
+        let _logging_guard = iroh_test::logging::setup();
+        let (relay_map, _relay_url, _relay_guard) = run_relay_server().await.unwrap();
+        let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42);
+        let ep1_secret_key = SecretKey::generate_with_rng(&mut rng);
+        let ep2_secret_key = SecretKey::generate_with_rng(&mut rng);
+        let ep1 = Endpoint::builder()
+            .secret_key(ep1_secret_key)
+            .insecure_skip_relay_cert_verify(true)
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .relay_mode(RelayMode::Custom(relay_map.clone()))
+            .bind()
+            .await
+            .unwrap();
+        let ep2 = Endpoint::builder()
+            .secret_key(ep2_secret_key)
+            .insecure_skip_relay_cert_verify(true)
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .relay_mode(RelayMode::Custom(relay_map))
+            .bind()
+            .await
+            .unwrap();
+
+        async fn handle_direct_conn(ep: &Endpoint, node_id: PublicKey) -> Result<()> {
+            let mut stream = ep.conn_type_stream(node_id)?;
+            let src = ep.node_id().fmt_short();
+            let dst = node_id.fmt_short();
+            while let Some(conn_type) = stream.next().await {
+                tracing::info!(me = %src, dst = %dst, conn_type = ?conn_type);
+                if matches!(conn_type, ConnectionType::Direct(_)) {
+                    return Ok(());
+                }
+            }
+            anyhow::bail!("conn_type stream ended before `ConnectionType::Direct`");
+        }
+
+        async fn accept(ep: &Endpoint) -> NodeId {
+            let incoming = ep.accept().await.unwrap();
+            let conn = incoming.await.unwrap();
+            let node_id = get_remote_node_id(&conn).unwrap();
+            tracing::info!(node_id=%node_id.fmt_short(), "accepted connection");
+            node_id
+        }
+
+        let ep1_nodeid = ep1.node_id();
+        let ep2_nodeid = ep2.node_id();
+
+        let ep1_nodeaddr = ep1.node_addr().await.unwrap();
+        tracing::info!(
+            "node id 1 {ep1_nodeid}, relay URL {:?}",
+            ep1_nodeaddr.relay_url()
+        );
+        tracing::info!("node id 2 {ep2_nodeid}");
+
+        let ep1_side = async move {
+            accept(&ep1).await;
+            handle_direct_conn(&ep1, ep2_nodeid).await
+        };
+
+        let ep2_side = async move {
+            ep2.connect(ep1_nodeaddr, TEST_ALPN).await.unwrap();
+            handle_direct_conn(&ep2, ep1_nodeid).await
+        };
+
+        let res_ep1 = tokio::spawn(tokio::time::timeout(TIMEOUT, ep1_side));
+
+        let ep1_abort_handle = res_ep1.abort_handle();
+        let _ep1_guard = CallOnDrop::new(move || {
+            ep1_abort_handle.abort();
+        });
+
+        let res_ep2 = tokio::spawn(tokio::time::timeout(TIMEOUT, ep2_side));
+        let ep2_abort_handle = res_ep2.abort_handle();
+        let _ep2_guard = CallOnDrop::new(move || {
+            ep2_abort_handle.abort();
+        });
+
+        let (r1, r2) = tokio::try_join!(res_ep1, res_ep2).unwrap();
+        r1.expect("ep1 timeout").unwrap();
+        r2.expect("ep2 timeout").unwrap();
+    }
+
+    #[tokio::test]
+    async fn test_direct_addresses_no_stun_relay() {
+        let _guard = iroh_test::logging::setup();
+        let (relay_map, _, _guard) = run_relay_server_with(None, false).await.unwrap();
+
+        let ep = Endpoint::builder()
+            .alpns(vec![TEST_ALPN.to_vec()])
+            .relay_mode(RelayMode::Custom(relay_map))
+            .insecure_skip_relay_cert_verify(true)
+            .bind()
+            .await
+            .unwrap();
+
+        tokio::time::timeout(Duration::from_secs(10), ep.direct_addresses().next())
+            .await
+            .unwrap()
+            .unwrap();
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/endpoint/rtt_actor.rs.html b/pr/2992/docs/src/iroh/endpoint/rtt_actor.rs.html new file mode 100644 index 0000000000..55dae45a05 --- /dev/null +++ b/pr/2992/docs/src/iroh/endpoint/rtt_actor.rs.html @@ -0,0 +1,417 @@ +rtt_actor.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+
//! Actor which coordinates the congestion controller for the magic socket
+
+use std::collections::HashMap;
+
+use futures_concurrency::stream::stream_group;
+use futures_lite::StreamExt;
+use iroh_base::key::NodeId;
+use iroh_metrics::inc;
+use tokio::{
+    sync::{mpsc, Notify},
+    time::Duration,
+};
+use tokio_util::task::AbortOnDropHandle;
+use tracing::{debug, error, info_span, trace, Instrument};
+
+use crate::{
+    magicsock::{ConnectionType, ConnectionTypeStream},
+    metrics::MagicsockMetrics,
+};
+
+#[derive(Debug)]
+pub(super) struct RttHandle {
+    // We should and some point use this to propagate panics and errors.
+    pub(super) _handle: AbortOnDropHandle<()>,
+    pub(super) msg_tx: mpsc::Sender<RttMessage>,
+}
+
+impl RttHandle {
+    pub(super) fn new() -> Self {
+        let mut actor = RttActor {
+            connection_events: stream_group::StreamGroup::new().keyed(),
+            connections: HashMap::new(),
+            tick: Notify::new(),
+        };
+        let (msg_tx, msg_rx) = mpsc::channel(16);
+        let handle = tokio::spawn(
+            async move {
+                actor.run(msg_rx).await;
+            }
+            .instrument(info_span!("rtt-actor")),
+        );
+        Self {
+            _handle: AbortOnDropHandle::new(handle),
+            msg_tx,
+        }
+    }
+}
+
+/// Messages to send to the [`RttActor`].
+#[derive(Debug)]
+pub(super) enum RttMessage {
+    /// Informs the [`RttActor`] of a new connection is should monitor.
+    NewConnection {
+        /// The connection.
+        connection: quinn::WeakConnectionHandle,
+        /// Path changes for this connection from the magic socket.
+        conn_type_changes: ConnectionTypeStream,
+        /// For reporting-only, the Node ID of this connection.
+        node_id: NodeId,
+    },
+}
+
+/// Actor to coordinate congestion controller state with magic socket state.
+///
+/// The magic socket can change the underlying network path, between two nodes.  If we can
+/// inform the QUIC congestion controller of this event it will work much more efficiently.
+#[derive(Debug)]
+struct RttActor {
+    /// Stream of connection type changes.
+    connection_events: stream_group::Keyed<ConnectionTypeStream>,
+    /// References to the connections.
+    ///
+    /// These are weak references so not to keep the connections alive.  The key allows
+    /// removing the corresponding stream from `conn_type_changes`.
+    /// The boolean is an indiciator of whether this connection was direct before.
+    /// This helps establish metrics on number of connections that became direct.
+    connections: HashMap<stream_group::Key, (quinn::WeakConnectionHandle, NodeId, bool)>,
+    /// A way to notify the main actor loop to run over.
+    ///
+    /// E.g. when a new stream was added.
+    tick: Notify,
+}
+
+impl RttActor {
+    /// Runs the actor main loop.
+    ///
+    /// The main loop will finish when the sender is dropped.
+    async fn run(&mut self, mut msg_rx: mpsc::Receiver<RttMessage>) {
+        let mut cleanup_interval = tokio::time::interval(Duration::from_secs(5));
+        cleanup_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
+        loop {
+            tokio::select! {
+                biased;
+                msg = msg_rx.recv() => {
+                    match msg {
+                        Some(msg) => self.handle_msg(msg),
+                        None => break,
+                    }
+                }
+                item = self.connection_events.next(), if !self.connection_events.is_empty() => {
+                    self.do_reset_rtt(item);
+                }
+                _ = cleanup_interval.tick() => self.do_connections_cleanup(),
+                () = self.tick.notified() => continue,
+            }
+        }
+        debug!("rtt-actor finished");
+    }
+
+    /// Handle actor messages.
+    fn handle_msg(&mut self, msg: RttMessage) {
+        match msg {
+            RttMessage::NewConnection {
+                connection,
+                conn_type_changes,
+                node_id,
+            } => {
+                self.handle_new_connection(connection, conn_type_changes, node_id);
+            }
+        }
+    }
+
+    /// Handles the new connection message.
+    fn handle_new_connection(
+        &mut self,
+        connection: quinn::WeakConnectionHandle,
+        conn_type_changes: ConnectionTypeStream,
+        node_id: NodeId,
+    ) {
+        let key = self.connection_events.insert(conn_type_changes);
+        self.connections.insert(key, (connection, node_id, false));
+        self.tick.notify_one();
+        inc!(MagicsockMetrics, connection_handshake_success);
+    }
+
+    /// Performs the congestion controller reset for a magic socket path change.
+    ///
+    /// Regardless of which kind of path we are changed to, the congestion controller needs
+    /// resetting.  Even when switching to mixed we should reset the state as e.g. switching
+    /// from direct to mixed back to direct should be a rare exception and is a bug if this
+    /// happens commonly.
+    fn do_reset_rtt(&mut self, item: Option<(stream_group::Key, ConnectionType)>) {
+        match item {
+            Some((key, new_conn_type)) => match self.connections.get_mut(&key) {
+                Some((handle, node_id, was_direct_before)) => {
+                    if handle.network_path_changed() {
+                        debug!(
+                            node_id = %node_id.fmt_short(),
+                            new_type = ?new_conn_type,
+                            "Congestion controller state reset",
+                        );
+                        if !*was_direct_before && matches!(new_conn_type, ConnectionType::Direct(_))
+                        {
+                            *was_direct_before = true;
+                            inc!(MagicsockMetrics, connection_became_direct);
+                        }
+                    } else {
+                        debug!(
+                            node_id = %node_id.fmt_short(),
+                            "removing dropped connection",
+                        );
+                        self.connection_events.remove(key);
+                    }
+                }
+                None => error!("No connection found for stream item"),
+            },
+            None => {
+                trace!("No more connections");
+            }
+        }
+    }
+
+    /// Performs cleanup for closed connection.
+    fn do_connections_cleanup(&mut self) {
+        for (key, (handle, node_id, _)) in self.connections.iter() {
+            if !handle.is_alive() {
+                trace!(node_id = %node_id.fmt_short(), "removing stale connection");
+                self.connection_events.remove(*key);
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[tokio::test]
+    async fn test_actor_mspc_close() {
+        let mut actor = RttActor {
+            connection_events: stream_group::StreamGroup::new().keyed(),
+            connections: HashMap::new(),
+            tick: Notify::new(),
+        };
+        let (msg_tx, msg_rx) = mpsc::channel(16);
+        let handle = tokio::spawn(async move {
+            actor.run(msg_rx).await;
+        });
+
+        // Dropping the msg_tx should stop the actor
+        drop(msg_tx);
+
+        let task_res = tokio::time::timeout(Duration::from_secs(5), handle)
+            .await
+            .expect("timeout - actor did not finish");
+        assert!(task_res.is_ok());
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/lib.rs.html b/pr/2992/docs/src/iroh/lib.rs.html new file mode 100644 index 0000000000..0716a3791e --- /dev/null +++ b/pr/2992/docs/src/iroh/lib.rs.html @@ -0,0 +1,521 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+
//! 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 node is created and controlled by the [`Endpoint`], e.g. connecting to
+//! another node:
+//!
+//! ```no_run
+//! # use iroh::{Endpoint, NodeAddr};
+//! # async fn wrapper() -> testresult::TestResult {
+//! let addr: NodeAddr = todo!();
+//! let ep = Endpoint::builder().bind().await?;
+//! let conn = ep.connect(addr, b"my-alpn").await?;
+//! let mut send_stream = conn.open_uni().await?;
+//! send_stream.write_all(b"msg").await?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! The other node can accept incoming connections using the [`Endpoint`] as well:
+//!
+//! ```no_run
+//! # use iroh::{Endpoint, NodeAddr};
+//! # async fn wrapper() -> testresult::TestResult {
+//! let ep = Endpoint::builder()
+//!     .alpns(vec![b"my-alpn".to_vec()])
+//!     .bind()
+//!     .await?;
+//! let conn = ep.accept().await.ok_or("err")?.await?;
+//! let mut recv_stream = conn.accept_uni().await?;
+//! let mut buf = [0u8; 3];
+//! recv_stream.read_exact(&mut buf).await?;
+//! # 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 nodes 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 nodes want to connect they
+//! first establish connection via this home relay.  As soon as connection between the two
+//! nodes 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 nodes can be reached directly, connectivity can also be
+//! established without involving a Relay server.  This is done by using the node'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 node has a
+//! unique [`SecretKey`] used to authenticate and encrypt the connection.  When an iroh
+//! node 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 node it is also known as
+//! the [`NodeId`].  As encryption is an integral part of TLS as used in QUIC this
+//! [`NodeId`] is always a required parameter to establish a connection.
+//!
+//! When accepting connections the peer's [`NodeId`] 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 nodes are always reachable.  They accept
+//! **encrypted** traffic for iroh nodes which are connected to them, forwarding it to
+//! the correct destination based on the [`NodeId`] only.  Since nodes only send encrypted
+//! traffic, the Relay servers can not decode any traffic for other iroh nodes 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 nodes, Relay servers
+//! provide some functions to assist in [hole punching].  They have various services to help
+//! nodes understand their own network situation.  This includes offering a [STUN] 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 node is managed using the [`Endpoint`] and this is used to create or accept
+//! connections to other nodes.  To establish a connection to an iroh node you need to
+//! know three pieces of information:
+//!
+//! - The [`NodeId`] 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>
+//!
+//! ## Node Discovery
+//!
+//! The need to know the [`RelayUrl`] *or* some direct addresses in addition to the
+//! [`NodeId`] to connect to an iroh node can be an obstacle.  To address this the
+//! [`endpoint::Builder`] allows to configure a [`discovery`] service.
+//!
+//! The [`DnsDiscovery`] service is a discovery service which will publish the [`RelayUrl`]
+//! and direct addresses to a service publishing those as DNS records.  To connect it looks
+//! up the [`NodeId`] in the DNS system to find the addressing details.  This enables
+//! connecting using only the [`NodeId`] which is often more convenient and resilient.
+//!
+//! See [the discovery module] for more details.
+//!
+//!
+//! # Examples
+//!
+//! The central struct is the [`Endpoint`], which allows you to connect to other nodes:
+//!
+//! ```no_run
+//! use anyhow::Result;
+//! use iroh::{Endpoint, NodeAddr};
+//!
+//! async fn connect(addr: NodeAddr) -> Result<()> {
+//!     // The Endpoint is the central object that manages an iroh node.
+//!     let ep = Endpoint::builder().bind().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?;
+//!     send_stream.write_all(b"hello").await?;
+//!     send_stream.finish()?;
+//!     let _msg = recv_stream.read_to_end(10).await?;
+//!
+//!     // 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
+//! use anyhow::{Context, Result};
+//! use futures_lite::StreamExt;
+//! use iroh::{ticket::NodeTicket, Endpoint, NodeAddr};
+//!
+//! async fn accept() -> Result<()> {
+//!     // To accept connections at least one ALPN must be configured.
+//!     let ep = Endpoint::builder()
+//!         .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?;
+//!     let (mut send_stream, mut recv_stream) = conn.accept_bi().await?;
+//!     let _msg = recv_stream.read_to_end(10).await?;
+//!     send_stream.write_all(b"world").await?;
+//!     send_stream.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://quickwg.org
+//! [bi-directional streams]: crate::endpoint::Connection::open_bi
+//! [`NodeTicket`]: crate::ticket::NodeTicket
+//! [hole punching]: https://en.wikipedia.org/wiki/Hole_punching_(networking)
+//! [socket addresses]: https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html
+//! [STUN]: https://en.wikipedia.org/wiki/STUN
+//! [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
+//! [HTTP3]: https://en.wikipedia.org/wiki/HTTP/3
+//! [`SecretKey`]: crate::key::SecretKey
+//! [`PublicKey`]: crate::key::PublicKey
+//! [`RelayUrl`]: crate::relay::RelayUrl
+//! [`discovery`]: crate::endpoint::Builder::discovery
+//! [`DnsDiscovery`]: crate::discovery::dns::DnsDiscovery
+//! [number 0]: https://n0.computer
+//! [`RelayMode::Default`]: crate::RelayMode::Default
+//! [the discovery module]: crate::discovery
+//! [`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(iroh_docsrs, feature(doc_cfg))]
+
+pub mod defaults;
+pub mod dialer;
+mod disco;
+pub mod discovery;
+pub mod dns;
+pub mod endpoint;
+mod magicsock;
+pub mod metrics;
+pub mod protocol;
+pub mod tls;
+
+pub(crate) mod util;
+
+pub use endpoint::{AddrInfo, AddrInfoOptions, Endpoint, NodeAddr, RelayMode};
+pub use iroh_base::{
+    hash, key,
+    key::NodeId,
+    relay_map::{RelayMap, RelayNode, RelayUrl},
+    ticket,
+};
+pub use iroh_relay as relay;
+
+#[cfg(any(test, feature = "test-utils"))]
+#[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+pub mod test_utils;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock.rs.html b/pr/2992/docs/src/iroh/magicsock.rs.html new file mode 100644 index 0000000000..661e9111ce --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock.rs.html @@ -0,0 +1,7839 @@ +magicsock.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+
//! Implements a socket that can change its communication path while in use, actively searching for the best way to communicate.
+//!
+//! Based on tailscale/wgengine/magicsock
+//!
+//! ### `DEV_RELAY_ONLY` env var:
+//! When present at *compile time*, this env var will force all packets
+//! to be sent over the relay connection, regardless of whether or
+//! not we have a direct UDP address for the given node.
+//!
+//! The intended use is for testing the relay protocol inside the MagicSock
+//! to ensure that we can rely on the relay to send packets when two nodes
+//! are unable to find direct UDP connections to each other.
+//!
+//! This also prevent this node from attempting to hole punch and prevents it
+//! from responding to any hole punching attempts. This node will still,
+//! however, read any packets that come off the UDP sockets.
+
+use std::{
+    collections::{BTreeMap, BTreeSet, HashMap},
+    fmt::Display,
+    io,
+    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
+    pin::Pin,
+    sync::{
+        atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering},
+        Arc, RwLock,
+    },
+    task::{Context, Poll, Waker},
+    time::{Duration, Instant},
+};
+
+use anyhow::{anyhow, Context as _, Result};
+use bytes::Bytes;
+use futures_lite::{FutureExt, Stream, StreamExt};
+use futures_util::stream::BoxStream;
+use iroh_base::key::NodeId;
+use iroh_metrics::{inc, inc_by};
+use iroh_relay::protos::stun;
+use netwatch::{interfaces, ip::LocalAddresses, netmon, UdpSocket};
+use quinn::AsyncUdpSocket;
+use rand::{seq::SliceRandom, Rng, SeedableRng};
+use smallvec::{smallvec, SmallVec};
+use tokio::{
+    sync::{self, mpsc, Mutex},
+    task::JoinSet,
+    time,
+};
+use tokio_util::sync::CancellationToken;
+use tracing::{
+    debug, error, error_span, event, info, info_span, instrument, trace, trace_span, warn,
+    Instrument, Level, Span,
+};
+use url::Url;
+use watchable::Watchable;
+
+use self::{
+    metrics::Metrics as MagicsockMetrics,
+    node_map::{NodeMap, PingAction, PingRole, SendPing},
+    relay_actor::{RelayActor, RelayActorMessage, RelayReadResult},
+    udp_conn::UdpConn,
+};
+use crate::{
+    defaults::timeouts::NET_REPORT_TIMEOUT,
+    disco::{self, CallMeMaybe, SendAddr},
+    discovery::{Discovery, DiscoveryItem},
+    dns::DnsResolver,
+    endpoint::NodeAddr,
+    key::{PublicKey, SecretKey, SharedSecret},
+    AddrInfo, RelayMap, RelayUrl,
+};
+
+mod metrics;
+mod node_map;
+mod relay_actor;
+mod timer;
+mod udp_conn;
+
+pub use node_map::Source;
+
+pub(super) use self::timer::Timer;
+pub use self::{
+    metrics::Metrics,
+    node_map::{ConnectionType, ConnectionTypeStream, ControlMsg, DirectAddrInfo, RemoteInfo},
+};
+
+/// How long we consider a STUN-derived endpoint valid for. UDP NAT mappings typically
+/// expire at 30 seconds, so this is a few seconds shy of that.
+const ENDPOINTS_FRESH_ENOUGH_DURATION: Duration = Duration::from_secs(27);
+
+const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
+
+/// Contains options for `MagicSock::listen`.
+#[derive(derive_more::Debug)]
+pub(crate) struct Options {
+    /// The IPv4 address to listen on.
+    ///
+    /// If set to `None` it will choose a random port and listen on `0.0.0.0:0`.
+    pub(crate) addr_v4: Option<SocketAddrV4>,
+    /// The IPv6 address to listen on.
+    ///
+    /// If set to `None` it will choose a random port and listen on `[::]:0`.
+    pub(crate) addr_v6: Option<SocketAddrV6>,
+
+    /// Secret key for this node.
+    pub(crate) secret_key: SecretKey,
+
+    /// The [`RelayMap`] to use, leave empty to not use a relay server.
+    pub(crate) relay_map: RelayMap,
+
+    /// An optional [`NodeMap`], to restore information about nodes.
+    pub(crate) node_map: Option<Vec<NodeAddr>>,
+
+    /// Optional node discovery mechanism.
+    pub(crate) discovery: Option<Box<dyn Discovery>>,
+
+    /// A DNS resolver to use for resolving relay URLs.
+    ///
+    /// You can use [`crate::dns::default_resolver`] for a resolver that uses the system's DNS
+    /// configuration.
+    pub(crate) dns_resolver: DnsResolver,
+
+    /// Proxy configuration.
+    pub(crate) proxy_url: Option<Url>,
+
+    /// Skip verification of SSL certificates from relay servers
+    ///
+    /// May only be used in tests.
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    pub(crate) insecure_skip_relay_cert_verify: bool,
+}
+
+impl Default for Options {
+    fn default() -> Self {
+        Options {
+            addr_v4: None,
+            addr_v6: None,
+            secret_key: SecretKey::generate(),
+            relay_map: RelayMap::empty(),
+            node_map: None,
+            discovery: None,
+            proxy_url: None,
+            dns_resolver: crate::dns::default_resolver().clone(),
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_relay_cert_verify: false,
+        }
+    }
+}
+
+/// Contents of a relay message. Use a SmallVec to avoid allocations for the very
+/// common case of a single packet.
+type RelayContents = SmallVec<[Bytes; 1]>;
+
+/// Handle for [`MagicSock`].
+///
+/// Dereferences to [`MagicSock`], and handles closing.
+#[derive(Clone, Debug, derive_more::Deref)]
+pub(crate) struct Handle {
+    #[deref(forward)]
+    msock: Arc<MagicSock>,
+    // Empty when closed
+    actor_tasks: Arc<Mutex<JoinSet<()>>>,
+}
+
+/// Iroh connectivity layer.
+///
+/// This is responsible for routing packets to nodes based on node IDs, it will initially
+/// route packets via a relay and transparently try and establish a node-to-node
+/// connection and upgrade to it.  It will also keep looking for better connections as the
+/// network details of both nodes change.
+///
+/// It is usually only necessary to use a single [`MagicSock`] instance in an application, it
+/// means any QUIC endpoints on top will be sharing as much information about nodes as
+/// possible.
+#[derive(derive_more::Debug)]
+pub(crate) struct MagicSock {
+    actor_sender: mpsc::Sender<ActorMessage>,
+    relay_actor_sender: mpsc::Sender<RelayActorMessage>,
+    /// String representation of the node_id of this node.
+    me: String,
+    /// Proxy
+    proxy_url: Option<Url>,
+
+    /// Used for receiving relay messages.
+    relay_recv_receiver: parking_lot::Mutex<mpsc::Receiver<RelayRecvResult>>,
+    /// Stores wakers, to be called when relay_recv_ch receives new data.
+    network_recv_wakers: parking_lot::Mutex<Option<Waker>>,
+    network_send_wakers: Arc<parking_lot::Mutex<Option<Waker>>>,
+
+    /// The DNS resolver to be used in this magicsock.
+    dns_resolver: DnsResolver,
+
+    /// Key for this node.
+    secret_key: SecretKey,
+
+    /// Cached version of the Ipv4 and Ipv6 addrs of the current connection.
+    local_addrs: std::sync::RwLock<(SocketAddr, Option<SocketAddr>)>,
+
+    /// Preferred port from `Options::port`; 0 means auto.
+    port: AtomicU16,
+
+    /// Close is in progress (or done)
+    closing: AtomicBool,
+    /// Close was called.
+    closed: AtomicBool,
+    /// If the last net_report report, reports IPv6 to be available.
+    ipv6_reported: Arc<AtomicBool>,
+
+    /// None (or zero nodes) means relay is disabled.
+    relay_map: RelayMap,
+    /// Nearest relay node ID; 0 means none/unknown.
+    my_relay: Watchable<Option<RelayUrl>>,
+    /// Tracks the networkmap node entity for each node discovery key.
+    node_map: NodeMap,
+    /// UDP IPv4 socket
+    pconn4: UdpConn,
+    /// UDP IPv6 socket
+    pconn6: Option<UdpConn>,
+    /// NetReport client
+    net_reporter: net_report::Addr,
+    /// The state for an active DiscoKey.
+    disco_secrets: DiscoSecrets,
+
+    /// UDP disco (ping) queue
+    udp_disco_sender: mpsc::Sender<(SocketAddr, PublicKey, disco::Message)>,
+
+    /// Optional discovery service
+    discovery: Option<Box<dyn Discovery>>,
+
+    /// Our discovered direct addresses.
+    direct_addrs: DiscoveredDirectAddrs,
+
+    /// List of CallMeMaybe disco messages that should be sent out after the next endpoint update
+    /// completes
+    pending_call_me_maybes: parking_lot::Mutex<HashMap<PublicKey, RelayUrl>>,
+
+    /// Indicates the direct addr update state.
+    direct_addr_update_state: DirectAddrUpdateState,
+
+    /// Skip verification of SSL certificates from relay servers
+    ///
+    /// May only be used in tests.
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    insecure_skip_relay_cert_verify: bool,
+}
+
+impl MagicSock {
+    /// Creates a magic [`MagicSock`] listening on [`Options::addr_v4`] and [`Options::addr_v6`].
+    pub(crate) async fn spawn(opts: Options) -> Result<Handle> {
+        Handle::new(opts).await
+    }
+
+    /// Returns the relay node we are connected to, that has the best latency.
+    ///
+    /// If `None`, then we are not connected to any relay nodes.
+    pub(crate) fn my_relay(&self) -> Option<RelayUrl> {
+        self.my_relay.get()
+    }
+
+    /// Get the current proxy configuration.
+    pub(crate) fn proxy_url(&self) -> Option<&Url> {
+        self.proxy_url.as_ref()
+    }
+
+    /// Sets the relay node with the best latency.
+    ///
+    /// If we are not connected to any relay nodes, set this to `None`.
+    fn set_my_relay(&self, my_relay: Option<RelayUrl>) -> Option<RelayUrl> {
+        self.my_relay.replace(my_relay)
+    }
+
+    fn is_closing(&self) -> bool {
+        self.closing.load(Ordering::Relaxed)
+    }
+
+    pub(crate) fn is_closed(&self) -> bool {
+        self.closed.load(Ordering::SeqCst)
+    }
+
+    fn public_key(&self) -> PublicKey {
+        self.secret_key.public()
+    }
+
+    /// Get the cached version of the Ipv4 and Ipv6 addrs of the current connection.
+    pub(crate) fn local_addr(&self) -> (SocketAddr, Option<SocketAddr>) {
+        *self.local_addrs.read().expect("not poisoned")
+    }
+
+    /// Returns `true` if we have at least one candidate address where we can send packets to.
+    pub(crate) fn has_send_address(&self, node_key: PublicKey) -> bool {
+        self.remote_info(node_key)
+            .map(|info| info.has_send_address())
+            .unwrap_or(false)
+    }
+
+    /// Return the [`RemoteInfo`]s of all nodes in the node map.
+    pub(crate) fn list_remote_infos(&self) -> Vec<RemoteInfo> {
+        self.node_map.list_remote_infos(Instant::now())
+    }
+
+    /// Return the [`RemoteInfo`] for a single node in the node map.
+    pub(crate) fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo> {
+        self.node_map.remote_info(node_id)
+    }
+
+    /// Returns the direct addresses as a stream.
+    ///
+    /// The [`MagicSock`] continuously monitors the direct addresses, the network addresses
+    /// it might be able to be contacted on, for changes.  Whenever changes are detected
+    /// this stream will yield a new list of addresses.
+    ///
+    /// Upon the first creation on the [`MagicSock`] it may not yet have completed a first
+    /// direct addresses discovery, in this case the first item of the stream will not be
+    /// immediately available.  Once this first set of direct addresses are discovered the
+    /// stream will always return the first set of addresses immediately, which are the most
+    /// recently discovered addresses.
+    ///
+    /// To get the current direct addresses, drop the stream after the first item was
+    /// received.
+    pub(crate) fn direct_addresses(&self) -> DirectAddrsStream {
+        self.direct_addrs.updates_stream()
+    }
+
+    /// Watch for changes to the home relay.
+    ///
+    /// Note that this can be used to wait for the initial home relay to be known. If the home
+    /// relay is known at this point, it will be the first item in the stream.
+    pub(crate) fn watch_home_relay(&self) -> impl Stream<Item = RelayUrl> {
+        let current = futures_lite::stream::iter(self.my_relay());
+        let changes = self
+            .my_relay
+            .watch()
+            .into_stream()
+            .filter_map(|maybe_relay| maybe_relay);
+        current.chain(changes)
+    }
+
+    /// Returns a stream that reports the [`ConnectionType`] we have to the
+    /// given `node_id`.
+    ///
+    /// The `NodeMap` continuously monitors the `node_id`'s endpoint for
+    /// [`ConnectionType`] changes, and sends the latest [`ConnectionType`]
+    /// on the stream.
+    ///
+    /// The current [`ConnectionType`] will the the initial entry on the stream.
+    ///
+    /// # Errors
+    ///
+    /// Will return an error if there is no address information known about the
+    /// given `node_id`.
+    pub(crate) fn conn_type_stream(&self, node_id: NodeId) -> Result<ConnectionTypeStream> {
+        self.node_map.conn_type_stream(node_id)
+    }
+
+    /// Returns the socket address which can be used by the QUIC layer to dial this node.
+    pub(crate) fn get_mapping_addr(&self, node_id: NodeId) -> Option<QuicMappedAddr> {
+        self.node_map.get_quic_mapped_addr_for_node_key(node_id)
+    }
+
+    /// Add addresses for a node to the magic socket's addresbook.
+    #[instrument(skip_all, fields(me = %self.me))]
+    pub fn add_node_addr(&self, mut addr: NodeAddr, source: node_map::Source) -> Result<()> {
+        let mut pruned = 0;
+        for my_addr in self.direct_addrs.sockaddrs() {
+            if addr.info.direct_addresses.remove(&my_addr) {
+                warn!( node_id=addr.node_id.fmt_short(), %my_addr, %source, "not adding our addr for node");
+                pruned += 1;
+            }
+        }
+        if !addr.info.is_empty() {
+            self.node_map.add_node_addr(addr, source);
+            Ok(())
+        } else if pruned != 0 {
+            Err(anyhow::anyhow!(
+                "empty addressing info, {pruned} direct addresses have been pruned"
+            ))
+        } else {
+            Err(anyhow::anyhow!("empty addressing info"))
+        }
+    }
+
+    /// Stores a new set of direct addresses.
+    ///
+    /// If the direct addresses have changed from the previous set, they are published to
+    /// discovery.
+    pub(super) fn store_direct_addresses(&self, addrs: BTreeSet<DirectAddr>) {
+        let updated = self.direct_addrs.update(addrs);
+        if updated {
+            self.node_map
+                .on_direct_addr_discovered(self.direct_addrs.sockaddrs());
+            self.publish_my_addr();
+        }
+    }
+
+    /// Get a reference to the DNS resolver used in this [`MagicSock`].
+    pub(crate) fn dns_resolver(&self) -> &DnsResolver {
+        &self.dns_resolver
+    }
+
+    /// Reference to optional discovery service
+    pub(crate) fn discovery(&self) -> Option<&dyn Discovery> {
+        self.discovery.as_ref().map(Box::as_ref)
+    }
+
+    /// Call to notify the system of potential network changes.
+    pub(crate) async fn network_change(&self) {
+        self.actor_sender
+            .send(ActorMessage::NetworkChange)
+            .await
+            .ok();
+    }
+
+    #[cfg(test)]
+    async fn force_network_change(&self, is_major: bool) {
+        self.actor_sender
+            .send(ActorMessage::ForceNetworkChange(is_major))
+            .await
+            .ok();
+    }
+
+    #[cfg_attr(windows, allow(dead_code))]
+    fn normalized_local_addr(&self) -> io::Result<SocketAddr> {
+        let (v4, v6) = self.local_addr();
+        let addr = if let Some(v6) = v6 { v6 } else { v4 };
+        Ok(addr)
+    }
+
+    fn create_io_poller(&self) -> Pin<Box<dyn quinn::UdpPoller>> {
+        // To do this properly the MagicSock would need a registry of pollers.  For each
+        // node we would look up the poller or create one.  Then on each try_send we can
+        // look up the correct poller and configure it to poll the paths it needs.
+        //
+        // Note however that the current quinn impl calls UdpPoller::poll_writable()
+        // **before** it calls try_send(), as opposed to how it is documented.  That is a
+        // problem as we would not yet know the path that needs to be polled.  To avoid such
+        // ambiguity the API could be changed to a .poll_send(&self, cx: &mut Context,
+        // io_poller: Pin<&mut dyn UdpPoller>, transmit: &Transmit) -> Poll<io::Result<()>>
+        // instead of the existing .try_send() because then we would have control over this.
+        //
+        // Right now however we have one single poller behaving the same for each
+        // connection.  It checks all paths and returns Poll::Ready as soon as any path is
+        // ready.
+        let ipv4_poller = self.pconn4.create_io_poller();
+        let ipv6_poller = self.pconn6.as_ref().map(|sock| sock.create_io_poller());
+        let relay_sender = self.relay_actor_sender.clone();
+        Box::pin(IoPoller {
+            ipv4_poller,
+            ipv6_poller,
+            relay_sender,
+            relay_send_waker: self.network_send_wakers.clone(),
+        })
+    }
+
+    /// Implementation for AsyncUdpSocket::try_send
+    #[instrument(skip_all)]
+    fn try_send(&self, transmit: &quinn_udp::Transmit) -> io::Result<()> {
+        inc_by!(MagicsockMetrics, send_data, transmit.contents.len() as _);
+
+        if self.is_closed() {
+            inc_by!(
+                MagicsockMetrics,
+                send_data_network_down,
+                transmit.contents.len() as _
+            );
+            return Err(io::Error::new(
+                io::ErrorKind::NotConnected,
+                "connection closed",
+            ));
+        }
+
+        let dest = QuicMappedAddr(transmit.destination);
+        trace!(
+            dst = %dest,
+            src = ?transmit.src_ip,
+            len = %transmit.contents.len(),
+            "sending",
+        );
+        let mut transmit = transmit.clone();
+        match self
+            .node_map
+            .get_send_addrs(dest, self.ipv6_reported.load(Ordering::Relaxed))
+        {
+            Some((node_id, udp_addr, relay_url, msgs)) => {
+                let mut pings_sent = false;
+                // If we have pings to send, we *have* to send them out first.
+                if !msgs.is_empty() {
+                    if let Err(err) = self.try_send_ping_actions(msgs) {
+                        warn!(
+                            node = %node_id.fmt_short(),
+                            "failed to handle ping actions: {err:#}",
+                        );
+                    }
+                    pings_sent = true;
+                }
+
+                let mut udp_sent = false;
+                let mut udp_error = None;
+                let mut relay_sent = false;
+                let mut relay_error = None;
+
+                // send udp
+                if let Some(addr) = udp_addr {
+                    // rewrite target address
+                    transmit.destination = addr;
+                    match self.try_send_udp(addr, &transmit) {
+                        Ok(()) => {
+                            trace!(node = %node_id.fmt_short(), dst = %addr,
+                                   "sent transmit over UDP");
+                            udp_sent = true;
+                        }
+                        Err(err) => {
+                            error!(node = %node_id.fmt_short(), dst = %addr,
+                                   "failed to send udp: {err:#}");
+                            udp_error = Some(err);
+                        }
+                    }
+                }
+
+                // send relay
+                if let Some(ref relay_url) = relay_url {
+                    match self.try_send_relay(relay_url, node_id, split_packets(&transmit)) {
+                        Ok(()) => {
+                            relay_sent = true;
+                        }
+                        Err(err) => {
+                            relay_error = Some(err);
+                        }
+                    }
+                }
+
+                let udp_pending = udp_error
+                    .as_ref()
+                    .map(|err| err.kind() == io::ErrorKind::WouldBlock)
+                    .unwrap_or_default();
+                let relay_pending = relay_error
+                    .as_ref()
+                    .map(|err| err.kind() == io::ErrorKind::WouldBlock)
+                    .unwrap_or_default();
+                if udp_pending && relay_pending {
+                    // Handle backpressure.
+                    Err(io::Error::new(io::ErrorKind::WouldBlock, "pending"))
+                } else {
+                    if relay_sent || udp_sent {
+                        trace!(
+                            node = %node_id.fmt_short(),
+                            send_udp = ?udp_addr,
+                            send_relay = ?relay_url,
+                            "sent transmit",
+                        );
+                    } else if !pings_sent {
+                        // Returning Ok here means we let QUIC handle a timeout for a lost
+                        // packet, same would happen if we returned any errors.  The
+                        // philosophy of quinn-udp is that a UDP connection could come back
+                        // at any time so these errors should be treated as transient and
+                        // are just timeouts.  Hence we opt for returning Ok.  See
+                        // test_try_send_no_udp_addr_or_relay_url to explore this further.
+                        error!(
+                            node = %node_id.fmt_short(),
+                            "no UDP or relay paths available for node",
+                        );
+                    }
+                    Ok(())
+                }
+            }
+            None => {
+                error!(%dest, "no NodeState for mapped address");
+                // Returning Ok here means we let QUIC timeout.  Returning WouldBlock
+                // triggers a hot loop.  Returning an error would immediately fail a
+                // connection.  The philosophy of quinn-udp is that a UDP connection could
+                // come back at any time or missing should be transient so chooses to let
+                // these kind of errors time out.  See test_try_send_no_send_addr to try
+                // this out.
+                Ok(())
+            }
+        }
+    }
+
+    fn try_send_relay(
+        &self,
+        url: &RelayUrl,
+        node: NodeId,
+        contents: RelayContents,
+    ) -> io::Result<()> {
+        trace!(
+            node = %node.fmt_short(),
+            relay_url = %url,
+            count = contents.len(),
+            len = contents.iter().map(|c| c.len()).sum::<usize>(),
+            "send relay",
+        );
+        let msg = RelayActorMessage::Send {
+            url: url.clone(),
+            contents,
+            remote_node: node,
+        };
+        match self.relay_actor_sender.try_send(msg) {
+            Ok(_) => {
+                trace!(node = %node.fmt_short(), relay_url = %url,
+                       "send relay: message queued");
+                Ok(())
+            }
+            Err(mpsc::error::TrySendError::Closed(_)) => {
+                warn!(node = %node.fmt_short(), relay_url = %url,
+                      "send relay: message dropped, channel to actor is closed");
+                Err(io::Error::new(
+                    io::ErrorKind::ConnectionReset,
+                    "channel to actor is closed",
+                ))
+            }
+            Err(mpsc::error::TrySendError::Full(_)) => {
+                warn!(node = %node.fmt_short(), relay_url = %url,
+                      "send relay: message dropped, channel to actor is full");
+                Err(io::Error::new(
+                    io::ErrorKind::WouldBlock,
+                    "channel to actor is full",
+                ))
+            }
+        }
+    }
+
+    fn try_send_udp(&self, addr: SocketAddr, transmit: &quinn_udp::Transmit) -> io::Result<()> {
+        let conn = self.conn_for_addr(addr)?;
+        conn.try_send(transmit)?;
+        let total_bytes: u64 = transmit.contents.len() as u64;
+        if addr.is_ipv6() {
+            inc_by!(MagicsockMetrics, send_ipv6, total_bytes);
+        } else {
+            inc_by!(MagicsockMetrics, send_ipv4, total_bytes);
+        }
+        Ok(())
+    }
+
+    fn conn_for_addr(&self, addr: SocketAddr) -> io::Result<&UdpConn> {
+        let sock = match addr {
+            SocketAddr::V4(_) => &self.pconn4,
+            SocketAddr::V6(_) => self
+                .pconn6
+                .as_ref()
+                .ok_or(io::Error::new(io::ErrorKind::Other, "no IPv6 connection"))?,
+        };
+        Ok(sock)
+    }
+
+    /// NOTE: Receiving on a [`Self::closed`] socket will return [`Poll::Pending`] indefinitely.
+    #[instrument(skip_all)]
+    fn poll_recv(
+        &self,
+        cx: &mut Context,
+        bufs: &mut [io::IoSliceMut<'_>],
+        metas: &mut [quinn_udp::RecvMeta],
+    ) -> Poll<io::Result<usize>> {
+        // FIXME: currently ipv4 load results in ipv6 traffic being ignored
+        debug_assert_eq!(bufs.len(), metas.len(), "non matching bufs & metas");
+        if self.is_closed() {
+            return Poll::Pending;
+        }
+
+        // order of polling is: UDPv4, UDPv6, relay
+        let (msgs, from_ipv4) = match self.pconn4.poll_recv(cx, bufs, metas)? {
+            Poll::Pending | Poll::Ready(0) => match &self.pconn6 {
+                Some(conn) => match conn.poll_recv(cx, bufs, metas)? {
+                    Poll::Pending | Poll::Ready(0) => {
+                        return self.poll_recv_relay(cx, bufs, metas);
+                    }
+                    Poll::Ready(n) => (n, false),
+                },
+                None => {
+                    return self.poll_recv_relay(cx, bufs, metas);
+                }
+            },
+            Poll::Ready(n) => (n, true),
+        };
+
+        // Adding the IP address we received something on results in Quinn using this
+        // address on the send path to send from.  However we let Quinn use a
+        // QuicMappedAddress, not a real address.  So we used to substitute our bind address
+        // here so that Quinn would send on the right address.  But that would sometimes
+        // result in the wrong address family and Windows trips up on that.
+        //
+        // What should be done is that this dst_ip from the RecvMeta is stored in the
+        // NodeState/PathState.  Then on the send path it should be retrieved from the
+        // NodeState/PathSate together with the send address and substituted at send time.
+        // This is relevant for IPv6 link-local addresses where the OS otherwise does not
+        // know which intervace to send from.
+        #[cfg(not(windows))]
+        let dst_ip = self.normalized_local_addr().ok().map(|addr| addr.ip());
+        // Reasoning for this here:
+        // https://github.com/n0-computer/iroh/pull/2595#issuecomment-2290947319
+        #[cfg(windows)]
+        let dst_ip = None;
+
+        let mut quic_packets_total = 0;
+
+        for (meta, buf) in metas.iter_mut().zip(bufs.iter_mut()).take(msgs) {
+            let mut is_quic = false;
+            let mut quic_packets_count = 0;
+            if meta.len > meta.stride {
+                trace!(%meta.len, %meta.stride, "GRO datagram received");
+                inc!(MagicsockMetrics, recv_gro_datagrams);
+            }
+
+            // find disco and stun packets and forward them to the actor
+            for packet in buf[..meta.len].chunks_mut(meta.stride) {
+                if packet.len() < meta.stride {
+                    trace!(
+                        len = %packet.len(),
+                        %meta.stride,
+                        "Last GRO datagram smaller than stride",
+                    );
+                }
+
+                let packet_is_quic = if stun::is(packet) {
+                    trace!(src = %meta.addr, len = %meta.stride, "UDP recv: stun packet");
+                    let packet2 = Bytes::copy_from_slice(packet);
+                    self.net_reporter.receive_stun_packet(packet2, meta.addr);
+                    false
+                } else if let Some((sender, sealed_box)) = disco::source_and_box(packet) {
+                    // Disco?
+                    trace!(src = %meta.addr, len = %meta.stride, "UDP recv: disco packet");
+                    self.handle_disco_message(
+                        sender,
+                        sealed_box,
+                        DiscoMessageSource::Udp(meta.addr),
+                    );
+                    false
+                } else {
+                    trace!(src = %meta.addr, len = %meta.stride, "UDP recv: quic packet");
+                    if from_ipv4 {
+                        inc_by!(MagicsockMetrics, recv_data_ipv4, packet.len() as _);
+                    } else {
+                        inc_by!(MagicsockMetrics, recv_data_ipv6, packet.len() as _);
+                    }
+                    true
+                };
+
+                if packet_is_quic {
+                    quic_packets_count += 1;
+                    is_quic = true;
+                } else {
+                    // overwrite the first byte of the packets with zero.
+                    // this makes quinn reliably and quickly ignore the packet as long as
+                    // [`quinn::EndpointConfig::grease_quic_bit`] is set to `false`
+                    // (which we always do in Endpoint::bind).
+                    packet[0] = 0u8;
+                }
+            }
+
+            if is_quic {
+                // remap addr
+                match self.node_map.receive_udp(meta.addr) {
+                    None => {
+                        warn!(src = ?meta.addr, count = %quic_packets_count, len = meta.len, "UDP recv quic packets: no node state found, skipping");
+                        // if we have no node state for the from addr, set len to 0 to make quinn skip the buf completely.
+                        meta.len = 0;
+                    }
+                    Some((node_id, quic_mapped_addr)) => {
+                        trace!(src = ?meta.addr, node = %node_id.fmt_short(), count = %quic_packets_count, len = meta.len, "UDP recv quic packets");
+                        quic_packets_total += quic_packets_count;
+                        meta.addr = quic_mapped_addr.0;
+                    }
+                }
+            } else {
+                // if there is no non-stun,non-disco packet in the chunk, set len to zero to make
+                // quinn skip the buf completely.
+                meta.len = 0;
+            }
+            // Normalize local_ip
+            meta.dst_ip = dst_ip;
+        }
+
+        if quic_packets_total > 0 {
+            inc_by!(MagicsockMetrics, recv_datagrams, quic_packets_total as _);
+            trace!("UDP recv: {} packets", quic_packets_total);
+        }
+
+        Poll::Ready(Ok(msgs))
+    }
+
+    #[instrument(skip_all)]
+    fn poll_recv_relay(
+        &self,
+        cx: &mut Context,
+        bufs: &mut [io::IoSliceMut<'_>],
+        metas: &mut [quinn_udp::RecvMeta],
+    ) -> Poll<io::Result<usize>> {
+        let mut num_msgs = 0;
+        for (buf_out, meta_out) in bufs.iter_mut().zip(metas.iter_mut()) {
+            if self.is_closed() {
+                break;
+            }
+            let mut relay_recv_receiver = self.relay_recv_receiver.lock();
+            match relay_recv_receiver.try_recv() {
+                Err(mpsc::error::TryRecvError::Empty) => {
+                    self.network_recv_wakers.lock().replace(cx.waker().clone());
+                    break;
+                }
+                Err(mpsc::error::TryRecvError::Disconnected) => {
+                    return Poll::Ready(Err(io::Error::new(
+                        io::ErrorKind::NotConnected,
+                        "connection closed",
+                    )));
+                }
+                Ok(Err(err)) => return Poll::Ready(Err(err)),
+                Ok(Ok((node_id, meta, bytes))) => {
+                    inc_by!(MagicsockMetrics, recv_data_relay, bytes.len() as _);
+                    trace!(src = %meta.addr, node = %node_id.fmt_short(), count = meta.len / meta.stride, len = meta.len, "recv quic packets from relay");
+                    buf_out[..bytes.len()].copy_from_slice(&bytes);
+                    *meta_out = meta;
+                    num_msgs += 1;
+                }
+            }
+        }
+
+        // If we have any msgs to report, they are in the first `num_msgs_total` slots
+        if num_msgs > 0 {
+            inc_by!(MagicsockMetrics, recv_datagrams, num_msgs as _);
+            Poll::Ready(Ok(num_msgs))
+        } else {
+            Poll::Pending
+        }
+    }
+
+    /// Handles a discovery message.
+    #[instrument("disco_in", skip_all, fields(node = %sender.fmt_short(), %src))]
+    fn handle_disco_message(&self, sender: PublicKey, sealed_box: &[u8], src: DiscoMessageSource) {
+        trace!("handle_disco_message start");
+        if self.is_closed() {
+            return;
+        }
+
+        // We're now reasonably sure we're expecting communication from
+        // this node, do the heavy crypto lifting to see what they want.
+        let dm = match self.disco_secrets.unseal_and_decode(
+            &self.secret_key,
+            sender,
+            sealed_box.to_vec(),
+        ) {
+            Ok(dm) => dm,
+            Err(DiscoBoxError::Open(err)) => {
+                warn!(?err, "failed to open disco box");
+                inc!(MagicsockMetrics, recv_disco_bad_key);
+                return;
+            }
+            Err(DiscoBoxError::Parse(err)) => {
+                // Couldn't parse it, but it was inside a correctly
+                // signed box, so just ignore it, assuming it's from a
+                // newer version of Tailscale that we don't
+                // understand. Not even worth logging about, lest it
+                // be too spammy for old clients.
+
+                inc!(MagicsockMetrics, recv_disco_bad_parse);
+                debug!(?err, "failed to parse disco message");
+                return;
+            }
+        };
+
+        if src.is_relay() {
+            inc!(MagicsockMetrics, recv_disco_relay);
+        } else {
+            inc!(MagicsockMetrics, recv_disco_udp);
+        }
+
+        let span = trace_span!("handle_disco", ?dm);
+        let _guard = span.enter();
+        trace!("receive disco message");
+        match dm {
+            disco::Message::Ping(ping) => {
+                inc!(MagicsockMetrics, recv_disco_ping);
+                self.handle_ping(ping, sender, src);
+            }
+            disco::Message::Pong(pong) => {
+                inc!(MagicsockMetrics, recv_disco_pong);
+                self.node_map.handle_pong(sender, &src, pong);
+            }
+            disco::Message::CallMeMaybe(cm) => {
+                inc!(MagicsockMetrics, recv_disco_call_me_maybe);
+                match src {
+                    DiscoMessageSource::Relay { url, .. } => {
+                        event!(
+                            target: "iroh::_events::call-me-maybe::recv",
+                            Level::DEBUG,
+                            remote_node = sender.fmt_short(),
+                            via = ?url,
+                            their_addrs = ?cm.my_numbers,
+                        );
+                    }
+                    _ => {
+                        warn!("call-me-maybe packets should only come via relay");
+                        return;
+                    }
+                }
+                let ping_actions = self.node_map.handle_call_me_maybe(sender, cm);
+                for action in ping_actions {
+                    match action {
+                        PingAction::SendCallMeMaybe { .. } => {
+                            warn!("Unexpected CallMeMaybe as response of handling a CallMeMaybe");
+                        }
+                        PingAction::SendPing(ping) => {
+                            self.send_ping_queued(ping);
+                        }
+                    }
+                }
+            }
+        }
+        trace!("disco message handled");
+    }
+
+    /// Handle a ping message.
+    fn handle_ping(&self, dm: disco::Ping, sender: NodeId, src: DiscoMessageSource) {
+        // Insert the ping into the node map, and return whether a ping with this tx_id was already
+        // received.
+        let addr: SendAddr = src.clone().into();
+        let handled = self.node_map.handle_ping(sender, addr.clone(), dm.tx_id);
+        match handled.role {
+            PingRole::Duplicate => {
+                debug!(%src, tx = %hex::encode(dm.tx_id), "received ping: path already confirmed, skip");
+                return;
+            }
+            PingRole::LikelyHeartbeat => {}
+            PingRole::NewPath => {
+                debug!(%src, tx = %hex::encode(dm.tx_id), "received ping: new path");
+            }
+            PingRole::Activate => {
+                debug!(%src, tx = %hex::encode(dm.tx_id), "received ping: path active");
+            }
+        }
+
+        // Send a pong.
+        debug!(tx = %hex::encode(dm.tx_id), %addr, dstkey = %sender.fmt_short(),
+               "sending pong");
+        let pong = disco::Message::Pong(disco::Pong {
+            tx_id: dm.tx_id,
+            ping_observed_addr: addr.clone(),
+        });
+        event!(
+            target: "iroh::_events::pong::sent",
+            Level::DEBUG,
+            remote_node = %sender.fmt_short(),
+            dst = ?addr,
+            txn = ?dm.tx_id,
+        );
+
+        if !self.send_disco_message_queued(addr.clone(), sender, pong) {
+            warn!(%addr, "failed to queue pong");
+        }
+
+        if let Some(ping) = handled.needs_ping_back {
+            debug!(
+                %addr,
+                dstkey = %sender.fmt_short(),
+                "sending direct ping back",
+            );
+            self.send_ping_queued(ping);
+        }
+    }
+
+    fn encode_disco_message(&self, dst_key: PublicKey, msg: &disco::Message) -> Bytes {
+        self.disco_secrets
+            .encode_and_seal(&self.secret_key, dst_key, msg)
+    }
+
+    fn send_ping_queued(&self, ping: SendPing) {
+        let SendPing {
+            id,
+            dst,
+            dst_node,
+            tx_id,
+            purpose,
+        } = ping;
+        let msg = disco::Message::Ping(disco::Ping {
+            tx_id,
+            node_key: self.public_key(),
+        });
+        let sent = match dst {
+            SendAddr::Udp(addr) => self
+                .udp_disco_sender
+                .try_send((addr, dst_node, msg))
+                .is_ok(),
+            SendAddr::Relay(ref url) => self.send_disco_message_relay(url, dst_node, msg),
+        };
+        if sent {
+            let msg_sender = self.actor_sender.clone();
+            trace!(%dst, tx = %hex::encode(tx_id), ?purpose, "ping sent (queued)");
+            self.node_map
+                .notify_ping_sent(id, dst, tx_id, purpose, msg_sender);
+        } else {
+            warn!(dst = ?dst, tx = %hex::encode(tx_id), ?purpose, "failed to send ping: queues full");
+        }
+    }
+
+    /// Tries to send the ping actions.
+    ///
+    /// Note that on failure the (remaining) ping actions are simply dropped.  That's bad!
+    /// The Endpoint will think a full ping was done and not request a new full-ping for a
+    /// while.  We should probably be buffering the pings.
+    fn try_send_ping_actions(&self, msgs: Vec<PingAction>) -> io::Result<()> {
+        for msg in msgs {
+            // Abort sending as soon as we know we are shutting down.
+            if self.is_closing() || self.is_closed() {
+                return Ok(());
+            }
+            match msg {
+                PingAction::SendCallMeMaybe {
+                    ref relay_url,
+                    dst_node,
+                } => {
+                    self.send_or_queue_call_me_maybe(relay_url, dst_node);
+                }
+                PingAction::SendPing(ping) => {
+                    self.try_send_ping(ping)?;
+                }
+            }
+        }
+        Ok(())
+    }
+
+    /// Send a disco message. UDP messages will be queued.
+    ///
+    /// If `dst` is [`SendAddr::Relay`], the message will be pushed into the relay client channel.
+    /// If `dst` is [`SendAddr::Udp`], the message will be pushed into the udp disco send channel.
+    ///
+    /// Returns true if the channel had capacity for the message, and false if the message was
+    /// dropped.
+    fn send_disco_message_queued(
+        &self,
+        dst: SendAddr,
+        dst_key: PublicKey,
+        msg: disco::Message,
+    ) -> bool {
+        match dst {
+            SendAddr::Udp(addr) => self.udp_disco_sender.try_send((addr, dst_key, msg)).is_ok(),
+            SendAddr::Relay(ref url) => self.send_disco_message_relay(url, dst_key, msg),
+        }
+    }
+
+    /// Send a disco message. UDP messages will be polled to send directly on the UDP socket.
+    fn try_send_disco_message(
+        &self,
+        dst: SendAddr,
+        dst_key: PublicKey,
+        msg: disco::Message,
+    ) -> io::Result<()> {
+        match dst {
+            SendAddr::Udp(addr) => {
+                self.try_send_disco_message_udp(addr, dst_key, &msg)?;
+            }
+            SendAddr::Relay(ref url) => {
+                self.send_disco_message_relay(url, dst_key, msg);
+            }
+        }
+        Ok(())
+    }
+
+    fn send_disco_message_relay(&self, url: &RelayUrl, dst: NodeId, msg: disco::Message) -> bool {
+        debug!(node = %dst.fmt_short(), %url, %msg, "send disco message (relay)");
+        let pkt = self.encode_disco_message(dst, &msg);
+        inc!(MagicsockMetrics, send_disco_relay);
+        match self.try_send_relay(url, dst, smallvec![pkt]) {
+            Ok(()) => {
+                if let disco::Message::CallMeMaybe(CallMeMaybe { ref my_numbers }) = msg {
+                    event!(
+                        target: "iroh::_events::call-me-maybe::sent",
+                        Level::DEBUG,
+                        remote_node = %dst.fmt_short(),
+                        via = ?url,
+                        addrs = ?my_numbers,
+                    );
+                }
+                inc!(MagicsockMetrics, sent_disco_relay);
+                disco_message_sent(&msg);
+                true
+            }
+            Err(_) => false,
+        }
+    }
+
+    async fn send_disco_message_udp(
+        &self,
+        dst: SocketAddr,
+        dst_node: NodeId,
+        msg: &disco::Message,
+    ) -> io::Result<()> {
+        futures_lite::future::poll_fn(move |cx| {
+            loop {
+                match self.try_send_disco_message_udp(dst, dst_node, msg) {
+                    Ok(()) => return Poll::Ready(Ok(())),
+                    Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
+                        // This is the socket .try_send_disco_message_udp used.
+                        let sock = self.conn_for_addr(dst)?;
+                        match sock.as_socket_ref().poll_writable(cx) {
+                            Poll::Ready(Ok(())) => continue,
+                            Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
+                            Poll::Pending => return Poll::Pending,
+                        }
+                    }
+                    Err(err) => return Poll::Ready(Err(err)),
+                }
+            }
+        })
+        .await
+    }
+
+    fn try_send_disco_message_udp(
+        &self,
+        dst: SocketAddr,
+        dst_node: NodeId,
+        msg: &disco::Message,
+    ) -> std::io::Result<()> {
+        trace!(%dst, %msg, "send disco message (UDP)");
+        if self.is_closed() {
+            return Err(io::Error::new(
+                io::ErrorKind::NotConnected,
+                "connection closed",
+            ));
+        }
+        let pkt = self.encode_disco_message(dst_node, msg);
+        // TODO: These metrics will be wrong with the poll impl
+        // Also - do we need it? I'd say the `sent_disco_udp` below is enough.
+        inc!(MagicsockMetrics, send_disco_udp);
+        let transmit = quinn_udp::Transmit {
+            destination: dst,
+            contents: &pkt,
+            ecn: None,
+            segment_size: None,
+            src_ip: None, // TODO
+        };
+        let sent = self.try_send_udp(dst, &transmit);
+        match sent {
+            Ok(()) => {
+                trace!(%dst, node = %dst_node.fmt_short(), %msg, "sent disco message");
+                inc!(MagicsockMetrics, sent_disco_udp);
+                disco_message_sent(msg);
+                Ok(())
+            }
+            Err(err) => {
+                warn!(%dst, node = %dst_node.fmt_short(), ?msg, ?err,
+                      "failed to send disco message");
+                Err(err)
+            }
+        }
+    }
+
+    #[instrument(skip_all)]
+    async fn handle_ping_actions(&mut self, msgs: Vec<PingAction>) {
+        // TODO: This used to make sure that all ping actions are sent.  Though on the
+        // poll_send/try_send path we also do fire-and-forget.  try_send_ping_actions()
+        // really should store any unsent pings on the Inner and send them at the next
+        // possible time.
+        if let Err(err) = self.try_send_ping_actions(msgs) {
+            warn!("Not all ping actions were sent: {err:#}");
+        }
+    }
+
+    fn try_send_ping(&self, ping: SendPing) -> io::Result<()> {
+        let SendPing {
+            id,
+            dst,
+            dst_node,
+            tx_id,
+            purpose,
+        } = ping;
+        let msg = disco::Message::Ping(disco::Ping {
+            tx_id,
+            node_key: self.public_key(),
+        });
+        self.try_send_disco_message(dst.clone(), dst_node, msg)?;
+        debug!(%dst, tx = %hex::encode(tx_id), ?purpose, "ping sent (polled)");
+        let msg_sender = self.actor_sender.clone();
+        self.node_map
+            .notify_ping_sent(id, dst.clone(), tx_id, purpose, msg_sender);
+        Ok(())
+    }
+
+    fn send_queued_call_me_maybes(&self) {
+        let msg = self.direct_addrs.to_call_me_maybe_message();
+        let msg = disco::Message::CallMeMaybe(msg);
+        for (public_key, url) in self.pending_call_me_maybes.lock().drain() {
+            if !self.send_disco_message_relay(&url, public_key, msg.clone()) {
+                warn!(node = %public_key.fmt_short(), "relay channel full, dropping call-me-maybe");
+            }
+        }
+    }
+
+    /// Sends the call-me-maybe DISCO message, queuing if addresses are too stale.
+    ///
+    /// To send the call-me-maybe message, we need to know our current direct addresses.  If
+    /// this information is too stale, the call-me-maybe is queued while a net_report run is
+    /// scheduled.  Once this run finishes, the call-me-maybe will be sent.
+    fn send_or_queue_call_me_maybe(&self, url: &RelayUrl, dst_node: NodeId) {
+        match self.direct_addrs.fresh_enough() {
+            Ok(()) => {
+                let msg = self.direct_addrs.to_call_me_maybe_message();
+                let msg = disco::Message::CallMeMaybe(msg);
+                if !self.send_disco_message_relay(url, dst_node, msg) {
+                    warn!(dstkey = %dst_node.fmt_short(), relayurl = %url,
+                      "relay channel full, dropping call-me-maybe");
+                } else {
+                    debug!(dstkey = %dst_node.fmt_short(), relayurl = %url, "call-me-maybe sent");
+                }
+            }
+            Err(last_refresh_ago) => {
+                self.pending_call_me_maybes
+                    .lock()
+                    .insert(dst_node, url.clone());
+                debug!(
+                    ?last_refresh_ago,
+                    "want call-me-maybe but direct addrs stale; queuing after restun",
+                );
+                self.re_stun("refresh-for-peering");
+            }
+        }
+    }
+
+    /// Triggers an address discovery. The provided why string is for debug logging only.
+    #[instrument(skip_all)]
+    fn re_stun(&self, why: &'static str) {
+        debug!("re_stun: {}", why);
+        inc!(MagicsockMetrics, re_stun_calls);
+        self.direct_addr_update_state.schedule_run(why);
+    }
+
+    /// Publishes our address to a discovery service, if configured.
+    ///
+    /// Called whenever our addresses or home relay node changes.
+    fn publish_my_addr(&self) {
+        if let Some(ref discovery) = self.discovery {
+            let info = AddrInfo {
+                relay_url: self.my_relay(),
+                direct_addresses: self.direct_addrs.sockaddrs(),
+            };
+            discovery.publish(&info);
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+enum DiscoMessageSource {
+    Udp(SocketAddr),
+    Relay { url: RelayUrl, key: PublicKey },
+}
+
+impl Display for DiscoMessageSource {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            Self::Udp(addr) => write!(f, "Udp({addr})"),
+            Self::Relay { ref url, key } => write!(f, "Relay({url}, {})", key.fmt_short()),
+        }
+    }
+}
+
+impl From<DiscoMessageSource> for SendAddr {
+    fn from(value: DiscoMessageSource) -> Self {
+        match value {
+            DiscoMessageSource::Udp(addr) => SendAddr::Udp(addr),
+            DiscoMessageSource::Relay { url, .. } => SendAddr::Relay(url),
+        }
+    }
+}
+
+impl From<&DiscoMessageSource> for SendAddr {
+    fn from(value: &DiscoMessageSource) -> Self {
+        match value {
+            DiscoMessageSource::Udp(addr) => SendAddr::Udp(*addr),
+            DiscoMessageSource::Relay { url, .. } => SendAddr::Relay(url.clone()),
+        }
+    }
+}
+
+impl DiscoMessageSource {
+    fn is_relay(&self) -> bool {
+        matches!(self, DiscoMessageSource::Relay { .. })
+    }
+}
+
+/// Manages currently running direct addr discovery, aka net_report runs.
+///
+/// Invariants:
+/// - only one direct addr update must be running at a time
+/// - if an update is scheduled while another one is running, remember that
+///   and start a new one when the current one has finished
+#[derive(Debug)]
+struct DirectAddrUpdateState {
+    /// If running, set to the reason for the currently the update.
+    running: sync::watch::Sender<Option<&'static str>>,
+    /// If set, start a new update as soon as the current one is finished.
+    want_update: parking_lot::Mutex<Option<&'static str>>,
+}
+
+impl DirectAddrUpdateState {
+    fn new() -> Self {
+        let (running, _) = sync::watch::channel(None);
+        DirectAddrUpdateState {
+            running,
+            want_update: Default::default(),
+        }
+    }
+
+    /// Schedules a new run, either starting it immediately if none is running or
+    /// scheduling it for later.
+    fn schedule_run(&self, why: &'static str) {
+        if self.is_running() {
+            let _ = self.want_update.lock().insert(why);
+        } else {
+            self.run(why);
+        }
+    }
+
+    /// Returns `true` if an update is currently in progress.
+    fn is_running(&self) -> bool {
+        self.running.borrow().is_some()
+    }
+
+    /// Trigger a new run.
+    fn run(&self, why: &'static str) {
+        self.running.send(Some(why)).ok();
+    }
+
+    /// Clears the current running state.
+    fn finish_run(&self) {
+        self.running.send(None).ok();
+    }
+
+    /// Returns the next update, if one is set.
+    fn next_update(&self) -> Option<&'static str> {
+        self.want_update.lock().take()
+    }
+}
+
+impl Handle {
+    /// Creates a magic [`MagicSock`] listening on [`Options::addr_v4`] and [`Options::addr_v6`].
+    async fn new(opts: Options) -> Result<Self> {
+        let me = opts.secret_key.public().fmt_short();
+        if crate::util::relay_only_mode() {
+            warn!(
+                "creating a MagicSock that will only send packets over a relay relay connection."
+            );
+        }
+
+        Self::with_name(me, opts)
+            .instrument(error_span!("magicsock"))
+            .await
+    }
+
+    async fn with_name(me: String, opts: Options) -> Result<Self> {
+        let port_mapper = portmapper::Client::default();
+
+        let Options {
+            addr_v4,
+            addr_v6,
+            secret_key,
+            relay_map,
+            node_map,
+            discovery,
+            dns_resolver,
+            proxy_url,
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_relay_cert_verify,
+        } = opts;
+
+        let (relay_recv_sender, relay_recv_receiver) = mpsc::channel(128);
+
+        let (pconn4, pconn6) = bind(addr_v4, addr_v6)?;
+        let port = pconn4.port();
+
+        // NOTE: we can end up with a zero port if `std::net::UdpSocket::socket_addr` fails
+        match port.try_into() {
+            Ok(non_zero_port) => {
+                port_mapper.update_local_port(non_zero_port);
+            }
+            Err(_zero_port) => debug!("Skipping port mapping with zero local port"),
+        }
+        let ipv4_addr = pconn4.local_addr()?;
+        let ipv6_addr = pconn6.as_ref().and_then(|c| c.local_addr().ok());
+
+        let net_reporter =
+            net_report::Client::new(Some(port_mapper.clone()), dns_resolver.clone())?;
+
+        let pconn4_sock = pconn4.as_socket();
+        let pconn6_sock = pconn6.as_ref().map(|p| p.as_socket());
+
+        let (actor_sender, actor_receiver) = mpsc::channel(256);
+        let (relay_actor_sender, relay_actor_receiver) = mpsc::channel(256);
+        let (udp_disco_sender, mut udp_disco_receiver) = mpsc::channel(256);
+
+        // load the node data
+        let node_map = node_map.unwrap_or_default();
+        let node_map = NodeMap::load_from_vec(node_map);
+
+        let inner = Arc::new(MagicSock {
+            me,
+            port: AtomicU16::new(port),
+            secret_key,
+            proxy_url,
+            local_addrs: std::sync::RwLock::new((ipv4_addr, ipv6_addr)),
+            closing: AtomicBool::new(false),
+            closed: AtomicBool::new(false),
+            relay_recv_receiver: parking_lot::Mutex::new(relay_recv_receiver),
+            network_recv_wakers: parking_lot::Mutex::new(None),
+            network_send_wakers: Arc::new(parking_lot::Mutex::new(None)),
+            actor_sender: actor_sender.clone(),
+            ipv6_reported: Arc::new(AtomicBool::new(false)),
+            relay_map,
+            my_relay: Default::default(),
+            net_reporter: net_reporter.addr(),
+            pconn4,
+            pconn6,
+            disco_secrets: DiscoSecrets::default(),
+            node_map,
+            relay_actor_sender: relay_actor_sender.clone(),
+            udp_disco_sender,
+            discovery,
+            direct_addrs: Default::default(),
+            pending_call_me_maybes: Default::default(),
+            direct_addr_update_state: DirectAddrUpdateState::new(),
+            dns_resolver,
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_relay_cert_verify,
+        });
+
+        let mut actor_tasks = JoinSet::default();
+
+        let relay_actor = RelayActor::new(inner.clone(), actor_sender.clone());
+        let relay_actor_cancel_token = relay_actor.cancel_token();
+        actor_tasks.spawn(
+            async move {
+                relay_actor.run(relay_actor_receiver).await;
+            }
+            .instrument(info_span!("relay-actor")),
+        );
+
+        let inner2 = inner.clone();
+        actor_tasks.spawn(async move {
+            while let Some((dst, dst_key, msg)) = udp_disco_receiver.recv().await {
+                if let Err(err) = inner2.send_disco_message_udp(dst, dst_key, &msg).await {
+                    warn!(%dst, node = %dst_key.fmt_short(), ?err, "failed to send disco message (UDP)");
+                }
+            }
+        });
+
+        let inner2 = inner.clone();
+        let network_monitor = netmon::Monitor::new().await?;
+        actor_tasks.spawn(
+            async move {
+                let actor = Actor {
+                    msg_receiver: actor_receiver,
+                    msg_sender: actor_sender,
+                    relay_actor_sender,
+                    relay_actor_cancel_token,
+                    msock: inner2,
+                    relay_recv_sender,
+                    periodic_re_stun_timer: new_re_stun_timer(false),
+                    net_info_last: None,
+                    port_mapper,
+                    pconn4: pconn4_sock,
+                    pconn6: pconn6_sock,
+                    no_v4_send: false,
+                    net_reporter,
+                    network_monitor,
+                };
+
+                if let Err(err) = actor.run().await {
+                    warn!("relay handler errored: {:?}", err);
+                }
+            }
+            .instrument(info_span!("actor")),
+        );
+
+        let c = Handle {
+            msock: inner,
+            actor_tasks: Arc::new(Mutex::new(actor_tasks)),
+        };
+
+        Ok(c)
+    }
+
+    /// Closes the connection.
+    ///
+    /// Only the first close does anything. Any later closes return nil.
+    /// Polling the socket ([`AsyncUdpSocket::poll_recv`]) will return [`Poll::Pending`]
+    /// indefinitely after this call.
+    #[instrument(skip_all, fields(me = %self.msock.me))]
+    pub(crate) async fn close(&self) -> Result<()> {
+        if self.msock.is_closed() {
+            return Ok(());
+        }
+        self.msock.closing.store(true, Ordering::Relaxed);
+        self.msock.actor_sender.send(ActorMessage::Shutdown).await?;
+        self.msock.closed.store(true, Ordering::SeqCst);
+        self.msock.direct_addrs.addrs.shutdown();
+
+        let mut tasks = self.actor_tasks.lock().await;
+
+        // give the tasks a moment to shutdown cleanly
+        let tasks_ref = &mut tasks;
+        let shutdown_done = time::timeout(Duration::from_millis(100), async move {
+            while let Some(task) = tasks_ref.join_next().await {
+                if let Err(err) = task {
+                    warn!("unexpected error in task shutdown: {:?}", err);
+                }
+            }
+        })
+        .await;
+        if shutdown_done.is_ok() {
+            debug!("tasks shutdown complete");
+        } else {
+            // shutdown all tasks
+            debug!("aborting remaining {}/3 tasks", tasks.len());
+            tasks.shutdown().await;
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug, Default)]
+struct DiscoSecrets(parking_lot::Mutex<HashMap<PublicKey, SharedSecret>>);
+
+impl DiscoSecrets {
+    fn get(
+        &self,
+        secret: &SecretKey,
+        node_id: PublicKey,
+    ) -> parking_lot::MappedMutexGuard<SharedSecret> {
+        parking_lot::MutexGuard::map(self.0.lock(), |inner| {
+            inner
+                .entry(node_id)
+                .or_insert_with(|| secret.shared(&node_id))
+        })
+    }
+
+    pub fn encode_and_seal(
+        &self,
+        secret_key: &SecretKey,
+        node_id: PublicKey,
+        msg: &disco::Message,
+    ) -> Bytes {
+        let mut seal = msg.as_bytes();
+        self.get(secret_key, node_id).seal(&mut seal);
+        disco::encode_message(&secret_key.public(), seal).into()
+    }
+
+    pub fn unseal_and_decode(
+        &self,
+        secret: &SecretKey,
+        node_id: PublicKey,
+        mut sealed_box: Vec<u8>,
+    ) -> Result<disco::Message, DiscoBoxError> {
+        self.get(secret, node_id)
+            .open(&mut sealed_box)
+            .map_err(DiscoBoxError::Open)?;
+        disco::Message::from_bytes(&sealed_box).map_err(DiscoBoxError::Parse)
+    }
+}
+
+#[derive(Debug, thiserror::Error)]
+enum DiscoBoxError {
+    #[error("Failed to open crypto box")]
+    Open(anyhow::Error),
+    #[error("Failed to parse disco message")]
+    Parse(anyhow::Error),
+}
+
+type RelayRecvResult = Result<(PublicKey, quinn_udp::RecvMeta, Bytes), io::Error>;
+
+impl AsyncUdpSocket for Handle {
+    fn create_io_poller(self: Arc<Self>) -> Pin<Box<dyn quinn::UdpPoller>> {
+        self.msock.create_io_poller()
+    }
+
+    fn try_send(&self, transmit: &quinn_udp::Transmit) -> io::Result<()> {
+        self.msock.try_send(transmit)
+    }
+
+    /// NOTE: Receiving on a [`Self::close`]d socket will return [`Poll::Pending`] indefinitely.
+    fn poll_recv(
+        &self,
+        cx: &mut Context,
+        bufs: &mut [io::IoSliceMut<'_>],
+        metas: &mut [quinn_udp::RecvMeta],
+    ) -> Poll<io::Result<usize>> {
+        self.msock.poll_recv(cx, bufs, metas)
+    }
+
+    fn local_addr(&self) -> io::Result<SocketAddr> {
+        match &*self.msock.local_addrs.read().expect("not poisoned") {
+            (ipv4, None) => {
+                // Pretend to be IPv6, because our QuinnMappedAddrs
+                // need to be IPv6.
+                let ip: IpAddr = match ipv4.ip() {
+                    IpAddr::V4(ip) => ip.to_ipv6_mapped().into(),
+                    IpAddr::V6(ip) => ip.into(),
+                };
+                Ok(SocketAddr::new(ip, ipv4.port()))
+            }
+            (_, Some(ipv6)) => Ok(*ipv6),
+        }
+    }
+
+    fn max_transmit_segments(&self) -> usize {
+        if let Some(pconn6) = self.pconn6.as_ref() {
+            std::cmp::min(
+                pconn6.max_transmit_segments(),
+                self.pconn4.max_transmit_segments(),
+            )
+        } else {
+            self.pconn4.max_transmit_segments()
+        }
+    }
+
+    fn max_receive_segments(&self) -> usize {
+        if let Some(pconn6) = self.pconn6.as_ref() {
+            // `max_receive_segments` controls the size of the `RecvMeta` buffer
+            // that quinn creates. Having buffers slightly bigger than necessary
+            // isn't terrible, and makes sure a single socket can read the maximum
+            // amount with a single poll. We considered adding these numbers instead,
+            // but we never get data from both sockets at the same time in `poll_recv`
+            // and it's impossible and unnecessary to be refactored that way.
+            std::cmp::max(
+                pconn6.max_receive_segments(),
+                self.pconn4.max_receive_segments(),
+            )
+        } else {
+            self.pconn4.max_receive_segments()
+        }
+    }
+
+    fn may_fragment(&self) -> bool {
+        if let Some(pconn6) = self.pconn6.as_ref() {
+            pconn6.may_fragment() || self.pconn4.may_fragment()
+        } else {
+            self.pconn4.may_fragment()
+        }
+    }
+}
+
+#[derive(Debug)]
+struct IoPoller {
+    ipv4_poller: Pin<Box<dyn quinn::UdpPoller>>,
+    ipv6_poller: Option<Pin<Box<dyn quinn::UdpPoller>>>,
+    relay_sender: mpsc::Sender<RelayActorMessage>,
+    relay_send_waker: Arc<parking_lot::Mutex<Option<Waker>>>,
+}
+
+impl quinn::UdpPoller for IoPoller {
+    fn poll_writable(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
+        // This version returns Ready as soon as any of them are ready.
+        let this = &mut *self;
+        match this.ipv4_poller.as_mut().poll_writable(cx) {
+            Poll::Ready(_) => return Poll::Ready(Ok(())),
+            Poll::Pending => (),
+        }
+        if let Some(ref mut ipv6_poller) = this.ipv6_poller {
+            match ipv6_poller.as_mut().poll_writable(cx) {
+                Poll::Ready(_) => return Poll::Ready(Ok(())),
+                Poll::Pending => (),
+            }
+        }
+        match this.relay_sender.capacity() {
+            0 => {
+                self.relay_send_waker.lock().replace(cx.waker().clone());
+                Poll::Pending
+            }
+            _ => Poll::Ready(Ok(())),
+        }
+    }
+}
+
+#[derive(Debug)]
+enum ActorMessage {
+    Shutdown,
+    ReceiveRelay(RelayReadResult),
+    EndpointPingExpired(usize, stun_rs::TransactionId),
+    NetReport(Result<Option<Arc<net_report::Report>>>, &'static str),
+    NetworkChange,
+    #[cfg(test)]
+    ForceNetworkChange(bool),
+}
+
+struct Actor {
+    msock: Arc<MagicSock>,
+    msg_receiver: mpsc::Receiver<ActorMessage>,
+    msg_sender: mpsc::Sender<ActorMessage>,
+    relay_actor_sender: mpsc::Sender<RelayActorMessage>,
+    relay_actor_cancel_token: CancellationToken,
+    /// Channel to send received relay messages on, for processing.
+    relay_recv_sender: mpsc::Sender<RelayRecvResult>,
+    /// When set, is an AfterFunc timer that will call MagicSock::do_periodic_stun.
+    periodic_re_stun_timer: time::Interval,
+    /// The `NetInfo` provided in the last call to `net_info_func`. It's used to deduplicate calls to netInfoFunc.
+    net_info_last: Option<NetInfo>,
+
+    // The underlying UDP sockets used to send/rcv packets.
+    pconn4: Arc<UdpSocket>,
+    pconn6: Option<Arc<UdpSocket>>,
+
+    /// The NAT-PMP/PCP/UPnP prober/client, for requesting port mappings from NAT devices.
+    port_mapper: portmapper::Client,
+
+    /// Whether IPv4 UDP is known to be unable to transmit
+    /// at all. This could happen if the socket is in an invalid state
+    /// (as can happen on darwin after a network link status change).
+    no_v4_send: bool,
+
+    /// The prober that discovers local network conditions, including the closest relay relay and NAT mappings.
+    net_reporter: net_report::Client,
+
+    network_monitor: netmon::Monitor,
+}
+
+impl Actor {
+    async fn run(mut self) -> Result<()> {
+        // Setup network monitoring
+        let (link_change_s, mut link_change_r) = mpsc::channel(8);
+        let _token = self
+            .network_monitor
+            .subscribe(move |is_major| {
+                let link_change_s = link_change_s.clone();
+                async move {
+                    link_change_s.send(is_major).await.ok();
+                }
+                .boxed()
+            })
+            .await?;
+
+        // Let the the heartbeat only start a couple seconds later
+        let mut direct_addr_heartbeat_timer = time::interval_at(
+            time::Instant::now() + HEARTBEAT_INTERVAL,
+            HEARTBEAT_INTERVAL,
+        );
+        let mut direct_addr_update_receiver =
+            self.msock.direct_addr_update_state.running.subscribe();
+        let mut portmap_watcher = self.port_mapper.watch_external_address();
+
+        let mut discovery_events: BoxStream<DiscoveryItem> =
+            Box::pin(futures_lite::stream::empty());
+        if let Some(d) = self.msock.discovery() {
+            if let Some(events) = d.subscribe() {
+                discovery_events = events;
+            }
+        }
+
+        let mut receiver_closed = false;
+        let mut portmap_watcher_closed = false;
+        let mut link_change_closed = false;
+        loop {
+            inc!(Metrics, actor_tick_main);
+            tokio::select! {
+                msg = self.msg_receiver.recv(), if !receiver_closed => {
+                    let Some(msg) = msg else {
+                        trace!("tick: magicsock receiver closed");
+                        inc!(Metrics, actor_tick_other);
+
+                        receiver_closed = true;
+                        continue;
+                    };
+
+                    trace!(?msg, "tick: msg");
+                    inc!(Metrics, actor_tick_msg);
+                    if self.handle_actor_message(msg).await {
+                        return Ok(());
+                    }
+                }
+                tick = self.periodic_re_stun_timer.tick() => {
+                    trace!("tick: re_stun {:?}", tick);
+                    inc!(Metrics, actor_tick_re_stun);
+                    self.msock.re_stun("periodic");
+                }
+                change = portmap_watcher.changed(), if !portmap_watcher_closed => {
+                    if change.is_err() {
+                        trace!("tick: portmap watcher closed");
+                        inc!(Metrics, actor_tick_other);
+
+                        portmap_watcher_closed = true;
+                        continue;
+                    }
+
+                    trace!("tick: portmap changed");
+                    inc!(Metrics, actor_tick_portmap_changed);
+                    let new_external_address = *portmap_watcher.borrow();
+                    debug!("external address updated: {new_external_address:?}");
+                    self.msock.re_stun("portmap_updated");
+                },
+                _ = direct_addr_heartbeat_timer.tick() => {
+                    trace!(
+                        "tick: direct addr heartbeat {} direct addrs",
+                        self.msock.node_map.node_count(),
+                    );
+                    inc!(Metrics, actor_tick_direct_addr_heartbeat);
+                    // TODO: this might trigger too many packets at once, pace this
+
+                    self.msock.node_map.prune_inactive();
+                    let msgs = self.msock.node_map.nodes_stayin_alive();
+                    self.handle_ping_actions(msgs).await;
+                }
+                _ = direct_addr_update_receiver.changed() => {
+                    let reason = *direct_addr_update_receiver.borrow();
+                    trace!("tick: direct addr update receiver {:?}", reason);
+                    inc!(Metrics, actor_tick_direct_addr_update_receiver);
+                    if let Some(reason) = reason {
+                        self.refresh_direct_addrs(reason).await;
+                    }
+                }
+                is_major = link_change_r.recv(), if !link_change_closed => {
+                    let Some(is_major) = is_major else {
+                        trace!("tick: link change receiver closed");
+                        inc!(Metrics, actor_tick_other);
+
+                        link_change_closed = true;
+                        continue;
+                    };
+
+                    trace!("tick: link change {}", is_major);
+                    inc!(Metrics, actor_link_change);
+                    self.handle_network_change(is_major).await;
+                }
+                // Even if `discovery_events` yields `None`, it could begin to yield
+                // `Some` again in the future, so we don't want to disable this branch
+                // forever like we do with the other branches that yield `Option`s
+                Some(discovery_item) = discovery_events.next() => {
+                    trace!("tick: discovery event, address discovered: {discovery_item:?}");
+                    let node_addr = NodeAddr {node_id: discovery_item.node_id, info: discovery_item.addr_info};
+                    if let Err(e) = self.msock.add_node_addr(node_addr.clone(), Source::Discovery { name: discovery_item.provenance.into() }) {
+                        warn!(?node_addr, "unable to add discovered node address to the node map: {e:?}");
+                    }
+                }
+            }
+        }
+    }
+
+    async fn handle_network_change(&mut self, is_major: bool) {
+        debug!("link change detected: major? {}", is_major);
+
+        if is_major {
+            if let Err(err) = self.pconn4.rebind() {
+                warn!("failed to rebind Udp IPv4 socket: {:?}", err);
+            };
+            if let Some(ref pconn6) = self.pconn6 {
+                if let Err(err) = pconn6.rebind() {
+                    warn!("failed to rebind Udp IPv6 socket: {:?}", err);
+                };
+            }
+            self.msock.dns_resolver.clear_cache();
+            self.msock.re_stun("link-change-major");
+            self.close_stale_relay_connections().await;
+            self.reset_endpoint_states();
+        } else {
+            self.msock.re_stun("link-change-minor");
+        }
+    }
+
+    #[instrument(skip_all)]
+    async fn handle_ping_actions(&mut self, msgs: Vec<PingAction>) {
+        // TODO: This used to make sure that all ping actions are sent.  Though on the
+        // poll_send/try_send path we also do fire-and-forget.  try_send_ping_actions()
+        // really should store any unsent pings on the Inner and send them at the next
+        // possible time.
+        if let Err(err) = self.msock.try_send_ping_actions(msgs) {
+            warn!("Not all ping actions were sent: {err:#}");
+        }
+    }
+
+    /// Processes an incoming actor message.
+    ///
+    /// Returns `true` if it was a shutdown.
+    async fn handle_actor_message(&mut self, msg: ActorMessage) -> bool {
+        match msg {
+            ActorMessage::Shutdown => {
+                debug!("shutting down");
+
+                self.msock.node_map.notify_shutdown();
+                self.port_mapper.deactivate();
+                self.relay_actor_cancel_token.cancel();
+
+                debug!("shutdown complete");
+                return true;
+            }
+            ActorMessage::ReceiveRelay(read_result) => {
+                let passthroughs = self.process_relay_read_result(read_result);
+                for passthrough in passthroughs {
+                    self.relay_recv_sender
+                        .send(passthrough)
+                        .await
+                        .expect("missing recv sender");
+                    let mut wakers = self.msock.network_recv_wakers.lock();
+                    if let Some(waker) = wakers.take() {
+                        waker.wake();
+                    }
+                }
+            }
+            ActorMessage::EndpointPingExpired(id, txid) => {
+                self.msock.node_map.notify_ping_timeout(id, txid);
+            }
+            ActorMessage::NetReport(report, why) => {
+                match report {
+                    Ok(report) => {
+                        self.handle_net_report_report(report).await;
+                    }
+                    Err(err) => {
+                        warn!(
+                            "failed to generate net_report report for: {}: {:?}",
+                            why, err
+                        );
+                    }
+                }
+                self.finalize_direct_addrs_update(why);
+            }
+            ActorMessage::NetworkChange => {
+                self.network_monitor.network_change().await.ok();
+            }
+            #[cfg(test)]
+            ActorMessage::ForceNetworkChange(is_major) => {
+                self.handle_network_change(is_major).await;
+            }
+        }
+
+        false
+    }
+
+    #[cfg_attr(windows, allow(dead_code))]
+    fn normalized_local_addr(&self) -> io::Result<SocketAddr> {
+        self.msock.normalized_local_addr()
+    }
+
+    fn process_relay_read_result(&mut self, dm: RelayReadResult) -> Vec<RelayRecvResult> {
+        trace!("process_relay_read {} bytes", dm.buf.len());
+        if dm.buf.is_empty() {
+            warn!("received empty relay packet");
+            return Vec::new();
+        }
+        let url = &dm.url;
+
+        let quic_mapped_addr = self.msock.node_map.receive_relay(url, dm.src);
+
+        // the relay packet is made up of multiple udp packets, prefixed by a u16 be length prefix
+        //
+        // split the packet into these parts
+        let parts = PacketSplitIter::new(dm.buf);
+        // Normalize local_ip
+        #[cfg(not(windows))]
+        let dst_ip = self.normalized_local_addr().ok().map(|addr| addr.ip());
+        // Reasoning for this here: https://github.com/n0-computer/iroh/pull/2595#issuecomment-2290947319
+        #[cfg(windows)]
+        let dst_ip = None;
+
+        let mut out = Vec::new();
+        for part in parts {
+            match part {
+                Ok(part) => {
+                    if self.handle_relay_disco_message(&part, url, dm.src) {
+                        // Message was internal, do not bubble up.
+                        continue;
+                    }
+
+                    let meta = quinn_udp::RecvMeta {
+                        len: part.len(),
+                        stride: part.len(),
+                        addr: quic_mapped_addr.0,
+                        dst_ip,
+                        ecn: None,
+                    };
+                    out.push(Ok((dm.src, meta, part)));
+                }
+                Err(e) => {
+                    out.push(Err(e));
+                }
+            }
+        }
+
+        out
+    }
+
+    /// Refreshes knowledge about our direct addresses.
+    ///
+    /// In other words, this triggers a net_report run.
+    ///
+    /// Note that invoking this is managed by the [`DirectAddrUpdateState`] and this should
+    /// never be invoked directly.  Some day this will be refactored to not allow this easy
+    /// mistake to be made.
+    #[instrument(level = "debug", skip_all)]
+    async fn refresh_direct_addrs(&mut self, why: &'static str) {
+        inc!(MagicsockMetrics, update_direct_addrs);
+
+        debug!("starting direct addr update ({})", why);
+        self.port_mapper.procure_mapping();
+        self.update_net_info(why).await;
+    }
+
+    /// Updates the direct addresses of this magic socket.
+    ///
+    /// Updates the [`DiscoveredDirectAddrs`] of this [`MagicSock`] with the current set of
+    /// direct addresses from:
+    ///
+    /// - The portmapper.
+    /// - A net_report report.
+    /// - The local interfaces IP addresses.
+    fn update_direct_addresses(&mut self, net_report_report: Option<Arc<net_report::Report>>) {
+        let portmap_watcher = self.port_mapper.watch_external_address();
+
+        // We only want to have one DirectAddr for each SocketAddr we have.  So we store
+        // this as a map of SocketAddr -> DirectAddrType.  At the end we will construct a
+        // DirectAddr from each entry.
+        let mut addrs: BTreeMap<SocketAddr, DirectAddrType> = BTreeMap::new();
+
+        // First add PortMapper provided addresses.
+        let maybe_port_mapped = *portmap_watcher.borrow();
+        if let Some(portmap_ext) = maybe_port_mapped.map(SocketAddr::V4) {
+            addrs
+                .entry(portmap_ext)
+                .or_insert(DirectAddrType::Portmapped);
+            self.set_net_info_have_port_map();
+        }
+
+        // Next add STUN addresses from the net_report report.
+        if let Some(net_report_report) = net_report_report {
+            if let Some(global_v4) = net_report_report.global_v4 {
+                addrs
+                    .entry(global_v4.into())
+                    .or_insert(DirectAddrType::Stun);
+
+                // If they're behind a hard NAT and are using a fixed
+                // port locally, assume they might've added a static
+                // port mapping on their router to the same explicit
+                // port that we are running with. Worst case it's an invalid candidate mapping.
+                let port = self.msock.port.load(Ordering::Relaxed);
+                if net_report_report
+                    .mapping_varies_by_dest_ip
+                    .unwrap_or_default()
+                    && port != 0
+                {
+                    let mut addr = global_v4;
+                    addr.set_port(port);
+                    addrs
+                        .entry(addr.into())
+                        .or_insert(DirectAddrType::Stun4LocalPort);
+                }
+            }
+            if let Some(global_v6) = net_report_report.global_v6 {
+                addrs
+                    .entry(global_v6.into())
+                    .or_insert(DirectAddrType::Stun);
+            }
+        }
+
+        let local_addr_v4 = self.pconn4.local_addr().ok();
+        let local_addr_v6 = self.pconn6.as_ref().and_then(|c| c.local_addr().ok());
+
+        let is_unspecified_v4 = local_addr_v4
+            .map(|a| a.ip().is_unspecified())
+            .unwrap_or(false);
+        let is_unspecified_v6 = local_addr_v6
+            .map(|a| a.ip().is_unspecified())
+            .unwrap_or(false);
+
+        let msock = self.msock.clone();
+
+        // The following code can be slow, we do not want to block the caller since it would
+        // block the actor loop.
+        tokio::spawn(
+            async move {
+                // If a socket is bound to the unspecified address, create SocketAddrs for
+                // each local IP address by pairing it with the port the socket is bound on.
+                if is_unspecified_v4 || is_unspecified_v6 {
+                    // Depending on the OS and network interfaces attached and their state
+                    // enumerating the local interfaces can take a long time.  Especially
+                    // Windows is very slow.
+                    let LocalAddresses {
+                        regular: mut ips,
+                        loopback,
+                    } = tokio::task::spawn_blocking(LocalAddresses::new)
+                        .await
+                        .unwrap();
+                    if ips.is_empty() && addrs.is_empty() {
+                        // Include loopback addresses only if there are no other interfaces
+                        // or public addresses, this allows testing offline.
+                        ips = loopback;
+                    }
+                    for ip in ips {
+                        let port_if_unspecified = match ip {
+                            IpAddr::V4(_) if is_unspecified_v4 => {
+                                local_addr_v4.map(|addr| addr.port())
+                            }
+                            IpAddr::V6(_) if is_unspecified_v6 => {
+                                local_addr_v6.map(|addr| addr.port())
+                            }
+                            _ => None,
+                        };
+                        if let Some(port) = port_if_unspecified {
+                            let addr = SocketAddr::new(ip, port);
+                            addrs.entry(addr).or_insert(DirectAddrType::Local);
+                        }
+                    }
+                }
+
+                // If a socket is bound to a specific address, add it.
+                if !is_unspecified_v4 {
+                    if let Some(addr) = local_addr_v4 {
+                        addrs.entry(addr).or_insert(DirectAddrType::Local);
+                    }
+                }
+                if !is_unspecified_v6 {
+                    if let Some(addr) = local_addr_v6 {
+                        addrs.entry(addr).or_insert(DirectAddrType::Local);
+                    }
+                }
+
+                // Finally create and store store all these direct addresses and send any
+                // queued call-me-maybe messages.
+                msock.store_direct_addresses(
+                    addrs
+                        .iter()
+                        .map(|(addr, typ)| DirectAddr {
+                            addr: *addr,
+                            typ: *typ,
+                        })
+                        .collect(),
+                );
+                msock.send_queued_call_me_maybes();
+            }
+            .instrument(Span::current()),
+        );
+    }
+
+    /// Called when a direct addr update is done, no matter if it was successful or not.
+    fn finalize_direct_addrs_update(&mut self, why: &'static str) {
+        let new_why = self.msock.direct_addr_update_state.next_update();
+        if !self.msock.is_closed() {
+            if let Some(new_why) = new_why {
+                self.msock.direct_addr_update_state.run(new_why);
+                return;
+            }
+            self.periodic_re_stun_timer = new_re_stun_timer(true);
+        }
+
+        self.msock.direct_addr_update_state.finish_run();
+        debug!("direct addr update done ({})", why);
+    }
+
+    /// Updates `NetInfo.HavePortMap` to true.
+    #[instrument(level = "debug", skip_all)]
+    fn set_net_info_have_port_map(&mut self) {
+        if let Some(ref mut net_info_last) = self.net_info_last {
+            if net_info_last.have_port_map {
+                // No change.
+                return;
+            }
+            net_info_last.have_port_map = true;
+            self.net_info_last = Some(net_info_last.clone());
+        }
+    }
+
+    #[instrument(level = "debug", skip_all)]
+    async fn call_net_info_callback(&mut self, ni: NetInfo) {
+        if let Some(ref net_info_last) = self.net_info_last {
+            if ni.basically_equal(net_info_last) {
+                return;
+            }
+        }
+
+        self.net_info_last = Some(ni);
+    }
+
+    /// Calls net_report.
+    ///
+    /// Note that invoking this is managed by [`DirectAddrUpdateState`] via
+    /// [`Actor::refresh_direct_addrs`] and this should never be invoked directly.  Some day
+    /// this will be refactored to not allow this easy mistake to be made.
+    #[instrument(level = "debug", skip_all)]
+    async fn update_net_info(&mut self, why: &'static str) {
+        if self.msock.relay_map.is_empty() {
+            debug!("skipping net_report, empty RelayMap");
+            self.msg_sender
+                .send(ActorMessage::NetReport(Ok(None), why))
+                .await
+                .ok();
+            return;
+        }
+
+        let relay_map = self.msock.relay_map.clone();
+        let pconn4 = Some(self.pconn4.clone());
+        let pconn6 = self.pconn6.clone();
+
+        debug!("requesting net_report report");
+        match self
+            .net_reporter
+            .get_report_channel(relay_map, pconn4, pconn6)
+            .await
+        {
+            Ok(rx) => {
+                let msg_sender = self.msg_sender.clone();
+                tokio::task::spawn(async move {
+                    let report = time::timeout(NET_REPORT_TIMEOUT, rx).await;
+                    let report: anyhow::Result<_> = match report {
+                        Ok(Ok(Ok(report))) => Ok(Some(report)),
+                        Ok(Ok(Err(err))) => Err(err),
+                        Ok(Err(_)) => Err(anyhow!("net_report report not received")),
+                        Err(err) => Err(anyhow!("net_report report timeout: {:?}", err)),
+                    };
+                    msg_sender
+                        .send(ActorMessage::NetReport(report, why))
+                        .await
+                        .ok();
+                    // The receiver of the NetReport message will call
+                    // .finalize_direct_addrs_update().
+                });
+            }
+            Err(err) => {
+                warn!("unable to start net_report generation: {:?}", err);
+                self.finalize_direct_addrs_update(why);
+            }
+        }
+    }
+
+    async fn handle_net_report_report(&mut self, report: Option<Arc<net_report::Report>>) {
+        if let Some(ref report) = report {
+            self.msock
+                .ipv6_reported
+                .store(report.ipv6, Ordering::Relaxed);
+            let r = &report;
+            trace!(
+                "setting no_v4_send {} -> {}",
+                self.no_v4_send,
+                !r.ipv4_can_send
+            );
+            self.no_v4_send = !r.ipv4_can_send;
+
+            let have_port_map = self.port_mapper.watch_external_address().borrow().is_some();
+            let mut ni = NetInfo {
+                relay_latency: Default::default(),
+                mapping_varies_by_dest_ip: r.mapping_varies_by_dest_ip,
+                hair_pinning: r.hair_pinning,
+                portmap_probe: r.portmap_probe.clone(),
+                have_port_map,
+                working_ipv6: Some(r.ipv6),
+                os_has_ipv6: Some(r.os_has_ipv6),
+                working_udp: Some(r.udp),
+                working_icmp_v4: r.icmpv4,
+                working_icmp_v6: r.icmpv6,
+                preferred_relay: r.preferred_relay.clone(),
+            };
+            for (rid, d) in r.relay_v4_latency.iter() {
+                ni.relay_latency
+                    .insert(format!("{rid}-v4"), d.as_secs_f64());
+            }
+            for (rid, d) in r.relay_v6_latency.iter() {
+                ni.relay_latency
+                    .insert(format!("{rid}-v6"), d.as_secs_f64());
+            }
+
+            if ni.preferred_relay.is_none() {
+                // Perhaps UDP is blocked. Pick a deterministic but arbitrary one.
+                ni.preferred_relay = self.pick_relay_fallback();
+            }
+
+            if !self.set_nearest_relay(ni.preferred_relay.clone()) {
+                ni.preferred_relay = None;
+            }
+
+            // TODO: set link type
+            self.call_net_info_callback(ni).await;
+        }
+        self.update_direct_addresses(report);
+    }
+
+    fn set_nearest_relay(&mut self, relay_url: Option<RelayUrl>) -> bool {
+        let my_relay = self.msock.my_relay();
+        if relay_url == my_relay {
+            // No change.
+            return true;
+        }
+        let old_relay = self.msock.set_my_relay(relay_url.clone());
+
+        if let Some(ref relay_url) = relay_url {
+            inc!(MagicsockMetrics, relay_home_change);
+
+            // On change, notify all currently connected relay servers and
+            // start connecting to our home relay if we are not already.
+            info!("home is now relay {}, was {:?}", relay_url, old_relay);
+            self.msock.publish_my_addr();
+
+            self.send_relay_actor(RelayActorMessage::SetHome {
+                url: relay_url.clone(),
+            });
+        }
+
+        true
+    }
+
+    /// Returns a deterministic relay node to connect to. This is only used if net_report
+    /// couldn't find the nearest one, for instance, if UDP is blocked and thus STUN
+    /// latency checks aren't working.
+    ///
+    /// If no the [`RelayMap`] is empty, returns `0`.
+    fn pick_relay_fallback(&self) -> Option<RelayUrl> {
+        // TODO: figure out which relay node most of our nodes are using,
+        // and use that region as our fallback.
+        //
+        // If we already had selected something in the past and it has any
+        // nodes, we want to stay on it. If there are no nodes at all,
+        // stay on whatever relay we previously picked. If we need to pick
+        // one and have no node info, pick a node randomly.
+        //
+        // We used to do the above for legacy clients, but never updated it for disco.
+
+        let my_relay = self.msock.my_relay();
+        if my_relay.is_some() {
+            return my_relay;
+        }
+
+        let ids = self.msock.relay_map.urls().collect::<Vec<_>>();
+        let mut rng = rand::rngs::StdRng::seed_from_u64(0);
+        ids.choose(&mut rng).map(|c| (*c).clone())
+    }
+
+    /// Resets the preferred address for all nodes.
+    /// This is called when connectivity changes enough that we no longer trust the old routes.
+    #[instrument(skip_all, fields(me = %self.msock.me))]
+    fn reset_endpoint_states(&mut self) {
+        self.msock.node_map.reset_node_states()
+    }
+
+    /// Tells the relay actor to close stale relay connections.
+    ///
+    /// The relay connections who's local endpoints no longer exist after a network change
+    /// will error out soon enough.  Closing them eagerly speeds this up however and allows
+    /// re-establishing a relay connection faster.
+    async fn close_stale_relay_connections(&self) {
+        let ifs = interfaces::State::new().await;
+        let local_ips = ifs
+            .interfaces
+            .values()
+            .flat_map(|netif| netif.addrs())
+            .map(|ipnet| ipnet.addr())
+            .collect();
+        self.send_relay_actor(RelayActorMessage::MaybeCloseRelaysOnRebind(local_ips));
+    }
+
+    fn send_relay_actor(&self, msg: RelayActorMessage) {
+        match self.relay_actor_sender.try_send(msg) {
+            Ok(_) => {}
+            Err(mpsc::error::TrySendError::Closed(_)) => {
+                warn!("unable to send to relay actor, already closed");
+            }
+            Err(mpsc::error::TrySendError::Full(_)) => {
+                warn!("dropping message for relay actor, channel is full");
+            }
+        }
+    }
+
+    fn handle_relay_disco_message(
+        &mut self,
+        msg: &[u8],
+        url: &RelayUrl,
+        relay_node_src: PublicKey,
+    ) -> bool {
+        match disco::source_and_box(msg) {
+            Some((source, sealed_box)) => {
+                if relay_node_src != source {
+                    // TODO: return here?
+                    warn!("Received relay disco message from connection for {}, but with message from {}", relay_node_src.fmt_short(), source.fmt_short());
+                }
+                self.msock.handle_disco_message(
+                    source,
+                    sealed_box,
+                    DiscoMessageSource::Relay {
+                        url: url.clone(),
+                        key: relay_node_src,
+                    },
+                );
+                true
+            }
+            None => false,
+        }
+    }
+}
+
+fn new_re_stun_timer(initial_delay: bool) -> time::Interval {
+    // Pick a random duration between 20 and 26 seconds (just under 30s,
+    // a common UDP NAT timeout on Linux,etc)
+    let mut rng = rand::thread_rng();
+    let d: Duration = rng.gen_range(Duration::from_secs(20)..=Duration::from_secs(26));
+    if initial_delay {
+        debug!("scheduling periodic_stun to run in {}s", d.as_secs());
+        time::interval_at(time::Instant::now() + d, d)
+    } else {
+        debug!(
+            "scheduling periodic_stun to run immediately and in {}s",
+            d.as_secs()
+        );
+        time::interval(d)
+    }
+}
+
+/// Initial connection setup.
+fn bind(
+    addr_v4: Option<SocketAddrV4>,
+    addr_v6: Option<SocketAddrV6>,
+) -> Result<(UdpConn, Option<UdpConn>)> {
+    let addr_v4 = addr_v4.unwrap_or_else(|| SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0));
+    let pconn4 = UdpConn::bind(SocketAddr::V4(addr_v4)).context("bind IPv4 failed")?;
+
+    let ip4_port = pconn4.local_addr()?.port();
+    let ip6_port = ip4_port.checked_add(1).unwrap_or(ip4_port - 1);
+    let addr_v6 =
+        addr_v6.unwrap_or_else(|| SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, ip6_port, 0, 0));
+    let pconn6 = match UdpConn::bind(SocketAddr::V6(addr_v6)) {
+        Ok(conn) => Some(conn),
+        Err(err) => {
+            info!("bind ignoring IPv6 bind failure: {:?}", err);
+            None
+        }
+    };
+
+    Ok((pconn4, pconn6))
+}
+
+/// The discovered direct addresses of this [`MagicSock`].
+///
+/// These are all the [`DirectAddr`]s that this [`MagicSock`] is aware of for itself.
+/// They include all locally bound ones as well as those discovered by other mechanisms like
+/// STUN.
+#[derive(derive_more::Debug, Default, Clone)]
+struct DiscoveredDirectAddrs {
+    /// The last set of discovered direct addresses.
+    addrs: Watchable<BTreeSet<DirectAddr>>,
+
+    /// The last time the direct addresses were updated, even if there was no change.
+    ///
+    /// This is only ever None at startup.
+    updated_at: Arc<RwLock<Option<Instant>>>,
+}
+
+impl DiscoveredDirectAddrs {
+    /// Updates the direct addresses, returns `true` if they changed, `false` if not.
+    fn update(&self, addrs: BTreeSet<DirectAddr>) -> bool {
+        *self.updated_at.write().unwrap() = Some(Instant::now());
+        let updated = self.addrs.update(addrs).is_ok();
+        if updated {
+            event!(
+                target: "iroh::_events::direct_addrs",
+                Level::DEBUG,
+                addrs = ?self.addrs.get(),
+            );
+        }
+        updated
+    }
+
+    fn sockaddrs(&self) -> BTreeSet<SocketAddr> {
+        self.addrs.read().iter().map(|da| da.addr).collect()
+    }
+
+    /// Whether the direct addr information is considered "fresh".
+    ///
+    /// If not fresh you should probably update the direct addresses before using this info.
+    ///
+    /// Returns `Ok(())` if fresh enough and `Err(elapsed)` if not fresh enough.
+    /// `elapsed` is the time elapsed since the direct addresses were last updated.
+    ///
+    /// If there is no direct address information `Err(Duration::ZERO)` is returned.
+    fn fresh_enough(&self) -> Result<(), Duration> {
+        match *self.updated_at.read().expect("poisoned") {
+            None => Err(Duration::ZERO),
+            Some(time) => {
+                let elapsed = time.elapsed();
+                if elapsed <= ENDPOINTS_FRESH_ENOUGH_DURATION {
+                    Ok(())
+                } else {
+                    Err(elapsed)
+                }
+            }
+        }
+    }
+
+    fn to_call_me_maybe_message(&self) -> disco::CallMeMaybe {
+        let my_numbers = self.addrs.read().iter().map(|da| da.addr).collect();
+        disco::CallMeMaybe { my_numbers }
+    }
+
+    fn updates_stream(&self) -> DirectAddrsStream {
+        DirectAddrsStream {
+            initial: Some(self.addrs.get()),
+            inner: self.addrs.watch().into_stream(),
+        }
+    }
+}
+
+/// Stream returning local endpoints as they change.
+#[derive(Debug)]
+pub struct DirectAddrsStream {
+    initial: Option<BTreeSet<DirectAddr>>,
+    inner: watchable::WatcherStream<BTreeSet<DirectAddr>>,
+}
+
+impl Stream for DirectAddrsStream {
+    type Item = BTreeSet<DirectAddr>;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        let this = &mut *self;
+        if let Some(addrs) = this.initial.take() {
+            if !addrs.is_empty() {
+                return Poll::Ready(Some(addrs));
+            }
+        }
+        loop {
+            match Pin::new(&mut this.inner).poll_next(cx) {
+                Poll::Pending => break Poll::Pending,
+                Poll::Ready(Some(addrs)) => {
+                    if addrs.is_empty() {
+                        // When we start up we might initially have empty direct addrs as
+                        // the magic socket has not yet figured this out.  Later on this set
+                        // should never be empty.  However even if it was the magicsock
+                        // would be in a state not very usable so skipping those events is
+                        // probably fine.
+                        // To make sure we install the right waker we loop rather than
+                        // returning Poll::Pending immediately here.
+                        continue;
+                    } else {
+                        break Poll::Ready(Some(addrs));
+                    }
+                }
+                Poll::Ready(None) => break Poll::Ready(None),
+            }
+        }
+    }
+}
+
+/// Split a transmit containing a GSO payload into individual packets.
+///
+/// This allocates the data.
+///
+/// If the transmit has a segment size it contains multiple GSO packets.  It will be split
+/// into multiple packets according to that segment size.  If it does not have a segment
+/// size, the contents will be sent as a single packet.
+// TODO: If quinn stayed on bytes this would probably be much cheaper, probably.  Need to
+// figure out where they allocate the Vec.
+fn split_packets(transmit: &quinn_udp::Transmit) -> RelayContents {
+    let mut res = SmallVec::with_capacity(1);
+    let contents = transmit.contents;
+    if let Some(segment_size) = transmit.segment_size {
+        for chunk in contents.chunks(segment_size) {
+            res.push(Bytes::from(chunk.to_vec()));
+        }
+    } else {
+        res.push(Bytes::from(contents.to_vec()));
+    }
+    res
+}
+
+/// Splits a packet into its component items.
+#[derive(Debug)]
+struct PacketSplitIter {
+    bytes: Bytes,
+}
+
+impl PacketSplitIter {
+    /// Create a new PacketSplitIter from a packet.
+    ///
+    /// Returns an error if the packet is too big.
+    fn new(bytes: Bytes) -> Self {
+        Self { bytes }
+    }
+
+    fn fail(&mut self) -> Option<std::io::Result<Bytes>> {
+        self.bytes.clear();
+        Some(Err(std::io::Error::new(
+            std::io::ErrorKind::UnexpectedEof,
+            "",
+        )))
+    }
+}
+
+impl Iterator for PacketSplitIter {
+    type Item = std::io::Result<Bytes>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        use bytes::Buf;
+        if self.bytes.has_remaining() {
+            if self.bytes.remaining() < 2 {
+                return self.fail();
+            }
+            let len = self.bytes.get_u16_le() as usize;
+            if self.bytes.remaining() < len {
+                return self.fail();
+            }
+            let item = self.bytes.split_to(len);
+            Some(Ok(item))
+        } else {
+            None
+        }
+    }
+}
+
+/// The fake address used by the QUIC layer to address a node.
+///
+/// You can consider this as nothing more than a lookup key for a node the [`MagicSock`] knows
+/// about.
+///
+/// [`MagicSock`] can reach a node by several real socket addresses, or maybe even via the relay
+/// node.  The QUIC layer however needs to address a node by a stable [`SocketAddr`] so
+/// that normal socket APIs can function.  Thus when a new node is introduced to a [`MagicSock`]
+/// it is given a new fake address.  This is the type of that address.
+///
+/// It is but a newtype.  And in our QUIC-facing socket APIs like [`AsyncUdpSocket`] it
+/// comes in as the inner [`SocketAddr`], in those interfaces we have to be careful to do
+/// the conversion to this type.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub(crate) struct QuicMappedAddr(pub(crate) SocketAddr);
+
+/// Counter to always generate unique addresses for [`QuicMappedAddr`].
+static ADDR_COUNTER: AtomicU64 = AtomicU64::new(1);
+
+impl QuicMappedAddr {
+    /// The Prefix/L of our Unique Local Addresses.
+    const ADDR_PREFIXL: u8 = 0xfd;
+    /// The Global ID used in our Unique Local Addresses.
+    const ADDR_GLOBAL_ID: [u8; 5] = [21, 7, 10, 81, 11];
+    /// The Subnet ID used in our Unique Local Addresses.
+    const ADDR_SUBNET: [u8; 2] = [0; 2];
+
+    /// Generates a globally unique fake UDP address.
+    ///
+    /// This generates and IPv6 Unique Local Address according to RFC 4193.
+    pub(crate) fn generate() -> Self {
+        let mut addr = [0u8; 16];
+        addr[0] = Self::ADDR_PREFIXL;
+        addr[1..6].copy_from_slice(&Self::ADDR_GLOBAL_ID);
+        addr[6..8].copy_from_slice(&Self::ADDR_SUBNET);
+
+        let counter = ADDR_COUNTER.fetch_add(1, Ordering::Relaxed);
+        addr[8..16].copy_from_slice(&counter.to_be_bytes());
+
+        Self(SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr)), 12345))
+    }
+}
+
+impl std::fmt::Display for QuicMappedAddr {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "QuicMappedAddr({})", self.0)
+    }
+}
+fn disco_message_sent(msg: &disco::Message) {
+    match msg {
+        disco::Message::Ping(_) => {
+            inc!(MagicsockMetrics, sent_disco_ping);
+        }
+        disco::Message::Pong(_) => {
+            inc!(MagicsockMetrics, sent_disco_pong);
+        }
+        disco::Message::CallMeMaybe(_) => {
+            inc!(MagicsockMetrics, sent_disco_call_me_maybe);
+        }
+    }
+}
+
+/// A *direct address* on which an iroh-node might be contactable.
+///
+/// Direct addresses are UDP socket addresses on which an iroh node could potentially be
+/// contacted.  These can come from various sources depending on the network topology of the
+/// iroh node, see [`DirectAddrType`] for the several kinds of sources.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct DirectAddr {
+    /// The address.
+    pub addr: SocketAddr,
+    /// The origin of this direct address.
+    pub typ: DirectAddrType,
+}
+
+/// The type of direct address.
+///
+/// These are the various sources or origins from which an iroh node might have found a
+/// possible [`DirectAddr`].
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum DirectAddrType {
+    /// Not yet determined..
+    Unknown,
+    /// A locally bound socket address.
+    Local,
+    /// Public internet address discovered via STUN.
+    ///
+    /// When possible an iroh node will perform STUN to discover which is the address
+    /// from which it sends data on the public internet.  This can be different from locally
+    /// bound addresses when the node is on a local network which performs NAT or similar.
+    Stun,
+    /// An address assigned by the router using port mapping.
+    ///
+    /// When possible an iroh node will request a port mapping from the local router to
+    /// get a publicly routable direct address.
+    Portmapped,
+    /// Hard NAT: STUN'ed IPv4 address + local fixed port.
+    ///
+    /// It is possible to configure iroh to bound to a specific port and independently
+    /// configure the router to forward this port to the iroh node.  This indicates a
+    /// situation like this, which still uses STUN to discover the public address.
+    Stun4LocalPort,
+}
+
+impl Display for DirectAddrType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            DirectAddrType::Unknown => write!(f, "?"),
+            DirectAddrType::Local => write!(f, "local"),
+            DirectAddrType::Stun => write!(f, "stun"),
+            DirectAddrType::Portmapped => write!(f, "portmap"),
+            DirectAddrType::Stun4LocalPort => write!(f, "stun4localport"),
+        }
+    }
+}
+
+/// Contains information about the host's network state.
+#[derive(Debug, Clone, PartialEq)]
+struct NetInfo {
+    /// Says whether the host's NAT mappings vary based on the destination IP.
+    mapping_varies_by_dest_ip: Option<bool>,
+
+    /// If their router does hairpinning. It reports true even if there's no NAT involved.
+    hair_pinning: Option<bool>,
+
+    /// Whether the host has IPv6 internet connectivity.
+    working_ipv6: Option<bool>,
+
+    /// Whether the OS supports IPv6 at all, regardless of whether IPv6 internet connectivity is available.
+    os_has_ipv6: Option<bool>,
+
+    /// Whether the host has UDP internet connectivity.
+    working_udp: Option<bool>,
+
+    /// Whether ICMPv4 works, `None` means not checked.
+    working_icmp_v4: Option<bool>,
+
+    /// Whether ICMPv6 works, `None` means not checked.
+    working_icmp_v6: Option<bool>,
+
+    /// Whether we have an existing portmap open (UPnP, PMP, or PCP).
+    have_port_map: bool,
+
+    /// Probe indicating the presence of port mapping protocols on the LAN.
+    portmap_probe: Option<portmapper::ProbeOutput>,
+
+    /// This node's preferred relay server for incoming traffic.
+    ///
+    /// The node might be be temporarily connected to multiple relay servers (to send to
+    /// other nodes) but this is the relay on which you can always contact this node.  Also
+    /// known as home relay.
+    preferred_relay: Option<RelayUrl>,
+
+    /// The fastest recent time to reach various relay STUN servers, in seconds.
+    ///
+    /// This should only be updated rarely, or when there's a
+    /// material change, as any change here also gets uploaded to the control plane.
+    relay_latency: BTreeMap<String, f64>,
+}
+
+impl NetInfo {
+    /// Checks if this is probably still the same network as *other*.
+    ///
+    /// This tries to compare the network situation, without taking into account things
+    /// expected to change a little like e.g. latency to the relay server.
+    fn basically_equal(&self, other: &Self) -> bool {
+        let eq_icmp_v4 = match (self.working_icmp_v4, other.working_icmp_v4) {
+            (Some(slf), Some(other)) => slf == other,
+            _ => true, // ignore for comparison if only one report had this info
+        };
+        let eq_icmp_v6 = match (self.working_icmp_v6, other.working_icmp_v6) {
+            (Some(slf), Some(other)) => slf == other,
+            _ => true, // ignore for comparison if only one report had this info
+        };
+        self.mapping_varies_by_dest_ip == other.mapping_varies_by_dest_ip
+            && self.hair_pinning == other.hair_pinning
+            && self.working_ipv6 == other.working_ipv6
+            && self.os_has_ipv6 == other.os_has_ipv6
+            && self.working_udp == other.working_udp
+            && eq_icmp_v4
+            && eq_icmp_v6
+            && self.have_port_map == other.have_port_map
+            && self.portmap_probe == other.portmap_probe
+            && self.preferred_relay == other.preferred_relay
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use anyhow::Context;
+    use iroh_test::CallOnDrop;
+    use rand::RngCore;
+    use tokio_util::task::AbortOnDropHandle;
+
+    use super::*;
+    use crate::{defaults::staging::EU_RELAY_HOSTNAME, tls, Endpoint, RelayMode};
+
+    const ALPN: &[u8] = b"n0/test/1";
+
+    impl MagicSock {
+        #[track_caller]
+        pub fn add_test_addr(&self, node_addr: NodeAddr) {
+            self.add_node_addr(
+                node_addr,
+                Source::NamedApp {
+                    name: "test".into(),
+                },
+            )
+            .unwrap()
+        }
+    }
+
+    /// Magicsock plus wrappers for sending packets
+    #[derive(Clone)]
+    struct MagicStack {
+        secret_key: SecretKey,
+        endpoint: Endpoint,
+    }
+
+    impl MagicStack {
+        async fn new(relay_mode: RelayMode) -> Result<Self> {
+            let secret_key = SecretKey::generate();
+
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+
+            let endpoint = Endpoint::builder()
+                .secret_key(secret_key.clone())
+                .transport_config(transport_config)
+                .relay_mode(relay_mode)
+                .alpns(vec![ALPN.to_vec()])
+                .bind()
+                .await?;
+
+            Ok(Self {
+                secret_key,
+                endpoint,
+            })
+        }
+
+        fn tracked_endpoints(&self) -> Vec<PublicKey> {
+            self.endpoint
+                .magic_sock()
+                .list_remote_infos()
+                .into_iter()
+                .map(|ep| ep.node_id)
+                .collect()
+        }
+
+        fn public(&self) -> PublicKey {
+            self.secret_key.public()
+        }
+    }
+
+    /// Monitors endpoint changes and plumbs things together.
+    ///
+    /// This is a way of connecting endpoints without a relay server.  Whenever the local
+    /// endpoints of a magic endpoint change this address is added to the other magic
+    /// sockets.  This function will await until the endpoints are connected the first time
+    /// before returning.
+    ///
+    /// When the returned drop guard is dropped, the tasks doing this updating are stopped.
+    #[instrument(skip_all)]
+    async fn mesh_stacks(stacks: Vec<MagicStack>) -> Result<CallOnDrop> {
+        /// Registers endpoint addresses of a node to all other nodes.
+        fn update_direct_addrs(
+            stacks: &[MagicStack],
+            my_idx: usize,
+            new_addrs: BTreeSet<DirectAddr>,
+        ) {
+            let me = &stacks[my_idx];
+            for (i, m) in stacks.iter().enumerate() {
+                if i == my_idx {
+                    continue;
+                }
+
+                let addr = NodeAddr {
+                    node_id: me.public(),
+                    info: crate::AddrInfo {
+                        relay_url: None,
+                        direct_addresses: new_addrs.iter().map(|ep| ep.addr).collect(),
+                    },
+                };
+                m.endpoint.magic_sock().add_test_addr(addr);
+            }
+        }
+
+        // For each node, start a task which monitors its local endpoints and registers them
+        // with the other nodes as local endpoints become known.
+        let mut tasks = JoinSet::new();
+        for (my_idx, m) in stacks.iter().enumerate() {
+            let m = m.clone();
+            let stacks = stacks.clone();
+            tasks.spawn(async move {
+                let me = m.endpoint.node_id().fmt_short();
+                let mut stream = m.endpoint.direct_addresses();
+                while let Some(new_eps) = stream.next().await {
+                    info!(%me, "conn{} endpoints update: {:?}", my_idx + 1, new_eps);
+                    update_direct_addrs(&stacks, my_idx, new_eps);
+                }
+            });
+        }
+        let guard = CallOnDrop::new(move || {
+            tasks.abort_all();
+        });
+
+        // Wait for all nodes to be registered with each other.
+        time::timeout(Duration::from_secs(10), async move {
+            let all_node_ids: Vec<_> = stacks.iter().map(|ms| ms.endpoint.node_id()).collect();
+            loop {
+                let mut ready = Vec::with_capacity(stacks.len());
+                for ms in stacks.iter() {
+                    let endpoints = ms.tracked_endpoints();
+                    let my_node_id = ms.endpoint.node_id();
+                    let all_nodes_meshed = all_node_ids
+                        .iter()
+                        .filter(|node_id| **node_id != my_node_id)
+                        .all(|node_id| endpoints.contains(node_id));
+                    ready.push(all_nodes_meshed);
+                }
+                if ready.iter().all(|meshed| *meshed) {
+                    break;
+                }
+                tokio::time::sleep(Duration::from_millis(200)).await;
+            }
+        })
+        .await
+        .context("failed to connect nodes")?;
+        info!("all nodes meshed");
+        Ok(guard)
+    }
+
+    #[instrument(skip_all, fields(me = %ep.endpoint.node_id().fmt_short()))]
+    async fn echo_receiver(ep: MagicStack) -> Result<()> {
+        info!("accepting conn");
+        let conn = ep.endpoint.accept().await.expect("no conn");
+
+        info!("connecting");
+        let conn = conn.await.context("[receiver] connecting")?;
+        info!("accepting bi");
+        let (mut send_bi, mut recv_bi) =
+            conn.accept_bi().await.context("[receiver] accepting bi")?;
+
+        info!("reading");
+        let val = recv_bi
+            .read_to_end(usize::MAX)
+            .await
+            .context("[receiver] reading to end")?;
+
+        info!("replying");
+        for chunk in val.chunks(12) {
+            send_bi
+                .write_all(chunk)
+                .await
+                .context("[receiver] sending chunk")?;
+        }
+
+        info!("finishing");
+        send_bi.finish().context("[receiver] finishing")?;
+        send_bi.stopped().await.context("[receiver] stopped")?;
+
+        let stats = conn.stats();
+        info!("stats: {:#?}", stats);
+        // TODO: ensure panics in this function are reported ok
+        assert!(
+            stats.path.lost_packets < 10,
+            "[receiver] should not loose many packets",
+        );
+
+        info!("close");
+        conn.close(0u32.into(), b"done");
+        info!("wait idle");
+        ep.endpoint.endpoint().wait_idle().await;
+
+        Ok(())
+    }
+
+    #[instrument(skip_all, fields(me = %ep.endpoint.node_id().fmt_short()))]
+    async fn echo_sender(ep: MagicStack, dest_id: PublicKey, msg: &[u8]) -> Result<()> {
+        info!("connecting to {}", dest_id.fmt_short());
+        let dest = NodeAddr::new(dest_id);
+        let conn = ep
+            .endpoint
+            .connect(dest, ALPN)
+            .await
+            .context("[sender] connect")?;
+
+        info!("opening bi");
+        let (mut send_bi, mut recv_bi) = conn.open_bi().await.context("[sender] open bi")?;
+
+        info!("writing message");
+        send_bi.write_all(msg).await.context("[sender] write all")?;
+
+        info!("finishing");
+        send_bi.finish().context("[sender] finish")?;
+        send_bi.stopped().await.context("[sender] stopped")?;
+
+        info!("reading_to_end");
+        let val = recv_bi.read_to_end(usize::MAX).await.context("[sender]")?;
+        assert_eq!(
+            val,
+            msg,
+            "[sender] expected {}, got {}",
+            hex::encode(msg),
+            hex::encode(&val)
+        );
+
+        let stats = conn.stats();
+        info!("stats: {:#?}", stats);
+        assert!(
+            stats.path.lost_packets < 10,
+            "[sender] should not loose many packets",
+        );
+
+        info!("close");
+        conn.close(0u32.into(), b"done");
+        info!("wait idle");
+        ep.endpoint.endpoint().wait_idle().await;
+        Ok(())
+    }
+
+    /// Runs a roundtrip between the [`echo_sender`] and [`echo_receiver`].
+    async fn run_roundtrip(sender: MagicStack, receiver: MagicStack, payload: &[u8]) {
+        let send_node_id = sender.endpoint.node_id();
+        let recv_node_id = receiver.endpoint.node_id();
+        info!("\nroundtrip: {send_node_id:#} -> {recv_node_id:#}");
+
+        let receiver_task = tokio::spawn(echo_receiver(receiver));
+        let sender_res = echo_sender(sender, recv_node_id, payload).await;
+        let sender_is_err = match sender_res {
+            Ok(()) => false,
+            Err(err) => {
+                eprintln!("[sender] Error:\n{err:#?}");
+                true
+            }
+        };
+        let receiver_is_err = match receiver_task.await {
+            Ok(Ok(())) => false,
+            Ok(Err(err)) => {
+                eprintln!("[receiver] Error:\n{err:#?}");
+                true
+            }
+            Err(joinerr) => {
+                if joinerr.is_panic() {
+                    std::panic::resume_unwind(joinerr.into_panic());
+                } else {
+                    eprintln!("[receiver] Error:\n{joinerr:#?}");
+                }
+                true
+            }
+        };
+        if sender_is_err || receiver_is_err {
+            panic!("Sender or receiver errored");
+        }
+    }
+
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_two_devices_roundtrip_quinn_magic() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+
+        let m1 = MagicStack::new(RelayMode::Disabled).await?;
+        let m2 = MagicStack::new(RelayMode::Disabled).await?;
+
+        let _guard = mesh_stacks(vec![m1.clone(), m2.clone()]).await?;
+
+        for i in 0..5 {
+            info!("\n-- round {i}");
+            run_roundtrip(m1.clone(), m2.clone(), b"hello m1").await;
+            run_roundtrip(m2.clone(), m1.clone(), b"hello m2").await;
+
+            info!("\n-- larger data");
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            run_roundtrip(m1.clone(), m2.clone(), &data).await;
+            run_roundtrip(m2.clone(), m1.clone(), &data).await;
+        }
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_regression_network_change_rebind_wakes_connection_driver(
+    ) -> testresult::TestResult {
+        let _ = iroh_test::logging::setup();
+        let m1 = MagicStack::new(RelayMode::Disabled).await?;
+        let m2 = MagicStack::new(RelayMode::Disabled).await?;
+
+        println!("Net change");
+        m1.endpoint.magic_sock().force_network_change(true).await;
+        tokio::time::sleep(Duration::from_secs(1)).await; // wait for socket rebinding
+
+        let _guard = mesh_stacks(vec![m1.clone(), m2.clone()]).await?;
+
+        let _handle = AbortOnDropHandle::new(tokio::spawn({
+            let endpoint = m2.endpoint.clone();
+            async move {
+                while let Some(incoming) = endpoint.accept().await {
+                    println!("Incoming first conn!");
+                    let conn = incoming.await?;
+                    conn.closed().await;
+                }
+
+                testresult::TestResult::Ok(())
+            }
+        }));
+
+        println!("first conn!");
+        let conn = m1
+            .endpoint
+            .connect(m2.endpoint.node_addr().await?, ALPN)
+            .await?;
+        println!("Closing first conn");
+        conn.close(0u32.into(), b"bye lolz");
+        conn.closed().await;
+        println!("Closed first conn");
+
+        Ok(())
+    }
+
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_two_devices_roundtrip_network_change() -> Result<()> {
+        time::timeout(
+            Duration::from_secs(90),
+            test_two_devices_roundtrip_network_change_impl(),
+        )
+        .await?
+    }
+
+    /// Same structure as `test_two_devices_roundtrip_quinn_magic`, but interrupts regularly
+    /// with (simulated) network changes.
+    async fn test_two_devices_roundtrip_network_change_impl() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+
+        let m1 = MagicStack::new(RelayMode::Disabled).await?;
+        let m2 = MagicStack::new(RelayMode::Disabled).await?;
+
+        let _guard = mesh_stacks(vec![m1.clone(), m2.clone()]).await?;
+
+        let offset = || {
+            let delay = rand::thread_rng().gen_range(10..=500);
+            Duration::from_millis(delay)
+        };
+        let rounds = 5;
+
+        // Regular network changes to m1 only.
+        let m1_network_change_guard = {
+            let m1 = m1.clone();
+            let task = tokio::spawn(async move {
+                loop {
+                    println!("[m1] network change");
+                    m1.endpoint.magic_sock().force_network_change(true).await;
+                    time::sleep(offset()).await;
+                }
+            });
+            CallOnDrop::new(move || {
+                task.abort();
+            })
+        };
+
+        for i in 0..rounds {
+            println!("-- [m1 changes] round {}", i + 1);
+            run_roundtrip(m1.clone(), m2.clone(), b"hello m1").await;
+            run_roundtrip(m2.clone(), m1.clone(), b"hello m2").await;
+
+            println!("-- [m1 changes] larger data");
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            run_roundtrip(m1.clone(), m2.clone(), &data).await;
+            run_roundtrip(m2.clone(), m1.clone(), &data).await;
+        }
+
+        std::mem::drop(m1_network_change_guard);
+
+        // Regular network changes to m2 only.
+        let m2_network_change_guard = {
+            let m2 = m2.clone();
+            let task = tokio::spawn(async move {
+                loop {
+                    println!("[m2] network change");
+                    m2.endpoint.magic_sock().force_network_change(true).await;
+                    time::sleep(offset()).await;
+                }
+            });
+            CallOnDrop::new(move || {
+                task.abort();
+            })
+        };
+
+        for i in 0..rounds {
+            println!("-- [m2 changes] round {}", i + 1);
+            run_roundtrip(m1.clone(), m2.clone(), b"hello m1").await;
+            run_roundtrip(m2.clone(), m1.clone(), b"hello m2").await;
+
+            println!("-- [m2 changes] larger data");
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            run_roundtrip(m1.clone(), m2.clone(), &data).await;
+            run_roundtrip(m2.clone(), m1.clone(), &data).await;
+        }
+
+        std::mem::drop(m2_network_change_guard);
+
+        // Regular network changes to both m1 and m2 only.
+        let m1_m2_network_change_guard = {
+            let m1 = m1.clone();
+            let m2 = m2.clone();
+            let task = tokio::spawn(async move {
+                println!("-- [m1] network change");
+                m1.endpoint.magic_sock().force_network_change(true).await;
+                println!("-- [m2] network change");
+                m2.endpoint.magic_sock().force_network_change(true).await;
+                time::sleep(offset()).await;
+            });
+            CallOnDrop::new(move || {
+                task.abort();
+            })
+        };
+
+        for i in 0..rounds {
+            println!("-- [m1 & m2 changes] round {}", i + 1);
+            run_roundtrip(m1.clone(), m2.clone(), b"hello m1").await;
+            run_roundtrip(m2.clone(), m1.clone(), b"hello m2").await;
+
+            println!("-- [m1 & m2 changes] larger data");
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            run_roundtrip(m1.clone(), m2.clone(), &data).await;
+            run_roundtrip(m2.clone(), m1.clone(), &data).await;
+        }
+
+        std::mem::drop(m1_m2_network_change_guard);
+        Ok(())
+    }
+
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_two_devices_setup_teardown() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+        for i in 0..10 {
+            println!("-- round {i}");
+            println!("setting up magic stack");
+            let m1 = MagicStack::new(RelayMode::Disabled).await?;
+            let m2 = MagicStack::new(RelayMode::Disabled).await?;
+
+            let _guard = mesh_stacks(vec![m1.clone(), m2.clone()]).await?;
+
+            println!("closing endpoints");
+            let msock1 = m1.endpoint.magic_sock();
+            let msock2 = m2.endpoint.magic_sock();
+            m1.endpoint.close().await?;
+            m2.endpoint.close().await?;
+
+            assert!(msock1.msock.is_closed());
+            assert!(msock2.msock.is_closed());
+        }
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_two_devices_roundtrip_quinn_raw() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        let make_conn = |addr: SocketAddr| -> anyhow::Result<quinn::Endpoint> {
+            let key = SecretKey::generate();
+            let conn = std::net::UdpSocket::bind(addr)?;
+
+            let quic_server_config = tls::make_server_config(&key, vec![ALPN.to_vec()], false)?;
+            let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(quic_server_config));
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.keep_alive_interval(Some(Duration::from_secs(5)));
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+            server_config.transport_config(Arc::new(transport_config));
+            let mut quic_ep = quinn::Endpoint::new(
+                quinn::EndpointConfig::default(),
+                Some(server_config),
+                conn,
+                Arc::new(quinn::TokioRuntime),
+            )?;
+
+            let quic_client_config =
+                tls::make_client_config(&key, None, vec![ALPN.to_vec()], false)?;
+            let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+            client_config.transport_config(Arc::new(transport_config));
+            quic_ep.set_default_client_config(client_config);
+
+            Ok(quic_ep)
+        };
+
+        let m1 = make_conn("127.0.0.1:0".parse().unwrap())?;
+        let m2 = make_conn("127.0.0.1:0".parse().unwrap())?;
+
+        // msg from  a -> b
+        macro_rules! roundtrip {
+            ($a:expr, $b:expr, $msg:expr) => {
+                let a = $a.clone();
+                let b = $b.clone();
+                let a_name = stringify!($a);
+                let b_name = stringify!($b);
+                println!("{} -> {} ({} bytes)", a_name, b_name, $msg.len());
+
+                let a_addr = a.local_addr()?;
+                let b_addr = b.local_addr()?;
+
+                println!("{}: {}, {}: {}", a_name, a_addr, b_name, b_addr);
+
+                let b_task = tokio::task::spawn(async move {
+                    println!("[{b_name}] accepting conn");
+                    let conn = b.accept().await.expect("no conn");
+                    println!("[{}] connecting", b_name);
+                    let conn = conn
+                        .await
+                        .with_context(|| format!("[{b_name}] connecting"))?;
+                    println!("[{}] accepting bi", b_name);
+                    let (mut send_bi, mut recv_bi) = conn
+                        .accept_bi()
+                        .await
+                        .with_context(|| format!("[{b_name}] accepting bi"))?;
+
+                    println!("[{b_name}] reading");
+                    let val = recv_bi
+                        .read_to_end(usize::MAX)
+                        .await
+                        .with_context(|| format!("[{b_name}] reading to end"))?;
+                    println!("[{b_name}] finishing");
+                    send_bi
+                        .finish()
+                        .with_context(|| format!("[{b_name}] finishing"))?;
+                    send_bi
+                        .stopped()
+                        .await
+                        .with_context(|| format!("[b_name] stopped"))?;
+
+                    println!("[{b_name}] close");
+                    conn.close(0u32.into(), b"done");
+                    println!("[{b_name}] closed");
+
+                    Ok::<_, anyhow::Error>(val)
+                });
+
+                println!("[{a_name}] connecting to {b_addr}");
+                let conn = a
+                    .connect(b_addr, "localhost")?
+                    .await
+                    .with_context(|| format!("[{a_name}] connect"))?;
+
+                println!("[{a_name}] opening bi");
+                let (mut send_bi, mut recv_bi) = conn
+                    .open_bi()
+                    .await
+                    .with_context(|| format!("[{a_name}] open bi"))?;
+                println!("[{a_name}] writing message");
+                send_bi
+                    .write_all(&$msg[..])
+                    .await
+                    .with_context(|| format!("[{a_name}] write all"))?;
+
+                println!("[{a_name}] finishing");
+                send_bi
+                    .finish()
+                    .with_context(|| format!("[{a_name}] finish"))?;
+                send_bi
+                    .stopped()
+                    .await
+                    .with_context(|| format!("[{a_name}] stopped"))?;
+
+                println!("[{a_name}] reading_to_end");
+                let _ = recv_bi
+                    .read_to_end(usize::MAX)
+                    .await
+                    .with_context(|| format!("[{a_name}] reading_to_end"))?;
+                println!("[{a_name}] close");
+                conn.close(0u32.into(), b"done");
+                println!("[{a_name}] wait idle");
+                a.wait_idle().await;
+
+                drop(send_bi);
+
+                // make sure the right values arrived
+                println!("[{a_name}] waiting for channel");
+                let val = b_task.await??;
+                anyhow::ensure!(
+                    val == $msg,
+                    "expected {}, got {}",
+                    hex::encode($msg),
+                    hex::encode(val)
+                );
+            };
+        }
+
+        for i in 0..10 {
+            println!("-- round {}", i + 1);
+            roundtrip!(m1, m2, b"hello m1");
+            roundtrip!(m2, m1, b"hello m2");
+
+            println!("-- larger data");
+
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            roundtrip!(m1, m2, data);
+            roundtrip!(m2, m1, data);
+        }
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_two_devices_roundtrip_quinn_rebinding_conn() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        fn make_conn(addr: SocketAddr) -> anyhow::Result<quinn::Endpoint> {
+            let key = SecretKey::generate();
+            let conn = UdpConn::bind(addr)?;
+
+            let quic_server_config = tls::make_server_config(&key, vec![ALPN.to_vec()], false)?;
+            let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(quic_server_config));
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.keep_alive_interval(Some(Duration::from_secs(5)));
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+            server_config.transport_config(Arc::new(transport_config));
+            let mut quic_ep = quinn::Endpoint::new_with_abstract_socket(
+                quinn::EndpointConfig::default(),
+                Some(server_config),
+                Arc::new(conn),
+                Arc::new(quinn::TokioRuntime),
+            )?;
+
+            let quic_client_config =
+                tls::make_client_config(&key, None, vec![ALPN.to_vec()], false)?;
+            let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+            let mut transport_config = quinn::TransportConfig::default();
+            transport_config.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
+            client_config.transport_config(Arc::new(transport_config));
+            quic_ep.set_default_client_config(client_config);
+
+            Ok(quic_ep)
+        }
+
+        let m1 = make_conn("127.0.0.1:7770".parse().unwrap())?;
+        let m2 = make_conn("127.0.0.1:7771".parse().unwrap())?;
+
+        // msg from  a -> b
+        macro_rules! roundtrip {
+            ($a:expr, $b:expr, $msg:expr) => {
+                let a = $a.clone();
+                let b = $b.clone();
+                let a_name = stringify!($a);
+                let b_name = stringify!($b);
+                println!("{} -> {} ({} bytes)", a_name, b_name, $msg.len());
+
+                let a_addr: SocketAddr = format!("127.0.0.1:{}", a.local_addr()?.port())
+                    .parse()
+                    .unwrap();
+                let b_addr: SocketAddr = format!("127.0.0.1:{}", b.local_addr()?.port())
+                    .parse()
+                    .unwrap();
+
+                println!("{}: {}, {}: {}", a_name, a_addr, b_name, b_addr);
+
+                let b_task = tokio::task::spawn(async move {
+                    println!("[{}] accepting conn", b_name);
+                    let conn = b.accept().await.expect("no conn");
+                    println!("[{}] connecting", b_name);
+                    let conn = conn
+                        .await
+                        .with_context(|| format!("[{}] connecting", b_name))?;
+                    println!("[{}] accepting bi", b_name);
+                    let (mut send_bi, mut recv_bi) = conn
+                        .accept_bi()
+                        .await
+                        .with_context(|| format!("[{}] accepting bi", b_name))?;
+
+                    println!("[{}] reading", b_name);
+                    let val = recv_bi
+                        .read_to_end(usize::MAX)
+                        .await
+                        .with_context(|| format!("[{}] reading to end", b_name))?;
+                    println!("[{}] finishing", b_name);
+                    send_bi
+                        .finish()
+                        .with_context(|| format!("[{}] finishing", b_name))?;
+                    send_bi
+                        .stopped()
+                        .await
+                        .with_context(|| format!("[{b_name}] stopped"))?;
+
+                    println!("[{}] close", b_name);
+                    conn.close(0u32.into(), b"done");
+                    println!("[{}] closed", b_name);
+
+                    Ok::<_, anyhow::Error>(val)
+                });
+
+                println!("[{}] connecting to {}", a_name, b_addr);
+                let conn = a
+                    .connect(b_addr, "localhost")?
+                    .await
+                    .with_context(|| format!("[{}] connect", a_name))?;
+
+                println!("[{}] opening bi", a_name);
+                let (mut send_bi, mut recv_bi) = conn
+                    .open_bi()
+                    .await
+                    .with_context(|| format!("[{}] open bi", a_name))?;
+                println!("[{}] writing message", a_name);
+                send_bi
+                    .write_all(&$msg[..])
+                    .await
+                    .with_context(|| format!("[{}] write all", a_name))?;
+
+                println!("[{}] finishing", a_name);
+                send_bi
+                    .finish()
+                    .with_context(|| format!("[{}] finish", a_name))?;
+                send_bi
+                    .stopped()
+                    .await
+                    .with_context(|| format!("[{a_name}] stopped"))?;
+
+                println!("[{}] reading_to_end", a_name);
+                let _ = recv_bi
+                    .read_to_end(usize::MAX)
+                    .await
+                    .with_context(|| format!("[{}]", a_name))?;
+                println!("[{}] close", a_name);
+                conn.close(0u32.into(), b"done");
+                println!("[{}] wait idle", a_name);
+                a.wait_idle().await;
+
+                drop(send_bi);
+
+                // make sure the right values arrived
+                println!("[{}] waiting for channel", a_name);
+                let val = b_task.await??;
+                anyhow::ensure!(
+                    val == $msg,
+                    "expected {}, got {}",
+                    hex::encode($msg),
+                    hex::encode(val)
+                );
+            };
+        }
+
+        for i in 0..10 {
+            println!("-- round {}", i + 1);
+            roundtrip!(m1, m2, b"hello m1");
+            roundtrip!(m2, m1, b"hello m2");
+
+            println!("-- larger data");
+
+            let mut data = vec![0u8; 10 * 1024];
+            rand::thread_rng().fill_bytes(&mut data);
+            roundtrip!(m1, m2, data);
+            roundtrip!(m2, m1, data);
+        }
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_split_packets() {
+        fn mk_transmit(contents: &[u8], segment_size: Option<usize>) -> quinn_udp::Transmit<'_> {
+            let destination = "127.0.0.1:0".parse().unwrap();
+            quinn_udp::Transmit {
+                destination,
+                ecn: None,
+                contents,
+                segment_size,
+                src_ip: None,
+            }
+        }
+        fn mk_expected(parts: impl IntoIterator<Item = &'static str>) -> RelayContents {
+            parts
+                .into_iter()
+                .map(|p| p.as_bytes().to_vec().into())
+                .collect()
+        }
+        // no split
+        assert_eq!(
+            split_packets(&mk_transmit(b"hello", None)),
+            mk_expected(["hello"])
+        );
+        // split without rest
+        assert_eq!(
+            split_packets(&mk_transmit(b"helloworld", Some(5))),
+            mk_expected(["hello", "world"])
+        );
+        // split with rest and second transmit
+        assert_eq!(
+            split_packets(&mk_transmit(b"hello world", Some(5))),
+            mk_expected(["hello", " worl", "d"]) // spellchecker:disable-line
+        );
+        // split that results in 1 packet
+        assert_eq!(
+            split_packets(&mk_transmit(b"hello world", Some(1000))),
+            mk_expected(["hello world"])
+        );
+    }
+
+    #[tokio::test]
+    async fn test_local_endpoints() {
+        let _guard = iroh_test::logging::setup();
+        let ms = Handle::new(Default::default()).await.unwrap();
+
+        // See if we can get endpoints.
+        let eps0 = ms.direct_addresses().next().await.unwrap();
+        println!("{eps0:?}");
+        assert!(!eps0.is_empty());
+
+        // Getting the endpoints again immediately should give the same results.
+        let eps1 = ms.direct_addresses().next().await.unwrap();
+        println!("{eps1:?}");
+        assert_eq!(eps0, eps1);
+    }
+
+    #[tokio::test]
+    async fn test_watch_home_relay() {
+        // use an empty relay map to get full control of the changes during the test
+        let ops = Options {
+            relay_map: RelayMap::empty(),
+            ..Default::default()
+        };
+        let msock = MagicSock::spawn(ops).await.unwrap();
+        let mut relay_stream = msock.watch_home_relay();
+
+        // no relay, nothing to report
+        assert_eq!(
+            futures_lite::future::poll_once(relay_stream.next()).await,
+            None
+        );
+
+        let url: RelayUrl = format!("https://{}", EU_RELAY_HOSTNAME).parse().unwrap();
+        msock.set_my_relay(Some(url.clone()));
+
+        assert_eq!(relay_stream.next().await, Some(url.clone()));
+
+        // drop the stream and query it again, the result should be immediately available
+
+        let mut relay_stream = msock.watch_home_relay();
+        assert_eq!(
+            futures_lite::future::poll_once(relay_stream.next()).await,
+            Some(Some(url))
+        );
+    }
+
+    /// Creates a new [`quinn::Endpoint`] hooked up to a [`MagicSock`].
+    ///
+    /// This is without involving [`crate::endpoint::Endpoint`].  The socket will accept
+    /// connections using [`ALPN`].
+    ///
+    /// Use [`magicsock_connect`] to establish connections.
+    #[instrument(name = "ep", skip_all, fields(me = secret_key.public().fmt_short()))]
+    async fn magicsock_ep(secret_key: SecretKey) -> anyhow::Result<(quinn::Endpoint, Handle)> {
+        let opts = Options {
+            addr_v4: None,
+            addr_v6: None,
+            secret_key: secret_key.clone(),
+            relay_map: RelayMap::empty(),
+            node_map: None,
+            discovery: None,
+            dns_resolver: crate::dns::default_resolver().clone(),
+            proxy_url: None,
+            insecure_skip_relay_cert_verify: true,
+        };
+        let msock = MagicSock::spawn(opts).await?;
+        let server_config = crate::endpoint::make_server_config(
+            &secret_key,
+            vec![ALPN.to_vec()],
+            Arc::new(quinn::TransportConfig::default()),
+            true,
+        )?;
+        let mut endpoint_config = quinn::EndpointConfig::default();
+        endpoint_config.grease_quic_bit(false);
+        let endpoint = quinn::Endpoint::new_with_abstract_socket(
+            endpoint_config,
+            Some(server_config),
+            Arc::new(msock.clone()),
+            Arc::new(quinn::TokioRuntime),
+        )?;
+        Ok((endpoint, msock))
+    }
+
+    /// Connects from `ep` returned by [`magicsock_ep`] to the `node_id`.
+    ///
+    /// Uses [`ALPN`], `node_id`, must match `addr`.
+    #[instrument(name = "connect", skip_all, fields(me = ep_secret_key.public().fmt_short()))]
+    async fn magicsock_connect(
+        ep: &quinn::Endpoint,
+        ep_secret_key: SecretKey,
+        addr: QuicMappedAddr,
+        node_id: NodeId,
+    ) -> Result<quinn::Connection> {
+        // Endpoint::connect sets this, do the same to have similar behaviour.
+        let mut transport_config = quinn::TransportConfig::default();
+        transport_config.keep_alive_interval(Some(Duration::from_secs(1)));
+
+        magicsock_connet_with_transport_config(
+            ep,
+            ep_secret_key,
+            addr,
+            node_id,
+            Arc::new(transport_config),
+        )
+        .await
+    }
+
+    /// Connects from `ep` returned by [`magicsock_ep`] to the `node_id`.
+    ///
+    /// This version allows customising the transport config.
+    ///
+    /// Uses [`ALPN`], `node_id`, must match `addr`.
+    #[instrument(name = "connect", skip_all, fields(me = ep_secret_key.public().fmt_short()))]
+    async fn magicsock_connet_with_transport_config(
+        ep: &quinn::Endpoint,
+        ep_secret_key: SecretKey,
+        addr: QuicMappedAddr,
+        node_id: NodeId,
+        transport_config: Arc<quinn::TransportConfig>,
+    ) -> Result<quinn::Connection> {
+        let alpns = vec![ALPN.to_vec()];
+        let quic_client_config =
+            tls::make_client_config(&ep_secret_key, Some(node_id), alpns, true)?;
+        let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+        client_config.transport_config(transport_config);
+        let connect = ep.connect_with(client_config, addr.0, "localhost")?;
+        let connection = connect.await?;
+        Ok(connection)
+    }
+
+    #[tokio::test]
+    async fn test_try_send_no_send_addr() {
+        // Regression test: if there is no send_addr we should keep being able to use the
+        // Endpoint.
+        let _guard = iroh_test::logging::setup();
+
+        let secret_key_1 = SecretKey::from_bytes(&[1u8; 32]);
+        let secret_key_2 = SecretKey::from_bytes(&[2u8; 32]);
+        let node_id_2 = secret_key_2.public();
+        let secret_key_missing_node = SecretKey::from_bytes(&[255u8; 32]);
+        let node_id_missing_node = secret_key_missing_node.public();
+
+        let (ep_1, msock_1) = magicsock_ep(secret_key_1.clone()).await.unwrap();
+
+        // Generate an address not present in the NodeMap.
+        let bad_addr = QuicMappedAddr::generate();
+
+        // 500ms is rather fast here.  Running this locally it should always be the correct
+        // timeout.  If this is too slow however the test will not become flaky as we are
+        // expecting the timeout, we might just get the timeout for the wrong reason.  But
+        // this speeds up the test.
+        let res = tokio::time::timeout(
+            Duration::from_millis(500),
+            magicsock_connect(&ep_1, secret_key_1.clone(), bad_addr, node_id_missing_node),
+        )
+        .await;
+        assert!(res.is_err(), "expecting timeout");
+
+        // Now check we can still create another connection with this endpoint.
+        let (ep_2, msock_2) = magicsock_ep(secret_key_2.clone()).await.unwrap();
+
+        // This needs an accept task
+        let accept_task = tokio::spawn({
+            async fn accept(ep: quinn::Endpoint) -> Result<()> {
+                let incoming = ep.accept().await.ok_or(anyhow!("no incoming"))?;
+                let _conn = incoming.accept()?.await?;
+
+                // Keep this connection alive for a while
+                tokio::time::sleep(Duration::from_secs(10)).await;
+                info!("accept finished");
+                Ok(())
+            }
+            let ep_2 = ep_2.clone();
+            async move {
+                if let Err(err) = accept(ep_2).await {
+                    error!("{err:#}");
+                }
+            }
+            .instrument(info_span!("ep2.accept, me = node_id_2.fmt_short()"))
+        });
+        let _accept_task = AbortOnDropHandle::new(accept_task);
+
+        let node_addr_2 = NodeAddr {
+            node_id: node_id_2,
+            info: AddrInfo {
+                relay_url: None,
+                direct_addresses: msock_2
+                    .direct_addresses()
+                    .next()
+                    .await
+                    .expect("no direct addrs")
+                    .into_iter()
+                    .map(|x| x.addr)
+                    .collect(),
+            },
+        };
+        msock_1
+            .add_node_addr(
+                node_addr_2,
+                Source::NamedApp {
+                    name: "test".into(),
+                },
+            )
+            .unwrap();
+        let addr = msock_1.get_mapping_addr(node_id_2).unwrap();
+        let res = tokio::time::timeout(
+            Duration::from_secs(10),
+            magicsock_connect(&ep_1, secret_key_1.clone(), addr, node_id_2),
+        )
+        .await
+        .expect("timeout while connecting");
+
+        // aka assert!(res.is_ok()) but with nicer error reporting.
+        res.unwrap();
+
+        // TODO: Now check if we can connect to a repaired ep_3, but we can't modify that
+        // much internal state for now.
+    }
+
+    #[tokio::test]
+    async fn test_try_send_no_udp_addr_or_relay_url() {
+        // This specifically tests the `if udp_addr.is_none() && relay_url.is_none()`
+        // behaviour of MagicSock::try_send.
+        let _logging_guard = iroh_test::logging::setup();
+
+        let secret_key_1 = SecretKey::from_bytes(&[1u8; 32]);
+        let secret_key_2 = SecretKey::from_bytes(&[2u8; 32]);
+        let node_id_2 = secret_key_2.public();
+
+        let (ep_1, msock_1) = magicsock_ep(secret_key_1.clone()).await.unwrap();
+        let (ep_2, msock_2) = magicsock_ep(secret_key_2.clone()).await.unwrap();
+
+        // We need a task to accept the connection.
+        let accept_task = tokio::spawn({
+            async fn accept(ep: quinn::Endpoint) -> Result<()> {
+                let incoming = ep.accept().await.ok_or(anyhow!("no incoming"))?;
+                let conn = incoming.accept()?.await?;
+                let mut stream = conn.accept_uni().await?;
+                stream.read_to_end(1 << 16).await?;
+                info!("accept finished");
+                Ok(())
+            }
+            let ep_2 = ep_2.clone();
+            async move {
+                if let Err(err) = accept(ep_2).await {
+                    error!("{err:#}");
+                }
+            }
+            .instrument(info_span!("ep2.accept", me = node_id_2.fmt_short()))
+        });
+        let _accept_task = AbortOnDropHandle::new(accept_task);
+
+        // Add an empty entry in the NodeMap of ep_1
+        msock_1.node_map.add_node_addr(
+            NodeAddr {
+                node_id: node_id_2,
+                info: AddrInfo::default(),
+            },
+            Source::NamedApp {
+                name: "test".into(),
+            },
+        );
+        let addr_2 = msock_1.get_mapping_addr(node_id_2).unwrap();
+
+        // Set a low max_idle_timeout so quinn gives up on this quickly and our test does
+        // not take forever.  You need to check the log output to verify this is really
+        // triggering the correct error.
+        // In test_try_send_no_send_addr() above you may have noticed we used
+        // tokio::time::timeout() on the connection attempt instead.  Here however we want
+        // Quinn itself to have fully given up on the connection attempt because we will
+        // later connect to **the same** node.  If Quinn did not give up on the connection
+        // we'd close it on drop, and the retransmits of the close packets would interfere
+        // with the next handshake, closing it during the handshake.  This makes the test a
+        // little slower though.
+        let mut transport_config = quinn::TransportConfig::default();
+        transport_config.max_idle_timeout(Some(Duration::from_millis(200).try_into().unwrap()));
+        let res = magicsock_connet_with_transport_config(
+            &ep_1,
+            secret_key_1.clone(),
+            addr_2,
+            node_id_2,
+            Arc::new(transport_config),
+        )
+        .await;
+        assert!(res.is_err(), "expected timeout");
+        info!("first connect timed out as expected");
+
+        // Provide correct addressing information
+        msock_1.node_map.add_node_addr(
+            NodeAddr {
+                node_id: node_id_2,
+                info: AddrInfo {
+                    relay_url: None,
+                    direct_addresses: msock_2
+                        .direct_addresses()
+                        .next()
+                        .await
+                        .expect("no direct addrs")
+                        .into_iter()
+                        .map(|x| x.addr)
+                        .collect(),
+                },
+            },
+            Source::NamedApp {
+                name: "test".into(),
+            },
+        );
+
+        // We can now connect
+        tokio::time::timeout(Duration::from_secs(10), async move {
+            info!("establishing new connection");
+            let conn = magicsock_connect(&ep_1, secret_key_1.clone(), addr_2, node_id_2)
+                .await
+                .unwrap();
+            info!("have connection");
+            let mut stream = conn.open_uni().await.unwrap();
+            stream.write_all(b"hello").await.unwrap();
+            stream.finish().unwrap();
+            stream.stopped().await.unwrap();
+            info!("finished stream");
+        })
+        .await
+        .expect("connection timed out");
+
+        // TODO: could remove the addresses again, send, add it back and see it recover.
+        // But we don't have that much private access to the NodeMap.  This will do for now.
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/metrics.rs.html b/pr/2992/docs/src/iroh/magicsock/metrics.rs.html new file mode 100644 index 0000000000..30b495cfad --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/metrics.rs.html @@ -0,0 +1,321 @@ +metrics.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+
use iroh_metrics::{
+    core::{Counter, Metric},
+    struct_iterable::Iterable,
+};
+
+/// Enum of metrics for the module
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Iterable)]
+#[non_exhaustive]
+pub struct Metrics {
+    pub re_stun_calls: Counter,
+    pub update_direct_addrs: Counter,
+
+    // Sends (data or disco)
+    pub send_ipv4: Counter,
+    pub send_ipv6: Counter,
+    pub send_relay: Counter,
+    pub send_relay_error: Counter,
+
+    // Data packets (non-disco)
+    pub send_data: Counter,
+    pub send_data_network_down: Counter,
+    pub recv_data_relay: Counter,
+    pub recv_data_ipv4: Counter,
+    pub recv_data_ipv6: Counter,
+    /// Number of QUIC datagrams received.
+    pub recv_datagrams: Counter,
+    /// Number of datagrams received using GRO
+    pub recv_gro_datagrams: Counter,
+
+    // Disco packets
+    pub send_disco_udp: Counter,
+    pub send_disco_relay: Counter,
+    pub sent_disco_udp: Counter,
+    pub sent_disco_relay: Counter,
+    pub sent_disco_ping: Counter,
+    pub sent_disco_pong: Counter,
+    pub sent_disco_call_me_maybe: Counter,
+    pub recv_disco_bad_key: Counter,
+    pub recv_disco_bad_parse: Counter,
+
+    pub recv_disco_udp: Counter,
+    pub recv_disco_relay: Counter,
+    pub recv_disco_ping: Counter,
+    pub recv_disco_pong: Counter,
+    pub recv_disco_call_me_maybe: Counter,
+    pub recv_disco_call_me_maybe_bad_disco: Counter,
+
+    // How many times our relay home node DI has changed from non-zero to a different non-zero.
+    pub relay_home_change: Counter,
+
+    /*
+     * Connection Metrics
+     */
+    /// The number of direct connections we have made to peers.
+    pub num_direct_conns_added: Counter,
+    /// The number of direct connections we have lost to peers.
+    pub num_direct_conns_removed: Counter,
+    /// The number of connections to peers we have added over relay.
+    pub num_relay_conns_added: Counter,
+    /// The number of connections to peers we have removed over relay.
+    pub num_relay_conns_removed: Counter,
+
+    pub actor_tick_main: Counter,
+    pub actor_tick_msg: Counter,
+    pub actor_tick_re_stun: Counter,
+    pub actor_tick_portmap_changed: Counter,
+    pub actor_tick_direct_addr_heartbeat: Counter,
+    pub actor_tick_direct_addr_update_receiver: Counter,
+    pub actor_link_change: Counter,
+    pub actor_tick_other: Counter,
+
+    /// Number of nodes we have attempted to contact.
+    pub nodes_contacted: Counter,
+    /// Number of nodes we have managed to contact directly.
+    pub nodes_contacted_directly: Counter,
+
+    /// Number of connections with a successful handshake.
+    pub connection_handshake_success: Counter,
+    /// Number of connections with a successful handshake that became direct.
+    pub connection_became_direct: Counter,
+}
+
+impl Default for Metrics {
+    fn default() -> Self {
+        Self {
+            num_relay_conns_added: Counter::new("num_relay_conns added"),
+            num_relay_conns_removed: Counter::new("num_relay_conns removed"),
+
+            re_stun_calls: Counter::new("restun_calls"),
+            update_direct_addrs: Counter::new("update_endpoints"),
+
+            // Sends (data or disco)
+            send_ipv4: Counter::new("send_ipv4"),
+            send_ipv6: Counter::new("send_ipv6"),
+            send_relay: Counter::new("send_relay"),
+            send_relay_error: Counter::new("send_relay_error"),
+
+            // Data packets (non-disco)
+            send_data: Counter::new("send_data"),
+            send_data_network_down: Counter::new("send_data_network_down"),
+            recv_data_relay: Counter::new("recv_data_relay"),
+            recv_data_ipv4: Counter::new("recv_data_ipv4"),
+            recv_data_ipv6: Counter::new("recv_data_ipv6"),
+            recv_datagrams: Counter::new("recv_datagrams"),
+            recv_gro_datagrams: Counter::new("recv_gro_packets"),
+
+            // Disco packets
+            send_disco_udp: Counter::new("disco_send_udp"),
+            send_disco_relay: Counter::new("disco_send_relay"),
+            sent_disco_udp: Counter::new("disco_sent_udp"),
+            sent_disco_relay: Counter::new("disco_sent_relay"),
+            sent_disco_ping: Counter::new("disco_sent_ping"),
+            sent_disco_pong: Counter::new("disco_sent_pong"),
+            sent_disco_call_me_maybe: Counter::new("disco_sent_callmemaybe"),
+            recv_disco_bad_key: Counter::new("disco_recv_bad_key"),
+            recv_disco_bad_parse: Counter::new("disco_recv_bad_parse"),
+
+            recv_disco_udp: Counter::new("disco_recv_udp"),
+            recv_disco_relay: Counter::new("disco_recv_relay"),
+            recv_disco_ping: Counter::new("disco_recv_ping"),
+            recv_disco_pong: Counter::new("disco_recv_pong"),
+            recv_disco_call_me_maybe: Counter::new("disco_recv_callmemaybe"),
+            recv_disco_call_me_maybe_bad_disco: Counter::new("disco_recv_callmemaybe_bad_disco"),
+
+            // How many times our relay home node DI has changed from non-zero to a different non-zero.
+            relay_home_change: Counter::new("relay_home_change"),
+
+            num_direct_conns_added: Counter::new(
+                "number of direct connections to a peer we have added",
+            ),
+            num_direct_conns_removed: Counter::new(
+                "number of direct connections to a peer we have removed",
+            ),
+
+            actor_tick_main: Counter::new("actor_tick_main"),
+            actor_tick_msg: Counter::new("actor_tick_msg"),
+            actor_tick_re_stun: Counter::new("actor_tick_re_stun"),
+            actor_tick_portmap_changed: Counter::new("actor_tick_portmap_changed"),
+            actor_tick_direct_addr_heartbeat: Counter::new("actor_tick_direct_addr_heartbeat"),
+            actor_tick_direct_addr_update_receiver: Counter::new(
+                "actor_tick_direct_addr_update_receiver",
+            ),
+            actor_link_change: Counter::new("actor_link_change"),
+            actor_tick_other: Counter::new("actor_tick_other"),
+
+            nodes_contacted: Counter::new("nodes_contacted"),
+            nodes_contacted_directly: Counter::new("nodes_contacted_directly"),
+
+            connection_handshake_success: Counter::new("connection_handshake_success"),
+            connection_became_direct: Counter::new("connection_became_direct"),
+        }
+    }
+}
+
+impl Metric for Metrics {
+    fn name() -> &'static str {
+        "magicsock"
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/node_map.rs.html b/pr/2992/docs/src/iroh/magicsock/node_map.rs.html new file mode 100644 index 0000000000..a1660b45f0 --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/node_map.rs.html @@ -0,0 +1,1661 @@ +node_map.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+
use std::{
+    collections::{hash_map::Entry, BTreeSet, HashMap},
+    hash::Hash,
+    net::{IpAddr, SocketAddr},
+    pin::Pin,
+    task::{Context, Poll},
+    time::Instant,
+};
+
+use futures_lite::stream::Stream;
+use iroh_base::key::NodeId;
+use iroh_metrics::inc;
+use iroh_relay::RelayUrl;
+use parking_lot::Mutex;
+use serde::{Deserialize, Serialize};
+use stun_rs::TransactionId;
+use tracing::{debug, info, instrument, trace, warn};
+
+use self::{
+    best_addr::ClearReason,
+    node_state::{NodeState, Options, PingHandled},
+};
+use super::{
+    metrics::Metrics as MagicsockMetrics, ActorMessage, DiscoMessageSource, QuicMappedAddr,
+};
+use crate::{
+    disco::{CallMeMaybe, Pong, SendAddr},
+    key::PublicKey,
+    NodeAddr,
+};
+
+mod best_addr;
+mod node_state;
+mod path_state;
+mod udp_paths;
+
+pub use node_state::{ConnectionType, ControlMsg, DirectAddrInfo, RemoteInfo};
+pub(super) use node_state::{DiscoPingPurpose, PingAction, PingRole, SendPing};
+
+/// Number of nodes that are inactive for which we keep info about. This limit is enforced
+/// periodically via [`NodeMap::prune_inactive`].
+const MAX_INACTIVE_NODES: usize = 30;
+
+/// Map of the [`NodeState`] information for all the known nodes.
+///
+/// The nodes can be looked up by:
+///
+/// - The node's ID in this map, only useful if you know the ID from an insert or lookup.
+///   This is static and never changes.
+///
+/// - The [`QuicMappedAddr`] which internally identifies the node to the QUIC stack.  This
+///   is static and never changes.
+///
+/// - The nodes's public key, aka `PublicKey` or "node_key".  This is static and never changes,
+///   however a node could be added when this is not yet known.
+///
+/// - A public socket address on which they are reachable on the internet, known as ip-port.
+///   These come and go as the node moves around on the internet
+///
+/// An index of nodeInfos by node key, QuicMappedAddr, and discovered ip:port endpoints.
+#[derive(Default, Debug)]
+pub(super) struct NodeMap {
+    inner: Mutex<NodeMapInner>,
+}
+
+#[derive(Default, Debug)]
+pub(super) struct NodeMapInner {
+    by_node_key: HashMap<NodeId, usize>,
+    by_ip_port: HashMap<IpPort, usize>,
+    by_quic_mapped_addr: HashMap<QuicMappedAddr, usize>,
+    by_id: HashMap<usize, NodeState>,
+    next_id: usize,
+}
+
+/// Identifier to look up a [`NodeState`] in the [`NodeMap`].
+///
+/// You can look up entries in [`NodeMap`] with various keys, depending on the context you
+/// have for the node.  These are all the keys the [`NodeMap`] can use.
+#[derive(Debug, Clone)]
+enum NodeStateKey {
+    Idx(usize),
+    NodeId(NodeId),
+    QuicMappedAddr(QuicMappedAddr),
+    IpPort(IpPort),
+}
+
+/// The origin or *source* through which an address associated with a remote node
+/// was discovered.
+///
+/// An aggregate of the [`Source`]s of all the addresses of a node describe the
+/// [`Source`]s of the node itself.
+///
+/// A [`Source`] helps track how and where an address was learned. Multiple
+/// sources can be associated with a single address, if we have discovered this
+/// address through multiple means.
+///
+/// Each time a [`NodeAddr`] is added to the node map, usually through
+/// [`crate::endpoint::Endpoint::add_node_addr_with_source`], a [`Source`] must be supplied to indicate
+/// how the address was obtained.
+///
+/// A [`Source`] can describe a variety of places that an address or node was
+/// discovered, such as a configured discovery service, the network itself
+/// (if another node has reached out to us), or as a user supplied [`NodeAddr`].
+
+#[derive(Serialize, Deserialize, strum::Display, Debug, Clone, Eq, PartialEq, Hash)]
+#[strum(serialize_all = "kebab-case")]
+pub enum Source {
+    /// Address was loaded from the fs.
+    Saved,
+    /// A node communicated with us first via UDP.
+    Udp,
+    /// A node communicated with us first via relay.
+    Relay,
+    /// Application layer added the address directly.
+    App,
+    /// The address was discovered by a discovery service.
+    #[strum(serialize = "{name}")]
+    Discovery {
+        /// The name of the discovery service that discovered the address.
+        name: String,
+    },
+    /// Application layer with a specific name added the node directly.
+    #[strum(serialize = "{name}")]
+    NamedApp {
+        /// The name of the application that added the node
+        name: String,
+    },
+}
+
+impl NodeMap {
+    /// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
+    pub(super) fn load_from_vec(nodes: Vec<NodeAddr>) -> Self {
+        Self::from_inner(NodeMapInner::load_from_vec(nodes))
+    }
+
+    fn from_inner(inner: NodeMapInner) -> Self {
+        Self {
+            inner: Mutex::new(inner),
+        }
+    }
+
+    /// Add the contact information for a node.
+    pub(super) fn add_node_addr(&self, node_addr: NodeAddr, source: Source) {
+        self.inner.lock().add_node_addr(node_addr, source)
+    }
+
+    /// Number of nodes currently listed.
+    pub(super) fn node_count(&self) -> usize {
+        self.inner.lock().node_count()
+    }
+
+    pub(super) fn receive_udp(&self, udp_addr: SocketAddr) -> Option<(PublicKey, QuicMappedAddr)> {
+        self.inner.lock().receive_udp(udp_addr)
+    }
+
+    pub(super) fn receive_relay(&self, relay_url: &RelayUrl, src: NodeId) -> QuicMappedAddr {
+        self.inner.lock().receive_relay(relay_url, src)
+    }
+
+    pub(super) fn notify_ping_sent(
+        &self,
+        id: usize,
+        dst: SendAddr,
+        tx_id: stun_rs::TransactionId,
+        purpose: DiscoPingPurpose,
+        msg_sender: tokio::sync::mpsc::Sender<ActorMessage>,
+    ) {
+        if let Some(ep) = self.inner.lock().get_mut(NodeStateKey::Idx(id)) {
+            ep.ping_sent(dst, tx_id, purpose, msg_sender);
+        }
+    }
+
+    pub(super) fn notify_ping_timeout(&self, id: usize, tx_id: stun_rs::TransactionId) {
+        if let Some(ep) = self.inner.lock().get_mut(NodeStateKey::Idx(id)) {
+            ep.ping_timeout(tx_id);
+        }
+    }
+
+    pub(super) fn get_quic_mapped_addr_for_node_key(
+        &self,
+        node_key: NodeId,
+    ) -> Option<QuicMappedAddr> {
+        self.inner
+            .lock()
+            .get(NodeStateKey::NodeId(node_key))
+            .map(|ep| *ep.quic_mapped_addr())
+    }
+
+    /// Insert a received ping into the node map, and return whether a ping with this tx_id was already
+    /// received.
+    pub(super) fn handle_ping(
+        &self,
+        sender: PublicKey,
+        src: SendAddr,
+        tx_id: TransactionId,
+    ) -> PingHandled {
+        self.inner.lock().handle_ping(sender, src, tx_id)
+    }
+
+    pub(super) fn handle_pong(&self, sender: PublicKey, src: &DiscoMessageSource, pong: Pong) {
+        self.inner.lock().handle_pong(sender, src, pong)
+    }
+
+    #[must_use = "actions must be handled"]
+    pub(super) fn handle_call_me_maybe(
+        &self,
+        sender: PublicKey,
+        cm: CallMeMaybe,
+    ) -> Vec<PingAction> {
+        self.inner.lock().handle_call_me_maybe(sender, cm)
+    }
+
+    #[allow(clippy::type_complexity)]
+    pub(super) fn get_send_addrs(
+        &self,
+        addr: QuicMappedAddr,
+        have_ipv6: bool,
+    ) -> Option<(
+        PublicKey,
+        Option<SocketAddr>,
+        Option<RelayUrl>,
+        Vec<PingAction>,
+    )> {
+        let mut inner = self.inner.lock();
+        let ep = inner.get_mut(NodeStateKey::QuicMappedAddr(addr))?;
+        let public_key = *ep.public_key();
+        trace!(dest = %addr, node_id = %public_key.fmt_short(), "dst mapped to NodeId");
+        let (udp_addr, relay_url, msgs) = ep.get_send_addrs(have_ipv6);
+        Some((public_key, udp_addr, relay_url, msgs))
+    }
+
+    pub(super) fn notify_shutdown(&self) {
+        let mut inner = self.inner.lock();
+        for (_, ep) in inner.node_states_mut() {
+            ep.reset();
+        }
+    }
+
+    pub(super) fn reset_node_states(&self) {
+        let mut inner = self.inner.lock();
+        for (_, ep) in inner.node_states_mut() {
+            ep.note_connectivity_change();
+        }
+    }
+
+    pub(super) fn nodes_stayin_alive(&self) -> Vec<PingAction> {
+        let mut inner = self.inner.lock();
+        inner
+            .node_states_mut()
+            .flat_map(|(_idx, node_state)| node_state.stayin_alive())
+            .collect()
+    }
+
+    /// Returns the [`RemoteInfo`]s for each node in the node map.
+    pub(super) fn list_remote_infos(&self, now: Instant) -> Vec<RemoteInfo> {
+        // NOTE: calls to this method will often call `into_iter` (or similar methods). Note that
+        // we can't avoid `collect` here since it would hold a lock for an indefinite time. Even if
+        // we were to find this acceptable, dealing with the lifetimes of the mutex's guard and the
+        // internal iterator will be a hassle, if possible at all.
+        self.inner.lock().remote_infos_iter(now).collect()
+    }
+
+    /// Returns a stream of [`ConnectionType`].
+    ///
+    /// Sends the current [`ConnectionType`] whenever any changes to the
+    /// connection type for `public_key` has occurred.
+    ///
+    /// # Errors
+    ///
+    /// Will return an error if there is not an entry in the [`NodeMap`] for
+    /// the `public_key`
+    pub(super) fn conn_type_stream(&self, node_id: NodeId) -> anyhow::Result<ConnectionTypeStream> {
+        self.inner.lock().conn_type_stream(node_id)
+    }
+
+    /// Get the [`RemoteInfo`]s for the node identified by [`NodeId`].
+    pub(super) fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo> {
+        self.inner.lock().remote_info(node_id)
+    }
+
+    /// Prunes nodes without recent activity so that at most [`MAX_INACTIVE_NODES`] are kept.
+    pub(super) fn prune_inactive(&self) {
+        self.inner.lock().prune_inactive();
+    }
+
+    pub(crate) fn on_direct_addr_discovered(&self, discovered: BTreeSet<SocketAddr>) {
+        self.inner.lock().on_direct_addr_discovered(discovered);
+    }
+}
+
+impl NodeMapInner {
+    /// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
+    fn load_from_vec(nodes: Vec<NodeAddr>) -> Self {
+        let mut me = Self::default();
+        for node_addr in nodes {
+            me.add_node_addr(node_addr, Source::Saved);
+        }
+        me
+    }
+
+    /// Add the contact information for a node.
+    #[instrument(skip_all, fields(node = %node_addr.node_id.fmt_short()))]
+    fn add_node_addr(&mut self, node_addr: NodeAddr, source: Source) {
+        let NodeAddr { node_id, info } = node_addr;
+
+        let source0 = source.clone();
+        let node_state = self.get_or_insert_with(NodeStateKey::NodeId(node_id), || Options {
+            node_id,
+            relay_url: info.relay_url.clone(),
+            active: false,
+            source,
+        });
+        node_state.update_from_node_addr(&info, source0);
+        let id = node_state.id();
+        for addr in &info.direct_addresses {
+            self.set_node_state_for_ip_port(*addr, id);
+        }
+    }
+
+    /// Prunes direct addresses from nodes that claim to share an address we know points to us.
+    pub(super) fn on_direct_addr_discovered(&mut self, discovered: BTreeSet<SocketAddr>) {
+        for addr in discovered {
+            self.remove_by_ipp(addr.into(), ClearReason::MatchesOurLocalAddr)
+        }
+    }
+
+    /// Removes a direct address from a node.
+    fn remove_by_ipp(&mut self, ipp: IpPort, reason: ClearReason) {
+        if let Some(id) = self.by_ip_port.remove(&ipp) {
+            if let Entry::Occupied(mut entry) = self.by_id.entry(id) {
+                let node = entry.get_mut();
+                node.remove_direct_addr(&ipp, reason);
+                if node.direct_addresses().count() == 0 {
+                    let node_id = node.public_key();
+                    let mapped_addr = node.quic_mapped_addr();
+                    self.by_node_key.remove(node_id);
+                    self.by_quic_mapped_addr.remove(mapped_addr);
+                    debug!(node_id=%node_id.fmt_short(), ?reason, "removing node");
+                    entry.remove();
+                }
+            }
+        }
+    }
+
+    fn get_id(&self, id: NodeStateKey) -> Option<usize> {
+        match id {
+            NodeStateKey::Idx(id) => Some(id),
+            NodeStateKey::NodeId(node_key) => self.by_node_key.get(&node_key).copied(),
+            NodeStateKey::QuicMappedAddr(addr) => self.by_quic_mapped_addr.get(&addr).copied(),
+            NodeStateKey::IpPort(ipp) => self.by_ip_port.get(&ipp).copied(),
+        }
+    }
+
+    fn get_mut(&mut self, id: NodeStateKey) -> Option<&mut NodeState> {
+        self.get_id(id).and_then(|id| self.by_id.get_mut(&id))
+    }
+
+    fn get(&self, id: NodeStateKey) -> Option<&NodeState> {
+        self.get_id(id).and_then(|id| self.by_id.get(&id))
+    }
+
+    fn get_or_insert_with(
+        &mut self,
+        id: NodeStateKey,
+        f: impl FnOnce() -> Options,
+    ) -> &mut NodeState {
+        let id = self.get_id(id);
+        match id {
+            None => self.insert_node(f()),
+            Some(id) => self.by_id.get_mut(&id).expect("is not empty"),
+        }
+    }
+
+    /// Number of nodes currently listed.
+    fn node_count(&self) -> usize {
+        self.by_id.len()
+    }
+
+    /// Marks the node we believe to be at `ipp` as recently used.
+    fn receive_udp(&mut self, udp_addr: SocketAddr) -> Option<(NodeId, QuicMappedAddr)> {
+        let ip_port: IpPort = udp_addr.into();
+        let Some(node_state) = self.get_mut(NodeStateKey::IpPort(ip_port)) else {
+            info!(src=%udp_addr, "receive_udp: no node_state found for addr, ignore");
+            return None;
+        };
+        node_state.receive_udp(ip_port, Instant::now());
+        Some((*node_state.public_key(), *node_state.quic_mapped_addr()))
+    }
+
+    #[instrument(skip_all, fields(src = %src.fmt_short()))]
+    fn receive_relay(&mut self, relay_url: &RelayUrl, src: NodeId) -> QuicMappedAddr {
+        let node_state = self.get_or_insert_with(NodeStateKey::NodeId(src), || {
+            trace!("packets from unknown node, insert into node map");
+            Options {
+                node_id: src,
+                relay_url: Some(relay_url.clone()),
+                active: true,
+                source: Source::Relay,
+            }
+        });
+        node_state.receive_relay(relay_url, src, Instant::now());
+        *node_state.quic_mapped_addr()
+    }
+
+    fn node_states(&self) -> impl Iterator<Item = (&usize, &NodeState)> {
+        self.by_id.iter()
+    }
+
+    fn node_states_mut(&mut self) -> impl Iterator<Item = (&usize, &mut NodeState)> {
+        self.by_id.iter_mut()
+    }
+
+    /// Get the [`RemoteInfo`]s for all nodes.
+    fn remote_infos_iter(&self, now: Instant) -> impl Iterator<Item = RemoteInfo> + '_ {
+        self.node_states().map(move |(_, ep)| ep.info(now))
+    }
+
+    /// Get the [`RemoteInfo`]s for each node.
+    fn remote_info(&self, node_id: NodeId) -> Option<RemoteInfo> {
+        self.get(NodeStateKey::NodeId(node_id))
+            .map(|ep| ep.info(Instant::now()))
+    }
+
+    /// Returns a stream of [`ConnectionType`].
+    ///
+    /// Sends the current [`ConnectionType`] whenever any changes to the
+    /// connection type for `public_key` has occurred.
+    ///
+    /// # Errors
+    ///
+    /// Will return an error if there is not an entry in the [`NodeMap`] for
+    /// the `public_key`
+    fn conn_type_stream(&self, node_id: NodeId) -> anyhow::Result<ConnectionTypeStream> {
+        match self.get(NodeStateKey::NodeId(node_id)) {
+            Some(ep) => Ok(ConnectionTypeStream {
+                initial: Some(ep.conn_type()),
+                inner: ep.conn_type_stream(),
+            }),
+            None => anyhow::bail!("No endpoint for {node_id:?} found"),
+        }
+    }
+
+    fn handle_pong(&mut self, sender: NodeId, src: &DiscoMessageSource, pong: Pong) {
+        if let Some(ns) = self.get_mut(NodeStateKey::NodeId(sender)).as_mut() {
+            let insert = ns.handle_pong(&pong, src.into());
+            if let Some((src, key)) = insert {
+                self.set_node_key_for_ip_port(src, &key);
+            }
+            trace!(?insert, "received pong")
+        } else {
+            warn!("received pong: node unknown, ignore")
+        }
+    }
+
+    #[must_use = "actions must be handled"]
+    fn handle_call_me_maybe(&mut self, sender: NodeId, cm: CallMeMaybe) -> Vec<PingAction> {
+        let ns_id = NodeStateKey::NodeId(sender);
+        if let Some(id) = self.get_id(ns_id.clone()) {
+            for number in &cm.my_numbers {
+                // ensure the new addrs are known
+                self.set_node_state_for_ip_port(*number, id);
+            }
+        }
+        match self.get_mut(ns_id) {
+            None => {
+                inc!(MagicsockMetrics, recv_disco_call_me_maybe_bad_disco);
+                debug!("received call-me-maybe: ignore, node is unknown");
+                vec![]
+            }
+            Some(ns) => {
+                debug!(endpoints = ?cm.my_numbers, "received call-me-maybe");
+
+                ns.handle_call_me_maybe(cm)
+            }
+        }
+    }
+
+    fn handle_ping(&mut self, sender: NodeId, src: SendAddr, tx_id: TransactionId) -> PingHandled {
+        let node_state = self.get_or_insert_with(NodeStateKey::NodeId(sender), || {
+            debug!("received ping: node unknown, add to node map");
+            let source = if src.is_relay() {
+                Source::Relay
+            } else {
+                Source::Udp
+            };
+            Options {
+                node_id: sender,
+                relay_url: src.relay_url(),
+                active: true,
+                source,
+            }
+        });
+
+        let handled = node_state.handle_ping(src.clone(), tx_id);
+        if let SendAddr::Udp(ref addr) = src {
+            if matches!(handled.role, PingRole::NewPath) {
+                self.set_node_key_for_ip_port(*addr, &sender);
+            }
+        }
+        handled
+    }
+
+    /// Inserts a new node into the [`NodeMap`].
+    fn insert_node(&mut self, options: Options) -> &mut NodeState {
+        info!(
+            node = %options.node_id.fmt_short(),
+            relay_url = ?options.relay_url,
+            source = %options.source,
+            "inserting new node in NodeMap",
+        );
+        let id = self.next_id;
+        self.next_id = self.next_id.wrapping_add(1);
+        let node_state = NodeState::new(id, options);
+
+        // update indices
+        self.by_quic_mapped_addr
+            .insert(*node_state.quic_mapped_addr(), id);
+        self.by_node_key.insert(*node_state.public_key(), id);
+
+        self.by_id.insert(id, node_state);
+        self.by_id.get_mut(&id).expect("just inserted")
+    }
+
+    /// Makes future node lookups by ipp return the same endpoint as a lookup by nk.
+    ///
+    /// This should only be called with a fully verified mapping of ipp to
+    /// nk, because calling this function defines the endpoint we hand to
+    /// WireGuard for packets received from ipp.
+    fn set_node_key_for_ip_port(&mut self, ipp: impl Into<IpPort>, nk: &PublicKey) {
+        let ipp = ipp.into();
+        if let Some(id) = self.by_ip_port.get(&ipp) {
+            if !self.by_node_key.contains_key(nk) {
+                self.by_node_key.insert(*nk, *id);
+            }
+            self.by_ip_port.remove(&ipp);
+        }
+        if let Some(id) = self.by_node_key.get(nk) {
+            trace!("insert ip -> id: {:?} -> {}", ipp, id);
+            self.by_ip_port.insert(ipp, *id);
+        }
+    }
+
+    fn set_node_state_for_ip_port(&mut self, ipp: impl Into<IpPort>, id: usize) {
+        let ipp = ipp.into();
+        trace!(?ipp, ?id, "set endpoint for ip:port");
+        self.by_ip_port.insert(ipp, id);
+    }
+
+    /// Prunes nodes without recent activity so that at most [`MAX_INACTIVE_NODES`] are kept.
+    fn prune_inactive(&mut self) {
+        let now = Instant::now();
+        let mut prune_candidates: Vec<_> = self
+            .by_id
+            .values()
+            .filter(|node| !node.is_active(&now))
+            .map(|node| (*node.public_key(), node.last_used()))
+            .collect();
+
+        let prune_count = prune_candidates.len().saturating_sub(MAX_INACTIVE_NODES);
+        if prune_count == 0 {
+            // within limits
+            return;
+        }
+
+        prune_candidates.sort_unstable_by_key(|(_pk, last_used)| *last_used);
+        prune_candidates.truncate(prune_count);
+        for (public_key, last_used) in prune_candidates.into_iter() {
+            let node = public_key.fmt_short();
+            match last_used.map(|instant| instant.elapsed()) {
+                Some(last_used) => trace!(%node, ?last_used, "pruning inactive"),
+                None => trace!(%node, last_used=%"never", "pruning inactive"),
+            }
+
+            let Some(id) = self.by_node_key.remove(&public_key) else {
+                debug_assert!(false, "missing by_node_key entry for pk in by_id");
+                continue;
+            };
+
+            let Some(ep) = self.by_id.remove(&id) else {
+                debug_assert!(false, "missing by_id entry for id in by_node_key");
+                continue;
+            };
+
+            for ip_port in ep.direct_addresses() {
+                self.by_ip_port.remove(&ip_port);
+            }
+
+            self.by_quic_mapped_addr.remove(ep.quic_mapped_addr());
+        }
+    }
+}
+
+/// Stream returning `ConnectionTypes`
+#[derive(Debug)]
+pub struct ConnectionTypeStream {
+    initial: Option<ConnectionType>,
+    inner: watchable::WatcherStream<ConnectionType>,
+}
+
+impl Stream for ConnectionTypeStream {
+    type Item = ConnectionType;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        let this = &mut *self;
+        if let Some(initial_conn_type) = this.initial.take() {
+            return Poll::Ready(Some(initial_conn_type));
+        }
+        Pin::new(&mut this.inner).poll_next(cx)
+    }
+}
+
+/// An (Ip, Port) pair.
+///
+/// NOTE: storing an [`IpPort`] is safer than storing a [`SocketAddr`] because for IPv6 socket
+/// addresses include fields that can't be assumed consistent even within a single connection.
+#[derive(Debug, derive_more::Display, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[display("{}", SocketAddr::from(*self))]
+pub struct IpPort {
+    ip: IpAddr,
+    port: u16,
+}
+
+impl From<SocketAddr> for IpPort {
+    fn from(socket_addr: SocketAddr) -> Self {
+        Self {
+            ip: socket_addr.ip(),
+            port: socket_addr.port(),
+        }
+    }
+}
+
+impl From<IpPort> for SocketAddr {
+    fn from(ip_port: IpPort) -> Self {
+        let IpPort { ip, port } = ip_port;
+        (ip, port).into()
+    }
+}
+
+impl IpPort {
+    pub fn ip(&self) -> &IpAddr {
+        &self.ip
+    }
+
+    pub fn port(&self) -> u16 {
+        self.port
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::Ipv4Addr;
+
+    use super::{node_state::MAX_INACTIVE_DIRECT_ADDRESSES, *};
+    use crate::key::SecretKey;
+
+    impl NodeMap {
+        #[track_caller]
+        fn add_test_addr(&self, node_addr: NodeAddr) {
+            self.add_node_addr(
+                node_addr,
+                Source::NamedApp {
+                    name: "test".into(),
+                },
+            )
+        }
+    }
+
+    /// Test persisting and loading of known nodes.
+    #[tokio::test]
+    async fn restore_from_vec() {
+        let _guard = iroh_test::logging::setup();
+
+        let node_map = NodeMap::default();
+
+        let node_a = SecretKey::generate().public();
+        let node_b = SecretKey::generate().public();
+        let node_c = SecretKey::generate().public();
+        let node_d = SecretKey::generate().public();
+
+        let relay_x: RelayUrl = "https://my-relay-1.com".parse().unwrap();
+        let relay_y: RelayUrl = "https://my-relay-2.com".parse().unwrap();
+
+        let direct_addresses_a = [addr(4000), addr(4001)];
+        let direct_addresses_c = [addr(5000)];
+
+        let node_addr_a = NodeAddr::new(node_a)
+            .with_relay_url(relay_x)
+            .with_direct_addresses(direct_addresses_a);
+        let node_addr_b = NodeAddr::new(node_b).with_relay_url(relay_y);
+        let node_addr_c = NodeAddr::new(node_c).with_direct_addresses(direct_addresses_c);
+        let node_addr_d = NodeAddr::new(node_d);
+
+        node_map.add_test_addr(node_addr_a);
+        node_map.add_test_addr(node_addr_b);
+        node_map.add_test_addr(node_addr_c);
+        node_map.add_test_addr(node_addr_d);
+
+        let mut addrs: Vec<NodeAddr> = node_map
+            .list_remote_infos(Instant::now())
+            .into_iter()
+            .filter_map(|info| {
+                let addr: NodeAddr = info.into();
+                if addr.info.is_empty() {
+                    return None;
+                }
+                Some(addr)
+            })
+            .collect();
+        let loaded_node_map = NodeMap::load_from_vec(addrs.clone());
+
+        let mut loaded: Vec<NodeAddr> = loaded_node_map
+            .list_remote_infos(Instant::now())
+            .into_iter()
+            .filter_map(|info| {
+                let addr: NodeAddr = info.into();
+                if addr.info.is_empty() {
+                    return None;
+                }
+                Some(addr)
+            })
+            .collect();
+
+        loaded.sort_unstable();
+        addrs.sort_unstable();
+
+        // compare the node maps via their known nodes
+        assert_eq!(addrs, loaded);
+    }
+
+    fn addr(port: u16) -> SocketAddr {
+        (std::net::IpAddr::V4(Ipv4Addr::LOCALHOST), port).into()
+    }
+
+    #[test]
+    fn test_prune_direct_addresses() {
+        let _guard = iroh_test::logging::setup();
+
+        let node_map = NodeMap::default();
+        let public_key = SecretKey::generate().public();
+        let id = node_map
+            .inner
+            .lock()
+            .insert_node(Options {
+                node_id: public_key,
+                relay_url: None,
+                active: false,
+                source: Source::NamedApp {
+                    name: "test".into(),
+                },
+            })
+            .id();
+
+        const LOCALHOST: IpAddr = IpAddr::V4(std::net::Ipv4Addr::LOCALHOST);
+
+        // add [`MAX_INACTIVE_DIRECT_ADDRESSES`] active direct addresses and double
+        // [`MAX_INACTIVE_DIRECT_ADDRESSES`] that are inactive
+
+        info!("Adding active addresses");
+        for i in 0..MAX_INACTIVE_DIRECT_ADDRESSES {
+            let addr = SocketAddr::new(LOCALHOST, 5000 + i as u16);
+            let node_addr = NodeAddr::new(public_key).with_direct_addresses([addr]);
+            // add address
+            node_map.add_test_addr(node_addr);
+            // make it active
+            node_map.inner.lock().receive_udp(addr);
+        }
+
+        info!("Adding offline/inactive addresses");
+        for i in 0..MAX_INACTIVE_DIRECT_ADDRESSES * 2 {
+            let addr = SocketAddr::new(LOCALHOST, 6000 + i as u16);
+            let node_addr = NodeAddr::new(public_key).with_direct_addresses([addr]);
+            node_map.add_test_addr(node_addr);
+        }
+
+        let mut node_map_inner = node_map.inner.lock();
+        let endpoint = node_map_inner.by_id.get_mut(&id).unwrap();
+
+        info!("Adding alive addresses");
+        for i in 0..MAX_INACTIVE_DIRECT_ADDRESSES {
+            let addr = SendAddr::Udp(SocketAddr::new(LOCALHOST, 7000 + i as u16));
+            let txid = stun_rs::TransactionId::from([i as u8; 12]);
+            // Note that this already invokes .prune_direct_addresses() because these are
+            // new UDP paths.
+            endpoint.handle_ping(addr, txid);
+        }
+
+        info!("Pruning addresses");
+        endpoint.prune_direct_addresses();
+
+        // Half the offline addresses should have been pruned.  All the active and alive
+        // addresses should have been kept.
+        assert_eq!(
+            endpoint.direct_addresses().count(),
+            MAX_INACTIVE_DIRECT_ADDRESSES * 3
+        );
+
+        // We should have both offline and alive addresses which are not active.
+        assert_eq!(
+            endpoint
+                .direct_address_states()
+                .filter(|(_addr, state)| !state.is_active())
+                .count(),
+            MAX_INACTIVE_DIRECT_ADDRESSES * 2
+        )
+    }
+
+    #[test]
+    fn test_prune_inactive() {
+        let node_map = NodeMap::default();
+        // add one active node and more than MAX_INACTIVE_NODES inactive nodes
+        let active_node = SecretKey::generate().public();
+        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 167);
+        node_map.add_test_addr(NodeAddr::new(active_node).with_direct_addresses([addr]));
+        node_map.inner.lock().receive_udp(addr).expect("registered");
+
+        for _ in 0..MAX_INACTIVE_NODES + 1 {
+            let node = SecretKey::generate().public();
+            node_map.add_test_addr(NodeAddr::new(node));
+        }
+
+        assert_eq!(node_map.node_count(), MAX_INACTIVE_NODES + 2);
+        node_map.prune_inactive();
+        assert_eq!(node_map.node_count(), MAX_INACTIVE_NODES + 1);
+        node_map
+            .inner
+            .lock()
+            .get(NodeStateKey::NodeId(active_node))
+            .expect("should not be pruned");
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/node_map/best_addr.rs.html b/pr/2992/docs/src/iroh/magicsock/node_map/best_addr.rs.html new file mode 100644 index 0000000000..fedbbe8de7 --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/node_map/best_addr.rs.html @@ -0,0 +1,447 @@ +best_addr.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+
//! The [`BestAddr`] is the currently active best address for UDP sends.
+
+use std::{
+    net::SocketAddr,
+    time::{Duration, Instant},
+};
+
+use tracing::{debug, info};
+
+/// How long we trust a UDP address as the exclusive path (without using relay) without having heard a Pong reply.
+const TRUST_UDP_ADDR_DURATION: Duration = Duration::from_millis(6500);
+
+#[derive(Debug, Default)]
+pub(super) struct BestAddr(Option<BestAddrInner>);
+
+#[derive(Debug)]
+struct BestAddrInner {
+    addr: AddrLatency,
+    trust_until: Option<Instant>,
+    confirmed_at: Instant,
+}
+
+impl BestAddrInner {
+    fn is_trusted(&self, now: Instant) -> bool {
+        self.trust_until
+            .map(|trust_until| trust_until >= now)
+            .unwrap_or(false)
+    }
+
+    fn addr(&self) -> SocketAddr {
+        self.addr.addr
+    }
+}
+
+#[derive(Debug)]
+pub(super) enum Source {
+    ReceivedPong,
+    BestCandidate,
+    Udp,
+}
+
+impl Source {
+    fn trust_until(&self, from: Instant) -> Instant {
+        match self {
+            Source::ReceivedPong => from + TRUST_UDP_ADDR_DURATION,
+            // TODO: Fix time
+            Source::BestCandidate => from + Duration::from_secs(60 * 60),
+            Source::Udp => from + TRUST_UDP_ADDR_DURATION,
+        }
+    }
+}
+
+#[derive(Debug)]
+pub(super) enum State<'a> {
+    Valid(&'a AddrLatency),
+    Outdated(&'a AddrLatency),
+    Empty,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum ClearReason {
+    Reset,
+    Inactive,
+    PongTimeout,
+    MatchesOurLocalAddr,
+}
+
+impl BestAddr {
+    #[cfg(test)]
+    pub fn from_parts(
+        addr: SocketAddr,
+        latency: Duration,
+        confirmed_at: Instant,
+        trust_until: Instant,
+    ) -> Self {
+        let inner = BestAddrInner {
+            addr: AddrLatency { addr, latency },
+            confirmed_at,
+            trust_until: Some(trust_until),
+        };
+        Self(Some(inner))
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_none()
+    }
+
+    /// Unconditionally clears the best address.
+    pub fn clear(&mut self, reason: ClearReason, has_relay: bool) {
+        let old = self.0.take();
+        if let Some(old_addr) = old.as_ref().map(BestAddrInner::addr) {
+            info!(?reason, ?has_relay, %old_addr, "clearing best_addr");
+        }
+    }
+
+    /// Clears the best address if equal to `addr`.
+    pub fn clear_if_equals(&mut self, addr: SocketAddr, reason: ClearReason, has_relay: bool) {
+        if self.addr() == Some(addr) {
+            self.clear(reason, has_relay)
+        }
+    }
+
+    pub fn clear_trust(&mut self, why: &'static str) {
+        if let Some(state) = self.0.as_mut() {
+            info!(
+                %why,
+                prev_trust_until = ?state.trust_until,
+                "clearing best_addr trust",
+            );
+            state.trust_until = None;
+        }
+    }
+
+    pub fn insert_if_better_or_reconfirm(
+        &mut self,
+        addr: SocketAddr,
+        latency: Duration,
+        source: Source,
+        confirmed_at: Instant,
+    ) {
+        match self.0.as_mut() {
+            None => {
+                self.insert(addr, latency, source, confirmed_at);
+            }
+            Some(state) => {
+                let candidate = AddrLatency { addr, latency };
+                if !state.is_trusted(confirmed_at) || candidate.is_better_than(&state.addr) {
+                    self.insert(addr, latency, source, confirmed_at);
+                } else if state.addr.addr == addr {
+                    state.confirmed_at = confirmed_at;
+                    state.trust_until = Some(source.trust_until(confirmed_at));
+                }
+            }
+        }
+    }
+
+    /// Reset the expiry, if the passed in addr matches the currently used one.
+    pub fn reconfirm_if_used(&mut self, addr: SocketAddr, source: Source, confirmed_at: Instant) {
+        if let Some(state) = self.0.as_mut() {
+            if state.addr.addr == addr {
+                state.confirmed_at = confirmed_at;
+                state.trust_until = Some(source.trust_until(confirmed_at));
+            }
+        }
+    }
+
+    fn insert(
+        &mut self,
+        addr: SocketAddr,
+        latency: Duration,
+        source: Source,
+        confirmed_at: Instant,
+    ) {
+        let trust_until = source.trust_until(confirmed_at);
+
+        if self
+            .0
+            .as_ref()
+            .map(|prev| prev.addr.addr == addr)
+            .unwrap_or_default()
+        {
+            debug!(
+                %addr,
+                latency = ?latency,
+                trust_for = ?trust_until.duration_since(Instant::now()),
+               "re-selecting direct path for node"
+            );
+        } else {
+            info!(
+               %addr,
+               latency = ?latency,
+               trust_for = ?trust_until.duration_since(Instant::now()),
+               "selecting new direct path for node"
+            );
+        }
+        let inner = BestAddrInner {
+            addr: AddrLatency { addr, latency },
+            trust_until: Some(trust_until),
+            confirmed_at,
+        };
+        self.0 = Some(inner);
+    }
+
+    pub fn state(&self, now: Instant) -> State {
+        match &self.0 {
+            None => State::Empty,
+            Some(state) => match state.trust_until {
+                Some(expiry) if now < expiry => State::Valid(&state.addr),
+                Some(_) | None => State::Outdated(&state.addr),
+            },
+        }
+    }
+
+    pub fn addr(&self) -> Option<SocketAddr> {
+        self.0.as_ref().map(BestAddrInner::addr)
+    }
+}
+
+/// A `SocketAddr` with an associated latency.
+#[derive(Debug, Clone)]
+pub struct AddrLatency {
+    pub addr: SocketAddr,
+    pub latency: Duration,
+}
+
+impl AddrLatency {
+    /// Reports whether `self` is a better addr to use than `other`.
+    fn is_better_than(&self, other: &Self) -> bool {
+        if self.addr == other.addr {
+            return false;
+        }
+        if self.addr.is_ipv6() && other.addr.is_ipv4() {
+            // Prefer IPv6 for being a bit more robust, as long as
+            // the latencies are roughly equivalent.
+            if self.latency / 10 * 9 < other.latency {
+                return true;
+            }
+        } else if self.addr.is_ipv4() && other.addr.is_ipv6() && other.is_better_than(self) {
+            return false;
+        }
+        self.latency < other.latency
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/node_map/node_state.rs.html b/pr/2992/docs/src/iroh/magicsock/node_map/node_state.rs.html new file mode 100644 index 0000000000..ec96df6418 --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/node_map/node_state.rs.html @@ -0,0 +1,3445 @@ +node_state.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+
use std::{
+    collections::{btree_map::Entry, BTreeSet, HashMap},
+    hash::Hash,
+    net::{IpAddr, SocketAddr},
+    time::{Duration, Instant},
+};
+
+use iroh_metrics::inc;
+use iroh_relay::{protos::stun, RelayUrl};
+use netwatch::ip::is_unicast_link_local;
+use serde::{Deserialize, Serialize};
+use tokio::sync::mpsc;
+use tracing::{debug, event, info, instrument, trace, warn, Level};
+use watchable::{Watchable, WatcherStream};
+
+use super::{
+    best_addr::{self, ClearReason, Source as BestAddrSource},
+    path_state::{summarize_node_paths, PathState},
+    udp_paths::{NodeUdpPaths, UdpSendAddr},
+    IpPort, Source,
+};
+use crate::{
+    disco::{self, SendAddr},
+    endpoint::AddrInfo,
+    key::PublicKey,
+    magicsock::{ActorMessage, MagicsockMetrics, QuicMappedAddr, Timer, HEARTBEAT_INTERVAL},
+    util::relay_only_mode,
+    NodeAddr, NodeId,
+};
+
+/// Number of addresses that are not active that we keep around per node.
+///
+/// See [`NodeState::prune_direct_addresses`].
+pub(super) const MAX_INACTIVE_DIRECT_ADDRESSES: usize = 20;
+
+/// How long since an endpoint path was last alive before it might be pruned.
+const LAST_ALIVE_PRUNE_DURATION: Duration = Duration::from_secs(120);
+
+/// How long we wait for a pong reply before assuming it's never coming.
+const PING_TIMEOUT_DURATION: Duration = Duration::from_secs(5);
+
+/// The latency at or under which we don't try to upgrade to a better path.
+const GOOD_ENOUGH_LATENCY: Duration = Duration::from_millis(5);
+
+/// How long since the last activity we try to keep an established endpoint peering alive.
+/// It's also the idle time at which we stop doing STUN queries to keep NAT mappings alive.
+pub(super) const SESSION_ACTIVE_TIMEOUT: Duration = Duration::from_secs(45);
+
+/// How often we try to upgrade to a better patheven if we have some non-relay route that works.
+const UPGRADE_INTERVAL: Duration = Duration::from_secs(60);
+
+/// How long until we send a stayin alive ping
+const STAYIN_ALIVE_MIN_ELAPSED: Duration = Duration::from_secs(2);
+
+#[derive(Debug)]
+pub(in crate::magicsock) enum PingAction {
+    SendCallMeMaybe {
+        relay_url: RelayUrl,
+        dst_node: NodeId,
+    },
+    SendPing(SendPing),
+}
+
+#[derive(Debug)]
+pub(in crate::magicsock) struct SendPing {
+    pub id: usize,
+    pub dst: SendAddr,
+    pub dst_node: NodeId,
+    pub tx_id: stun::TransactionId,
+    pub purpose: DiscoPingPurpose,
+}
+
+/// Indicating an [`NodeState`] has handled a ping.
+#[derive(Debug)]
+pub struct PingHandled {
+    /// What this ping did to the [`NodeState`].
+    pub role: PingRole,
+    /// Whether the sender path should also be pinged.
+    ///
+    /// This is the case if an [`NodeState`] does not yet have a direct path, i.e. it has no
+    /// best_addr.  In this case we want to ping right back to open the direct path in this
+    /// direction as well.
+    pub needs_ping_back: Option<SendPing>,
+}
+
+#[derive(Debug)]
+pub enum PingRole {
+    Duplicate,
+    NewPath,
+    LikelyHeartbeat,
+    Activate,
+}
+
+/// An iroh node, which we can have connections with.
+///
+/// The whole point of the magicsock is that we can have multiple **paths** to a particular
+/// node.  One of these paths is via the endpoint's home relay node but as we establish a
+/// connection we'll hopefully discover more direct paths.
+#[derive(Debug)]
+pub(super) struct NodeState {
+    /// The ID used as index in the [`NodeMap`].
+    ///
+    /// [`NodeMap`]: super::NodeMap
+    id: usize,
+    /// The UDP address used on the QUIC-layer to address this node.
+    quic_mapped_addr: QuicMappedAddr,
+    /// The global identifier for this endpoint.
+    node_id: NodeId,
+    /// The last time we pinged all endpoints.
+    last_full_ping: Option<Instant>,
+    /// The url of relay node that we can relay over to communicate.
+    ///
+    /// The fallback/bootstrap path, if non-zero (non-zero for well-behaved clients).
+    relay_url: Option<(RelayUrl, PathState)>,
+    udp_paths: NodeUdpPaths,
+    sent_pings: HashMap<stun::TransactionId, SentPing>,
+    /// Last time this node was used.
+    ///
+    /// A node is marked as in use when sending datagrams to them, or when having received
+    /// datagrams from it. Regardless of whether the datagrams are payload or DISCO, and whether
+    /// they go via UDP or the relay.
+    ///
+    /// Note that sending datagrams to a node does not mean the node receives them.
+    last_used: Option<Instant>,
+    /// Last time we sent a call-me-maybe.
+    ///
+    /// When we do not have a direct connection and we try to send some data, we will try to
+    /// do a full ping + call-me-maybe.  Usually each side only needs to send one
+    /// call-me-maybe to the other for holes to be punched in both directions however.  So
+    /// we only try and send one per [`HEARTBEAT_INTERVAL`].  Each [`HEARTBEAT_INTERVAL`]
+    /// the [`NodeState::stayin_alive`] function is called, which will trigger new
+    /// call-me-maybe messages as backup.
+    last_call_me_maybe: Option<Instant>,
+    /// The type of connection we have to the node, either direct, relay, mixed, or none.
+    conn_type: Watchable<ConnectionType>,
+    /// Whether the conn_type was ever observed to be `Direct` at some point.
+    ///
+    /// Used for metric reporting.
+    has_been_direct: bool,
+}
+
+/// Options for creating a new [`NodeState`].
+#[derive(Debug)]
+pub(super) struct Options {
+    pub(super) node_id: NodeId,
+    pub(super) relay_url: Option<RelayUrl>,
+    /// Is this endpoint currently active (sending data)?
+    pub(super) active: bool,
+    pub(super) source: super::Source,
+}
+
+impl NodeState {
+    pub(super) fn new(id: usize, options: Options) -> Self {
+        let quic_mapped_addr = QuicMappedAddr::generate();
+
+        if options.relay_url.is_some() {
+            // we potentially have a relay connection to the node
+            inc!(MagicsockMetrics, num_relay_conns_added);
+        }
+
+        let now = Instant::now();
+
+        NodeState {
+            id,
+            quic_mapped_addr,
+            node_id: options.node_id,
+            last_full_ping: None,
+            relay_url: options.relay_url.map(|url| {
+                (
+                    url.clone(),
+                    PathState::new(options.node_id, SendAddr::Relay(url), options.source, now),
+                )
+            }),
+            udp_paths: NodeUdpPaths::new(),
+            sent_pings: HashMap::new(),
+            last_used: options.active.then(Instant::now),
+            last_call_me_maybe: None,
+            conn_type: Watchable::new(ConnectionType::None),
+            has_been_direct: false,
+        }
+    }
+
+    pub(super) fn public_key(&self) -> &PublicKey {
+        &self.node_id
+    }
+
+    pub(super) fn quic_mapped_addr(&self) -> &QuicMappedAddr {
+        &self.quic_mapped_addr
+    }
+
+    pub(super) fn id(&self) -> usize {
+        self.id
+    }
+
+    pub(super) fn conn_type(&self) -> ConnectionType {
+        self.conn_type.get()
+    }
+
+    pub(super) fn conn_type_stream(&self) -> WatcherStream<ConnectionType> {
+        self.conn_type.watch().into_stream()
+    }
+
+    /// Returns info about this node.
+    pub(super) fn info(&self, now: Instant) -> RemoteInfo {
+        let conn_type = self.conn_type.get();
+        let latency = match conn_type {
+            ConnectionType::Direct(addr) => self
+                .udp_paths
+                .paths
+                .get(&addr.into())
+                .and_then(|state| state.latency()),
+            ConnectionType::Relay(ref url) => self
+                .relay_url
+                .as_ref()
+                .filter(|(relay_url, _)| relay_url == url)
+                .and_then(|(_, state)| state.latency()),
+            ConnectionType::Mixed(addr, ref url) => {
+                let addr_latency = self
+                    .udp_paths
+                    .paths
+                    .get(&addr.into())
+                    .and_then(|state| state.latency());
+                let relay_latency = self
+                    .relay_url
+                    .as_ref()
+                    .filter(|(relay_url, _)| relay_url == url)
+                    .and_then(|(_, state)| state.latency());
+                addr_latency.min(relay_latency)
+            }
+            ConnectionType::None => None,
+        };
+
+        let addrs = self
+            .udp_paths
+            .paths
+            .iter()
+            .map(|(addr, path_state)| DirectAddrInfo {
+                addr: SocketAddr::from(*addr),
+                latency: path_state.recent_pong.as_ref().map(|pong| pong.latency),
+                last_control: path_state.last_control_msg(now),
+                last_payload: path_state
+                    .last_payload_msg
+                    .as_ref()
+                    .map(|instant| now.duration_since(*instant)),
+                last_alive: path_state
+                    .last_alive()
+                    .map(|instant| now.duration_since(instant)),
+                sources: path_state
+                    .sources
+                    .iter()
+                    .map(|(source, instant)| (source.clone(), now.duration_since(*instant)))
+                    .collect(),
+            })
+            .collect();
+
+        RemoteInfo {
+            node_id: self.node_id,
+            relay_url: self.relay_url.clone().map(|r| r.into()),
+            addrs,
+            conn_type,
+            latency,
+            last_used: self.last_used.map(|instant| now.duration_since(instant)),
+        }
+    }
+
+    /// Returns the relay url of this endpoint
+    pub(super) fn relay_url(&self) -> Option<RelayUrl> {
+        self.relay_url.as_ref().map(|(url, _state)| url.clone())
+    }
+
+    /// Returns the address(es) that should be used for sending the next packet.
+    ///
+    /// This may return to send on one, both or no paths.
+    fn addr_for_send(
+        &mut self,
+        now: &Instant,
+        have_ipv6: bool,
+    ) -> (Option<SocketAddr>, Option<RelayUrl>) {
+        if relay_only_mode() {
+            debug!("in `DEV_relay_ONLY` mode, giving the relay address as the only viable address for this endpoint");
+            return (None, self.relay_url());
+        }
+        let (best_addr, relay_url) = match self.udp_paths.send_addr(*now, have_ipv6) {
+            UdpSendAddr::Valid(addr) => {
+                // If we have a valid address we use it.
+                trace!(%addr, "UdpSendAddr is valid, use it");
+                (Some(addr), None)
+            }
+            UdpSendAddr::Outdated(addr) => {
+                // If the address is outdated we use it, but send via relay at the same time.
+                // We also send disco pings so that it will become valid again if it still
+                // works (i.e. we don't need to holepunch again).
+                trace!(%addr, "UdpSendAddr is outdated, use it together with relay");
+                (Some(addr), self.relay_url())
+            }
+            UdpSendAddr::Unconfirmed(addr) => {
+                trace!(%addr, "UdpSendAddr is unconfirmed, use it together with relay");
+                (Some(addr), self.relay_url())
+            }
+            UdpSendAddr::None => {
+                trace!("No UdpSendAddr, use relay");
+                (None, self.relay_url())
+            }
+        };
+        let typ = match (best_addr, relay_url.clone()) {
+            (Some(best_addr), Some(relay_url)) => ConnectionType::Mixed(best_addr, relay_url),
+            (Some(best_addr), None) => ConnectionType::Direct(best_addr),
+            (None, Some(relay_url)) => ConnectionType::Relay(relay_url),
+            (None, None) => ConnectionType::None,
+        };
+        if !self.has_been_direct && matches!(&typ, ConnectionType::Direct(_)) {
+            self.has_been_direct = true;
+            inc!(MagicsockMetrics, nodes_contacted_directly);
+        }
+        if let Ok(prev_typ) = self.conn_type.update(typ.clone()) {
+            // The connection type has changed.
+            event!(
+                target: "iroh::_events::conn_type::changed",
+                Level::DEBUG,
+                remote_node = %self.node_id.fmt_short(),
+                conn_type = ?typ,
+            );
+            info!(%typ, "new connection type");
+
+            // Update some metrics
+            match (prev_typ, typ) {
+                (ConnectionType::Relay(_), ConnectionType::Direct(_))
+                | (ConnectionType::Mixed(_, _), ConnectionType::Direct(_)) => {
+                    inc!(MagicsockMetrics, num_direct_conns_added);
+                    inc!(MagicsockMetrics, num_relay_conns_removed);
+                }
+                (ConnectionType::Direct(_), ConnectionType::Relay(_))
+                | (ConnectionType::Direct(_), ConnectionType::Mixed(_, _)) => {
+                    inc!(MagicsockMetrics, num_direct_conns_removed);
+                    inc!(MagicsockMetrics, num_relay_conns_added);
+                }
+                (ConnectionType::None, ConnectionType::Direct(_)) => {
+                    inc!(MagicsockMetrics, num_direct_conns_added)
+                }
+                (ConnectionType::Direct(_), ConnectionType::None) => {
+                    inc!(MagicsockMetrics, num_direct_conns_removed)
+                }
+                (ConnectionType::None, ConnectionType::Relay(_))
+                | (ConnectionType::None, ConnectionType::Mixed(_, _)) => {
+                    inc!(MagicsockMetrics, num_relay_conns_added)
+                }
+                (ConnectionType::Relay(_), ConnectionType::None)
+                | (ConnectionType::Mixed(_, _), ConnectionType::None) => {
+                    inc!(MagicsockMetrics, num_relay_conns_removed)
+                }
+                _ => (),
+            }
+        }
+        (best_addr, relay_url)
+    }
+
+    /// Removes a direct address for this node.
+    ///
+    /// If this is also the best address, it will be cleared as well.
+    pub(super) fn remove_direct_addr(&mut self, ip_port: &IpPort, reason: ClearReason) {
+        let Some(state) = self.udp_paths.paths.remove(ip_port) else {
+            return;
+        };
+
+        match state.last_alive().map(|instant| instant.elapsed()) {
+            Some(last_alive) => debug!(%ip_port, ?last_alive, ?reason, "pruning address"),
+            None => debug!(%ip_port, last_seen=%"never", ?reason, "pruning address"),
+        }
+
+        self.udp_paths.best_addr.clear_if_equals(
+            (*ip_port).into(),
+            reason,
+            self.relay_url.is_some(),
+        );
+    }
+
+    /// Whether we need to send another call-me-maybe to the endpoint.
+    ///
+    /// Basically we need to send a call-me-maybe if we need to find a better path.  Maybe
+    /// we only have a relay path, or our path is expired.
+    ///
+    /// When a call-me-maybe message is sent we also need to send pings to all known paths
+    /// of the endpoint.  The [`NodeState::send_call_me_maybe`] function takes care of this.
+    #[instrument("want_call_me_maybe", skip_all)]
+    fn want_call_me_maybe(&self, now: &Instant) -> bool {
+        trace!("full ping: wanted?");
+        let Some(last_full_ping) = self.last_full_ping else {
+            debug!("no previous full ping: need full ping");
+            return true;
+        };
+        match self.udp_paths.best_addr.state(*now) {
+            best_addr::State::Empty => {
+                debug!("best addr not set: need full ping");
+                true
+            }
+            best_addr::State::Outdated(_) => {
+                debug!("best addr expired: need full ping");
+                true
+            }
+            best_addr::State::Valid(addr) => {
+                if addr.latency > GOOD_ENOUGH_LATENCY && *now - last_full_ping >= UPGRADE_INTERVAL {
+                    debug!(
+                        "full ping interval expired and latency is only {}ms: need full ping",
+                        addr.latency.as_millis()
+                    );
+                    true
+                } else {
+                    trace!(?now, "best_addr valid: not needed");
+                    false
+                }
+            }
+        }
+    }
+
+    /// Cleanup the expired ping for the passed in txid.
+    #[instrument("disco", skip_all, fields(node = %self.node_id.fmt_short()))]
+    pub(super) fn ping_timeout(&mut self, txid: stun::TransactionId) {
+        if let Some(sp) = self.sent_pings.remove(&txid) {
+            debug!(tx = %hex::encode(txid), addr = %sp.to, "pong not received in timeout");
+            match sp.to {
+                SendAddr::Udp(addr) => {
+                    if let Some(path_state) = self.udp_paths.paths.get_mut(&addr.into()) {
+                        path_state.last_ping = None;
+                        let consider_alive = path_state
+                            .last_alive()
+                            .map(|last_alive| last_alive.elapsed() <= PING_TIMEOUT_DURATION)
+                            .unwrap_or(false);
+                        if !consider_alive {
+                            // If there was no sign of life from this path during the time
+                            // which we should have received the pong, clear best addr and
+                            // pong.  Both are used to select this path again, but we know
+                            // it's not a usable path now.
+                            path_state.recent_pong = None;
+                            self.udp_paths.best_addr.clear_if_equals(
+                                addr,
+                                ClearReason::PongTimeout,
+                                self.relay_url().is_some(),
+                            )
+                        }
+                    } else {
+                        // If we have no state for the best addr it should have been cleared
+                        // anyway.
+                        self.udp_paths.best_addr.clear_if_equals(
+                            addr,
+                            ClearReason::PongTimeout,
+                            self.relay_url.is_some(),
+                        );
+                    }
+                }
+                SendAddr::Relay(ref url) => {
+                    if let Some((home_relay, relay_state)) = self.relay_url.as_mut() {
+                        if home_relay == url {
+                            // lost connectivity via relay
+                            relay_state.last_ping = None;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    #[must_use = "pings must be handled"]
+    fn start_ping(&self, dst: SendAddr, purpose: DiscoPingPurpose) -> Option<SendPing> {
+        if relay_only_mode() && !dst.is_relay() {
+            // don't attempt any hole punching in relay only mode
+            warn!("in `DEV_relay_ONLY` mode, ignoring request to start a hole punching attempt.");
+            return None;
+        }
+        let tx_id = stun::TransactionId::default();
+        trace!(tx = %hex::encode(tx_id), %dst, ?purpose,
+               dst = %self.node_id.fmt_short(), "start ping");
+        event!(
+            target: "iroh::_events::ping::sent",
+            Level::DEBUG,
+            remote_node = %self.node_id.fmt_short(),
+            ?dst,
+            txn = ?tx_id,
+            ?purpose,
+        );
+        Some(SendPing {
+            id: self.id,
+            dst,
+            dst_node: self.node_id,
+            tx_id,
+            purpose,
+        })
+    }
+
+    /// Record the fact that a ping has been sent out.
+    pub(super) fn ping_sent(
+        &mut self,
+        to: SendAddr,
+        tx_id: stun::TransactionId,
+        purpose: DiscoPingPurpose,
+        sender: mpsc::Sender<ActorMessage>,
+    ) {
+        trace!(%to, tx = %hex::encode(tx_id), ?purpose, "record ping sent");
+
+        let now = Instant::now();
+        let mut path_found = false;
+        match to {
+            SendAddr::Udp(addr) => {
+                if let Some(st) = self.udp_paths.paths.get_mut(&addr.into()) {
+                    st.last_ping.replace(now);
+                    path_found = true
+                }
+            }
+            SendAddr::Relay(ref url) => {
+                if let Some((home_relay, relay_state)) = self.relay_url.as_mut() {
+                    if home_relay == url {
+                        relay_state.last_ping.replace(now);
+                        path_found = true
+                    }
+                }
+            }
+        }
+        if !path_found {
+            // Shouldn't happen. But don't ping an endpoint that's not active for us.
+            warn!(%to, ?purpose, "unexpected attempt to ping no longer live path");
+            return;
+        }
+
+        let id = self.id;
+        let timer = Timer::after(PING_TIMEOUT_DURATION, async move {
+            sender
+                .send(ActorMessage::EndpointPingExpired(id, tx_id))
+                .await
+                .ok();
+        });
+        self.sent_pings.insert(
+            tx_id,
+            SentPing {
+                to,
+                at: now,
+                purpose,
+                timer,
+            },
+        );
+    }
+
+    /// Send a DISCO call-me-maybe message to the peer.
+    ///
+    /// This takes care of sending the needed pings beforehand.  This ensures that we open
+    /// our firewall's port so that when the receiver sends us DISCO pings in response to
+    /// our call-me-maybe they will reach us and the other side establishes a direct
+    /// connection upon our subsequent pong response.
+    ///
+    /// For [`SendCallMeMaybe::IfNoRecent`], **no** paths will be pinged if there already
+    /// was a recent call-me-maybe sent.
+    ///
+    /// The caller is responsible for sending the messages.
+    #[must_use = "actions must be handled"]
+    fn send_call_me_maybe(&mut self, now: Instant, always: SendCallMeMaybe) -> Vec<PingAction> {
+        match always {
+            SendCallMeMaybe::Always => (),
+            SendCallMeMaybe::IfNoRecent => {
+                let had_recent_call_me_maybe = self
+                    .last_call_me_maybe
+                    .map(|when| when.elapsed() < HEARTBEAT_INTERVAL)
+                    .unwrap_or(false);
+                if had_recent_call_me_maybe {
+                    trace!("skipping call-me-maybe, still recent");
+                    return Vec::new();
+                }
+            }
+        }
+
+        // We send pings regardless of whether we have a RelayUrl.  If we were given any
+        // direct address paths to contact but no RelayUrl, we still need to send a DISCO
+        // ping to the direct address paths so that the other node will learn about us and
+        // accepts the connection.
+        let mut msgs = self.send_pings(now);
+
+        if let Some(url) = self.relay_url() {
+            debug!(%url, "queue call-me-maybe");
+            msgs.push(PingAction::SendCallMeMaybe {
+                relay_url: url,
+                dst_node: self.node_id,
+            });
+            self.last_call_me_maybe = Some(now);
+        } else {
+            debug!("can not send call-me-maybe, no relay URL");
+        }
+
+        msgs
+    }
+
+    /// Send DISCO Pings to all the paths of this node.
+    ///
+    /// Any paths to the node which have not been recently pinged will be sent a disco
+    /// ping.
+    ///
+    /// The caller is responsible for sending the messages.
+    #[must_use = "actions must be handled"]
+    fn send_pings(&mut self, now: Instant) -> Vec<PingAction> {
+        // We allocate +1 in case the caller wants to add a call-me-maybe message.
+        let mut ping_msgs = Vec::with_capacity(self.udp_paths.paths.len() + 1);
+
+        if let Some((url, state)) = self.relay_url.as_ref() {
+            if state.needs_ping(&now) {
+                debug!(%url, "relay path needs ping");
+                if let Some(msg) =
+                    self.start_ping(SendAddr::Relay(url.clone()), DiscoPingPurpose::Discovery)
+                {
+                    ping_msgs.push(PingAction::SendPing(msg))
+                }
+            }
+        }
+        if relay_only_mode() {
+            warn!(
+                "in `DEV_relay_ONLY` mode, ignoring request to respond to a hole punching attempt."
+            );
+            return ping_msgs;
+        }
+        self.prune_direct_addresses();
+        let mut ping_dsts = String::from("[");
+        self.udp_paths
+            .paths
+            .iter()
+            .filter_map(|(ipp, state)| state.needs_ping(&now).then_some(*ipp))
+            .filter_map(|ipp| {
+                self.start_ping(SendAddr::Udp(ipp.into()), DiscoPingPurpose::Discovery)
+            })
+            .for_each(|msg| {
+                use std::fmt::Write;
+                write!(&mut ping_dsts, " {} ", msg.dst).ok();
+                ping_msgs.push(PingAction::SendPing(msg));
+            });
+        ping_dsts.push(']');
+        debug!(
+            %ping_dsts,
+            dst = %self.node_id.fmt_short(),
+            paths = %summarize_node_paths(&self.udp_paths.paths),
+            "sending pings to node",
+        );
+        self.last_full_ping.replace(now);
+        ping_msgs
+    }
+
+    pub(super) fn update_from_node_addr(&mut self, n: &AddrInfo, source: super::Source) {
+        if self.udp_paths.best_addr.is_empty() {
+            // we do not have a direct connection, so changing the relay information may
+            // have an effect on our connection status
+            if self.relay_url.is_none() && n.relay_url.is_some() {
+                // we did not have a relay connection before, but now we do
+                inc!(MagicsockMetrics, num_relay_conns_added)
+            } else if self.relay_url.is_some() && n.relay_url.is_none() {
+                // we had a relay connection before but do not have one now
+                inc!(MagicsockMetrics, num_relay_conns_removed)
+            }
+        }
+
+        let now = Instant::now();
+
+        if n.relay_url.is_some() && n.relay_url != self.relay_url() {
+            debug!(
+                "Changing relay node from {:?} to {:?}",
+                self.relay_url, n.relay_url
+            );
+            self.relay_url = n.relay_url.as_ref().map(|url| {
+                (
+                    url.clone(),
+                    PathState::new(self.node_id, url.clone().into(), source.clone(), now),
+                )
+            });
+        }
+
+        for &addr in n.direct_addresses.iter() {
+            self.udp_paths
+                .paths
+                .entry(addr.into())
+                .and_modify(|path_state| {
+                    path_state.add_source(source.clone(), now);
+                })
+                .or_insert_with(|| {
+                    PathState::new(self.node_id, SendAddr::from(addr), source.clone(), now)
+                });
+        }
+        let paths = summarize_node_paths(&self.udp_paths.paths);
+        debug!(new = ?n.direct_addresses , %paths, "added new direct paths for endpoint");
+    }
+
+    /// Clears all the endpoint's p2p state, reverting it to a relay-only endpoint.
+    #[instrument(skip_all, fields(node = %self.node_id.fmt_short()))]
+    pub(super) fn reset(&mut self) {
+        self.last_full_ping = None;
+        self.udp_paths
+            .best_addr
+            .clear(ClearReason::Reset, self.relay_url.is_some());
+
+        for es in self.udp_paths.paths.values_mut() {
+            es.last_ping = None;
+        }
+    }
+
+    /// Handle a received Disco Ping.
+    ///
+    /// - Ensures the paths the ping was received on is a known path for this endpoint.
+    ///
+    /// - If there is no best_addr for this endpoint yet, sends a ping itself to try and
+    ///   establish one.
+    ///
+    /// This is called once we've already verified that we got a valid discovery message
+    /// from `self` via ep.
+    pub(super) fn handle_ping(
+        &mut self,
+        path: SendAddr,
+        tx_id: stun::TransactionId,
+    ) -> PingHandled {
+        let now = Instant::now();
+
+        let role = match path {
+            SendAddr::Udp(addr) => match self.udp_paths.paths.entry(addr.into()) {
+                Entry::Occupied(mut occupied) => occupied.get_mut().handle_ping(tx_id, now),
+                Entry::Vacant(vacant) => {
+                    info!(%addr, "new direct addr for node");
+                    vacant.insert(PathState::with_ping(
+                        self.node_id,
+                        path.clone(),
+                        tx_id,
+                        Source::Udp,
+                        now,
+                    ));
+                    PingRole::NewPath
+                }
+            },
+            SendAddr::Relay(ref url) => {
+                match self.relay_url.as_mut() {
+                    Some((home_url, _state)) if home_url != url => {
+                        // either the node changed relays or we didn't have a relay address for the
+                        // node. In both cases, trust the new confirmed url
+                        info!(%url, "new relay addr for node");
+                        self.relay_url = Some((
+                            url.clone(),
+                            PathState::with_ping(
+                                self.node_id,
+                                path.clone(),
+                                tx_id,
+                                Source::Relay,
+                                now,
+                            ),
+                        ));
+                        PingRole::NewPath
+                    }
+                    Some((_home_url, state)) => state.handle_ping(tx_id, now),
+                    None => {
+                        info!(%url, "new relay addr for node");
+                        self.relay_url = Some((
+                            url.clone(),
+                            PathState::with_ping(
+                                self.node_id,
+                                path.clone(),
+                                tx_id,
+                                Source::Relay,
+                                now,
+                            ),
+                        ));
+                        PingRole::NewPath
+                    }
+                }
+            }
+        };
+        event!(
+            target: "iroh::_events::ping::recv",
+            Level::DEBUG,
+            remote_node = %self.node_id.fmt_short(),
+            src = ?path,
+            txn = ?tx_id,
+            ?role,
+        );
+
+        if matches!(path, SendAddr::Udp(_)) && matches!(role, PingRole::NewPath) {
+            self.prune_direct_addresses();
+        }
+
+        // if the endpoint does not yet have a best_addrr
+        let needs_ping_back = if matches!(path, SendAddr::Udp(_))
+            && matches!(
+                self.udp_paths.best_addr.state(now),
+                best_addr::State::Empty | best_addr::State::Outdated(_)
+            ) {
+            // We also need to send a ping to make this path available to us as well.  This
+            // is always sent together with a pong.  So in the worst case the pong gets lost
+            // and this ping does not.  In that case we ping-pong until both sides have
+            // received at least one pong.  Once both sides have received one pong they both
+            // have a best_addr and this ping will stop being sent.
+            self.start_ping(path, DiscoPingPurpose::PingBack)
+        } else {
+            None
+        };
+
+        debug!(
+            ?role,
+            needs_ping_back = ?needs_ping_back.is_some(),
+            paths = %summarize_node_paths(&self.udp_paths.paths),
+            "endpoint handled ping",
+        );
+        PingHandled {
+            role,
+            needs_ping_back,
+        }
+    }
+
+    /// Prune inactive paths.
+    ///
+    /// This trims the list of inactive paths for an endpoint.  At most
+    /// [`MAX_INACTIVE_DIRECT_ADDRESSES`] are kept.
+    pub(super) fn prune_direct_addresses(&mut self) {
+        // prune candidates are addresses that are not active
+        let mut prune_candidates: Vec<_> = self
+            .udp_paths
+            .paths
+            .iter()
+            .filter(|(_ip_port, state)| !state.is_active())
+            .map(|(ip_port, state)| (*ip_port, state.last_alive()))
+            .filter(|(_ipp, last_alive)| match last_alive {
+                Some(last_seen) => last_seen.elapsed() > LAST_ALIVE_PRUNE_DURATION,
+                None => true,
+            })
+            .collect();
+        let prune_count = prune_candidates
+            .len()
+            .saturating_sub(MAX_INACTIVE_DIRECT_ADDRESSES);
+        if prune_count == 0 {
+            // nothing to do, within limits
+            debug!(
+                paths = %summarize_node_paths(&self.udp_paths.paths),
+                "prune addresses: {prune_count} pruned",
+            );
+            return;
+        }
+
+        // sort leaving the worst addresses first (never contacted) and better ones (most recently
+        // used ones) last
+        prune_candidates.sort_unstable_by_key(|(_ip_port, last_alive)| *last_alive);
+        prune_candidates.truncate(prune_count);
+        for (ip_port, _last_alive) in prune_candidates.into_iter() {
+            self.remove_direct_addr(&ip_port, ClearReason::Inactive)
+        }
+        debug!(
+            paths = %summarize_node_paths(&self.udp_paths.paths),
+            "prune addresses: {prune_count} pruned",
+        );
+    }
+
+    /// Called when connectivity changes enough that we should question our earlier
+    /// assumptions about which paths work.
+    #[instrument("disco", skip_all, fields(node = %self.node_id.fmt_short()))]
+    pub(super) fn note_connectivity_change(&mut self) {
+        self.udp_paths.best_addr.clear_trust("connectivity changed");
+        for es in self.udp_paths.paths.values_mut() {
+            es.clear();
+        }
+    }
+
+    /// Handles a Pong message (a reply to an earlier ping).
+    ///
+    /// It reports the address and key that should be inserted for the endpoint if any.
+    #[instrument(skip(self))]
+    pub(super) fn handle_pong(
+        &mut self,
+        m: &disco::Pong,
+        src: SendAddr,
+    ) -> Option<(SocketAddr, PublicKey)> {
+        event!(
+            target: "iroh::_events::pong::recv",
+            Level::DEBUG,
+            remote_node = self.node_id.fmt_short(),
+            ?src,
+            txn = ?m.tx_id,
+        );
+        let is_relay = src.is_relay();
+        match self.sent_pings.remove(&m.tx_id) {
+            None => {
+                // This is not a pong for a ping we sent.
+                warn!(tx = %hex::encode(m.tx_id), "received pong with unknown transaction id");
+                None
+            }
+            Some(sp) => {
+                sp.timer.abort();
+
+                let mut node_map_insert = None;
+
+                let now = Instant::now();
+                let latency = now - sp.at;
+
+                debug!(
+                    tx = %hex::encode(m.tx_id),
+                    src = %src,
+                    reported_ping_src = %m.ping_observed_addr,
+                    ping_dst = %sp.to,
+                    is_relay = %src.is_relay(),
+                    latency = %latency.as_millis(),
+                    "received pong",
+                );
+
+                match src {
+                    SendAddr::Udp(addr) => {
+                        match self.udp_paths.paths.get_mut(&addr.into()) {
+                            None => {
+                                warn!("ignoring pong: no state for src addr");
+                                // This is no longer an endpoint we care about.
+                                return node_map_insert;
+                            }
+                            Some(st) => {
+                                node_map_insert = Some((addr, self.node_id));
+                                st.add_pong_reply(PongReply {
+                                    latency,
+                                    pong_at: now,
+                                    from: src,
+                                    pong_src: m.ping_observed_addr.clone(),
+                                });
+                            }
+                        }
+                        debug!(
+                            paths = %summarize_node_paths(&self.udp_paths.paths),
+                            "handled pong",
+                        );
+                    }
+                    SendAddr::Relay(ref url) => match self.relay_url.as_mut() {
+                        Some((home_url, state)) if home_url == url => {
+                            state.add_pong_reply(PongReply {
+                                latency,
+                                pong_at: now,
+                                from: src,
+                                pong_src: m.ping_observed_addr.clone(),
+                            });
+                        }
+                        other => {
+                            // if we are here then we sent this ping, but the url changed
+                            // waiting for the response. It was either set to None or changed to
+                            // another relay. This should either never happen or be extremely
+                            // unlikely. Log and ignore for now
+                            warn!(
+                                stored=?other,
+                                received=?url,
+                                "ignoring pong via relay for different relay from last one",
+                            );
+                        }
+                    },
+                }
+
+                // Promote this pong response to our current best address if it's lower latency.
+                // TODO(bradfitz): decide how latency vs. preference order affects decision
+                if let SendAddr::Udp(to) = sp.to {
+                    debug_assert!(!is_relay, "mismatching relay & udp");
+                    self.udp_paths.best_addr.insert_if_better_or_reconfirm(
+                        to,
+                        latency,
+                        best_addr::Source::ReceivedPong,
+                        now,
+                    );
+                }
+
+                node_map_insert
+            }
+        }
+    }
+
+    /// Handles a DISCO CallMeMaybe discovery message.
+    ///
+    /// The contract for use of this message is that the node has already pinged to us via
+    /// UDP, so their stateful firewall should be open. Now we can Ping back and make it
+    /// through.
+    ///
+    /// However if the remote side has no direct path information to us, they would not have
+    /// had any [`IpPort`]s to send pings to and our pings might end up blocked.  But at
+    /// least open the firewalls on our side, giving the other side another change of making
+    /// it through when it pings in response.
+    pub(super) fn handle_call_me_maybe(&mut self, m: disco::CallMeMaybe) -> Vec<PingAction> {
+        let now = Instant::now();
+        let mut call_me_maybe_ipps = BTreeSet::new();
+
+        for peer_sockaddr in &m.my_numbers {
+            if let IpAddr::V6(ip) = peer_sockaddr.ip() {
+                if is_unicast_link_local(ip) {
+                    // We send these out, but ignore them for now.
+                    // TODO: teach the ping code to ping on all interfaces for these.
+                    continue;
+                }
+            }
+            let ipp = IpPort::from(*peer_sockaddr);
+            call_me_maybe_ipps.insert(ipp);
+            self.udp_paths
+                .paths
+                .entry(ipp)
+                .or_insert_with(|| {
+                    PathState::new(
+                        self.node_id,
+                        SendAddr::from(*peer_sockaddr),
+                        Source::Relay,
+                        now,
+                    )
+                })
+                .call_me_maybe_time
+                .replace(now);
+        }
+
+        // Zero out all the last_ping times to force send_pings to send new ones, even if
+        // it's been less than 5 seconds ago.  Also clear pongs for direct addresses not
+        // included in the updated set.
+        for (ipp, st) in self.udp_paths.paths.iter_mut() {
+            st.last_ping = None;
+            if !call_me_maybe_ipps.contains(ipp) {
+                // TODO: This seems like a weird way to signal that the endpoint no longer
+                // thinks it has this IpPort as an available path.
+                if st.recent_pong.is_some() {
+                    debug!(path=?ipp ,"clearing recent pong");
+                    st.recent_pong = None;
+                }
+            }
+        }
+        // Clear trust on our best_addr if it is not included in the updated set.  Also
+        // clear the last call-me-maybe send time so we will send one again.
+        if let Some(addr) = self.udp_paths.best_addr.addr() {
+            let ipp: IpPort = addr.into();
+            if !call_me_maybe_ipps.contains(&ipp) {
+                self.udp_paths
+                    .best_addr
+                    .clear_trust("best_addr not in new call-me-maybe");
+                self.last_call_me_maybe = None;
+            }
+        }
+        debug!(
+            paths = %summarize_node_paths(&self.udp_paths.paths),
+            "updated endpoint paths from call-me-maybe",
+        );
+        self.send_pings(now)
+    }
+
+    /// Marks this node as having received a UDP payload message.
+    pub(super) fn receive_udp(&mut self, addr: IpPort, now: Instant) {
+        let Some(state) = self.udp_paths.paths.get_mut(&addr) else {
+            debug_assert!(false, "node map inconsistency by_ip_port <-> direct addr");
+            return;
+        };
+        state.last_payload_msg = Some(now);
+        self.last_used = Some(now);
+        self.udp_paths
+            .best_addr
+            .reconfirm_if_used(addr.into(), BestAddrSource::Udp, now);
+    }
+
+    pub(super) fn receive_relay(&mut self, url: &RelayUrl, src: NodeId, now: Instant) {
+        match self.relay_url.as_mut() {
+            Some((current_home, state)) if current_home == url => {
+                // We received on the expected url. update state.
+                state.last_payload_msg = Some(now);
+            }
+            Some((_current_home, _state)) => {
+                // we have a different url. we only update on ping, not on receive_relay.
+            }
+            None => {
+                self.relay_url = Some((
+                    url.clone(),
+                    PathState::with_last_payload(
+                        src,
+                        SendAddr::from(url.clone()),
+                        Source::Relay,
+                        now,
+                    ),
+                ));
+            }
+        }
+        self.last_used = Some(now);
+    }
+
+    pub(super) fn last_ping(&self, addr: &SendAddr) -> Option<Instant> {
+        match addr {
+            SendAddr::Udp(addr) => self
+                .udp_paths
+                .paths
+                .get(&(*addr).into())
+                .and_then(|ep| ep.last_ping),
+            SendAddr::Relay(url) => self
+                .relay_url
+                .as_ref()
+                .filter(|(home_url, _state)| home_url == url)
+                .and_then(|(_home_url, state)| state.last_ping),
+        }
+    }
+
+    /// Checks if this `Endpoint` is currently actively being used.
+    pub(super) fn is_active(&self, now: &Instant) -> bool {
+        match self.last_used {
+            Some(last_active) => now.duration_since(last_active) <= SESSION_ACTIVE_TIMEOUT,
+            None => false,
+        }
+    }
+
+    /// Send a heartbeat to the node to keep the connection alive, or trigger a full ping
+    /// if necessary.
+    #[instrument("stayin_alive", skip_all, fields(node = %self.node_id.fmt_short()))]
+    pub(super) fn stayin_alive(&mut self) -> Vec<PingAction> {
+        trace!("stayin_alive");
+        let now = Instant::now();
+        if !self.is_active(&now) {
+            trace!("skipping stayin alive: session is inactive");
+            return Vec::new();
+        }
+
+        // If we do not have an optimal addr, send pings to all known places.
+        if self.want_call_me_maybe(&now) {
+            debug!("sending a call-me-maybe");
+            return self.send_call_me_maybe(now, SendCallMeMaybe::Always);
+        }
+
+        // Send heartbeat ping to keep the current addr going as long as we need it.
+        if let Some(udp_addr) = self.udp_paths.best_addr.addr() {
+            let elapsed = self.last_ping(&SendAddr::Udp(udp_addr)).map(|l| now - l);
+            // Send a ping if the last ping is older than 2 seconds.
+            let needs_ping = match elapsed {
+                Some(e) => e >= STAYIN_ALIVE_MIN_ELAPSED,
+                None => false,
+            };
+
+            if needs_ping {
+                debug!(
+                    dst = %udp_addr,
+                    since_last_ping=?elapsed,
+                    "send stayin alive ping",
+                );
+                if let Some(msg) =
+                    self.start_ping(SendAddr::Udp(udp_addr), DiscoPingPurpose::StayinAlive)
+                {
+                    return vec![PingAction::SendPing(msg)];
+                }
+            }
+        }
+
+        Vec::new()
+    }
+
+    /// Returns the addresses on which a payload should be sent right now.
+    ///
+    /// This is in the hot path of `.poll_send()`.
+    #[instrument("get_send_addrs", skip_all, fields(node = %self.node_id.fmt_short()))]
+    pub(crate) fn get_send_addrs(
+        &mut self,
+        have_ipv6: bool,
+    ) -> (Option<SocketAddr>, Option<RelayUrl>, Vec<PingAction>) {
+        let now = Instant::now();
+        let prev = self.last_used.replace(now);
+        if prev.is_none() {
+            // this is the first time we are trying to connect to this node
+            inc!(MagicsockMetrics, nodes_contacted);
+        }
+        let (udp_addr, relay_url) = self.addr_for_send(&now, have_ipv6);
+        let mut ping_msgs = Vec::new();
+
+        if self.want_call_me_maybe(&now) {
+            ping_msgs = self.send_call_me_maybe(now, SendCallMeMaybe::IfNoRecent);
+        }
+
+        trace!(
+            ?udp_addr,
+            ?relay_url,
+            pings = %ping_msgs.len(),
+            "found send address",
+        );
+
+        (udp_addr, relay_url, ping_msgs)
+    }
+
+    /// Get the direct addresses for this endpoint.
+    pub(super) fn direct_addresses(&self) -> impl Iterator<Item = IpPort> + '_ {
+        self.udp_paths.paths.keys().copied()
+    }
+
+    #[cfg(test)]
+    pub(super) fn direct_address_states(&self) -> impl Iterator<Item = (&IpPort, &PathState)> + '_ {
+        self.udp_paths.paths.iter()
+    }
+
+    pub(super) fn last_used(&self) -> Option<Instant> {
+        self.last_used
+    }
+}
+
+impl From<RemoteInfo> for NodeAddr {
+    fn from(info: RemoteInfo) -> Self {
+        let direct_addresses = info
+            .addrs
+            .into_iter()
+            .map(|info| info.addr)
+            .collect::<BTreeSet<_>>();
+
+        NodeAddr {
+            node_id: info.node_id,
+            info: AddrInfo {
+                relay_url: info.relay_url.map(Into::into),
+                direct_addresses,
+            },
+        }
+    }
+}
+
+/// Whether to send a call-me-maybe message after sending pings to all known paths.
+///
+/// `IfNoRecent` will only send a call-me-maybe if no previous one was sent in the last
+/// [`HEARTBEAT_INTERVAL`].
+#[derive(Debug)]
+enum SendCallMeMaybe {
+    Always,
+    IfNoRecent,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub(super) struct PongReply {
+    pub(super) latency: Duration,
+    /// When we received the pong.
+    pub(super) pong_at: Instant,
+    /// The pong's src (usually same as endpoint map key).
+    pub(super) from: SendAddr,
+    /// What they reported they heard.
+    pub(super) pong_src: SendAddr,
+}
+
+#[derive(Debug)]
+pub(super) struct SentPing {
+    pub(super) to: SendAddr,
+    pub(super) at: Instant,
+    #[allow(dead_code)]
+    pub(super) purpose: DiscoPingPurpose,
+    pub(super) timer: Timer,
+}
+
+/// The reason why a discovery ping message was sent.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DiscoPingPurpose {
+    /// The purpose of a ping was to see if a path was valid.
+    Discovery,
+    /// Ping to ensure the current route is still valid.
+    StayinAlive,
+    /// When a ping was received and no direct connection exists yet.
+    ///
+    /// When a ping was received we suspect a direct connection is possible.  If we do not
+    /// yet have one that triggers a ping, indicated with this reason.
+    PingBack,
+}
+
+/// The type of control message we have received.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, derive_more::Display)]
+pub enum ControlMsg {
+    /// We received a Ping from the node.
+    #[display("ping←")]
+    Ping,
+    /// We received a Pong from the node.
+    #[display("pong←")]
+    Pong,
+    /// We received a CallMeMaybe.
+    #[display("call me")]
+    CallMeMaybe,
+}
+
+/// Information about a *direct address*.
+///
+/// The *direct addresses* of an iroh node are those that could be used by other nodes to
+/// establish direct connectivity, depending on the network situation. Due to NAT configurations,
+/// for example, not all direct addresses of a node are usable by all peers.
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+pub struct DirectAddrInfo {
+    /// The UDP address reported by the remote node.
+    pub addr: SocketAddr,
+    /// The latency to the remote node over this network path.
+    ///
+    /// If there has never been any connectivity via this address no latency will be known.
+    pub latency: Option<Duration>,
+    /// Last control message received by this node about this address.
+    ///
+    /// This contains the elapsed duration since the control message was received and the
+    /// kind of control message received at that time.  Only the most recent control message
+    /// is returned.
+    ///
+    /// Note that [`ControlMsg::CallMeMaybe`] is received via a relay path, while
+    /// [`ControlMsg::Ping`] and [`ControlMsg::Pong`] are received on the path to
+    /// [`DirectAddrInfo::addr`] itself and thus convey very different information.
+    pub last_control: Option<(Duration, ControlMsg)>,
+    /// Elapsed time since the last payload message was received on this network path.
+    ///
+    /// This indicates how long ago a QUIC datagram was received from the remote node sent
+    /// from this [`DirectAddrInfo::addr`].  It indicates the network path was in use to
+    /// transport payload data.
+    pub last_payload: Option<Duration>,
+    /// Elapsed time since this network path was known to exist.
+    ///
+    /// A network path is considered to exist only because the remote node advertised it.
+    /// It may not mean the path is usable.  However, if there was any communication with
+    /// the remote node over this network path it also means the path exists.
+    ///
+    /// The elapsed time since *any* confirmation of the path's existence was received is
+    /// returned.  If the remote node moved networks and no longer has this path, this could
+    /// be a long duration.  If the path was added via [`Endpoint::add_node_addr`] or some
+    /// node discovery the path may never have been known to exist.
+    ///
+    /// [`Endpoint::add_node_addr`]: crate::endpoint::Endpoint::add_node_addr
+    pub last_alive: Option<Duration>,
+    /// A [`HashMap`] of [`Source`]s to [`Duration`]s.
+    ///
+    /// The [`Duration`] indicates the elapsed time since this source last
+    /// recorded this address.
+    ///
+    /// The [`Duration`] will always indicate the most recent time the source
+    /// recorded this address.
+    pub sources: HashMap<Source, Duration>,
+}
+
+/// Information about the network path to a remote node via a relay server.
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+pub struct RelayUrlInfo {
+    /// The relay URL.
+    pub relay_url: RelayUrl,
+    /// Elapsed time since this relay path last received payload or control data.
+    pub last_alive: Option<Duration>,
+    /// Latency to the remote node over this relayed network path.
+    pub latency: Option<Duration>,
+}
+
+impl From<(RelayUrl, PathState)> for RelayUrlInfo {
+    fn from(value: (RelayUrl, PathState)) -> Self {
+        RelayUrlInfo {
+            relay_url: value.0,
+            last_alive: value.1.last_alive().map(|i| i.elapsed()),
+            latency: value.1.latency(),
+        }
+    }
+}
+
+impl From<RelayUrlInfo> for RelayUrl {
+    fn from(value: RelayUrlInfo) -> Self {
+        value.relay_url
+    }
+}
+
+/// Details about a remote iroh node which is known to this node.
+///
+/// Having details of a node does not mean it can be connected to, nor that it has ever been
+/// connected to in the past. There are various reasons a node might be known: it could have
+/// been manually added via [`Endpoint::add_node_addr`], it could have been added by some
+/// discovery mechanism, the node could have contacted this node, etc.
+///
+/// [`Endpoint::add_node_addr`]: crate::endpoint::Endpoint::add_node_addr
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+pub struct RemoteInfo {
+    /// The globally unique identifier for this node.
+    pub node_id: NodeId,
+    /// Relay server information, if available.
+    pub relay_url: Option<RelayUrlInfo>,
+    /// The addresses at which this node might be reachable.
+    ///
+    /// Some of these addresses might only be valid for networks we are not part of, but the remote
+    /// node might be a part of.
+    pub addrs: Vec<DirectAddrInfo>,
+    /// The type of connection we have to the node, either direct or over relay.
+    pub conn_type: ConnectionType,
+    /// The latency of the current network path to the remote node.
+    pub latency: Option<Duration>,
+    /// Time elapsed time since last we have sent to or received from the node.
+    ///
+    /// This is the duration since *any* data (payload or control messages) was sent or receive
+    /// from the remote node. Note that sending to the remote node does not imply
+    /// the remote node received anything.
+    pub last_used: Option<Duration>,
+}
+
+impl RemoteInfo {
+    /// Get the duration since the last activity we received from this endpoint
+    /// on any of its direct addresses.
+    pub fn last_received(&self) -> Option<Duration> {
+        self.addrs
+            .iter()
+            .filter_map(|addr| addr.last_control.map(|x| x.0).min(addr.last_payload))
+            .min()
+    }
+
+    /// Whether there is a possible known network path to the remote node.
+    ///
+    /// Note that this does not provide any guarantees of whether any network path is
+    /// usable.
+    pub fn has_send_address(&self) -> bool {
+        self.relay_url.is_some() || !self.addrs.is_empty()
+    }
+
+    /// Returns a deduplicated list of [`Source`]s merged from all address in the [`RemoteInfo`].
+    ///
+    /// Deduplication is on the (`Source`, `Duration`) tuple, so you will get multiple [`Source`]s
+    /// for each `Source` variant, if different addresses were discovered from the same [`Source`]
+    /// at different times.
+    ///
+    /// The list is sorted from least to most recent [`Source`].
+    pub fn sources(&self) -> Vec<(Source, Duration)> {
+        let mut sources = vec![];
+        for addr in &self.addrs {
+            for source in &addr.sources {
+                let source = (source.0.clone(), *source.1);
+                if !sources.contains(&source) {
+                    sources.push(source)
+                }
+            }
+        }
+        sources.sort_by(|a, b| b.1.cmp(&a.1));
+        sources
+    }
+}
+
+/// The type of connection we have to the endpoint.
+#[derive(derive_more::Display, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+pub enum ConnectionType {
+    /// Direct UDP connection
+    #[display("direct({_0})")]
+    Direct(SocketAddr),
+    /// Relay connection over relay
+    #[display("relay({_0})")]
+    Relay(RelayUrl),
+    /// Both a UDP and a relay connection are used.
+    ///
+    /// This is the case if we do have a UDP address, but are missing a recent confirmation that
+    /// the address works.
+    #[display("mixed(udp: {_0}, relay: {_1})")]
+    Mixed(SocketAddr, RelayUrl),
+    /// We have no verified connection to this PublicKey
+    #[display("none")]
+    None,
+}
+
+#[cfg(test)]
+mod tests {
+    use std::{collections::BTreeMap, net::Ipv4Addr};
+
+    use best_addr::BestAddr;
+
+    use super::*;
+    use crate::{
+        key::SecretKey,
+        magicsock::node_map::{NodeMap, NodeMapInner},
+    };
+
+    #[test]
+    fn test_remote_infos() {
+        let now = Instant::now();
+        let elapsed = Duration::from_secs(3);
+        let later = now + elapsed;
+        let send_addr: RelayUrl = "https://my-relay.com".parse().unwrap();
+        let pong_src = SendAddr::Udp("0.0.0.0:1".parse().unwrap());
+        let latency = Duration::from_millis(50);
+
+        let relay_and_state = |node_id: NodeId, url: RelayUrl| {
+            let relay_state = PathState::with_pong_reply(
+                node_id,
+                PongReply {
+                    latency,
+                    pong_at: now,
+                    from: SendAddr::Relay(send_addr.clone()),
+                    pong_src: pong_src.clone(),
+                },
+            );
+            Some((url, relay_state))
+        };
+
+        // endpoint with a `best_addr` that has a latency but no relay
+        let (a_endpoint, a_socket_addr) = {
+            let key = SecretKey::generate();
+            let node_id = key.public();
+            let ip_port = IpPort {
+                ip: Ipv4Addr::UNSPECIFIED.into(),
+                port: 10,
+            };
+            let endpoint_state = BTreeMap::from([(
+                ip_port,
+                PathState::with_pong_reply(
+                    node_id,
+                    PongReply {
+                        latency,
+                        pong_at: now,
+                        from: SendAddr::Udp(ip_port.into()),
+                        pong_src: pong_src.clone(),
+                    },
+                ),
+            )]);
+            (
+                NodeState {
+                    id: 0,
+                    quic_mapped_addr: QuicMappedAddr::generate(),
+                    node_id: key.public(),
+                    last_full_ping: None,
+                    relay_url: None,
+                    udp_paths: NodeUdpPaths::from_parts(
+                        endpoint_state,
+                        BestAddr::from_parts(
+                            ip_port.into(),
+                            latency,
+                            now,
+                            now + Duration::from_secs(100),
+                        ),
+                    ),
+                    sent_pings: HashMap::new(),
+                    last_used: Some(now),
+                    last_call_me_maybe: None,
+                    conn_type: Watchable::new(ConnectionType::Direct(ip_port.into())),
+                    has_been_direct: true,
+                },
+                ip_port.into(),
+            )
+        };
+        // endpoint w/ no best addr but a relay w/ latency
+        let b_endpoint = {
+            // let socket_addr = "0.0.0.0:9".parse().unwrap();
+            let key = SecretKey::generate();
+            NodeState {
+                id: 1,
+                quic_mapped_addr: QuicMappedAddr::generate(),
+                node_id: key.public(),
+                last_full_ping: None,
+                relay_url: relay_and_state(key.public(), send_addr.clone()),
+                udp_paths: NodeUdpPaths::new(),
+                sent_pings: HashMap::new(),
+                last_used: Some(now),
+                last_call_me_maybe: None,
+                conn_type: Watchable::new(ConnectionType::Relay(send_addr.clone())),
+                has_been_direct: false,
+            }
+        };
+
+        // endpoint w/ no best addr but a relay w/ no latency
+        let c_endpoint = {
+            // let socket_addr = "0.0.0.0:8".parse().unwrap();
+            let key = SecretKey::generate();
+            NodeState {
+                id: 2,
+                quic_mapped_addr: QuicMappedAddr::generate(),
+                node_id: key.public(),
+                last_full_ping: None,
+                relay_url: Some((
+                    send_addr.clone(),
+                    PathState::new(
+                        key.public(),
+                        SendAddr::from(send_addr.clone()),
+                        Source::App,
+                        now,
+                    ),
+                )),
+                udp_paths: NodeUdpPaths::new(),
+                sent_pings: HashMap::new(),
+                last_used: Some(now),
+                last_call_me_maybe: None,
+                conn_type: Watchable::new(ConnectionType::Relay(send_addr.clone())),
+                has_been_direct: false,
+            }
+        };
+
+        // endpoint w/ expired best addr and relay w/ latency
+        let (d_endpoint, d_socket_addr) = {
+            let socket_addr: SocketAddr = "0.0.0.0:7".parse().unwrap();
+            let expired = now.checked_sub(Duration::from_secs(100)).unwrap();
+            let key = SecretKey::generate();
+            let node_id = key.public();
+            let endpoint_state = BTreeMap::from([(
+                IpPort::from(socket_addr),
+                PathState::with_pong_reply(
+                    node_id,
+                    PongReply {
+                        latency,
+                        pong_at: now,
+                        from: SendAddr::Udp(socket_addr),
+                        pong_src: pong_src.clone(),
+                    },
+                ),
+            )]);
+            (
+                NodeState {
+                    id: 3,
+                    quic_mapped_addr: QuicMappedAddr::generate(),
+                    node_id: key.public(),
+                    last_full_ping: None,
+                    relay_url: relay_and_state(key.public(), send_addr.clone()),
+                    udp_paths: NodeUdpPaths::from_parts(
+                        endpoint_state,
+                        BestAddr::from_parts(socket_addr, Duration::from_millis(80), now, expired),
+                    ),
+                    sent_pings: HashMap::new(),
+                    last_used: Some(now),
+                    last_call_me_maybe: None,
+                    conn_type: Watchable::new(ConnectionType::Mixed(
+                        socket_addr,
+                        send_addr.clone(),
+                    )),
+                    has_been_direct: false,
+                },
+                socket_addr,
+            )
+        };
+
+        let mut expect = Vec::from([
+            RemoteInfo {
+                node_id: a_endpoint.node_id,
+                relay_url: None,
+                addrs: Vec::from([DirectAddrInfo {
+                    addr: a_socket_addr,
+                    latency: Some(latency),
+                    last_control: Some((elapsed, ControlMsg::Pong)),
+                    last_payload: None,
+                    last_alive: Some(elapsed),
+                    sources: HashMap::new(),
+                }]),
+                conn_type: ConnectionType::Direct(a_socket_addr),
+                latency: Some(latency),
+                last_used: Some(elapsed),
+            },
+            RemoteInfo {
+                node_id: b_endpoint.node_id,
+                relay_url: Some(RelayUrlInfo {
+                    relay_url: b_endpoint.relay_url.as_ref().unwrap().0.clone(),
+                    last_alive: None,
+                    latency: Some(latency),
+                }),
+                addrs: Vec::new(),
+                conn_type: ConnectionType::Relay(send_addr.clone()),
+                latency: Some(latency),
+                last_used: Some(elapsed),
+            },
+            RemoteInfo {
+                node_id: c_endpoint.node_id,
+                relay_url: Some(RelayUrlInfo {
+                    relay_url: c_endpoint.relay_url.as_ref().unwrap().0.clone(),
+                    last_alive: None,
+                    latency: None,
+                }),
+                addrs: Vec::new(),
+                conn_type: ConnectionType::Relay(send_addr.clone()),
+                latency: None,
+                last_used: Some(elapsed),
+            },
+            RemoteInfo {
+                node_id: d_endpoint.node_id,
+                relay_url: Some(RelayUrlInfo {
+                    relay_url: d_endpoint.relay_url.as_ref().unwrap().0.clone(),
+                    last_alive: None,
+                    latency: Some(latency),
+                }),
+                addrs: Vec::from([DirectAddrInfo {
+                    addr: d_socket_addr,
+                    latency: Some(latency),
+                    last_control: Some((elapsed, ControlMsg::Pong)),
+                    last_payload: None,
+                    last_alive: Some(elapsed),
+                    sources: HashMap::new(),
+                }]),
+                conn_type: ConnectionType::Mixed(d_socket_addr, send_addr.clone()),
+                latency: Some(Duration::from_millis(50)),
+                last_used: Some(elapsed),
+            },
+        ]);
+
+        let node_map = NodeMap::from_inner(NodeMapInner {
+            by_node_key: HashMap::from([
+                (a_endpoint.node_id, a_endpoint.id),
+                (b_endpoint.node_id, b_endpoint.id),
+                (c_endpoint.node_id, c_endpoint.id),
+                (d_endpoint.node_id, d_endpoint.id),
+            ]),
+            by_ip_port: HashMap::from([
+                (a_socket_addr.into(), a_endpoint.id),
+                (d_socket_addr.into(), d_endpoint.id),
+            ]),
+            by_quic_mapped_addr: HashMap::from([
+                (a_endpoint.quic_mapped_addr, a_endpoint.id),
+                (b_endpoint.quic_mapped_addr, b_endpoint.id),
+                (c_endpoint.quic_mapped_addr, c_endpoint.id),
+                (d_endpoint.quic_mapped_addr, d_endpoint.id),
+            ]),
+            by_id: HashMap::from([
+                (a_endpoint.id, a_endpoint),
+                (b_endpoint.id, b_endpoint),
+                (c_endpoint.id, c_endpoint),
+                (d_endpoint.id, d_endpoint),
+            ]),
+            next_id: 5,
+        });
+        let mut got = node_map.list_remote_infos(later);
+        got.sort_by_key(|p| p.node_id);
+        expect.sort_by_key(|p| p.node_id);
+        remove_non_deterministic_fields(&mut got);
+        assert_eq!(expect, got);
+    }
+
+    fn remove_non_deterministic_fields(infos: &mut [RemoteInfo]) {
+        for info in infos.iter_mut() {
+            if info.relay_url.is_some() {
+                info.relay_url.as_mut().unwrap().last_alive = None;
+            }
+        }
+    }
+
+    #[test]
+    fn test_prune_direct_addresses() {
+        // When we handle a call-me-maybe with more than MAX_INACTIVE_DIRECT_ADDRESSES we do
+        // not want to prune them right away but send pings to all of them.
+
+        let key = SecretKey::generate();
+        let opts = Options {
+            node_id: key.public(),
+            relay_url: None,
+            active: true,
+            source: crate::magicsock::Source::NamedApp {
+                name: "test".into(),
+            },
+        };
+        let mut ep = NodeState::new(0, opts);
+
+        let my_numbers_count: u16 = (MAX_INACTIVE_DIRECT_ADDRESSES + 5).try_into().unwrap();
+        let my_numbers = (0u16..my_numbers_count)
+            .map(|i| SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 1000 + i))
+            .collect();
+        let call_me_maybe = disco::CallMeMaybe { my_numbers };
+
+        let ping_messages = ep.handle_call_me_maybe(call_me_maybe);
+
+        // We have no relay server and no previous direct addresses, so we should get the same
+        // number of pings as direct addresses in the call-me-maybe.
+        assert_eq!(ping_messages.len(), my_numbers_count as usize);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/node_map/path_state.rs.html b/pr/2992/docs/src/iroh/magicsock/node_map/path_state.rs.html new file mode 100644 index 0000000000..b9eaf6fbed --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/node_map/path_state.rs.html @@ -0,0 +1,655 @@ +path_state.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+
//! The state kept for each network path to a remote node.
+
+use std::{
+    collections::{BTreeMap, HashMap},
+    net::SocketAddr,
+    time::{Duration, Instant},
+};
+
+use iroh_base::key::NodeId;
+use iroh_relay::protos::stun;
+use tracing::{debug, event, Level};
+
+use super::{
+    node_state::{ControlMsg, PongReply, SESSION_ACTIVE_TIMEOUT},
+    IpPort, PingRole, Source,
+};
+use crate::{disco::SendAddr, magicsock::HEARTBEAT_INTERVAL};
+
+/// The minimum time between pings to an endpoint.
+///
+/// Except in the case of CallMeMaybe frames resetting the counter, as the first pings
+/// likely didn't through the firewall.
+const DISCO_PING_INTERVAL: Duration = Duration::from_secs(5);
+
+/// State about a particular path to another [`NodeState`].
+///
+/// This state is used for both the relay path and any direct UDP paths.
+///
+/// [`NodeState`]: super::node_state::NodeState
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(super) struct PathState {
+    /// The node for which this path exists.
+    node_id: NodeId,
+    /// The path this applies for.
+    path: SendAddr,
+    /// The last (outgoing) ping time.
+    pub(super) last_ping: Option<Instant>,
+
+    /// If non-zero, means that this was an endpoint that we learned about at runtime (from an
+    /// incoming ping). If so, we keep the time updated and use it to discard old candidates.
+    // NOTE: tx_id Originally added in tailscale due to <https://github.com/tailscale/tailscale/issues/7078>.
+    last_got_ping: Option<(Instant, stun::TransactionId)>,
+
+    /// The time this endpoint was last advertised via a call-me-maybe DISCO message.
+    pub(super) call_me_maybe_time: Option<Instant>,
+
+    /// The most recent [`PongReply`].
+    ///
+    /// Previous replies are cleared when they are no longer relevant to determine whether
+    /// this path can still be used to reach the remote node.
+    pub(super) recent_pong: Option<PongReply>,
+    /// When the last payload data was **received** via this path.
+    ///
+    /// This excludes DISCO messages.
+    pub(super) last_payload_msg: Option<Instant>,
+    /// Sources is a map of [`Source`]s to [`Instant`]s, keeping track of all the ways we have
+    /// learned about this path
+    ///
+    /// We keep track of only the latest [`Instant`] for each [`Source`], keeping the size of
+    /// the map of sources down to one entry per type of source.
+    pub(super) sources: HashMap<Source, Instant>,
+}
+
+impl PathState {
+    pub(super) fn new(node_id: NodeId, path: SendAddr, source: Source, now: Instant) -> Self {
+        let mut sources = HashMap::new();
+        sources.insert(source, now);
+        Self {
+            node_id,
+            path,
+            last_ping: None,
+            last_got_ping: None,
+            call_me_maybe_time: None,
+            recent_pong: None,
+            last_payload_msg: None,
+            sources,
+        }
+    }
+
+    pub(super) fn udp_addr(&self) -> Option<SocketAddr> {
+        match self.path {
+            SendAddr::Udp(addr) => Some(addr),
+            SendAddr::Relay(_) => None,
+        }
+    }
+
+    pub(super) fn with_last_payload(
+        node_id: NodeId,
+        path: SendAddr,
+        source: Source,
+        now: Instant,
+    ) -> Self {
+        let mut sources = HashMap::new();
+        sources.insert(source, now);
+        PathState {
+            node_id,
+            path,
+            last_ping: None,
+            last_got_ping: None,
+            call_me_maybe_time: None,
+            recent_pong: None,
+            last_payload_msg: Some(now),
+            sources,
+        }
+    }
+
+    pub(super) fn with_ping(
+        node_id: NodeId,
+        path: SendAddr,
+        tx_id: stun::TransactionId,
+        source: Source,
+        now: Instant,
+    ) -> Self {
+        let mut new = PathState::new(node_id, path, source, now);
+        new.handle_ping(tx_id, now);
+        new
+    }
+
+    pub(super) fn add_pong_reply(&mut self, r: PongReply) {
+        if let SendAddr::Udp(ref path) = self.path {
+            if self.recent_pong.is_none() {
+                event!(
+                    target: "iroh::_events::holepunched",
+                    Level::DEBUG,
+                    remote_node = %self.node_id.fmt_short(),
+                    path = ?path,
+                    direction = "outgoing",
+                );
+            }
+        }
+        self.recent_pong = Some(r);
+    }
+
+    #[cfg(test)]
+    pub(super) fn with_pong_reply(node_id: NodeId, r: PongReply) -> Self {
+        PathState {
+            node_id,
+            path: r.from.clone(),
+            last_ping: None,
+            last_got_ping: None,
+            call_me_maybe_time: None,
+            recent_pong: Some(r),
+            last_payload_msg: None,
+            sources: HashMap::new(),
+        }
+    }
+
+    /// Check whether this path is considered active.
+    ///
+    /// Active means the path has received payload messages within the last
+    /// [`SESSION_ACTIVE_TIMEOUT`].
+    ///
+    /// Note that a path might be alive but not active if it's contactable but not in
+    /// use.
+    pub(super) fn is_active(&self) -> bool {
+        self.last_payload_msg
+            .as_ref()
+            .map(|instant| instant.elapsed() <= SESSION_ACTIVE_TIMEOUT)
+            .unwrap_or(false)
+    }
+
+    /// Returns the instant the last incoming ping was received.
+    pub(super) fn last_incoming_ping(&self) -> Option<&Instant> {
+        self.last_got_ping.as_ref().map(|(time, _tx_id)| time)
+    }
+
+    /// Reports the last instant this path was considered alive.
+    ///
+    /// Alive means the path is considered in use by the remote endpoint.  Either because we
+    /// received a payload message, a DISCO message (ping, pong) or it was advertised in a
+    /// call-me-maybe message.
+    ///
+    /// This is the most recent instant between:
+    /// - when last pong was received.
+    /// - when this path was last advertised in a received CallMeMaybe message.
+    /// - When the last payload transmission occurred.
+    /// - when the last ping from them was received.
+    pub(super) fn last_alive(&self) -> Option<Instant> {
+        self.recent_pong
+            .as_ref()
+            .map(|pong| &pong.pong_at)
+            .into_iter()
+            .chain(self.last_payload_msg.as_ref())
+            .chain(self.call_me_maybe_time.as_ref())
+            .chain(self.last_incoming_ping())
+            .max()
+            .copied()
+    }
+
+    /// The last control or DISCO message **about** this path.
+    ///
+    /// This is the most recent instant among:
+    /// - when last pong was received.
+    /// - when this path was last advertised in a received CallMeMaybe message.
+    /// - when the last ping from them was received.
+    ///
+    /// Returns the time elapsed since the last control message, and the type of control message.
+    pub(super) fn last_control_msg(&self, now: Instant) -> Option<(Duration, ControlMsg)> {
+        // get every control message and assign it its kind
+        let last_pong = self
+            .recent_pong
+            .as_ref()
+            .map(|pong| (pong.pong_at, ControlMsg::Pong));
+        let last_call_me_maybe = self
+            .call_me_maybe_time
+            .as_ref()
+            .map(|call_me| (*call_me, ControlMsg::CallMeMaybe));
+        let last_ping = self
+            .last_incoming_ping()
+            .map(|ping| (*ping, ControlMsg::Ping));
+
+        last_pong
+            .into_iter()
+            .chain(last_call_me_maybe)
+            .chain(last_ping)
+            .max_by_key(|(instant, _kind)| *instant)
+            .map(|(instant, kind)| (now.duration_since(instant), kind))
+    }
+
+    /// Returns the latency from the most recent pong, if available.
+    pub(super) fn latency(&self) -> Option<Duration> {
+        self.recent_pong.as_ref().map(|p| p.latency)
+    }
+
+    pub(super) fn needs_ping(&self, now: &Instant) -> bool {
+        match self.last_ping {
+            None => true,
+            Some(last_ping) => {
+                let elapsed = now.duration_since(last_ping);
+
+                // TODO: remove!
+                // This logs "ping is too new" for each send whenever the endpoint does *not* need
+                // a ping. Pretty sure this is not a useful log, but maybe there was a reason?
+                // if !needs_ping {
+                //     debug!("ping is too new: {}ms", elapsed.as_millis());
+                // }
+                elapsed > DISCO_PING_INTERVAL
+            }
+        }
+    }
+
+    pub(super) fn handle_ping(&mut self, tx_id: stun::TransactionId, now: Instant) -> PingRole {
+        if Some(&tx_id) == self.last_got_ping.as_ref().map(|(_t, tx_id)| tx_id) {
+            PingRole::Duplicate
+        } else {
+            let prev = self.last_got_ping.replace((now, tx_id));
+            let heartbeat_deadline = HEARTBEAT_INTERVAL + (HEARTBEAT_INTERVAL / 2);
+            match prev {
+                Some((prev_time, _tx)) if now.duration_since(prev_time) <= heartbeat_deadline => {
+                    PingRole::LikelyHeartbeat
+                }
+                Some((prev_time, _tx)) => {
+                    debug!(
+                        elapsed = ?now.duration_since(prev_time),
+                        "heartbeat missed, reactivating",
+                    );
+                    PingRole::Activate
+                }
+                None => {
+                    if let SendAddr::Udp(ref addr) = self.path {
+                        event!(
+                            target: "iroh::_events::holepunched",
+                            Level::DEBUG,
+                            remote_node = %self.node_id.fmt_short(),
+                            path = ?addr,
+                            direction = "incoming",
+                        );
+                    }
+                    PingRole::Activate
+                }
+            }
+        }
+    }
+
+    pub(super) fn add_source(&mut self, source: Source, now: Instant) {
+        self.sources.insert(source, now);
+    }
+
+    pub(super) fn clear(&mut self) {
+        self.last_ping = None;
+        self.last_got_ping = None;
+        self.call_me_maybe_time = None;
+        self.recent_pong = None;
+    }
+
+    fn summary(&self, mut w: impl std::fmt::Write) -> std::fmt::Result {
+        write!(w, "{{ ")?;
+        if self.is_active() {
+            write!(w, "active ")?;
+        }
+        if let Some(ref pong) = self.recent_pong {
+            write!(w, "pong-received({:?} ago) ", pong.pong_at.elapsed())?;
+        }
+        if let Some(when) = self.last_incoming_ping() {
+            write!(w, "ping-received({:?} ago) ", when.elapsed())?;
+        }
+        if let Some(ref when) = self.last_ping {
+            write!(w, "ping-sent({:?} ago) ", when.elapsed())?;
+        }
+        if let Some(last_source) = self.sources.iter().max_by_key(|&(_, instant)| instant) {
+            write!(
+                w,
+                "last-source: {}({:?} ago)",
+                last_source.0,
+                last_source.1.elapsed()
+            )?;
+        }
+        write!(w, "}}")
+    }
+}
+
+// TODO: Make an `EndpointPaths` struct and do things nicely.
+pub(super) fn summarize_node_paths(paths: &BTreeMap<IpPort, PathState>) -> String {
+    use std::fmt::Write;
+
+    let mut w = String::new();
+    write!(&mut w, "[").ok();
+    for (i, (ipp, state)) in paths.iter().enumerate() {
+        if i > 0 {
+            write!(&mut w, ", ").ok();
+        }
+        write!(&mut w, "{ipp}").ok();
+        state.summary(&mut w).ok();
+    }
+    write!(&mut w, "]").ok();
+    w
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/node_map/udp_paths.rs.html b/pr/2992/docs/src/iroh/magicsock/node_map/udp_paths.rs.html new file mode 100644 index 0000000000..cade0a7536 --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/node_map/udp_paths.rs.html @@ -0,0 +1,367 @@ +udp_paths.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+
//! Path state for UDP addresses of a single peer node.
+//!
+//! This started as simply moving the [`NodeState`]'s `direct_addresses` and `best_addr`
+//! into one place together.  The aim is for external places to not directly interact with
+//! the inside and instead only notifies this struct of state changes to each path.
+//!
+//! [`NodeState`]: super::node_state::NodeState
+use std::{
+    collections::BTreeMap,
+    net::SocketAddr,
+    time::{Duration, Instant},
+};
+
+use rand::seq::IteratorRandom;
+use tracing::warn;
+
+use super::{
+    best_addr::{self, BestAddr},
+    node_state::PongReply,
+    path_state::PathState,
+    IpPort,
+};
+use crate::disco::SendAddr;
+
+/// The address on which to send datagrams over UDP.
+///
+/// The [`MagicSock`] sends packets to zero or one UDP address, depending on the known paths
+/// to the remote node.  This conveys the UDP address to send on from the [`NodeUdpPaths`]
+/// to the [`NodeState`].
+///
+/// [`NodeUdpPaths`] contains all the UDP path states, while [`NodeState`] has to decide the
+/// bigger picture including the relay server.
+///
+/// See [`NodeUdpPaths::send_addr`].
+///
+/// [`MagicSock`]: crate::magicsock::MagicSock
+/// [`NodeState`]: super::node_state::NodeState
+#[derive(Debug)]
+pub(super) enum UdpSendAddr {
+    /// The UDP address can be relied on to deliver data to the remote node.
+    ///
+    /// This means this path is usable with a reasonable latency and can be fully trusted to
+    /// transport payload data to the remote node.
+    Valid(SocketAddr),
+    /// The UDP address is highly likely to work, but has not been used for a while.
+    ///
+    /// The path should be usable but has not carried DISCO or payload data for a little too
+    /// long.  It is best to also use a backup, i.e. relay, path if possible.
+    Outdated(SocketAddr),
+    /// The UDP address is not known to work, but it might.
+    ///
+    /// We know this UDP address belongs to the remote node, but we do not know if the path
+    /// already works or may need holepunching before it will start to work.  It might even
+    /// never work.  It is still useful to send to this together with backup path,
+    /// i.e. relay, in case the path works: if the path does not need holepunching it might
+    /// be much faster.  And if there is no relay path at all it might be the only way to
+    /// establish a connection.
+    Unconfirmed(SocketAddr),
+    /// No known UDP path exists to the remote node.
+    None,
+}
+
+/// The UDP paths for a single node.
+///
+/// Paths are identified by the [`IpPort`] of their UDP address.
+///
+/// Initially this collects two structs directly from the [`NodeState`] into one place,
+/// leaving the APIs and astractions the same.  The goal is that this slowly migrates
+/// directly interacting with this data into only receiving [`PathState`] updates.  This
+/// will consolidate the logic of direct path selection and make this simpler to reason
+/// about.  However doing that all at once is too large a refactor.
+///
+/// [`NodeState`]: super::node_state::NodeState
+#[derive(Debug, Default)]
+pub(super) struct NodeUdpPaths {
+    /// The state for each of this node's direct paths.
+    pub(super) paths: BTreeMap<IpPort, PathState>,
+    /// Best UDP path currently selected.
+    pub(super) best_addr: BestAddr,
+    /// If we had to choose a path because we had no `best_addr` it is stored here.
+    chosen_candidate: Option<IpPort>,
+}
+
+impl NodeUdpPaths {
+    pub(super) fn new() -> Self {
+        Default::default()
+    }
+
+    #[cfg(test)]
+    pub(super) fn from_parts(paths: BTreeMap<IpPort, PathState>, best_addr: BestAddr) -> Self {
+        Self {
+            paths,
+            best_addr,
+            chosen_candidate: None,
+        }
+    }
+
+    /// Returns the current UDP address to send on.
+    ///
+    /// TODO: The goal here is for this to simply return the already known send address, so
+    /// it should be `&self` and not `&mut self`.  This is only possible once the state from
+    /// [`NodeUdpPaths`] is no longer modified from outside.
+    pub(super) fn send_addr(&mut self, now: Instant, have_ipv6: bool) -> UdpSendAddr {
+        self.assign_best_addr_from_candidates_if_empty();
+        match self.best_addr.state(now) {
+            best_addr::State::Valid(addr) => UdpSendAddr::Valid(addr.addr),
+            best_addr::State::Outdated(addr) => UdpSendAddr::Outdated(addr.addr),
+            best_addr::State::Empty => {
+                // No direct connection has been used before.  If we know of any possible
+                // candidate addresses, randomly try to use one.  This path is most
+                // effective when folks use a NodeAddr with exactly one direct address which
+                // they know to work, effectively like using a traditional socket or QUIC
+                // endpoint.
+                let addr = self
+                    .chosen_candidate
+                    .and_then(|ipp| self.paths.get(&ipp))
+                    .and_then(|path| path.udp_addr())
+                    .filter(|addr| addr.is_ipv4() || have_ipv6)
+                    .or_else(|| {
+                        // Look for a new candidate in all the known paths.  This may look
+                        // like a RNG use on the hot-path but this is normally invoked at
+                        // most most once at startup.
+                        let addr = self
+                            .paths
+                            .values()
+                            .filter_map(|path| path.udp_addr())
+                            .filter(|addr| addr.is_ipv4() || have_ipv6)
+                            .choose(&mut rand::thread_rng());
+                        self.chosen_candidate = addr.map(IpPort::from);
+                        addr
+                    });
+                match addr {
+                    Some(addr) => UdpSendAddr::Unconfirmed(addr),
+                    None => UdpSendAddr::None,
+                }
+            }
+        }
+    }
+
+    /// Fixup best_addr from candidates.
+    ///
+    /// If somehow we end up in a state where we failed to set a best_addr, while we do have
+    /// valid candidates, this will chose a candidate and set best_addr again.  Most likely
+    /// this is a bug elsewhere though.
+    fn assign_best_addr_from_candidates_if_empty(&mut self) {
+        if !self.best_addr.is_empty() {
+            return;
+        }
+
+        // The highest acceptable latency for an endpoint path.  If the latency is higher
+        // then this the path will be ignored.
+        const MAX_LATENCY: Duration = Duration::from_secs(60 * 60);
+        let best_pong = self.paths.iter().fold(None, |best_pong, (ipp, state)| {
+            let best_latency = best_pong
+                .map(|p: &PongReply| p.latency)
+                .unwrap_or(MAX_LATENCY);
+            match state.recent_pong {
+                // This pong is better if it has a lower latency, or if it has the same
+                // latency but on an IPv6 path.
+                Some(ref pong)
+                    if pong.latency < best_latency
+                        || (pong.latency == best_latency && ipp.ip().is_ipv6()) =>
+                {
+                    Some(pong)
+                }
+                _ => best_pong,
+            }
+        });
+
+        // If we found a candidate, set to best addr
+        if let Some(pong) = best_pong {
+            if let SendAddr::Udp(addr) = pong.from {
+                warn!(%addr, "No best_addr was set, choose candidate with lowest latency");
+                self.best_addr.insert_if_better_or_reconfirm(
+                    addr,
+                    pong.latency,
+                    best_addr::Source::BestCandidate,
+                    pong.pong_at,
+                )
+            }
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/relay_actor.rs.html b/pr/2992/docs/src/iroh/magicsock/relay_actor.rs.html new file mode 100644 index 0000000000..af3228808a --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/relay_actor.rs.html @@ -0,0 +1,1581 @@ +relay_actor.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+
use std::{
+    collections::{BTreeMap, BTreeSet},
+    future::Future,
+    net::{IpAddr, SocketAddr},
+    sync::{atomic::Ordering, Arc},
+    time::{Duration, Instant},
+};
+
+use anyhow::Context;
+use backoff::backoff::Backoff;
+use bytes::{Bytes, BytesMut};
+use iroh_metrics::{inc, inc_by};
+use iroh_relay::{self as relay, client::ClientError, ReceivedMessage, RelayUrl, MAX_PACKET_SIZE};
+use tokio::{
+    sync::{mpsc, oneshot},
+    task::{JoinHandle, JoinSet},
+    time,
+};
+use tokio_util::sync::CancellationToken;
+use tracing::{debug, info, info_span, trace, warn, Instrument};
+
+use super::{ActorMessage, MagicSock, Metrics as MagicsockMetrics, RelayContents};
+use crate::key::{NodeId, PUBLIC_KEY_LENGTH};
+
+/// How long a non-home relay connection needs to be idle (last written to) before we close it.
+const RELAY_INACTIVE_CLEANUP_TIME: Duration = Duration::from_secs(60);
+
+/// How often `clean_stale_relay` runs when there are potentially-stale relay connections to close.
+const RELAY_CLEAN_STALE_INTERVAL: Duration = Duration::from_secs(15);
+
+pub(super) enum RelayActorMessage {
+    Send {
+        url: RelayUrl,
+        contents: RelayContents,
+        remote_node: NodeId,
+    },
+    MaybeCloseRelaysOnRebind(Vec<IpAddr>),
+    SetHome {
+        url: RelayUrl,
+    },
+}
+
+/// Contains fields for an active relay connection.
+#[derive(Debug)]
+struct ActiveRelay {
+    /// The time of the last request for its write
+    /// channel (currently even if there was no write).
+    last_write: Instant,
+    msg_sender: mpsc::Sender<ActorMessage>,
+    url: RelayUrl,
+    relay_client: relay::client::Client,
+    relay_client_receiver: relay::client::ClientReceiver,
+    /// The set of remote nodes we know are present on this relay server.
+    ///
+    /// If we receive messages from a remote node via, this server it is added to this set.
+    /// If the server notifies us this node is gone, it is removed from this set.
+    node_present: BTreeSet<NodeId>,
+    backoff: backoff::exponential::ExponentialBackoff<backoff::SystemClock>,
+    last_packet_time: Option<Instant>,
+    last_packet_src: Option<NodeId>,
+}
+
+#[derive(Debug)]
+#[allow(clippy::large_enum_variant)]
+enum ActiveRelayMessage {
+    GetLastWrite(oneshot::Sender<Instant>),
+    Ping(oneshot::Sender<Result<Duration, ClientError>>),
+    GetLocalAddr(oneshot::Sender<Option<SocketAddr>>),
+    GetNodeRoute(NodeId, oneshot::Sender<Option<relay::client::Client>>),
+    GetClient(oneshot::Sender<relay::client::Client>),
+    NotePreferred(bool),
+    Shutdown,
+}
+
+impl ActiveRelay {
+    fn new(
+        url: RelayUrl,
+        relay_client: relay::client::Client,
+        relay_client_receiver: relay::client::ClientReceiver,
+        msg_sender: mpsc::Sender<ActorMessage>,
+    ) -> Self {
+        ActiveRelay {
+            last_write: Instant::now(),
+            msg_sender,
+            url,
+            node_present: BTreeSet::new(),
+            backoff: backoff::exponential::ExponentialBackoffBuilder::new()
+                .with_initial_interval(Duration::from_millis(10))
+                .with_max_interval(Duration::from_secs(5))
+                .build(),
+            last_packet_time: None,
+            last_packet_src: None,
+            relay_client,
+            relay_client_receiver,
+        }
+    }
+
+    async fn run(mut self, mut inbox: mpsc::Receiver<ActiveRelayMessage>) -> anyhow::Result<()> {
+        debug!("initial dial {}", self.url);
+        self.relay_client
+            .connect()
+            .await
+            .context("initial connection")?;
+
+        loop {
+            // If a read error occurred on the connection it might have been lost.  But we
+            // need this connection to stay alive so we can receive more messages sent by
+            // peers via the relay even if we don't start sending again first.
+            if !self.relay_client.is_connected().await? {
+                debug!("relay re-connecting");
+                self.relay_client.connect().await.context("keepalive")?;
+            }
+            tokio::select! {
+                msg = inbox.recv() => {
+                    let Some(msg) = msg else {
+                        debug!("all clients closed");
+                        break;
+                    };
+
+                    trace!("tick: inbox: {:?}", msg);
+                    match msg {
+                        ActiveRelayMessage::GetLastWrite(r) => {
+                            r.send(self.last_write).ok();
+                        }
+                        ActiveRelayMessage::Ping(r) => {
+                            r.send(self.relay_client.ping().await).ok();
+                        }
+                        ActiveRelayMessage::GetLocalAddr(r) => {
+                            r.send(self.relay_client.local_addr().await).ok();
+                        }
+                        ActiveRelayMessage::GetClient(r) => {
+                            self.last_write = Instant::now();
+                            r.send(self.relay_client.clone()).ok();
+                        }
+                        ActiveRelayMessage::NotePreferred(is_preferred) => {
+                            self.relay_client.note_preferred(is_preferred).await;
+                        }
+                        ActiveRelayMessage::GetNodeRoute(peer, r) => {
+                            let client = if self.node_present.contains(&peer) {
+                                Some(self.relay_client.clone())
+                            } else {
+                                None
+                            };
+                            r.send(client).ok();
+                        }
+                        ActiveRelayMessage::Shutdown => {
+                            debug!("shutdown");
+                            break;
+                        }
+                    }
+                }
+
+                msg = self.relay_client_receiver.recv() => {
+                    trace!("tick: relay_client_receiver");
+                    if let Some(msg) = msg {
+                        if self.handle_relay_msg(msg).await == ReadResult::Break {
+                            // fatal error
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        debug!("exiting");
+        self.relay_client.close().await?;
+        Ok(())
+    }
+
+    async fn handle_relay_msg(&mut self, msg: Result<ReceivedMessage, ClientError>) -> ReadResult {
+        match msg {
+            Err(err) => {
+                warn!("recv error {:?}", err);
+
+                // Forget that all these peers have routes.
+                self.node_present.clear();
+
+                if matches!(
+                    err,
+                    relay::client::ClientError::Closed | relay::client::ClientError::IPDisabled
+                ) {
+                    // drop client
+                    return ReadResult::Break;
+                }
+
+                // If our relay connection broke, it might be because our network
+                // conditions changed. Start that check.
+                // TODO:
+                // self.re_stun("relay-recv-error").await;
+
+                // Back off a bit before reconnecting.
+                match self.backoff.next_backoff() {
+                    Some(t) => {
+                        debug!("backoff sleep: {}ms", t.as_millis());
+                        time::sleep(t).await;
+                        ReadResult::Continue
+                    }
+                    None => ReadResult::Break,
+                }
+            }
+            Ok(msg) => {
+                // reset
+                self.backoff.reset();
+                let now = Instant::now();
+                if self
+                    .last_packet_time
+                    .as_ref()
+                    .map(|t| t.elapsed() > Duration::from_secs(5))
+                    .unwrap_or(true)
+                {
+                    self.last_packet_time = Some(now);
+                }
+
+                match msg {
+                    ReceivedMessage::ReceivedPacket { source, data } => {
+                        trace!(len=%data.len(), "received msg");
+                        // If this is a new sender we hadn't seen before, remember it and
+                        // register a route for this peer.
+                        if self
+                            .last_packet_src
+                            .as_ref()
+                            .map(|p| *p != source)
+                            .unwrap_or(true)
+                        {
+                            // avoid map lookup w/ high throughput single peer
+                            self.last_packet_src = Some(source);
+                            self.node_present.insert(source);
+                        }
+
+                        let res = RelayReadResult {
+                            url: self.url.clone(),
+                            src: source,
+                            buf: data,
+                        };
+                        if let Err(err) = self.msg_sender.try_send(ActorMessage::ReceiveRelay(res))
+                        {
+                            warn!("dropping received relay packet: {:?}", err);
+                        }
+
+                        ReadResult::Continue
+                    }
+                    ReceivedMessage::Ping(data) => {
+                        // Best effort reply to the ping.
+                        let dc = self.relay_client.clone();
+                        tokio::task::spawn(async move {
+                            if let Err(err) = dc.send_pong(data).await {
+                                warn!("pong error: {:?}", err);
+                            }
+                        });
+                        ReadResult::Continue
+                    }
+                    ReceivedMessage::Health { .. } => ReadResult::Continue,
+                    ReceivedMessage::NodeGone(key) => {
+                        self.node_present.remove(&key);
+                        ReadResult::Continue
+                    }
+                    other => {
+                        trace!("ignoring: {:?}", other);
+                        // Ignore.
+                        ReadResult::Continue
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub(super) struct RelayActor {
+    msock: Arc<MagicSock>,
+    /// relay Url -> connection to the node
+    active_relay: BTreeMap<RelayUrl, (mpsc::Sender<ActiveRelayMessage>, JoinHandle<()>)>,
+    msg_sender: mpsc::Sender<ActorMessage>,
+    ping_tasks: JoinSet<(RelayUrl, bool)>,
+    cancel_token: CancellationToken,
+}
+
+impl RelayActor {
+    pub(super) fn new(msock: Arc<MagicSock>, msg_sender: mpsc::Sender<ActorMessage>) -> Self {
+        let cancel_token = CancellationToken::new();
+        Self {
+            msock,
+            active_relay: Default::default(),
+            msg_sender,
+            ping_tasks: Default::default(),
+            cancel_token,
+        }
+    }
+
+    pub fn cancel_token(&self) -> CancellationToken {
+        self.cancel_token.clone()
+    }
+
+    pub(super) async fn run(mut self, mut receiver: mpsc::Receiver<RelayActorMessage>) {
+        let mut cleanup_timer = time::interval_at(
+            time::Instant::now() + RELAY_CLEAN_STALE_INTERVAL,
+            RELAY_CLEAN_STALE_INTERVAL,
+        );
+
+        loop {
+            tokio::select! {
+                biased;
+
+                _ = self.cancel_token.cancelled() => {
+                    trace!("shutting down");
+                    break;
+                }
+                // `ping_tasks` being empty is a normal situation - in fact it starts empty
+                // until a `MaybeCloseRelaysOnRebind` message is received.
+                Some(task_result) = self.ping_tasks.join_next() => {
+                    match task_result {
+                        Ok((url, ping_success)) => {
+                            if !ping_success {
+                                with_cancel(
+                                    self.cancel_token.child_token(),
+                                    self.close_or_reconnect_relay(&url, "rebind-ping-fail")
+                                ).await;
+                            }
+                        }
+
+                        Err(err) => {
+                            warn!("ping task error: {:?}", err);
+                        }
+                    }
+                }
+
+                msg = receiver.recv() => {
+                    let Some(msg) = msg else {
+                        trace!("shutting down relay recv loop");
+                        break;
+                    };
+
+                    with_cancel(self.cancel_token.child_token(), self.handle_msg(msg)).await;
+                }
+                _ = cleanup_timer.tick() => {
+                    trace!("tick: cleanup");
+                    with_cancel(self.cancel_token.child_token(), self.clean_stale_relay()).await;
+                }
+            }
+        }
+
+        // try shutdown
+        self.close_all_relay("conn-close").await;
+    }
+
+    async fn handle_msg(&mut self, msg: RelayActorMessage) {
+        match msg {
+            RelayActorMessage::Send {
+                url,
+                contents,
+                remote_node,
+            } => {
+                self.send_relay(&url, contents, remote_node).await;
+            }
+            RelayActorMessage::SetHome { url } => {
+                self.note_preferred(&url).await;
+                self.connect_relay(&url, None).await;
+            }
+            RelayActorMessage::MaybeCloseRelaysOnRebind(ifs) => {
+                self.maybe_close_relays_on_rebind(&ifs).await;
+            }
+        }
+    }
+
+    async fn note_preferred(&self, my_url: &RelayUrl) {
+        futures_buffered::join_all(self.active_relay.iter().map(|(url, (s, _))| async move {
+            let is_preferred = url == my_url;
+            s.send(ActiveRelayMessage::NotePreferred(is_preferred))
+                .await
+                .ok()
+        }))
+        .await;
+    }
+
+    async fn send_relay(&mut self, url: &RelayUrl, contents: RelayContents, remote_node: NodeId) {
+        trace!(
+            %url,
+            remote_node = %remote_node.fmt_short(),
+            len = contents.iter().map(|c| c.len()).sum::<usize>(),
+            "sending over relay",
+        );
+        // Relay Send
+        let relay_client = self.connect_relay(url, Some(&remote_node)).await;
+        for content in &contents {
+            trace!(%url, ?remote_node, "sending {}B", content.len());
+        }
+        let total_bytes = contents.iter().map(|c| c.len() as u64).sum::<u64>();
+
+        const PAYLAOD_SIZE: usize = MAX_PACKET_SIZE - PUBLIC_KEY_LENGTH;
+
+        // Split into multiple packets if needed.
+        // In almost all cases this will be a single packet.
+        // But we have no guarantee that the total size of the contents including
+        // length prefix will be smaller than the payload size.
+        for packet in PacketizeIter::<_, PAYLAOD_SIZE>::new(contents) {
+            match relay_client.send(remote_node, packet).await {
+                Ok(_) => {
+                    inc_by!(MagicsockMetrics, send_relay, total_bytes);
+                }
+                Err(err) => {
+                    warn!(%url, "send: failed {:?}", err);
+                    inc!(MagicsockMetrics, send_relay_error);
+                }
+            }
+        }
+
+        // Wake up the send waker if one is waiting for space in the channel
+        let mut wakers = self.msock.network_send_wakers.lock();
+        if let Some(waker) = wakers.take() {
+            waker.wake();
+        }
+    }
+
+    /// Returns `true`if the message was sent successfully.
+    async fn send_to_active(&mut self, url: &RelayUrl, msg: ActiveRelayMessage) -> bool {
+        let res = self.active_relay.get(url);
+        match res {
+            Some((s, _)) => match s.send(msg).await {
+                Ok(_) => true,
+                Err(mpsc::error::SendError(_)) => {
+                    self.close_relay(url, "sender-closed").await;
+                    false
+                }
+            },
+            None => false,
+        }
+    }
+
+    /// Connect to the given relay node.
+    async fn connect_relay(
+        &mut self,
+        url: &RelayUrl,
+        remote_node: Option<&NodeId>,
+    ) -> relay::client::Client {
+        trace!(%url, ?remote_node, "connect relay");
+        // See if we have a connection open to that relay node ID first. If so, might as
+        // well use it. (It's a little arbitrary whether we use this one vs. the reverse route
+        // below when we have both.)
+
+        {
+            let (os, or) = oneshot::channel();
+            if self
+                .send_to_active(url, ActiveRelayMessage::GetClient(os))
+                .await
+            {
+                if let Ok(client) = or.await {
+                    return client;
+                }
+            }
+        }
+
+        // If we don't have an open connection to the peer's home relay
+        // node, see if we have an open connection to a relay node
+        // where we'd heard from that peer already. For instance,
+        // perhaps peer's home is Frankfurt, but they dialed our home relay
+        // node in SF to reach us, so we can reply to them using our
+        // SF connection rather than dialing Frankfurt.
+        if let Some(node) = remote_node {
+            for url in self
+                .active_relay
+                .keys()
+                .cloned()
+                .collect::<Vec<_>>()
+                .into_iter()
+            {
+                let (os, or) = oneshot::channel();
+                if self
+                    .send_to_active(&url, ActiveRelayMessage::GetNodeRoute(*node, os))
+                    .await
+                {
+                    if let Ok(Some(client)) = or.await {
+                        return client;
+                    }
+                }
+            }
+        }
+
+        let why = if let Some(node) = remote_node {
+            format!("{node:?}")
+        } else {
+            "home-keep-alive".to_string()
+        };
+        info!("adding connection to relay: {url} for {why}");
+
+        let my_relay = self.msock.my_relay();
+        let ipv6_reported = self.msock.ipv6_reported.clone();
+        let url = url.clone();
+        let url1 = url.clone();
+
+        // building a client dials the relay
+        let mut builder = relay::client::ClientBuilder::new(url1.clone());
+        if let Some(url) = self.msock.proxy_url() {
+            builder = builder.proxy_url(url.clone());
+        }
+        let builder = builder
+            .address_family_selector(move || {
+                let ipv6_reported = ipv6_reported.clone();
+                Box::pin(async move { ipv6_reported.load(Ordering::Relaxed) })
+            })
+            .can_ack_pings(true)
+            .is_preferred(my_relay.as_ref() == Some(&url1));
+
+        #[cfg(any(test, feature = "test-utils"))]
+        let builder = builder.insecure_skip_cert_verify(self.msock.insecure_skip_relay_cert_verify);
+
+        let (dc, dc_receiver) = builder.build(
+            self.msock.secret_key.clone(),
+            self.msock.dns_resolver.clone(),
+        );
+
+        let (s, r) = mpsc::channel(64);
+
+        let c = dc.clone();
+        let msg_sender = self.msg_sender.clone();
+        let url1 = url.clone();
+        let handle = tokio::task::spawn(
+            async move {
+                let ad = ActiveRelay::new(url1, c, dc_receiver, msg_sender);
+
+                if let Err(err) = ad.run(r).await {
+                    warn!("connection error: {:?}", err);
+                }
+            }
+            .instrument(info_span!("active-relay", %url)),
+        );
+
+        // Insert, to make sure we do not attempt to double connect.
+        self.active_relay.insert(url.clone(), (s, handle));
+
+        inc!(MagicsockMetrics, num_relay_conns_added);
+
+        self.log_active_relay();
+
+        dc
+    }
+
+    /// Closes the relay connections not originating from a local IP address.
+    ///
+    /// Called in response to a rebind, any relay connection originating from an address
+    /// that's not known to be currently a local IP address should be closed.  All the other
+    /// relay connections are pinged.
+    async fn maybe_close_relays_on_rebind(&mut self, okay_local_ips: &[IpAddr]) {
+        let mut tasks = Vec::new();
+        for url in self
+            .active_relay
+            .keys()
+            .cloned()
+            .collect::<Vec<_>>()
+            .into_iter()
+        {
+            let (os, or) = oneshot::channel();
+            let la = if self
+                .send_to_active(&url, ActiveRelayMessage::GetLocalAddr(os))
+                .await
+            {
+                match or.await {
+                    Ok(None) | Err(_) => {
+                        tasks.push((url, "rebind-no-localaddr"));
+                        continue;
+                    }
+                    Ok(Some(la)) => la,
+                }
+            } else {
+                tasks.push((url.clone(), "rebind-no-localaddr"));
+                continue;
+            };
+
+            if !okay_local_ips.contains(&la.ip()) {
+                tasks.push((url, "rebind-default-route-change"));
+                continue;
+            }
+
+            let (os, or) = oneshot::channel();
+            let ping_sent = self
+                .send_to_active(&url, ActiveRelayMessage::Ping(os))
+                .await;
+
+            self.ping_tasks.spawn(async move {
+                let ping_success = time::timeout(Duration::from_secs(3), async {
+                    if ping_sent {
+                        or.await.is_ok()
+                    } else {
+                        false
+                    }
+                })
+                .await
+                .unwrap_or(false);
+
+                (url, ping_success)
+            });
+        }
+
+        for (url, why) in tasks {
+            self.close_or_reconnect_relay(&url, why).await;
+        }
+
+        self.log_active_relay();
+    }
+
+    /// Closes the relay connection to the provided `url` and starts reconnecting it if it's
+    /// our current home relay.
+    async fn close_or_reconnect_relay(&mut self, url: &RelayUrl, why: &'static str) {
+        self.close_relay(url, why).await;
+        if self.msock.my_relay().as_ref() == Some(url) {
+            self.connect_relay(url, None).await;
+        }
+    }
+
+    async fn clean_stale_relay(&mut self) {
+        trace!("checking {} relays for staleness", self.active_relay.len());
+        let now = Instant::now();
+
+        let mut to_close = Vec::new();
+        for (i, (s, _)) in &self.active_relay {
+            if Some(i) == self.msock.my_relay().as_ref() {
+                continue;
+            }
+            let (os, or) = oneshot::channel();
+            match s.send(ActiveRelayMessage::GetLastWrite(os)).await {
+                Ok(_) => match or.await {
+                    Ok(last_write) => {
+                        if last_write.duration_since(now) > RELAY_INACTIVE_CLEANUP_TIME {
+                            to_close.push(i.clone());
+                        }
+                    }
+                    Err(_) => {
+                        to_close.push(i.clone());
+                    }
+                },
+                Err(_) => {
+                    to_close.push(i.clone());
+                }
+            }
+        }
+
+        let dirty = !to_close.is_empty();
+        trace!(
+            "closing {} of {} relays",
+            to_close.len(),
+            self.active_relay.len()
+        );
+        for i in to_close {
+            self.close_relay(&i, "idle").await;
+        }
+        if dirty {
+            self.log_active_relay();
+        }
+    }
+
+    async fn close_all_relay(&mut self, why: &'static str) {
+        if self.active_relay.is_empty() {
+            return;
+        }
+        // Need to collect to avoid double borrow
+        let urls: Vec<_> = self.active_relay.keys().cloned().collect();
+        for url in urls {
+            self.close_relay(&url, why).await;
+        }
+        self.log_active_relay();
+    }
+
+    async fn close_relay(&mut self, url: &RelayUrl, why: &'static str) {
+        if let Some((s, t)) = self.active_relay.remove(url) {
+            debug!(%url, "closing connection: {}", why);
+
+            s.send(ActiveRelayMessage::Shutdown).await.ok();
+            t.abort(); // ensure the task is shutdown
+
+            inc!(MagicsockMetrics, num_relay_conns_removed);
+        }
+    }
+
+    fn log_active_relay(&self) {
+        debug!("{} active relay conns{}", self.active_relay.len(), {
+            let mut s = String::new();
+            if !self.active_relay.is_empty() {
+                s += ":";
+                for node in self.active_relay_sorted() {
+                    s += &format!(" relay-{}", node,);
+                }
+            }
+            s
+        });
+    }
+
+    fn active_relay_sorted(&self) -> impl Iterator<Item = RelayUrl> {
+        let mut ids: Vec<_> = self.active_relay.keys().cloned().collect();
+        ids.sort();
+
+        ids.into_iter()
+    }
+}
+
+#[derive(derive_more::Debug)]
+pub(super) struct RelayReadResult {
+    pub(super) url: RelayUrl,
+    pub(super) src: NodeId,
+    /// packet data
+    #[debug(skip)]
+    pub(super) buf: Bytes,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(super) enum ReadResult {
+    Break,
+    Continue,
+}
+
+/// Combines blobs into packets of at most MAX_PACKET_SIZE.
+///
+/// Each item in a packet has a little-endian 2-byte length prefix.
+pub(super) struct PacketizeIter<I: Iterator, const N: usize> {
+    iter: std::iter::Peekable<I>,
+    buffer: BytesMut,
+}
+
+impl<I: Iterator, const N: usize> PacketizeIter<I, N> {
+    /// Create a new new PacketizeIter from something that can be turned into an
+    /// iterator of slices, like a `Vec<Bytes>`.
+    pub(super) fn new(iter: impl IntoIterator<IntoIter = I>) -> Self {
+        Self {
+            iter: iter.into_iter().peekable(),
+            buffer: BytesMut::with_capacity(N),
+        }
+    }
+}
+
+impl<I: Iterator, const N: usize> Iterator for PacketizeIter<I, N>
+where
+    I::Item: AsRef<[u8]>,
+{
+    type Item = Bytes;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        use bytes::BufMut;
+        while let Some(next_bytes) = self.iter.peek() {
+            let next_bytes = next_bytes.as_ref();
+            assert!(next_bytes.len() + 2 <= N);
+            let next_length: u16 = next_bytes.len().try_into().expect("items < 64k size");
+            if self.buffer.len() + next_bytes.len() + 2 > N {
+                break;
+            }
+            self.buffer.put_u16_le(next_length);
+            self.buffer.put_slice(next_bytes);
+            self.iter.next();
+        }
+        if !self.buffer.is_empty() {
+            Some(self.buffer.split().freeze())
+        } else {
+            None
+        }
+    }
+}
+
+async fn with_cancel<F>(token: CancellationToken, f: F)
+where
+    F: Future<Output = ()>,
+{
+    tokio::select! {
+        _ = token.cancelled_owned() => {
+            // abort
+        }
+        _ = f => {
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_packetize_iter() {
+        let empty_vec: Vec<Bytes> = Vec::new();
+        let mut iter = PacketizeIter::<_, MAX_PACKET_SIZE>::new(empty_vec);
+        assert_eq!(None, iter.next());
+
+        let single_vec = vec!["Hello"];
+        let iter = PacketizeIter::<_, MAX_PACKET_SIZE>::new(single_vec);
+        let result = iter.collect::<Vec<_>>();
+        assert_eq!(1, result.len());
+        assert_eq!(&[5, 0, b'H', b'e', b'l', b'l', b'o'], &result[0][..]);
+
+        let spacer = vec![0u8; MAX_PACKET_SIZE - 10];
+        let multiple_vec = vec![&b"Hello"[..], &spacer, &b"World"[..]];
+        let iter = PacketizeIter::<_, MAX_PACKET_SIZE>::new(multiple_vec);
+        let result = iter.collect::<Vec<_>>();
+        assert_eq!(2, result.len());
+        assert_eq!(&[5, 0, b'H', b'e', b'l', b'l', b'o'], &result[0][..7]);
+        assert_eq!(&[5, 0, b'W', b'o', b'r', b'l', b'd'], &result[1][..]);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/timer.rs.html b/pr/2992/docs/src/iroh/magicsock/timer.rs.html new file mode 100644 index 0000000000..5ec7a936e1 --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/timer.rs.html @@ -0,0 +1,203 @@ +timer.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+
use std::{future::Future, time::Duration};
+
+use tokio::{task::JoinHandle, time};
+
+/// A timer that works similar to golangs `Timer`.
+#[derive(Debug)]
+pub struct Timer {
+    t: JoinHandle<()>,
+}
+
+impl Timer {
+    /// Will trigger the execution of `f` after time `d` once.
+    pub fn after<F>(d: Duration, f: F) -> Self
+    where
+        F: Future<Output = ()> + Send + Sync + 'static,
+    {
+        let t = tokio::task::spawn(async move {
+            time::sleep(d).await;
+            f.await
+        });
+
+        Timer { t }
+    }
+
+    /// Abort the timer.
+    pub fn abort(self) {
+        self.t.abort();
+    }
+}
+
+impl Future for Timer {
+    type Output = ();
+
+    fn poll(
+        mut self: std::pin::Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> std::task::Poll<Self::Output> {
+        std::pin::Pin::new(&mut self.t).poll(cx).map(|_| ())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::sync::{
+        atomic::{AtomicBool, Ordering},
+        Arc,
+    };
+
+    use super::*;
+
+    #[tokio::test(flavor = "current_thread", start_paused = true)]
+    async fn test_timer_success() {
+        let val = Arc::new(AtomicBool::new(false));
+
+        assert!(!val.load(Ordering::Relaxed));
+
+        let moved_val = val.clone();
+        let timer = Timer::after(Duration::from_millis(10), async move {
+            moved_val.store(true, Ordering::Relaxed);
+        });
+
+        assert!(!val.load(Ordering::Relaxed));
+
+        timer.await;
+        assert!(val.load(Ordering::Relaxed));
+    }
+
+    #[tokio::test(flavor = "current_thread", start_paused = true)]
+    async fn test_timer_abort() {
+        let val = Arc::new(AtomicBool::new(false));
+
+        assert!(!val.load(Ordering::Relaxed));
+
+        let moved_val = val.clone();
+        let timer = Timer::after(Duration::from_millis(10), async move {
+            moved_val.store(true, Ordering::Relaxed);
+        });
+
+        assert!(!val.load(Ordering::Relaxed));
+        timer.abort();
+        assert!(!val.load(Ordering::Relaxed));
+    }
+
+    #[tokio::test(flavor = "current_thread", start_paused = true)]
+    async fn test_timer_abort_late() {
+        let val = Arc::new(AtomicBool::new(false));
+
+        assert!(!val.load(Ordering::Relaxed));
+
+        let moved_val = val.clone();
+        let timer = Timer::after(Duration::from_millis(50), async move {
+            moved_val.store(true, Ordering::Relaxed);
+        });
+
+        assert!(!val.load(Ordering::Relaxed));
+        time::sleep(Duration::from_millis(75)).await;
+
+        timer.abort();
+        assert!(val.load(Ordering::Relaxed));
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/magicsock/udp_conn.rs.html b/pr/2992/docs/src/iroh/magicsock/udp_conn.rs.html new file mode 100644 index 0000000000..e0fdc33a5f --- /dev/null +++ b/pr/2992/docs/src/iroh/magicsock/udp_conn.rs.html @@ -0,0 +1,449 @@ +udp_conn.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+
use std::{
+    fmt::Debug,
+    io,
+    net::SocketAddr,
+    pin::Pin,
+    sync::Arc,
+    task::{Context, Poll},
+};
+
+use anyhow::{bail, Context as _};
+use netwatch::UdpSocket;
+use quinn::AsyncUdpSocket;
+use quinn_udp::Transmit;
+use tracing::debug;
+
+/// A UDP socket implementing Quinn's [`AsyncUdpSocket`].
+#[derive(Debug, Clone)]
+pub struct UdpConn {
+    io: Arc<UdpSocket>,
+}
+
+impl UdpConn {
+    pub(super) fn as_socket(&self) -> Arc<UdpSocket> {
+        self.io.clone()
+    }
+
+    pub(super) fn as_socket_ref(&self) -> &UdpSocket {
+        &self.io
+    }
+
+    pub(super) fn bind(addr: SocketAddr) -> anyhow::Result<Self> {
+        let sock = bind(addr)?;
+
+        Ok(Self { io: Arc::new(sock) })
+    }
+
+    pub fn port(&self) -> u16 {
+        self.local_addr().map(|p| p.port()).unwrap_or_default()
+    }
+
+    pub(super) fn create_io_poller(&self) -> Pin<Box<dyn quinn::UdpPoller>> {
+        Box::pin(IoPoller {
+            io: self.io.clone(),
+        })
+    }
+}
+
+impl AsyncUdpSocket for UdpConn {
+    fn create_io_poller(self: Arc<Self>) -> Pin<Box<dyn quinn::UdpPoller>> {
+        (*self).create_io_poller()
+    }
+
+    fn try_send(&self, transmit: &Transmit<'_>) -> io::Result<()> {
+        self.io.try_send_quinn(transmit)
+    }
+
+    fn poll_recv(
+        &self,
+        cx: &mut Context,
+        bufs: &mut [io::IoSliceMut<'_>],
+        meta: &mut [quinn_udp::RecvMeta],
+    ) -> Poll<io::Result<usize>> {
+        self.io.poll_recv_quinn(cx, bufs, meta)
+    }
+
+    fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.io.local_addr()
+    }
+
+    fn may_fragment(&self) -> bool {
+        self.io.may_fragment()
+    }
+
+    fn max_transmit_segments(&self) -> usize {
+        self.io.max_gso_segments()
+    }
+
+    fn max_receive_segments(&self) -> usize {
+        self.io.gro_segments()
+    }
+}
+
+fn bind(mut addr: SocketAddr) -> anyhow::Result<UdpSocket> {
+    debug!(%addr, "binding");
+
+    // Build a list of preferred ports.
+    // - Best is the port that the user requested.
+    // - Second best is the port that is currently in use.
+    // - If those fail, fall back to 0.
+
+    let mut ports = Vec::new();
+    if addr.port() != 0 {
+        ports.push(addr.port());
+    }
+    // Backup port
+    ports.push(0);
+    // Remove duplicates. (All duplicates are consecutive.)
+    ports.dedup();
+    debug!(?ports, "candidate ports");
+
+    for port in &ports {
+        addr.set_port(*port);
+        match UdpSocket::bind_full(addr) {
+            Ok(pconn) => {
+                let local_addr = pconn.local_addr().context("UDP socket not bound")?;
+                debug!(%addr, %local_addr, "successfully bound");
+                return Ok(pconn);
+            }
+            Err(err) => {
+                debug!(%addr, "failed to bind: {err:#}");
+                continue;
+            }
+        }
+    }
+
+    // Failed to bind, including on port 0 (!).
+    bail!("failed to bind any ports on {:?} (tried {:?})", addr, ports);
+}
+
+/// Poller for when the socket is writable.
+#[derive(Debug)]
+struct IoPoller {
+    io: Arc<UdpSocket>,
+}
+
+impl quinn::UdpPoller for IoPoller {
+    fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
+        self.io.poll_writable(cx)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use anyhow::Result;
+    use netwatch::IpFamily;
+    use tokio::sync::mpsc;
+    use tracing::{info_span, Instrument};
+
+    use super::*;
+    use crate::{key, tls};
+
+    const ALPN: &[u8] = b"n0/test/1";
+
+    fn wrap_socket(conn: impl AsyncUdpSocket) -> Result<(quinn::Endpoint, key::SecretKey)> {
+        let key = key::SecretKey::generate();
+        let quic_server_config = tls::make_server_config(&key, vec![ALPN.to_vec()], false)?;
+        let server_config = quinn::ServerConfig::with_crypto(Arc::new(quic_server_config));
+        let mut quic_ep = quinn::Endpoint::new_with_abstract_socket(
+            quinn::EndpointConfig::default(),
+            Some(server_config),
+            Arc::new(conn),
+            Arc::new(quinn::TokioRuntime),
+        )?;
+
+        let quic_client_config = tls::make_client_config(&key, None, vec![ALPN.to_vec()], false)?;
+        let client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+        quic_ep.set_default_client_config(client_config);
+        Ok((quic_ep, key))
+    }
+
+    #[tokio::test]
+    async fn test_rebinding_conn_send_recv_ipv4() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+        rebinding_conn_send_recv(IpFamily::V4).await
+    }
+
+    #[tokio::test]
+    async fn test_rebinding_conn_send_recv_ipv6() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+        if !net_report::os_has_ipv6() {
+            return Ok(());
+        }
+        rebinding_conn_send_recv(IpFamily::V6).await
+    }
+
+    async fn rebinding_conn_send_recv(network: IpFamily) -> Result<()> {
+        let m1 = UdpConn::bind(SocketAddr::new(network.unspecified_addr(), 0))?;
+        let (m1, _m1_key) = wrap_socket(m1)?;
+
+        let m2 = UdpConn::bind(SocketAddr::new(network.unspecified_addr(), 0))?;
+        let (m2, _m2_key) = wrap_socket(m2)?;
+
+        let m1_addr = SocketAddr::new(network.local_addr(), m1.local_addr()?.port());
+        let (m1_send, mut m1_recv) = mpsc::channel(8);
+
+        let m1_task = tokio::task::spawn(
+            async move {
+                // we skip accept() errors, they can be caused by retransmits
+                if let Some(conn) = m1.accept().await.and_then(|inc| inc.accept().ok()) {
+                    let conn = conn.await?;
+                    let (mut send_bi, mut recv_bi) = conn.accept_bi().await?;
+
+                    let val = recv_bi.read_to_end(usize::MAX).await?;
+                    m1_send.send(val).await?;
+                    send_bi.finish()?;
+                    send_bi.stopped().await?;
+                }
+
+                Ok::<_, anyhow::Error>(())
+            }
+            .instrument(info_span!("m1_task")),
+        );
+
+        let conn = m2.connect(m1_addr, "localhost")?.await?;
+
+        let (mut send_bi, mut recv_bi) = conn.open_bi().await?;
+        send_bi.write_all(b"hello").await?;
+        send_bi.finish()?;
+
+        let _ = recv_bi.read_to_end(usize::MAX).await?;
+        conn.close(0u32.into(), b"done");
+        m2.wait_idle().await;
+
+        drop(send_bi);
+
+        // make sure the right values arrived
+        let val = m1_recv.recv().await.unwrap();
+        assert_eq!(val, b"hello");
+
+        m1_task.await??;
+
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/metrics.rs.html b/pr/2992/docs/src/iroh/metrics.rs.html new file mode 100644 index 0000000000..5aea102825 --- /dev/null +++ b/pr/2992/docs/src/iroh/metrics.rs.html @@ -0,0 +1,17 @@ +metrics.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+
//! Co-locating all of the iroh metrics structs
+#[cfg(feature = "test-utils")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "test-utils")))]
+pub use iroh_relay::server::Metrics as RelayMetrics;
+pub use net_report::Metrics as NetReportMetrics;
+pub use portmapper::Metrics as PortmapMetrics;
+
+pub use crate::magicsock::Metrics as MagicsockMetrics;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/protocol.rs.html b/pr/2992/docs/src/iroh/protocol.rs.html new file mode 100644 index 0000000000..88f1b104f7 --- /dev/null +++ b/pr/2992/docs/src/iroh/protocol.rs.html @@ -0,0 +1,799 @@ +protocol.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+
//! Tools for spawning an accept loop that routes incoming requests to the right protocol.
+//!
+//! ## Example
+//!
+//! ```no_run
+//! # use std::sync::Arc;
+//! # use anyhow::Result;
+//! # use futures_lite::future::Boxed as BoxedFuture;
+//! # use iroh::{endpoint::Connecting, protocol::{ProtocolHandler, Router}, Endpoint, NodeAddr};
+//! #
+//! # async fn test_compile() -> Result<()> {
+//! let endpoint = Endpoint::builder().discovery_n0().bind().await?;
+//!
+//! const ALPN: &[u8] = b"/my/alpn";
+//! let router = Router::builder(endpoint)
+//!     .accept(&ALPN, Arc::new(Echo))
+//!     .spawn()
+//!     .await?;
+//! # Ok(())
+//! # }
+//!
+//! // The protocol definition:
+//! #[derive(Debug, Clone)]
+//! struct Echo;
+//!
+//! impl ProtocolHandler for Echo {
+//!     fn accept(self: Arc<Self>, connecting: Connecting) -> BoxedFuture<Result<()>> {
+//!         Box::pin(async move {
+//!             let connection = connecting.await?;
+//!             let (mut send, mut recv) = connection.accept_bi().await?;
+//!
+//!             // Echo any bytes received back directly.
+//!             let bytes_sent = tokio::io::copy(&mut recv, &mut send).await?;
+//!
+//!             send.finish()?;
+//!             connection.closed().await;
+//!
+//!             Ok(())
+//!         })
+//!     }
+//! }
+//! ```
+use std::{any::Any, collections::BTreeMap, sync::Arc};
+
+use anyhow::Result;
+use futures_buffered::join_all;
+use futures_lite::future::Boxed as BoxedFuture;
+use tokio::{sync::Mutex, task::JoinSet};
+use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
+use tracing::{error, info_span, trace, warn, Instrument};
+
+use crate::{endpoint::Connecting, Endpoint};
+
+/// The built router.
+///
+/// Construct this using [`Router::builder`].
+///
+/// When dropped, this will abort listening the tasks, so make sure to store it.
+///
+/// Even with this abort-on-drop behaviour, it's recommended to call and await
+/// [`Router::shutdown`] before ending the process.
+///
+/// As an example for graceful shutdown, e.g. for tests or CLI tools,
+/// wait for [`tokio::signal::ctrl_c()`]:
+///
+/// ```no_run
+/// # use std::sync::Arc;
+/// # use anyhow::Result;
+/// # use futures_lite::future::Boxed as BoxedFuture;
+/// # use iroh::{endpoint::Connecting, protocol::{ProtocolHandler, Router}, Endpoint, NodeAddr};
+/// #
+/// # async fn test_compile() -> Result<()> {
+/// let endpoint = Endpoint::builder().discovery_n0().bind().await?;
+///
+/// let router = Router::builder(endpoint)
+///     // .accept(&ALPN, <something>)
+///     .spawn()
+///     .await?;
+///
+/// // wait until the user wants to
+/// tokio::signal::ctrl_c().await?;
+/// router.shutdown().await?;
+/// # Ok(())
+/// # }
+/// ```
+#[derive(Clone, Debug)]
+pub struct Router {
+    endpoint: Endpoint,
+    protocols: Arc<ProtocolMap>,
+    // `Router` needs to be `Clone + Send`, and we need to `task.await` in its `shutdown()` impl.
+    task: Arc<Mutex<Option<AbortOnDropHandle<()>>>>,
+    cancel_token: CancellationToken,
+}
+
+/// Builder for creating a [`Router`] for accepting protocols.
+#[derive(Debug)]
+pub struct RouterBuilder {
+    endpoint: Endpoint,
+    protocols: ProtocolMap,
+}
+
+/// Handler for incoming connections.
+///
+/// A router accepts connections for arbitrary ALPN protocols.
+///
+/// With this trait, you can handle incoming connections for any protocol.
+///
+/// Implement this trait on a struct that should handle incoming connections.
+/// The protocol handler must then be registered on the node for an ALPN protocol with
+/// [`crate::protocol::RouterBuilder::accept`].
+pub trait ProtocolHandler: Send + Sync + IntoArcAny + std::fmt::Debug + 'static {
+    /// Handle an incoming connection.
+    ///
+    /// This runs on a freshly spawned tokio task so this can be long-running.
+    fn accept(self: Arc<Self>, conn: Connecting) -> BoxedFuture<Result<()>>;
+
+    /// Called when the node shuts down.
+    fn shutdown(self: Arc<Self>) -> BoxedFuture<()> {
+        Box::pin(async move {})
+    }
+}
+
+/// Helper trait to facilite casting from `Arc<dyn T>` to `Arc<dyn Any>`.
+///
+/// This trait has a blanket implementation so there is no need to implement this yourself.
+pub trait IntoArcAny {
+    /// Casts `Arc<Self>` into `Arc<dyn Any + Send + Sync>`.
+    fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
+}
+
+impl<T: Send + Sync + 'static> IntoArcAny for T {
+    fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
+        self
+    }
+}
+
+/// A typed map of protocol handlers, mapping them from ALPNs.
+#[derive(Debug, Clone, Default)]
+pub struct ProtocolMap(BTreeMap<Vec<u8>, Arc<dyn ProtocolHandler>>);
+
+impl ProtocolMap {
+    /// Returns the registered protocol handler for an ALPN as a concrete type.
+    pub fn get_typed<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>> {
+        let protocol: Arc<dyn ProtocolHandler> = self.0.get(alpn)?.clone();
+        let protocol_any: Arc<dyn Any + Send + Sync> = protocol.into_arc_any();
+        let protocol_ref = Arc::downcast(protocol_any).ok()?;
+        Some(protocol_ref)
+    }
+
+    /// Returns the registered protocol handler for an ALPN as a [`Arc<dyn ProtocolHandler>`].
+    pub fn get(&self, alpn: &[u8]) -> Option<Arc<dyn ProtocolHandler>> {
+        self.0.get(alpn).cloned()
+    }
+
+    /// Inserts a protocol handler.
+    pub fn insert(&mut self, alpn: Vec<u8>, handler: Arc<dyn ProtocolHandler>) {
+        self.0.insert(alpn, handler);
+    }
+
+    /// Returns an iterator of all registered ALPN protocol identifiers.
+    pub fn alpns(&self) -> impl Iterator<Item = &Vec<u8>> {
+        self.0.keys()
+    }
+
+    /// Shuts down all protocol handlers.
+    ///
+    /// Calls and awaits [`ProtocolHandler::shutdown`] for all registered handlers concurrently.
+    pub async fn shutdown(&self) {
+        let handlers = self.0.values().cloned().map(ProtocolHandler::shutdown);
+        join_all(handlers).await;
+    }
+}
+
+impl Router {
+    /// Creates a new [`Router`] using given [`Endpoint`].
+    pub fn builder(endpoint: Endpoint) -> RouterBuilder {
+        RouterBuilder::new(endpoint)
+    }
+
+    /// Returns a protocol handler for an ALPN.
+    ///
+    /// This downcasts to the concrete type and returns `None` if the handler registered for `alpn`
+    /// does not match the passed type.
+    pub fn get_protocol<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>> {
+        self.protocols.get_typed(alpn)
+    }
+
+    /// Returns the [`Endpoint`] stored in this router.
+    pub fn endpoint(&self) -> &Endpoint {
+        &self.endpoint
+    }
+
+    /// Checks if the router is already shutdown.
+    pub fn is_shutdown(&self) -> bool {
+        self.cancel_token.is_cancelled()
+    }
+
+    /// Shuts down the accept loop cleanly.
+    ///
+    /// When this function returns, all [`ProtocolHandler`]s will be shutdown and
+    /// `Endpoint::close` will have been called.
+    ///
+    /// If already shutdown, it returns `Ok`.
+    ///
+    /// If some [`ProtocolHandler`] panicked in the accept loop, this will propagate
+    /// that panic into the result here.
+    pub async fn shutdown(&self) -> Result<()> {
+        if self.is_shutdown() {
+            return Ok(());
+        }
+
+        // Trigger shutdown of the main run task by activating the cancel token.
+        self.cancel_token.cancel();
+
+        // Wait for the main task to terminate.
+        if let Some(task) = self.task.lock().await.take() {
+            task.await?;
+        }
+
+        Ok(())
+    }
+}
+
+impl RouterBuilder {
+    /// Creates a new router builder using given [`Endpoint`].
+    pub fn new(endpoint: Endpoint) -> Self {
+        Self {
+            endpoint,
+            protocols: ProtocolMap::default(),
+        }
+    }
+
+    /// Configures the router to accept the [`ProtocolHandler`] when receiving a connection
+    /// with this `alpn`.
+    pub fn accept(mut self, alpn: impl AsRef<[u8]>, handler: Arc<dyn ProtocolHandler>) -> Self {
+        self.protocols.insert(alpn.as_ref().to_vec(), handler);
+        self
+    }
+
+    /// Returns the [`Endpoint`] of the node.
+    pub fn endpoint(&self) -> &Endpoint {
+        &self.endpoint
+    }
+
+    /// Returns a protocol handler for an ALPN.
+    ///
+    /// This downcasts to the concrete type and returns `None` if the handler registered for `alpn`
+    /// does not match the passed type.
+    pub fn get_protocol<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>> {
+        self.protocols.get_typed(alpn)
+    }
+
+    /// Spawns an accept loop and returns a handle to it encapsulated as the [`Router`].
+    pub async fn spawn(self) -> Result<Router> {
+        // Update the endpoint with our alpns.
+        let alpns = self
+            .protocols
+            .alpns()
+            .map(|alpn| alpn.to_vec())
+            .collect::<Vec<_>>();
+
+        let protocols = Arc::new(self.protocols);
+        if let Err(err) = self.endpoint.set_alpns(alpns) {
+            shutdown(&self.endpoint, protocols.clone()).await;
+            return Err(err);
+        }
+
+        let mut join_set = JoinSet::new();
+        let endpoint = self.endpoint.clone();
+        let protos = protocols.clone();
+
+        // We use a child token of the endpoint, to ensure that this is shutdown
+        // when the endpoint is shutdown, but that we can shutdown ourselves independently.
+        let cancel = endpoint.cancel_token().child_token();
+        let cancel_token = cancel.clone();
+
+        let run_loop_fut = async move {
+            // Make sure to cancel the token, if this future ever exits.
+            let _cancel_guard = cancel_token.clone().drop_guard();
+
+            let protocols = protos;
+            loop {
+                tokio::select! {
+                    biased;
+                    _ = cancel_token.cancelled() => {
+                        break;
+                    },
+                    // handle task terminations and quit on panics.
+                    res = join_set.join_next(), if !join_set.is_empty() => {
+                        match res {
+                            Some(Err(outer)) => {
+                                if outer.is_panic() {
+                                    error!("Task panicked: {outer:?}");
+                                    break;
+                                } else if outer.is_cancelled() {
+                                    trace!("Task cancelled: {outer:?}");
+                                } else {
+                                    error!("Task failed: {outer:?}");
+                                    break;
+                                }
+                            }
+                            Some(Ok(Some(()))) => {
+                                trace!("Task finished");
+                            }
+                            Some(Ok(None)) => {
+                                trace!("Task cancelled");
+                            }
+                            _ => {}
+                        }
+                    },
+
+                    // handle incoming p2p connections.
+                    incoming = endpoint.accept() => {
+                        let Some(incoming) = incoming else {
+                            break;
+                        };
+
+                        let protocols = protocols.clone();
+                        let token = cancel_token.child_token();
+                        join_set.spawn(async move {
+                            token.run_until_cancelled(handle_connection(incoming, protocols)).await
+                        }.instrument(info_span!("router.accept")));
+                    },
+                }
+            }
+
+            shutdown(&endpoint, protocols).await;
+
+            // Abort remaining tasks.
+            tracing::info!("Shutting down remaining tasks");
+            join_set.shutdown().await;
+        };
+        let task = tokio::task::spawn(run_loop_fut);
+        let task = AbortOnDropHandle::new(task);
+
+        Ok(Router {
+            endpoint: self.endpoint,
+            protocols,
+            task: Arc::new(Mutex::new(Some(task))),
+            cancel_token: cancel,
+        })
+    }
+}
+
+/// Shutdown the different parts of the router concurrently.
+async fn shutdown(endpoint: &Endpoint, protocols: Arc<ProtocolMap>) {
+    // We ignore all errors during shutdown.
+    let _ = tokio::join!(
+        // Close the endpoint.
+        endpoint.close(),
+        // Shutdown protocol handlers.
+        protocols.shutdown(),
+    );
+}
+
+async fn handle_connection(incoming: crate::endpoint::Incoming, protocols: Arc<ProtocolMap>) {
+    let mut connecting = match incoming.accept() {
+        Ok(conn) => conn,
+        Err(err) => {
+            warn!("Ignoring connection: accepting failed: {err:#}");
+            return;
+        }
+    };
+    let alpn = match connecting.alpn().await {
+        Ok(alpn) => alpn,
+        Err(err) => {
+            warn!("Ignoring connection: invalid handshake: {err:#}");
+            return;
+        }
+    };
+    let Some(handler) = protocols.get(&alpn) else {
+        warn!("Ignoring connection: unsupported ALPN protocol");
+        return;
+    };
+    if let Err(err) = handler.accept(connecting).await {
+        warn!("Handling incoming connection ended with error: {err}");
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[tokio::test]
+    async fn test_shutdown() -> Result<()> {
+        let endpoint = Endpoint::builder().bind().await?;
+        let router = Router::builder(endpoint.clone()).spawn().await?;
+
+        assert!(!router.is_shutdown());
+        assert!(!endpoint.is_closed());
+
+        router.shutdown().await?;
+
+        assert!(router.is_shutdown());
+        assert!(endpoint.is_closed());
+
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/test_utils.rs.html b/pr/2992/docs/src/iroh/test_utils.rs.html new file mode 100644 index 0000000000..eb66eb0da8 --- /dev/null +++ b/pr/2992/docs/src/iroh/test_utils.rs.html @@ -0,0 +1,979 @@ +test_utils.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+
//! Internal utilities to support testing.
+use std::net::Ipv4Addr;
+
+use anyhow::Result;
+pub use dns_and_pkarr_servers::DnsPkarrServer;
+pub use dns_server::create_dns_resolver;
+use iroh_relay::server::{
+    CertConfig, QuicConfig, RelayConfig, Server, ServerConfig, StunConfig, TlsConfig,
+};
+use tokio::sync::oneshot;
+
+use crate::{defaults::DEFAULT_STUN_PORT, RelayMap, RelayNode, RelayUrl};
+
+/// A drop guard to clean up test infrastructure.
+///
+/// After dropping the test infrastructure will asynchronously shutdown and release its
+/// resources.
+// Nightly sees the sender as dead code currently, but we only rely on Drop of the
+// sender.
+#[derive(Debug)]
+#[allow(dead_code)]
+pub struct CleanupDropGuard(pub(crate) oneshot::Sender<()>);
+
+/// Runs a relay server with STUN and QUIC enabled suitable for tests.
+///
+/// The returned `Url` is the url of the relay server in the returned [`RelayMap`].
+/// When dropped, the returned [`Server`] does will stop running.
+pub async fn run_relay_server() -> Result<(RelayMap, RelayUrl, Server)> {
+    run_relay_server_with(
+        Some(StunConfig {
+            bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        }),
+        true,
+    )
+    .await
+}
+
+/// Runs a relay server with STUN enabled suitable for tests.
+///
+/// The returned `Url` is the url of the relay server in the returned [`RelayMap`].
+/// When dropped, the returned [`Server`] does will stop running.
+pub async fn run_relay_server_with_stun() -> Result<(RelayMap, RelayUrl, Server)> {
+    run_relay_server_with(
+        Some(StunConfig {
+            bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        }),
+        false,
+    )
+    .await
+}
+
+/// Runs a relay server.
+///
+/// `stun` can be set to `None` to disable stun, or set to `Some` `StunConfig`,
+/// to enable stun on a specific socket.
+///
+/// If `quic` is set to `true`, it will make the appropriate [`QuicConfig`] from the generated tls certificates and run the quic server at a random free port.
+///
+///
+/// The return value is similar to [`run_relay_server`].
+pub async fn run_relay_server_with(
+    stun: Option<StunConfig>,
+    quic: bool,
+) -> Result<(RelayMap, RelayUrl, Server)> {
+    let (certs, server_config) = iroh_relay::server::testing::self_signed_tls_certs_and_config();
+    let tls = TlsConfig {
+        cert: CertConfig::<(), ()>::Manual { certs },
+        https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        quic_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        server_config,
+    };
+    let quic = if quic {
+        Some(QuicConfig {
+            server_config: tls.server_config.clone(),
+            bind_addr: tls.quic_bind_addr,
+        })
+    } else {
+        None
+    };
+    let config = ServerConfig {
+        relay: Some(RelayConfig {
+            http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+            tls: Some(tls),
+            limits: Default::default(),
+        }),
+        quic,
+        stun,
+        #[cfg(feature = "metrics")]
+        metrics_addr: None,
+    };
+    let server = Server::spawn(config).await.unwrap();
+    let url: RelayUrl = format!("https://{}", server.https_addr().expect("configured"))
+        .parse()
+        .unwrap();
+    let quic = server
+        .quic_addr()
+        .map(|addr| iroh_base::relay_map::QuicConfig { port: addr.port() });
+    let m = RelayMap::from_nodes([RelayNode {
+        url: url.clone(),
+        stun_only: false,
+        stun_port: server.stun_addr().map_or(DEFAULT_STUN_PORT, |s| s.port()),
+        quic,
+    }])
+    .unwrap();
+    Ok((m, url, server))
+}
+
+pub(crate) mod dns_and_pkarr_servers {
+    use std::{net::SocketAddr, time::Duration};
+
+    use anyhow::Result;
+    use iroh_base::key::{NodeId, SecretKey};
+    use url::Url;
+
+    use super::{create_dns_resolver, CleanupDropGuard};
+    use crate::{
+        discovery::{dns::DnsDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery},
+        dns::DnsResolver,
+        test_utils::{
+            dns_server::run_dns_server, pkarr_dns_state::State, pkarr_relay::run_pkarr_relay,
+        },
+    };
+
+    /// Handle and drop guard for test DNS and Pkarr servers.
+    ///
+    /// Once the struct is dropped the servers will shut down.
+    #[derive(Debug)]
+    pub struct DnsPkarrServer {
+        /// The node origin domain.
+        pub node_origin: String,
+        /// The shared state of the DNS and Pkarr servers.
+        state: State,
+        /// The socket address of the DNS server.
+        pub nameserver: SocketAddr,
+        /// The HTTP URL of the Pkarr server.
+        pub pkarr_url: Url,
+        _dns_drop_guard: CleanupDropGuard,
+        _pkarr_drop_guard: CleanupDropGuard,
+    }
+
+    impl DnsPkarrServer {
+        /// Run DNS and Pkarr servers on localhost.
+        pub async fn run() -> anyhow::Result<Self> {
+            Self::run_with_origin("dns.iroh.test".to_string()).await
+        }
+
+        /// Run DNS and Pkarr servers on localhost with the specified `node_origin` domain.
+        pub async fn run_with_origin(node_origin: String) -> anyhow::Result<Self> {
+            let state = State::new(node_origin.clone());
+            let (nameserver, dns_drop_guard) = run_dns_server(state.clone()).await?;
+            let (pkarr_url, pkarr_drop_guard) = run_pkarr_relay(state.clone()).await?;
+            Ok(Self {
+                node_origin,
+                nameserver,
+                pkarr_url,
+                state,
+                _dns_drop_guard: dns_drop_guard,
+                _pkarr_drop_guard: pkarr_drop_guard,
+            })
+        }
+
+        /// Create a [`ConcurrentDiscovery`] with [`DnsDiscovery`] and [`PkarrPublisher`]
+        /// configured to use the test servers.
+        pub fn discovery(&self, secret_key: SecretKey) -> Box<ConcurrentDiscovery> {
+            Box::new(ConcurrentDiscovery::from_services(vec![
+                // Enable DNS discovery by default
+                Box::new(DnsDiscovery::new(self.node_origin.clone())),
+                // Enable pkarr publishing by default
+                Box::new(PkarrPublisher::new(secret_key, self.pkarr_url.clone())),
+            ]))
+        }
+
+        /// Create a [`DnsResolver`] configured to use the test DNS server.
+        pub fn dns_resolver(&self) -> DnsResolver {
+            create_dns_resolver(self.nameserver).expect("failed to create DNS resolver")
+        }
+
+        /// Wait until a Pkarr announce for a node is published to the server.
+        ///
+        /// If `timeout` elapses an error is returned.
+        pub async fn on_node(&self, node_id: &NodeId, timeout: Duration) -> Result<()> {
+            self.state.on_node(node_id, timeout).await
+        }
+    }
+}
+
+pub(crate) mod dns_server {
+    use std::{
+        future::Future,
+        net::{Ipv4Addr, SocketAddr},
+    };
+
+    use anyhow::{ensure, Result};
+    use futures_lite::future::Boxed as BoxFuture;
+    use hickory_proto::{
+        op::{header::MessageType, Message},
+        serialize::binary::BinDecodable,
+    };
+    use hickory_resolver::{config::NameServerConfig, TokioAsyncResolver};
+    use tokio::{net::UdpSocket, sync::oneshot};
+    use tracing::{debug, error, warn};
+
+    use super::CleanupDropGuard;
+
+    /// Trait used by [`run_dns_server`] for answering DNS queries.
+    pub trait QueryHandler: Send + Sync + 'static {
+        fn resolve(
+            &self,
+            query: &Message,
+            reply: &mut Message,
+        ) -> impl Future<Output = Result<()>> + Send;
+    }
+
+    pub type QueryHandlerFunction =
+        Box<dyn Fn(&Message, &mut Message) -> BoxFuture<Result<()>> + Send + Sync + 'static>;
+
+    impl QueryHandler for QueryHandlerFunction {
+        fn resolve(
+            &self,
+            query: &Message,
+            reply: &mut Message,
+        ) -> impl Future<Output = Result<()>> + Send {
+            (self)(query, reply)
+        }
+    }
+
+    /// Run a DNS server.
+    ///
+    /// Must pass a [`QueryHandler`] that answers queries.
+    pub async fn run_dns_server(
+        resolver: impl QueryHandler,
+    ) -> Result<(SocketAddr, CleanupDropGuard)> {
+        let bind_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));
+        let socket = UdpSocket::bind(bind_addr).await?;
+        let bound_addr = socket.local_addr()?;
+        let s = TestDnsServer { socket, resolver };
+        let (tx, mut rx) = oneshot::channel();
+        tokio::task::spawn(async move {
+            tokio::select! {
+                _ = &mut rx => {
+                    debug!("shutting down dns server");
+                }
+                res = s.run() => {
+                    if let Err(e) = res {
+                        error!("error running dns server {e:?}");
+                    }
+                }
+            }
+        });
+        Ok((bound_addr, CleanupDropGuard(tx)))
+    }
+
+    /// Create a DNS resolver with a single nameserver.
+    pub fn create_dns_resolver(nameserver: SocketAddr) -> Result<TokioAsyncResolver> {
+        let mut config = hickory_resolver::config::ResolverConfig::new();
+        let nameserver_config =
+            NameServerConfig::new(nameserver, hickory_resolver::config::Protocol::Udp);
+        config.add_name_server(nameserver_config);
+        let resolver = hickory_resolver::AsyncResolver::tokio(config, Default::default());
+        Ok(resolver)
+    }
+
+    struct TestDnsServer<R> {
+        resolver: R,
+        socket: UdpSocket,
+    }
+
+    impl<R: QueryHandler> TestDnsServer<R> {
+        async fn run(self) -> Result<()> {
+            let mut buf = [0; 1450];
+            loop {
+                let res = self.socket.recv_from(&mut buf).await;
+                let (len, from) = res?;
+                if let Err(err) = self.handle_datagram(from, &buf[..len]).await {
+                    warn!(?err, %from, "failed to handle incoming datagram");
+                }
+            }
+        }
+
+        async fn handle_datagram(&self, from: SocketAddr, buf: &[u8]) -> Result<()> {
+            let packet = Message::from_bytes(buf)?;
+            debug!(queries = ?packet.queries(), %from, "received query");
+            let mut reply = packet.clone();
+            reply.set_message_type(MessageType::Response);
+            self.resolver.resolve(&packet, &mut reply).await?;
+            debug!(?reply, %from, "send reply");
+            let buf = reply.to_vec()?;
+            let len = self.socket.send_to(&buf, from).await?;
+            ensure!(len == buf.len(), "failed to send complete packet");
+            Ok(())
+        }
+    }
+}
+
+pub(crate) mod pkarr_relay {
+    use std::{
+        future::IntoFuture,
+        net::{Ipv4Addr, SocketAddr},
+    };
+
+    use anyhow::Result;
+    use axum::{
+        extract::{Path, State},
+        response::IntoResponse,
+        routing::put,
+        Router,
+    };
+    use bytes::Bytes;
+    use tokio::sync::oneshot;
+    use tracing::{debug, error, warn};
+    use url::Url;
+
+    use super::CleanupDropGuard;
+    use crate::test_utils::pkarr_dns_state::State as AppState;
+
+    pub async fn run_pkarr_relay(state: AppState) -> Result<(Url, CleanupDropGuard)> {
+        let bind_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0));
+        let app = Router::new()
+            .route("/pkarr/:key", put(pkarr_put))
+            .with_state(state);
+        let listener = tokio::net::TcpListener::bind(bind_addr).await?;
+        let bound_addr = listener.local_addr()?;
+        let url: Url = format!("http://{bound_addr}/pkarr")
+            .parse()
+            .expect("valid url");
+
+        let (tx, mut rx) = oneshot::channel();
+        tokio::spawn(async move {
+            let serve = axum::serve(listener, app);
+            tokio::select! {
+                _ = &mut rx => {
+                    debug!("shutting down pkarr server");
+                }
+                res = serve.into_future() => {
+                    if let Err(e) = res {
+                        error!("pkarr server error: {e:?}");
+                    }
+                }
+            }
+        });
+        Ok((url, CleanupDropGuard(tx)))
+    }
+
+    async fn pkarr_put(
+        State(state): State<AppState>,
+        Path(key): Path<String>,
+        body: Bytes,
+    ) -> Result<impl IntoResponse, AppError> {
+        let key = pkarr::PublicKey::try_from(key.as_str())?;
+        let signed_packet = pkarr::SignedPacket::from_relay_payload(&key, &body)?;
+        let _updated = state.upsert(signed_packet)?;
+        Ok(http::StatusCode::NO_CONTENT)
+    }
+
+    #[derive(Debug)]
+    struct AppError(anyhow::Error);
+    impl<T: Into<anyhow::Error>> From<T> for AppError {
+        fn from(value: T) -> Self {
+            Self(value.into())
+        }
+    }
+    impl IntoResponse for AppError {
+        fn into_response(self) -> axum::response::Response {
+            warn!(err = ?self, "request failed");
+            (http::StatusCode::INTERNAL_SERVER_ERROR, self.0.to_string()).into_response()
+        }
+    }
+}
+
+pub(crate) mod pkarr_dns_state {
+    use std::{
+        collections::{hash_map, HashMap},
+        future::Future,
+        ops::Deref,
+        sync::Arc,
+        time::Duration,
+    };
+
+    use anyhow::{bail, Result};
+    use parking_lot::{Mutex, MutexGuard};
+    use pkarr::SignedPacket;
+
+    use crate::{
+        dns::node_info::{node_id_from_hickory_name, NodeInfo},
+        test_utils::dns_server::QueryHandler,
+        NodeId,
+    };
+
+    #[derive(Debug, Clone)]
+    pub struct State {
+        packets: Arc<Mutex<HashMap<NodeId, SignedPacket>>>,
+        origin: String,
+        notify: Arc<tokio::sync::Notify>,
+    }
+
+    impl State {
+        pub fn new(origin: String) -> Self {
+            Self {
+                packets: Default::default(),
+                origin,
+                notify: Arc::new(tokio::sync::Notify::new()),
+            }
+        }
+
+        pub fn on_update(&self) -> tokio::sync::futures::Notified<'_> {
+            self.notify.notified()
+        }
+
+        pub async fn on_node(&self, node: &NodeId, timeout: Duration) -> Result<()> {
+            let timeout = tokio::time::sleep(timeout);
+            tokio::pin!(timeout);
+            while self.get(node).is_none() {
+                tokio::select! {
+                    _ = &mut timeout => bail!("timeout"),
+                    _ = self.on_update() => {}
+                }
+            }
+            Ok(())
+        }
+
+        pub fn upsert(&self, signed_packet: SignedPacket) -> anyhow::Result<bool> {
+            let node_id = NodeId::from_bytes(&signed_packet.public_key().to_bytes())?;
+            let mut map = self.packets.lock();
+            let updated = match map.entry(node_id) {
+                hash_map::Entry::Vacant(e) => {
+                    e.insert(signed_packet);
+                    true
+                }
+                hash_map::Entry::Occupied(mut e) => {
+                    if signed_packet.more_recent_than(e.get()) {
+                        e.insert(signed_packet);
+                        true
+                    } else {
+                        false
+                    }
+                }
+            };
+            if updated {
+                self.notify.notify_waiters();
+            }
+            Ok(updated)
+        }
+
+        /// Returns a mutex guard, do not hold over await points
+        pub fn get(&self, node_id: &NodeId) -> Option<impl Deref<Target = SignedPacket> + '_> {
+            let map = self.packets.lock();
+            if map.contains_key(node_id) {
+                let guard = MutexGuard::map(map, |state| state.get_mut(node_id).unwrap());
+                Some(guard)
+            } else {
+                None
+            }
+        }
+
+        pub fn resolve_dns(
+            &self,
+            query: &hickory_proto::op::Message,
+            reply: &mut hickory_proto::op::Message,
+            ttl: u32,
+        ) -> Result<()> {
+            for query in query.queries() {
+                let Some(node_id) = node_id_from_hickory_name(query.name()) else {
+                    continue;
+                };
+                let packet = self.get(&node_id);
+                let Some(packet) = packet.as_ref() else {
+                    continue;
+                };
+                let node_info = NodeInfo::from_pkarr_signed_packet(packet)?;
+                for record in node_info.to_hickory_records(&self.origin, ttl)? {
+                    reply.add_answer(record);
+                }
+            }
+            Ok(())
+        }
+    }
+
+    impl QueryHandler for State {
+        fn resolve(
+            &self,
+            query: &hickory_proto::op::Message,
+            reply: &mut hickory_proto::op::Message,
+        ) -> impl Future<Output = Result<()>> + Send {
+            const TTL: u32 = 30;
+            let res = self.resolve_dns(query, reply, TTL);
+            std::future::ready(res)
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/tls.rs.html b/pr/2992/docs/src/iroh/tls.rs.html new file mode 100644 index 0000000000..7418255d07 --- /dev/null +++ b/pr/2992/docs/src/iroh/tls.rs.html @@ -0,0 +1,193 @@ +tls.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+
//! TLS configuration based on libp2p TLS specs.
+//!
+//! See <https://github.com/libp2p/specs/blob/master/tls/tls.md>.
+//! Based on rust-libp2p/transports/tls
+
+use std::sync::Arc;
+
+use quinn::crypto::rustls::{NoInitialCipherSuite, QuicClientConfig, QuicServerConfig};
+use tracing::warn;
+
+use self::certificate::AlwaysResolvesCert;
+use crate::key::{PublicKey, SecretKey};
+
+pub mod certificate;
+mod verifier;
+
+/// Error for generating iroh p2p TLS configs.
+#[derive(Debug, thiserror::Error)]
+pub enum CreateConfigError {
+    /// Error generating the certificate.
+    #[error("Error generating the certificate")]
+    CertError(#[from] certificate::GenError),
+    /// Error creating QUIC config.
+    #[error("Error creating QUIC config")]
+    ConfigError(#[from] NoInitialCipherSuite),
+}
+
+/// Create a TLS client configuration.
+///
+/// If *keylog* is `true` this will enable logging of the pre-master key to the file in the
+/// `SSLKEYLOGFILE` environment variable.  This can be used to inspect the traffic for
+/// debugging purposes.
+pub fn make_client_config(
+    secret_key: &SecretKey,
+    remote_peer_id: Option<PublicKey>,
+    alpn_protocols: Vec<Vec<u8>>,
+    keylog: bool,
+) -> Result<QuicClientConfig, CreateConfigError> {
+    let (certificate, secret_key) = certificate::generate(secret_key)?;
+
+    let cert_resolver = Arc::new(
+        AlwaysResolvesCert::new(certificate, &secret_key)
+            .expect("Client cert key DER is valid; qed"),
+    );
+
+    let mut crypto = rustls::ClientConfig::builder_with_provider(Arc::new(
+        rustls::crypto::ring::default_provider(),
+    ))
+    .with_protocol_versions(verifier::PROTOCOL_VERSIONS)
+    .expect("version supported by ring")
+    .dangerous()
+    .with_custom_certificate_verifier(Arc::new(
+        verifier::Libp2pCertificateVerifier::with_remote_peer_id(remote_peer_id),
+    ))
+    .with_client_cert_resolver(cert_resolver);
+    crypto.alpn_protocols = alpn_protocols;
+    if keylog {
+        warn!("enabling SSLKEYLOGFILE for TLS pre-master keys");
+        crypto.key_log = Arc::new(rustls::KeyLogFile::new());
+    }
+    let config = crypto.try_into()?;
+    Ok(config)
+}
+
+/// Create a TLS server configuration.
+///
+/// If *keylog* is `true` this will enable logging of the pre-master key to the file in the
+/// `SSLKEYLOGFILE` environment variable.  This can be used to inspect the traffic for
+/// debugging purposes.
+pub fn make_server_config(
+    secret_key: &SecretKey,
+    alpn_protocols: Vec<Vec<u8>>,
+    keylog: bool,
+) -> Result<QuicServerConfig, CreateConfigError> {
+    let (certificate, secret_key) = certificate::generate(secret_key)?;
+
+    let cert_resolver = Arc::new(
+        AlwaysResolvesCert::new(certificate, &secret_key)
+            .expect("Server cert key DER is valid; qed"),
+    );
+
+    let mut crypto = rustls::ServerConfig::builder_with_provider(Arc::new(
+        rustls::crypto::ring::default_provider(),
+    ))
+    .with_protocol_versions(verifier::PROTOCOL_VERSIONS)
+    .expect("fixed config")
+    .with_client_cert_verifier(Arc::new(verifier::Libp2pCertificateVerifier::new()))
+    .with_cert_resolver(cert_resolver);
+    crypto.alpn_protocols = alpn_protocols;
+    if keylog {
+        warn!("enabling SSLKEYLOGFILE for TLS pre-master keys");
+        crypto.key_log = Arc::new(rustls::KeyLogFile::new());
+    }
+    let config = crypto.try_into()?;
+    Ok(config)
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/tls/certificate.rs.html b/pr/2992/docs/src/iroh/tls/certificate.rs.html new file mode 100644 index 0000000000..7466e48f4f --- /dev/null +++ b/pr/2992/docs/src/iroh/tls/certificate.rs.html @@ -0,0 +1,889 @@ +certificate.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+
//! X.509 certificate handling.
+//!
+//! This module handles generation, signing, and verification of certificates.
+//!
+//! Based on rust-libp2p/transports/tls/src/certificate.rs originally licensed under MIT by Parity
+//! Technologies (UK) Ltd.
+
+use std::sync::Arc;
+
+use der::{asn1::OctetStringRef, Decode, Encode, Sequence};
+use x509_parser::prelude::*;
+
+use crate::key::{PublicKey, SecretKey, Signature};
+
+/// The libp2p Public Key Extension is a X.509 extension
+/// with the Object Identifier 1.3.6.1.4.1.53594.1.1,
+/// allocated by IANA to the libp2p project at Protocol Labs.
+const P2P_EXT_OID: [u64; 9] = [1, 3, 6, 1, 4, 1, 53594, 1, 1];
+
+/// The peer signs the concatenation of the string `libp2p-tls-handshake:`
+/// and the public key that it used to generate the certificate carrying
+/// the libp2p Public Key Extension, using its private host key.
+/// This signature provides cryptographic proof that the peer was
+/// in possession of the private host key at the time the certificate was signed.
+const P2P_SIGNING_PREFIX: [u8; 21] = *b"libp2p-tls-handshake:";
+
+// Certificates MUST use the NamedCurve encoding for elliptic curve parameters.
+// Similarly, hash functions with an output length less than 256 bits MUST NOT be used.
+static P2P_SIGNATURE_ALGORITHM: &rcgen::SignatureAlgorithm = &rcgen::PKCS_ECDSA_P256_SHA256;
+
+#[derive(Debug)]
+pub(crate) struct AlwaysResolvesCert(Arc<rustls::sign::CertifiedKey>);
+
+impl AlwaysResolvesCert {
+    pub(crate) fn new(
+        cert: rustls::pki_types::CertificateDer<'static>,
+        key: &rustls::pki_types::PrivateKeyDer<'_>,
+    ) -> Result<Self, rustls::Error> {
+        let certified_key = rustls::sign::CertifiedKey::new(
+            vec![cert],
+            rustls::crypto::ring::sign::any_ecdsa_type(key)?,
+        );
+        Ok(Self(Arc::new(certified_key)))
+    }
+}
+
+impl rustls::client::ResolvesClientCert for AlwaysResolvesCert {
+    fn resolve(
+        &self,
+        _root_hint_subjects: &[&[u8]],
+        _sigschemes: &[rustls::SignatureScheme],
+    ) -> Option<Arc<rustls::sign::CertifiedKey>> {
+        Some(Arc::clone(&self.0))
+    }
+
+    fn has_certs(&self) -> bool {
+        true
+    }
+}
+
+impl rustls::server::ResolvesServerCert for AlwaysResolvesCert {
+    fn resolve(
+        &self,
+        _client_hello: rustls::server::ClientHello<'_>,
+    ) -> Option<Arc<rustls::sign::CertifiedKey>> {
+        Some(Arc::clone(&self.0))
+    }
+}
+
+/// The public host key and the signature are ANS.1-encoded
+/// into the SignedKey data structure, which is carried  in the libp2p Public Key Extension.
+#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
+struct SignedKey<'a> {
+    public_key: OctetStringRef<'a>,
+    signature: OctetStringRef<'a>,
+}
+
+/// Generates a self-signed TLS certificate that includes a libp2p-specific
+/// certificate extension containing the public key of the given secret key.
+pub fn generate(
+    identity_secret_key: &SecretKey,
+) -> Result<
+    (
+        rustls::pki_types::CertificateDer<'static>,
+        rustls::pki_types::PrivateKeyDer<'static>,
+    ),
+    GenError,
+> {
+    // SecretKey used to sign the certificate.
+    // SHOULD NOT be related to the host's key.
+    // Endpoints MAY generate a new key and certificate
+    // for every connection attempt, or they MAY reuse the same key
+    // and certificate for multiple connections.
+    let certificate_keypair = rcgen::KeyPair::generate_for(P2P_SIGNATURE_ALGORITHM)?;
+    let rustls_key =
+        rustls::pki_types::PrivateKeyDer::try_from(certificate_keypair.serialize_der()).unwrap();
+    let certificate = {
+        let mut params = rcgen::CertificateParams::default();
+        params.distinguished_name = rcgen::DistinguishedName::new();
+        params.custom_extensions.push(make_libp2p_extension(
+            identity_secret_key,
+            &certificate_keypair,
+        )?);
+        params
+            .self_signed(&certificate_keypair)
+            .expect("self signed certificate to be generated")
+    };
+
+    Ok((certificate.der().clone(), rustls_key))
+}
+
+/// Attempts to parse the provided bytes as a [`P2pCertificate`].
+///
+/// For this to succeed, the certificate must contain the specified extension and the signature must
+/// match the embedded public key.
+pub fn parse<'a>(
+    certificate: &'a rustls::pki_types::CertificateDer<'_>,
+) -> Result<P2pCertificate<'a>, ParseError> {
+    let certificate = parse_unverified(certificate.as_ref())?;
+
+    certificate.verify()?;
+
+    Ok(certificate)
+}
+
+/// An X.509 certificate with a libp2p-specific extension
+/// is used to secure libp2p connections.
+#[derive(Debug)]
+pub struct P2pCertificate<'a> {
+    certificate: X509Certificate<'a>,
+    /// This is a specific libp2p Public Key Extension with two values:
+    /// * the public host key
+    /// * a signature performed using the private host key
+    extension: P2pExtension,
+}
+
+/// The contents of the specific libp2p extension, containing the public host key
+/// and a signature performed using the private host key.
+#[derive(Debug)]
+pub struct P2pExtension {
+    public_key: crate::key::PublicKey,
+    /// This signature provides cryptographic proof that the peer was
+    /// in possession of the private host key at the time the certificate was signed.
+    signature: crate::key::Signature,
+}
+
+/// An error that occurs during certificate generation.
+#[derive(Debug, thiserror::Error)]
+#[error(transparent)]
+pub struct GenError(#[from] rcgen::Error);
+
+/// An error that occurs during certificate parsing.
+#[derive(Debug, thiserror::Error)]
+#[error(transparent)]
+pub struct ParseError(#[from] pub(crate) webpki::Error);
+
+/// An error that occurs during signature verification.
+#[derive(Debug, thiserror::Error)]
+#[error(transparent)]
+pub struct VerificationError(#[from] pub(crate) webpki::Error);
+
+/// Internal function that only parses but does not verify the certificate.
+///
+/// Useful for testing but unsuitable for production.
+fn parse_unverified(der_input: &[u8]) -> Result<P2pCertificate, webpki::Error> {
+    let x509 = X509Certificate::from_der(der_input)
+        .map(|(_rest_input, x509)| x509)
+        .map_err(|_| webpki::Error::BadDer)?;
+
+    let p2p_ext_oid = der_parser::oid::Oid::from(&P2P_EXT_OID)
+        .expect("This is a valid OID of p2p extension; qed");
+
+    let mut libp2p_extension = None;
+
+    for ext in x509.extensions() {
+        let oid = &ext.oid;
+        if oid == &p2p_ext_oid && libp2p_extension.is_some() {
+            // The extension was already parsed
+            return Err(webpki::Error::BadDer);
+        }
+
+        if oid == &p2p_ext_oid {
+            let signed_key =
+                SignedKey::from_der(ext.value).map_err(|_| webpki::Error::ExtensionValueInvalid)?;
+            let public_key_raw = signed_key.public_key.as_bytes();
+            let public_key =
+                PublicKey::try_from(public_key_raw).map_err(|_| webpki::Error::UnknownIssuer)?;
+
+            let signature = Signature::from_slice(signed_key.signature.as_bytes())
+                .map_err(|_| webpki::Error::UnknownIssuer)?;
+            let ext = P2pExtension {
+                public_key,
+                signature,
+            };
+            libp2p_extension = Some(ext);
+            continue;
+        }
+
+        if ext.critical {
+            // Endpoints MUST abort the connection attempt if the certificate
+            // contains critical extensions that the endpoint does not understand.
+            return Err(webpki::Error::UnsupportedCriticalExtension);
+        }
+
+        // Implementations MUST ignore non-critical extensions with unknown OIDs.
+    }
+
+    // The certificate MUST contain the libp2p Public Key Extension.
+    // If this extension is missing, endpoints MUST abort the connection attempt.
+    let extension = libp2p_extension.ok_or(webpki::Error::BadDer)?;
+
+    let certificate = P2pCertificate {
+        certificate: x509,
+        extension,
+    };
+
+    Ok(certificate)
+}
+
+fn make_libp2p_extension(
+    identity_secret_key: &SecretKey,
+    certificate_keypair: &rcgen::KeyPair,
+) -> Result<rcgen::CustomExtension, rcgen::Error> {
+    // The peer signs the concatenation of the string `libp2p-tls-handshake:`
+    // and the public key that it used to generate the certificate carrying
+    // the libp2p Public Key Extension, using its private host key.
+    let signature = {
+        let mut msg = vec![];
+        msg.extend(P2P_SIGNING_PREFIX);
+        msg.extend(certificate_keypair.public_key_der());
+
+        identity_secret_key.sign(&msg)
+    };
+
+    let public_key = identity_secret_key.public();
+    let public_key_ref = OctetStringRef::new(&public_key.as_bytes()[..])
+        .map_err(|_| rcgen::Error::CouldNotParseKeyPair)?;
+    let signature = signature.to_bytes();
+    let signature_ref =
+        OctetStringRef::new(&signature).map_err(|_| rcgen::Error::CouldNotParseCertificate)?;
+    let key = SignedKey {
+        public_key: public_key_ref,
+        signature: signature_ref,
+    };
+
+    let mut extension_content = Vec::new();
+    key.encode_to_vec(&mut extension_content).expect("vec");
+
+    // This extension MAY be marked critical.
+    let mut ext = rcgen::CustomExtension::from_oid_content(&P2P_EXT_OID, extension_content);
+    ext.set_criticality(true);
+
+    Ok(ext)
+}
+
+impl P2pCertificate<'_> {
+    /// The [`PublicKey`] of the remote peer.
+    pub fn peer_id(&self) -> PublicKey {
+        self.extension.public_key
+    }
+
+    /// Verify the `signature` of the `message` signed by the secret key corresponding to the public key stored
+    /// in the certificate.
+    pub fn verify_signature(
+        &self,
+        signature_scheme: rustls::SignatureScheme,
+        message: &[u8],
+        signature: &[u8],
+    ) -> Result<(), VerificationError> {
+        let pk = self.public_key(signature_scheme)?;
+        pk.verify(message, signature)
+            .map_err(|_| webpki::Error::InvalidSignatureForPublicKey)?;
+
+        Ok(())
+    }
+
+    /// Get a [`ring::signature::UnparsedPublicKey`] for this `signature_scheme`.
+    /// Return `Error` if the `signature_scheme` does not match the public key signature
+    /// and hashing algorithm or if the `signature_scheme` is not supported.
+    fn public_key(
+        &self,
+        signature_scheme: rustls::SignatureScheme,
+    ) -> Result<ring::signature::UnparsedPublicKey<&[u8]>, webpki::Error> {
+        use ring::signature;
+        use rustls::SignatureScheme::*;
+
+        let current_signature_scheme = self.signature_scheme()?;
+        if signature_scheme != current_signature_scheme {
+            // This certificate was signed with a different signature scheme
+            return Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey);
+        }
+
+        let verification_algorithm: &dyn signature::VerificationAlgorithm = match signature_scheme {
+            ECDSA_NISTP256_SHA256 => &signature::ECDSA_P256_SHA256_ASN1,
+            ECDSA_NISTP384_SHA384 => &signature::ECDSA_P384_SHA384_ASN1,
+            ECDSA_NISTP521_SHA512 => {
+                // See https://github.com/briansmith/ring/issues/824
+                return Err(webpki::Error::UnsupportedSignatureAlgorithm);
+            }
+            ED25519 => &signature::ED25519,
+            ED448 => {
+                // See https://github.com/briansmith/ring/issues/463
+                return Err(webpki::Error::UnsupportedSignatureAlgorithm);
+            }
+            // No support for RSA
+            RSA_PKCS1_SHA256 | RSA_PKCS1_SHA384 | RSA_PKCS1_SHA512 | RSA_PSS_SHA256
+            | RSA_PSS_SHA384 | RSA_PSS_SHA512 => {
+                return Err(webpki::Error::UnsupportedSignatureAlgorithm)
+            }
+            // Similarly, hash functions with an output length less than 256 bits
+            // MUST NOT be used, due to the possibility of collision attacks.
+            // In particular, MD5 and SHA1 MUST NOT be used.
+            RSA_PKCS1_SHA1 => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
+            ECDSA_SHA1_Legacy => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
+            Unknown(_) => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
+            _ => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
+        };
+        let spki = &self.certificate.tbs_certificate.subject_pki;
+        let key = signature::UnparsedPublicKey::new(
+            verification_algorithm,
+            spki.subject_public_key.as_ref(),
+        );
+
+        Ok(key)
+    }
+
+    /// This method validates the certificate according to libp2p TLS 1.3 specs.
+    /// The certificate MUST:
+    /// 1. be valid at the time it is received by the peer;
+    /// 2. use the NamedCurve encoding;
+    /// 3. use hash functions with an output length not less than 256 bits;
+    /// 4. be self signed;
+    /// 5. contain a valid signature in the specific libp2p extension.
+    fn verify(&self) -> Result<(), webpki::Error> {
+        use webpki::Error;
+
+        // The certificate MUST have NotBefore and NotAfter fields set
+        // such that the certificate is valid at the time it is received by the peer.
+        if !self.certificate.validity().is_valid() {
+            return Err(Error::InvalidCertValidity);
+        }
+
+        // Certificates MUST use the NamedCurve encoding for elliptic curve parameters.
+        // Similarly, hash functions with an output length less than 256 bits
+        // MUST NOT be used, due to the possibility of collision attacks.
+        // In particular, MD5 and SHA1 MUST NOT be used.
+        // Endpoints MUST abort the connection attempt if it is not used.
+        let signature_scheme = self.signature_scheme()?;
+        // Endpoints MUST abort the connection attempt if the certificate’s
+        // self-signature is not valid.
+        let raw_certificate = self.certificate.tbs_certificate.as_ref();
+        let signature = self.certificate.signature_value.as_ref();
+        // check if self signed
+        self.verify_signature(signature_scheme, raw_certificate, signature)
+            .map_err(|_| Error::SignatureAlgorithmMismatch)?;
+
+        let subject_pki = self.certificate.public_key().raw;
+
+        // The peer signs the concatenation of the string `libp2p-tls-handshake:`
+        // and the public key that it used to generate the certificate carrying
+        // the libp2p Public Key Extension, using its private host key.
+        let mut msg = vec![];
+        msg.extend(P2P_SIGNING_PREFIX);
+        msg.extend(subject_pki);
+
+        // This signature provides cryptographic proof that the peer was in possession
+        // of the private host key at the time the certificate was signed.
+        // Peers MUST verify the signature, and abort the connection attempt
+        // if signature verification fails.
+        let user_owns_sk = self
+            .extension
+            .public_key
+            .verify(&msg, &self.extension.signature)
+            .is_ok();
+        if !user_owns_sk {
+            return Err(Error::UnknownIssuer);
+        }
+
+        Ok(())
+    }
+
+    /// Return the signature scheme corresponding to [`AlgorithmIdentifier`]s
+    /// of `subject_pki` and `signature_algorithm`
+    /// according to <https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.3>.
+    fn signature_scheme(&self) -> Result<rustls::SignatureScheme, webpki::Error> {
+        // Certificates MUST use the NamedCurve encoding for elliptic curve parameters.
+        // Endpoints MUST abort the connection attempt if it is not used.
+        use oid_registry::*;
+        use rustls::SignatureScheme::*;
+
+        let signature_algorithm = &self.certificate.signature_algorithm;
+        let pki_algorithm = &self.certificate.tbs_certificate.subject_pki.algorithm;
+
+        if pki_algorithm.algorithm == OID_KEY_TYPE_EC_PUBLIC_KEY {
+            let signature_param = pki_algorithm
+                .parameters
+                .as_ref()
+                .ok_or(webpki::Error::BadDer)?
+                .as_oid()
+                .map_err(|_| webpki::Error::BadDer)?;
+            if signature_param == OID_EC_P256
+                && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA256
+            {
+                return Ok(ECDSA_NISTP256_SHA256);
+            }
+            if signature_param == OID_NIST_EC_P384
+                && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA384
+            {
+                return Ok(ECDSA_NISTP384_SHA384);
+            }
+            if signature_param == OID_NIST_EC_P521
+                && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA512
+            {
+                return Ok(ECDSA_NISTP521_SHA512);
+            }
+            return Err(webpki::Error::UnsupportedSignatureAlgorithm);
+        }
+
+        if signature_algorithm.algorithm == OID_SIG_ED25519 {
+            return Ok(ED25519);
+        }
+        if signature_algorithm.algorithm == OID_SIG_ED448 {
+            return Ok(ED448);
+        }
+
+        Err(webpki::Error::UnsupportedSignatureAlgorithm)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn sanity_check() {
+        let secret_key = SecretKey::generate();
+
+        let (cert, _) = generate(&secret_key).unwrap();
+        let parsed_cert = parse(&cert).unwrap();
+
+        assert!(parsed_cert.verify().is_ok());
+        assert_eq!(secret_key.public(), parsed_cert.extension.public_key);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/tls/verifier.rs.html b/pr/2992/docs/src/iroh/tls/verifier.rs.html new file mode 100644 index 0000000000..1a4f898043 --- /dev/null +++ b/pr/2992/docs/src/iroh/tls/verifier.rs.html @@ -0,0 +1,455 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+
//! TLS 1.3 certificates and handshakes handling for libp2p
+//!
+//! This module handles a verification of a client/server certificate chain
+//! and signatures allegedly by the given certificates.
+//!
+//! Based on rust-libp2p/transports/tls/src/verifier.rs originally licensed under MIT by Parity
+//! Technologies (UK) Ltd.
+use std::sync::Arc;
+
+use rustls::{
+    client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
+    pki_types::CertificateDer as Certificate,
+    server::danger::{ClientCertVerified, ClientCertVerifier},
+    CertificateError, DigitallySignedStruct, DistinguishedName, OtherError, PeerMisbehaved,
+    SignatureScheme, SupportedProtocolVersion,
+};
+
+use super::certificate;
+use crate::key::PublicKey;
+
+/// The protocol versions supported by this verifier.
+///
+/// The spec says:
+///
+/// > The libp2p handshake uses TLS 1.3 (and higher).
+/// > Endpoints MUST NOT negotiate lower TLS versions.
+pub static PROTOCOL_VERSIONS: &[&SupportedProtocolVersion] = &[&rustls::version::TLS13];
+
+/// Implementation of the `rustls` certificate verification traits for libp2p.
+///
+/// Only TLS 1.3 is supported. TLS 1.2 should be disabled in the configuration of `rustls`.
+#[derive(Debug)]
+pub struct Libp2pCertificateVerifier {
+    /// The peer ID we intend to connect to
+    remote_peer_id: Option<PublicKey>,
+}
+
+/// libp2p requires the following of X.509 server certificate chains:
+///
+/// - Exactly one certificate must be presented.
+/// - The certificate must be self-signed.
+/// - The certificate must have a valid libp2p extension that includes a
+///   signature of its public key.
+impl Libp2pCertificateVerifier {
+    pub fn new() -> Self {
+        Self {
+            remote_peer_id: None,
+        }
+    }
+    pub fn with_remote_peer_id(remote_peer_id: Option<PublicKey>) -> Self {
+        Self { remote_peer_id }
+    }
+
+    /// Return the list of SignatureSchemes that this verifier will handle,
+    /// in `verify_tls12_signature` and `verify_tls13_signature` calls.
+    ///
+    /// This should be in priority order, with the most preferred first.
+    fn verification_schemes() -> Vec<SignatureScheme> {
+        vec![
+            // TODO SignatureScheme::ECDSA_NISTP521_SHA512 is not supported by `ring` yet
+            SignatureScheme::ECDSA_NISTP384_SHA384,
+            SignatureScheme::ECDSA_NISTP256_SHA256,
+            // TODO SignatureScheme::ED448 is not supported by `ring` yet
+            SignatureScheme::ED25519,
+            // In particular, RSA SHOULD NOT be used.
+        ]
+    }
+}
+
+impl ServerCertVerifier for Libp2pCertificateVerifier {
+    fn verify_server_cert(
+        &self,
+        end_entity: &Certificate,
+        intermediates: &[Certificate],
+        _server_name: &rustls::pki_types::ServerName,
+        _ocsp_response: &[u8],
+        _now: rustls::pki_types::UnixTime,
+    ) -> Result<ServerCertVerified, rustls::Error> {
+        let peer_id = verify_presented_certs(end_entity, intermediates)?;
+
+        if let Some(ref remote_peer_id) = self.remote_peer_id {
+            // The public host key allows the peer to calculate the peer ID of the peer
+            // it is connecting to. Clients MUST verify that the peer ID derived from
+            // the certificate matches the peer ID they intended to connect to,
+            // and MUST abort the connection if there is a mismatch.
+            if remote_peer_id != &peer_id {
+                return Err(rustls::Error::PeerMisbehaved(
+                    PeerMisbehaved::BadCertChainExtensions,
+                ));
+            }
+        }
+
+        Ok(ServerCertVerified::assertion())
+    }
+
+    fn verify_tls12_signature(
+        &self,
+        _message: &[u8],
+        _cert: &Certificate,
+        _dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, rustls::Error> {
+        unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
+    }
+
+    fn verify_tls13_signature(
+        &self,
+        message: &[u8],
+        cert: &Certificate,
+        dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, rustls::Error> {
+        verify_tls13_signature(cert, dss.scheme, message, dss.signature())
+    }
+
+    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
+        Self::verification_schemes()
+    }
+}
+
+/// libp2p requires the following of X.509 client certificate chains:
+///
+/// - Exactly one certificate must be presented. In particular, client
+///   authentication is mandatory in libp2p.
+/// - The certificate must be self-signed.
+/// - The certificate must have a valid libp2p extension that includes a
+///   signature of its public key.
+impl ClientCertVerifier for Libp2pCertificateVerifier {
+    fn offer_client_auth(&self) -> bool {
+        true
+    }
+
+    fn verify_client_cert(
+        &self,
+        end_entity: &Certificate,
+        intermediates: &[Certificate],
+        _now: rustls::pki_types::UnixTime,
+    ) -> Result<ClientCertVerified, rustls::Error> {
+        verify_presented_certs(end_entity, intermediates)?;
+
+        Ok(ClientCertVerified::assertion())
+    }
+
+    fn verify_tls12_signature(
+        &self,
+        _message: &[u8],
+        _cert: &Certificate,
+        _dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, rustls::Error> {
+        unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
+    }
+
+    fn verify_tls13_signature(
+        &self,
+        message: &[u8],
+        cert: &Certificate,
+        dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, rustls::Error> {
+        verify_tls13_signature(cert, dss.scheme, message, dss.signature())
+    }
+
+    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
+        Self::verification_schemes()
+    }
+
+    fn root_hint_subjects(&self) -> &[DistinguishedName] {
+        &[][..]
+    }
+}
+
+/// When receiving the certificate chain, an endpoint
+/// MUST check these conditions and abort the connection attempt if
+/// (a) the presented certificate is not yet valid, OR
+/// (b) if it is expired.
+/// Endpoints MUST abort the connection attempt if more than one certificate is received,
+/// or if the certificate’s self-signature is not valid.
+fn verify_presented_certs(
+    end_entity: &Certificate,
+    intermediates: &[Certificate],
+) -> Result<PublicKey, rustls::Error> {
+    if !intermediates.is_empty() {
+        return Err(rustls::Error::General(
+            "libp2p-tls requires exactly one certificate".into(),
+        ));
+    }
+
+    let cert = certificate::parse(end_entity)?;
+
+    Ok(cert.peer_id())
+}
+
+fn verify_tls13_signature(
+    cert: &Certificate,
+    signature_scheme: SignatureScheme,
+    message: &[u8],
+    signature: &[u8],
+) -> Result<HandshakeSignatureValid, rustls::Error> {
+    certificate::parse(cert)?.verify_signature(signature_scheme, message, signature)?;
+
+    Ok(HandshakeSignatureValid::assertion())
+}
+
+impl From<certificate::ParseError> for rustls::Error {
+    fn from(certificate::ParseError(e): certificate::ParseError) -> Self {
+        use webpki::Error::*;
+        match e {
+            BadDer => rustls::Error::InvalidCertificate(CertificateError::BadEncoding),
+            e => {
+                rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(Arc::new(e))))
+            }
+        }
+    }
+}
+impl From<certificate::VerificationError> for rustls::Error {
+    fn from(certificate::VerificationError(e): certificate::VerificationError) -> Self {
+        use webpki::Error::*;
+        match e {
+            InvalidSignatureForPublicKey => {
+                rustls::Error::InvalidCertificate(CertificateError::BadSignature)
+            }
+            UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => {
+                rustls::Error::InvalidCertificate(CertificateError::BadSignature)
+            }
+            e => {
+                rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(Arc::new(e))))
+            }
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh/util.rs.html b/pr/2992/docs/src/iroh/util.rs.html new file mode 100644 index 0000000000..4c412b35cc --- /dev/null +++ b/pr/2992/docs/src/iroh/util.rs.html @@ -0,0 +1,83 @@ +util.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
//! Utilities used in [`iroh`][`crate`]
+
+use std::{
+    future::Future,
+    pin::Pin,
+    task::{Context, Poll},
+};
+
+/// Resolves to pending if the inner is `None`.
+#[derive(Debug)]
+pub(crate) struct MaybeFuture<T> {
+    /// Future to be polled.
+    pub inner: Option<T>,
+}
+
+// NOTE: explicit implementation to bypass derive unnecessary bounds
+impl<T> Default for MaybeFuture<T> {
+    fn default() -> Self {
+        MaybeFuture { inner: None }
+    }
+}
+
+impl<T: Future + Unpin> Future for MaybeFuture<T> {
+    type Output = T::Output;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        match self.inner {
+            Some(ref mut t) => Pin::new(t).poll(cx),
+            None => Poll::Pending,
+        }
+    }
+}
+
+/// Check if we are running in "relay only" mode, as informed
+/// by the compile time env var `DEV_RELAY_ONLY`.
+///
+/// "relay only" mode implies we only use the relay to communicate
+/// and do not attempt to do any hole punching.
+pub(crate) fn relay_only_mode() -> bool {
+    std::option_env!("DEV_RELAY_ONLY").is_some()
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/base32.rs.html b/pr/2992/docs/src/iroh_base/base32.rs.html new file mode 100644 index 0000000000..6e8d5b442f --- /dev/null +++ b/pr/2992/docs/src/iroh_base/base32.rs.html @@ -0,0 +1,135 @@ +base32.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+
pub use data_encoding::{DecodeError, DecodeKind};
+use hex::FromHexError;
+
+/// Convert to a base32 string
+pub fn fmt(bytes: impl AsRef<[u8]>) -> String {
+    let mut text = data_encoding::BASE32_NOPAD.encode(bytes.as_ref());
+    text.make_ascii_lowercase();
+    text
+}
+
+/// Convert to a base32 string and append out `out`
+pub fn fmt_append(bytes: impl AsRef<[u8]>, out: &mut String) {
+    let start = out.len();
+    data_encoding::BASE32_NOPAD.encode_append(bytes.as_ref(), out);
+    let end = out.len();
+    out[start..end].make_ascii_lowercase();
+}
+
+/// Convert to a base32 string limited to the first 10 bytes
+pub fn fmt_short(bytes: impl AsRef<[u8]>) -> String {
+    let len = bytes.as_ref().len().min(10);
+    let mut text = data_encoding::BASE32_NOPAD.encode(&bytes.as_ref()[..len]);
+    text.make_ascii_lowercase();
+    text
+}
+
+/// Parse from a base32 string into a byte array
+pub fn parse_array<const N: usize>(input: &str) -> Result<[u8; N], DecodeError> {
+    data_encoding::BASE32_NOPAD
+        .decode(input.to_ascii_uppercase().as_bytes())?
+        .try_into()
+        .map_err(|_| DecodeError {
+            position: N,
+            kind: DecodeKind::Length,
+        })
+}
+
+/// Decode form a base32 string to a vector of bytes
+pub fn parse_vec(input: &str) -> Result<Vec<u8>, DecodeError> {
+    data_encoding::BASE32_NOPAD.decode(input.to_ascii_uppercase().as_bytes())
+}
+
+/// Error when parsing a hex or base32 string.
+#[derive(thiserror::Error, Debug)]
+pub enum HexOrBase32ParseError {
+    /// Error when decoding the base32.
+    #[error("base32: {0}")]
+    Base32(#[from] data_encoding::DecodeError),
+    /// Error when decoding the public key.
+    #[error("hex: {0}")]
+    Hex(#[from] FromHexError),
+}
+
+/// Parse a fixed length hex or base32 string into a byte array
+///
+/// For fixed length we can know the encoding by the length of the string.
+pub fn parse_array_hex_or_base32<const LEN: usize>(
+    input: &str,
+) -> std::result::Result<[u8; LEN], HexOrBase32ParseError> {
+    let mut bytes = [0u8; LEN];
+    if input.len() == LEN * 2 {
+        hex::decode_to_slice(input, &mut bytes)?;
+        Ok(bytes)
+    } else {
+        Ok(parse_array(input)?)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/hash.rs.html b/pr/2992/docs/src/iroh_base/hash.rs.html new file mode 100644 index 0000000000..030114e323 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/hash.rs.html @@ -0,0 +1,1133 @@ +hash.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+
//! The blake3 hash used in Iroh.
+
+use std::{borrow::Borrow, fmt, str::FromStr};
+
+use postcard::experimental::max_size::MaxSize;
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::base32::{self, parse_array_hex_or_base32, HexOrBase32ParseError};
+
+/// Hash type used throughout.
+#[derive(PartialEq, Eq, Copy, Clone, Hash)]
+pub struct Hash(blake3::Hash);
+
+impl fmt::Debug for Hash {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Hash").field(&DD(self.to_hex())).finish()
+    }
+}
+
+struct DD<T: fmt::Display>(T);
+
+impl<T: fmt::Display> fmt::Debug for DD<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
+
+impl Hash {
+    /// The hash for the empty byte range (`b""`).
+    pub const EMPTY: Hash = Hash::from_bytes([
+        175, 19, 73, 185, 245, 249, 161, 166, 160, 64, 77, 234, 54, 220, 201, 73, 155, 203, 37,
+        201, 173, 193, 18, 183, 204, 154, 147, 202, 228, 31, 50, 98,
+    ]);
+
+    /// Calculate the hash of the provided bytes.
+    pub fn new(buf: impl AsRef<[u8]>) -> Self {
+        let val = blake3::hash(buf.as_ref());
+        Hash(val)
+    }
+
+    /// Bytes of the hash.
+    pub fn as_bytes(&self) -> &[u8; 32] {
+        self.0.as_bytes()
+    }
+
+    /// Create a `Hash` from its raw bytes representation.
+    pub const fn from_bytes(bytes: [u8; 32]) -> Self {
+        Self(blake3::Hash::from_bytes(bytes))
+    }
+
+    /// Convert the hash to a hex string.
+    pub fn to_hex(&self) -> String {
+        self.0.to_hex().to_string()
+    }
+
+    /// Convert to a base32 string limited to the first 10 bytes for a friendly string
+    /// representation of the hash.
+    pub fn fmt_short(&self) -> String {
+        base32::fmt_short(self.as_bytes())
+    }
+}
+
+impl AsRef<[u8]> for Hash {
+    fn as_ref(&self) -> &[u8] {
+        self.0.as_bytes()
+    }
+}
+
+impl Borrow<[u8]> for Hash {
+    fn borrow(&self) -> &[u8] {
+        self.0.as_bytes()
+    }
+}
+
+impl Borrow<[u8; 32]> for Hash {
+    fn borrow(&self) -> &[u8; 32] {
+        self.0.as_bytes()
+    }
+}
+
+impl From<Hash> for blake3::Hash {
+    fn from(value: Hash) -> Self {
+        value.0
+    }
+}
+
+impl From<blake3::Hash> for Hash {
+    fn from(value: blake3::Hash) -> Self {
+        Hash(value)
+    }
+}
+
+impl From<[u8; 32]> for Hash {
+    fn from(value: [u8; 32]) -> Self {
+        Hash(blake3::Hash::from(value))
+    }
+}
+
+impl From<Hash> for [u8; 32] {
+    fn from(value: Hash) -> Self {
+        *value.as_bytes()
+    }
+}
+
+impl From<&[u8; 32]> for Hash {
+    fn from(value: &[u8; 32]) -> Self {
+        Hash(blake3::Hash::from(*value))
+    }
+}
+
+impl PartialOrd for Hash {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.0.as_bytes().cmp(other.0.as_bytes()))
+    }
+}
+
+impl Ord for Hash {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.0.as_bytes().cmp(other.0.as_bytes())
+    }
+}
+
+impl fmt::Display for Hash {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // result will be 52 bytes
+        let mut res = [b'b'; 52];
+        // write the encoded bytes
+        data_encoding::BASE32_NOPAD.encode_mut(self.as_bytes(), &mut res);
+        // convert to string, this is guaranteed to succeed
+        let t = std::str::from_utf8_mut(res.as_mut()).unwrap();
+        // hack since data_encoding doesn't have BASE32LOWER_NOPAD as a const
+        t.make_ascii_lowercase();
+        // write the str, no allocations
+        f.write_str(t)
+    }
+}
+
+impl FromStr for Hash {
+    type Err = HexOrBase32ParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        parse_array_hex_or_base32(s).map(Hash::from)
+    }
+}
+
+impl Serialize for Hash {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        if serializer.is_human_readable() {
+            serializer.serialize_str(self.to_string().as_str())
+        } else {
+            self.0.as_bytes().serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for Hash {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        if deserializer.is_human_readable() {
+            let s = String::deserialize(deserializer)?;
+            s.parse().map_err(de::Error::custom)
+        } else {
+            let data: [u8; 32] = Deserialize::deserialize(deserializer)?;
+            Ok(Self(blake3::Hash::from(data)))
+        }
+    }
+}
+
+impl MaxSize for Hash {
+    const POSTCARD_MAX_SIZE: usize = 32;
+}
+
+/// A format identifier
+#[derive(
+    Clone,
+    Copy,
+    PartialEq,
+    Eq,
+    PartialOrd,
+    Ord,
+    Serialize,
+    Deserialize,
+    Default,
+    Debug,
+    MaxSize,
+    Hash,
+    derive_more::Display,
+)]
+pub enum BlobFormat {
+    /// Raw blob
+    #[default]
+    Raw,
+    /// A sequence of BLAKE3 hashes
+    HashSeq,
+}
+
+impl From<BlobFormat> for u64 {
+    fn from(value: BlobFormat) -> Self {
+        match value {
+            BlobFormat::Raw => 0,
+            BlobFormat::HashSeq => 1,
+        }
+    }
+}
+
+impl BlobFormat {
+    /// Is raw format
+    pub const fn is_raw(&self) -> bool {
+        matches!(self, BlobFormat::Raw)
+    }
+
+    /// Is hash seq format
+    pub const fn is_hash_seq(&self) -> bool {
+        matches!(self, BlobFormat::HashSeq)
+    }
+}
+
+/// A hash and format pair
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, MaxSize, Hash)]
+pub struct HashAndFormat {
+    /// The hash
+    pub hash: Hash,
+    /// The format
+    pub format: BlobFormat,
+}
+
+#[cfg(feature = "redb")]
+#[cfg_attr(iroh_docsrs, cfg(feature = "redb"))]
+mod redb_support {
+    use postcard::experimental::max_size::MaxSize;
+    use redb::{Key as RedbKey, Value as RedbValue};
+
+    use super::{Hash, HashAndFormat};
+
+    impl RedbValue for Hash {
+        type SelfType<'a> = Self;
+
+        type AsBytes<'a> = &'a [u8; 32];
+
+        fn fixed_width() -> Option<usize> {
+            Some(32)
+        }
+
+        fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
+        where
+            Self: 'a,
+        {
+            let contents: &'a [u8; 32] = data.try_into().unwrap();
+            (*contents).into()
+        }
+
+        fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
+        where
+            Self: 'a,
+            Self: 'b,
+        {
+            value.as_bytes()
+        }
+
+        fn type_name() -> redb::TypeName {
+            redb::TypeName::new("iroh_base::Hash")
+        }
+    }
+
+    impl RedbKey for Hash {
+        fn compare(data1: &[u8], data2: &[u8]) -> std::cmp::Ordering {
+            data1.cmp(data2)
+        }
+    }
+
+    impl RedbValue for HashAndFormat {
+        type SelfType<'a> = Self;
+
+        type AsBytes<'a> = [u8; Self::POSTCARD_MAX_SIZE];
+
+        fn fixed_width() -> Option<usize> {
+            Some(Self::POSTCARD_MAX_SIZE)
+        }
+
+        fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
+        where
+            Self: 'a,
+        {
+            let t: &'a [u8; Self::POSTCARD_MAX_SIZE] = data.try_into().unwrap();
+            postcard::from_bytes(t.as_slice()).unwrap()
+        }
+
+        fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
+        where
+            Self: 'a,
+            Self: 'b,
+        {
+            let mut res = [0u8; 33];
+            postcard::to_slice(&value, &mut res).unwrap();
+            res
+        }
+
+        fn type_name() -> redb::TypeName {
+            redb::TypeName::new("iroh_base::HashAndFormat")
+        }
+    }
+}
+
+impl HashAndFormat {
+    /// Create a new hash and format pair.
+    pub fn new(hash: Hash, format: BlobFormat) -> Self {
+        Self { hash, format }
+    }
+
+    /// Create a new hash and format pair, using the default (raw) format.
+    pub fn raw(hash: Hash) -> Self {
+        Self {
+            hash,
+            format: BlobFormat::Raw,
+        }
+    }
+
+    /// Create a new hash and format pair, using the collection format.
+    pub fn hash_seq(hash: Hash) -> Self {
+        Self {
+            hash,
+            format: BlobFormat::HashSeq,
+        }
+    }
+}
+
+impl fmt::Display for HashAndFormat {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut slice = [0u8; 65];
+        hex::encode_to_slice(self.hash.as_bytes(), &mut slice[1..]).unwrap();
+        match self.format {
+            BlobFormat::Raw => {
+                write!(f, "{}", std::str::from_utf8(&slice[1..]).unwrap())
+            }
+            BlobFormat::HashSeq => {
+                slice[0] = b's';
+                write!(f, "{}", std::str::from_utf8(&slice).unwrap())
+            }
+        }
+    }
+}
+
+impl FromStr for HashAndFormat {
+    type Err = anyhow::Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let s = s.as_bytes();
+        let mut hash = [0u8; 32];
+        match s.len() {
+            64 => {
+                hex::decode_to_slice(s, &mut hash)?;
+                Ok(Self::raw(hash.into()))
+            }
+            65 if s[0].to_ascii_lowercase() == b's' => {
+                hex::decode_to_slice(&s[1..], &mut hash)?;
+                Ok(Self::hash_seq(hash.into()))
+            }
+            _ => anyhow::bail!("invalid hash and format"),
+        }
+    }
+}
+
+impl Serialize for HashAndFormat {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        if serializer.is_human_readable() {
+            serializer.serialize_str(self.to_string().as_str())
+        } else {
+            (self.hash, self.format).serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for HashAndFormat {
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        if deserializer.is_human_readable() {
+            let s = String::deserialize(deserializer)?;
+            s.parse().map_err(de::Error::custom)
+        } else {
+            let (hash, format) = <(Hash, BlobFormat)>::deserialize(deserializer)?;
+            Ok(Self { hash, format })
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};
+    use serde_test::{assert_tokens, Configure, Token};
+
+    use super::*;
+
+    #[test]
+    fn test_display_parse_roundtrip() {
+        for i in 0..100 {
+            let hash: Hash = blake3::hash(&[i]).into();
+            let text = hash.to_string();
+            let hash1 = text.parse::<Hash>().unwrap();
+            assert_eq!(hash, hash1);
+
+            let text = hash.to_hex();
+            let hash1 = Hash::from_str(&text).unwrap();
+            assert_eq!(hash, hash1);
+        }
+    }
+
+    #[test]
+    fn test_hash() {
+        let data = b"hello world";
+        let hash = Hash::new(data);
+
+        let encoded = hash.to_string();
+        assert_eq!(encoded.parse::<Hash>().unwrap(), hash);
+    }
+
+    #[test]
+    fn test_empty_hash() {
+        let hash = Hash::new(b"");
+        assert_eq!(hash, Hash::EMPTY);
+    }
+
+    #[test]
+    fn hash_wire_format() {
+        let hash = Hash::from([0xab; 32]);
+        let serialized = postcard::to_stdvec(&hash).unwrap();
+        let expected = parse_hexdump(r"
+            ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab # hash
+        ").unwrap();
+        assert_eq_hex!(serialized, expected);
+    }
+
+    #[cfg(feature = "redb")]
+    #[test]
+    fn hash_redb() {
+        use redb::Value as RedbValue;
+        let bytes: [u8; 32] = (0..32).collect::<Vec<_>>().as_slice().try_into().unwrap();
+        let hash = Hash::from(bytes);
+        assert_eq!(<Hash as RedbValue>::fixed_width(), Some(32));
+        assert_eq!(
+            <Hash as RedbValue>::type_name(),
+            redb::TypeName::new("iroh_base::Hash")
+        );
+        let serialized = <Hash as RedbValue>::as_bytes(&hash);
+        assert_eq!(serialized, &bytes);
+        let deserialized = <Hash as RedbValue>::from_bytes(serialized.as_slice());
+        assert_eq!(deserialized, hash);
+        let expected = parse_hexdump(
+            r"
+            00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+            10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f # hash
+        ",
+        )
+        .unwrap();
+        assert_eq_hex!(serialized, expected);
+    }
+
+    #[cfg(feature = "redb")]
+    #[test]
+    fn hash_and_format_redb() {
+        use redb::Value as RedbValue;
+        let hash_bytes: [u8; 32] = (0..32).collect::<Vec<_>>().as_slice().try_into().unwrap();
+        let hash = Hash::from(hash_bytes);
+        let haf = HashAndFormat::raw(hash);
+        assert_eq!(<HashAndFormat as RedbValue>::fixed_width(), Some(33));
+        assert_eq!(
+            <HashAndFormat as RedbValue>::type_name(),
+            redb::TypeName::new("iroh_base::HashAndFormat")
+        );
+        let serialized = <HashAndFormat as RedbValue>::as_bytes(&haf);
+        let mut bytes = [0u8; 33];
+        bytes[0..32].copy_from_slice(&hash_bytes);
+        assert_eq!(serialized, bytes);
+        let deserialized = <HashAndFormat as RedbValue>::from_bytes(serialized.as_slice());
+        assert_eq!(deserialized, haf);
+        let expected = parse_hexdump(
+            r"
+            00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+            10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f # hash
+            00 # format (raw)
+        ",
+        )
+        .unwrap();
+        assert_eq_hex!(serialized, expected);
+    }
+
+    #[test]
+    fn test_hash_serde() {
+        let hash = Hash::new("hello");
+
+        // Hashes are serialized as 32 tuples
+        let mut tokens = Vec::new();
+        tokens.push(Token::Tuple { len: 32 });
+        for byte in hash.as_bytes() {
+            tokens.push(Token::U8(*byte));
+        }
+        tokens.push(Token::TupleEnd);
+        assert_eq!(tokens.len(), 34);
+
+        assert_tokens(&hash.compact(), &tokens);
+
+        let tokens = vec![Token::String(
+            "5khrmpntq2bjexseshc6ldklwnig56gbj23yvbxjbdcwestheahq",
+        )];
+        assert_tokens(&hash.readable(), &tokens);
+    }
+
+    #[test]
+    fn test_hash_postcard() {
+        let hash = Hash::new("hello");
+        let ser = postcard::to_stdvec(&hash).unwrap();
+        let de = postcard::from_bytes(&ser).unwrap();
+        assert_eq!(hash, de);
+
+        assert_eq!(ser.len(), 32);
+    }
+
+    #[test]
+    fn test_hash_json() {
+        let hash = Hash::new("hello");
+        let ser = serde_json::to_string(&hash).unwrap();
+        let de = serde_json::from_str(&ser).unwrap();
+        assert_eq!(hash, de);
+        // 52 bytes of base32 + 2 quotes
+        assert_eq!(ser.len(), 54);
+    }
+
+    #[test]
+    fn test_hash_and_format_parse() {
+        let hash = Hash::new("hello");
+
+        let expected = HashAndFormat::raw(hash);
+        let actual = expected.to_string().parse::<HashAndFormat>().unwrap();
+        assert_eq!(expected, actual);
+
+        let expected = HashAndFormat::hash_seq(hash);
+        let actual = expected.to_string().parse::<HashAndFormat>().unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_hash_and_format_postcard() {
+        let haf = HashAndFormat::raw(Hash::new("hello"));
+        let ser = postcard::to_stdvec(&haf).unwrap();
+        let de = postcard::from_bytes(&ser).unwrap();
+        assert_eq!(haf, de);
+    }
+
+    #[test]
+    fn test_hash_and_format_json() {
+        let haf = HashAndFormat::raw(Hash::new("hello"));
+        let ser = serde_json::to_string(&haf).unwrap();
+        let de = serde_json::from_str(&ser).unwrap();
+        assert_eq!(haf, de);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/key.rs.html b/pr/2992/docs/src/iroh_base/key.rs.html new file mode 100644 index 0000000000..bf8b0fdc69 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/key.rs.html @@ -0,0 +1,1003 @@ +key.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+
//! Cryptographic key handling for `iroh`.
+
+mod encryption;
+
+use std::{
+    fmt::{Debug, Display},
+    hash::Hash,
+    str::FromStr,
+    sync::Mutex,
+    time::Duration,
+};
+
+pub use ed25519_dalek::{Signature, PUBLIC_KEY_LENGTH};
+use ed25519_dalek::{SignatureError, SigningKey, VerifyingKey};
+use once_cell::sync::OnceCell;
+use rand_core::CryptoRngCore;
+use serde::{Deserialize, Serialize};
+use ssh_key::LineEnding;
+use ttl_cache::TtlCache;
+
+pub use self::encryption::SharedSecret;
+use self::encryption::{public_ed_box, secret_ed_box};
+use crate::base32::{self, HexOrBase32ParseError};
+
+#[derive(Debug)]
+struct CryptoKeys {
+    verifying_key: VerifyingKey,
+    crypto_box: crypto_box::PublicKey,
+}
+
+impl CryptoKeys {
+    fn new(verifying_key: VerifyingKey) -> Self {
+        let crypto_box = public_ed_box(&verifying_key);
+        Self {
+            verifying_key,
+            crypto_box,
+        }
+    }
+}
+
+/// Expiry time for the crypto key cache.
+///
+/// Basically, if no crypto operations have been performed with a key for this
+/// duration, the crypto keys will be removed from the cache and need to be
+/// re-created when they are used again.
+const KEY_CACHE_TTL: Duration = Duration::from_secs(60);
+/// Maximum number of keys in the crypto key cache. CryptoKeys are 224 bytes,
+/// keys are 32 bytes, so each entry is 256 bytes plus some overhead.
+///
+/// So that is about 4MB of max memory for the cache.
+const KEY_CACHE_CAPACITY: usize = 1024 * 16;
+static KEY_CACHE: OnceCell<Mutex<TtlCache<[u8; 32], CryptoKeys>>> = OnceCell::new();
+
+fn lock_key_cache() -> std::sync::MutexGuard<'static, TtlCache<[u8; 32], CryptoKeys>> {
+    let mutex = KEY_CACHE.get_or_init(|| Mutex::new(TtlCache::new(KEY_CACHE_CAPACITY)));
+    mutex.lock().expect("not poisoned")
+}
+
+/// Get or create the crypto keys, and project something out of them.
+///
+/// If the key has been verified before, this will not fail.
+fn get_or_create_crypto_keys<T>(
+    key: &[u8; 32],
+    f: impl Fn(&CryptoKeys) -> T,
+) -> std::result::Result<T, SignatureError> {
+    let mut state = lock_key_cache();
+    Ok(match state.entry(*key) {
+        ttl_cache::Entry::Occupied(entry) => {
+            // cache hit
+            f(entry.get())
+        }
+        ttl_cache::Entry::Vacant(entry) => {
+            // cache miss, create. This might fail if the key is invalid.
+            let vk = VerifyingKey::from_bytes(key)?;
+            let item = CryptoKeys::new(vk);
+            let item = entry.insert(item, KEY_CACHE_TTL);
+            f(item)
+        }
+    })
+}
+
+/// A public key.
+///
+/// The key itself is just a 32 byte array, but a key has associated crypto
+/// information that is cached for performance reasons.
+///
+/// The cache item will be refreshed every time a crypto operation is performed,
+/// or when a key is deserialised or created from a byte array.
+///
+/// Serialisation or creation from a byte array is cheap if the key is already
+/// in the cache, but expensive if it is not.
+#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
+pub struct PublicKey([u8; 32]);
+
+/// The identifier for a node in the (iroh) network.
+///
+/// Each node in iroh has a unique identifier created as a cryptographic key.  This can be
+/// used to globally identify a node.  Since it is also a cryptographic key it is also the
+/// mechanism by which all traffic is always encrypted for a specific node only.
+///
+/// This is equivalent to [`PublicKey`].  By convention we will (or should) use `PublicKey`
+/// as type name when performing cryptographic operations, but use `NodeId` when referencing
+/// a node.  E.g.:
+///
+/// - `encrypt(key: PublicKey)`
+/// - `send_to(node: NodeId)`
+pub type NodeId = PublicKey;
+
+impl Hash for PublicKey {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+impl Serialize for PublicKey {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        if serializer.is_human_readable() {
+            serializer.serialize_str(&self.to_string())
+        } else {
+            self.0.serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for PublicKey {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        if deserializer.is_human_readable() {
+            let s = String::deserialize(deserializer)?;
+            Self::from_str(&s).map_err(serde::de::Error::custom)
+        } else {
+            let data: [u8; 32] = serde::Deserialize::deserialize(deserializer)?;
+            Self::try_from(data.as_ref()).map_err(serde::de::Error::custom)
+        }
+    }
+}
+
+impl PublicKey {
+    /// Get this public key as a byte array.
+    pub fn as_bytes(&self) -> &[u8; 32] {
+        &self.0
+    }
+
+    fn public(&self) -> VerifyingKey {
+        get_or_create_crypto_keys(&self.0, |item| item.verifying_key).expect("key has been checked")
+    }
+
+    fn public_crypto_box(&self) -> crypto_box::PublicKey {
+        get_or_create_crypto_keys(&self.0, |item| item.crypto_box.clone())
+            .expect("key has been checked")
+    }
+
+    /// Construct a `PublicKey` from a slice of bytes.
+    ///
+    /// # Warning
+    ///
+    /// This will return a [`SignatureError`] if the bytes passed into this method do not represent
+    /// a valid `ed25519_dalek` curve point. Will never fail for bytes return from [`Self::as_bytes`].
+    /// See [`VerifyingKey::from_bytes`] for details.
+    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError> {
+        get_or_create_crypto_keys(bytes, |item| item.verifying_key)?;
+        Ok(Self(*bytes))
+    }
+
+    /// Verify a signature on a message with this secret key's public key.
+    ///
+    /// # Return
+    ///
+    /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
+    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
+        self.public().verify_strict(message, signature)
+    }
+
+    /// Convert to a base32 string limited to the first 10 bytes for a friendly string
+    /// representation of the key.
+    pub fn fmt_short(&self) -> String {
+        base32::fmt_short(self.as_bytes())
+    }
+}
+
+impl TryFrom<&[u8]> for PublicKey {
+    type Error = SignatureError;
+
+    #[inline]
+    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
+        Ok(match <[u8; 32]>::try_from(bytes) {
+            Ok(bytes) => {
+                // using from_bytes is faster than going via the verifying
+                // key in case the key is already in the cache, which should
+                // be quite common.
+                Self::from_bytes(&bytes)?
+            }
+            Err(_) => {
+                // this will always fail since the size is wrong.
+                // but there is no public constructor for SignatureError,
+                // so ¯\_(ツ)_/¯...
+                let vk = VerifyingKey::try_from(bytes)?;
+                vk.into()
+            }
+        })
+    }
+}
+
+impl TryFrom<&[u8; 32]> for PublicKey {
+    type Error = SignatureError;
+
+    #[inline]
+    fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
+        Self::from_bytes(bytes)
+    }
+}
+
+impl AsRef<[u8]> for PublicKey {
+    fn as_ref(&self) -> &[u8] {
+        self.as_bytes()
+    }
+}
+
+impl From<VerifyingKey> for PublicKey {
+    fn from(verifying_key: VerifyingKey) -> Self {
+        let item = CryptoKeys::new(verifying_key);
+        let key = *verifying_key.as_bytes();
+        let mut table = lock_key_cache();
+        // we already have performed the crypto operation, so no need for
+        // get_or_create_crypto_keys. Just insert in any case.
+        table.insert(key, item, KEY_CACHE_TTL);
+        PublicKey(key)
+    }
+}
+
+impl Debug for PublicKey {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "PublicKey({})", base32::fmt_short(self.as_bytes()))
+    }
+}
+
+impl Display for PublicKey {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if f.alternate() {
+            write!(f, "{}", base32::fmt_short(self.as_bytes()))
+        } else {
+            write!(f, "{}", base32::fmt(self.as_bytes()))
+        }
+    }
+}
+
+/// Error when deserialising a [`PublicKey`] or a [`SecretKey`].
+#[derive(thiserror::Error, Debug)]
+pub enum KeyParsingError {
+    /// Error when decoding the base32.
+    #[error("decoding: {0}")]
+    Base32(#[from] HexOrBase32ParseError),
+    /// Error when decoding the public key.
+    #[error("key: {0}")]
+    Key(#[from] ed25519_dalek::SignatureError),
+}
+
+/// Deserialises the [`PublicKey`] from it's base32 encoding.
+///
+/// [`Display`] is capable of serialising this format.
+impl FromStr for PublicKey {
+    type Err = KeyParsingError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let bytes = base32::parse_array_hex_or_base32::<32>(s)?;
+        Ok(Self::try_from(bytes.as_ref())?)
+    }
+}
+
+/// A secret key.
+#[derive(Clone)]
+pub struct SecretKey {
+    secret: SigningKey,
+    secret_crypto_box: OnceCell<crypto_box::SecretKey>,
+}
+
+impl Debug for SecretKey {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "SecretKey({})", base32::fmt_short(self.to_bytes()))
+    }
+}
+
+impl Display for SecretKey {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", base32::fmt(self.to_bytes()))
+    }
+}
+
+impl FromStr for SecretKey {
+    type Err = KeyParsingError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(SecretKey::from(base32::parse_array_hex_or_base32::<32>(s)?))
+    }
+}
+
+impl Serialize for SecretKey {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        self.secret.serialize(serializer)
+    }
+}
+
+impl<'de> Deserialize<'de> for SecretKey {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        let secret = SigningKey::deserialize(deserializer)?;
+        Ok(secret.into())
+    }
+}
+
+impl SecretKey {
+    /// The public key of this [`SecretKey`].
+    pub fn public(&self) -> PublicKey {
+        self.secret.verifying_key().into()
+    }
+
+    /// Generate a new [`SecretKey`] with the default randomness generator.
+    pub fn generate() -> Self {
+        let mut rng = rand::rngs::OsRng;
+        Self::generate_with_rng(&mut rng)
+    }
+
+    /// Generate a new [`SecretKey`] with a randomness generator.
+    pub fn generate_with_rng<R: CryptoRngCore + ?Sized>(csprng: &mut R) -> Self {
+        let secret = SigningKey::generate(csprng);
+
+        Self {
+            secret,
+            secret_crypto_box: OnceCell::default(),
+        }
+    }
+
+    /// Serialise this key to OpenSSH format.
+    pub fn to_openssh(&self) -> ssh_key::Result<zeroize::Zeroizing<String>> {
+        let ckey = ssh_key::private::Ed25519Keypair {
+            public: self.secret.verifying_key().into(),
+            private: self.secret.clone().into(),
+        };
+        ssh_key::private::PrivateKey::from(ckey).to_openssh(LineEnding::default())
+    }
+
+    /// Deserialise this key from OpenSSH format.
+    pub fn try_from_openssh<T: AsRef<[u8]>>(data: T) -> anyhow::Result<Self> {
+        let ser_key = ssh_key::private::PrivateKey::from_openssh(data)?;
+        match ser_key.key_data() {
+            ssh_key::private::KeypairData::Ed25519(kp) => Ok(SecretKey {
+                secret: kp.private.clone().into(),
+                secret_crypto_box: OnceCell::default(),
+            }),
+            _ => anyhow::bail!("invalid key format"),
+        }
+    }
+
+    /// Sign the given message and return a digital signature
+    pub fn sign(&self, msg: &[u8]) -> Signature {
+        use ed25519_dalek::Signer;
+
+        self.secret.sign(msg)
+    }
+
+    /// Convert this to the bytes representing the secret part.
+    /// The public part can always be recovered.
+    pub fn to_bytes(&self) -> [u8; 32] {
+        self.secret.to_bytes()
+    }
+
+    /// Create a secret key from its byte representation.
+    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
+        let secret = SigningKey::from_bytes(bytes);
+        secret.into()
+    }
+
+    fn secret_crypto_box(&self) -> &crypto_box::SecretKey {
+        self.secret_crypto_box
+            .get_or_init(|| secret_ed_box(&self.secret))
+    }
+}
+
+impl From<SigningKey> for SecretKey {
+    fn from(secret: SigningKey) -> Self {
+        SecretKey {
+            secret,
+            secret_crypto_box: OnceCell::default(),
+        }
+    }
+}
+
+impl From<[u8; 32]> for SecretKey {
+    fn from(value: [u8; 32]) -> Self {
+        Self::from_bytes(&value)
+    }
+}
+
+impl TryFrom<&[u8]> for SecretKey {
+    type Error = SignatureError;
+
+    #[inline]
+    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
+        let secret = SigningKey::try_from(bytes)?;
+        Ok(secret.into())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};
+
+    use super::*;
+
+    #[test]
+    fn test_public_key_postcard() {
+        let public_key =
+            PublicKey::from_str("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
+                .unwrap();
+        let bytes = postcard::to_stdvec(&public_key).unwrap();
+        let expected =
+            parse_hexdump("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
+                .unwrap();
+        assert_eq_hex!(bytes, expected);
+    }
+
+    #[test]
+    fn test_secret_key_openssh_roundtrip() {
+        let kp = SecretKey::generate();
+        let ser = kp.to_openssh().unwrap();
+        let de = SecretKey::try_from_openssh(&ser).unwrap();
+        assert_eq!(kp.to_bytes(), de.to_bytes());
+    }
+
+    #[test]
+    fn public_key_postcard() {
+        let key = PublicKey::from_bytes(&[0; 32]).unwrap();
+        let bytes = postcard::to_stdvec(&key).unwrap();
+        let key2: PublicKey = postcard::from_bytes(&bytes).unwrap();
+        assert_eq!(key, key2);
+    }
+
+    #[test]
+    fn public_key_json() {
+        let key = PublicKey::from_bytes(&[0; 32]).unwrap();
+        let bytes = serde_json::to_string(&key).unwrap();
+        let key2: PublicKey = serde_json::from_str(&bytes).unwrap();
+        assert_eq!(key, key2);
+    }
+
+    #[test]
+    fn test_display_from_str() {
+        let key = SecretKey::generate();
+        assert_eq!(
+            SecretKey::from_str(&key.to_string()).unwrap().to_bytes(),
+            key.to_bytes()
+        );
+
+        assert_eq!(
+            PublicKey::from_str(&key.public().to_string()).unwrap(),
+            key.public()
+        );
+    }
+
+    /// Test the different ways a key can come into existence, and that they
+    /// all populate the key cache.
+    #[test]
+    fn test_key_creation_cache() {
+        let random_verifying_key = || {
+            let sk = SigningKey::generate(&mut rand::thread_rng());
+            sk.verifying_key()
+        };
+        let random_public_key = || random_verifying_key().to_bytes();
+        let k1 = random_public_key();
+        let _key = PublicKey::from_bytes(&k1).unwrap();
+        assert!(lock_key_cache().contains_key(&k1));
+
+        let k2 = random_public_key();
+        let _key = PublicKey::try_from(&k2).unwrap();
+        assert!(lock_key_cache().contains_key(&k2));
+
+        let k3 = random_public_key();
+        let _key = PublicKey::try_from(k3.as_slice()).unwrap();
+        assert!(lock_key_cache().contains_key(&k3));
+
+        let k4 = random_verifying_key();
+        let _key = PublicKey::from(k4);
+        assert!(lock_key_cache().contains_key(k4.as_bytes()));
+
+        let k5 = random_verifying_key();
+        let bytes = postcard::to_stdvec(&k5).unwrap();
+        // VerifyingKey serialises with a length prefix, PublicKey does not.
+        let _key: PublicKey = postcard::from_bytes(&bytes[1..]).unwrap();
+        assert!(lock_key_cache().contains_key(k5.as_bytes()));
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/key/encryption.rs.html b/pr/2992/docs/src/iroh_base/key/encryption.rs.html new file mode 100644 index 0000000000..2f04f900bc --- /dev/null +++ b/pr/2992/docs/src/iroh_base/key/encryption.rs.html @@ -0,0 +1,265 @@ +encryption.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+
//! The private and public keys of a node.
+
+use std::fmt::Debug;
+
+use aead::Buffer;
+use anyhow::{anyhow, ensure, Context, Result};
+
+pub(crate) const NONCE_LEN: usize = 24;
+
+pub(super) fn public_ed_box(key: &ed25519_dalek::VerifyingKey) -> crypto_box::PublicKey {
+    crypto_box::PublicKey::from(key.to_montgomery())
+}
+
+pub(super) fn secret_ed_box(key: &ed25519_dalek::SigningKey) -> crypto_box::SecretKey {
+    crypto_box::SecretKey::from(key.to_scalar())
+}
+
+/// Shared Secret.
+pub struct SharedSecret(crypto_box::ChaChaBox);
+
+impl Debug for SharedSecret {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "SharedSecret(crypto_box::ChaChaBox)")
+    }
+}
+
+impl SharedSecret {
+    fn new(this: &crypto_box::SecretKey, other: &crypto_box::PublicKey) -> Self {
+        SharedSecret(crypto_box::ChaChaBox::new(other, this))
+    }
+
+    /// Seals the provided cleartext.
+    pub fn seal(&self, buffer: &mut dyn Buffer) {
+        use aead::{AeadCore, AeadInPlace, OsRng};
+
+        let nonce = crypto_box::ChaChaBox::generate_nonce(&mut OsRng);
+        self.0
+            .encrypt_in_place(&nonce, &[], buffer)
+            .expect("encryption failed");
+
+        buffer.extend_from_slice(&nonce).expect("buffer too small");
+    }
+
+    /// Opens the ciphertext, which must have been created using `Self::seal`, and places the clear text into the provided buffer.
+    pub fn open(&self, buffer: &mut dyn Buffer) -> Result<()> {
+        use aead::AeadInPlace;
+        ensure!(buffer.len() > NONCE_LEN, "too short");
+
+        let offset = buffer.len() - NONCE_LEN;
+        let nonce: [u8; NONCE_LEN] = buffer.as_ref()[offset..]
+            .try_into()
+            .context("nonce wrong length")?;
+
+        buffer.truncate(offset);
+        self.0
+            .decrypt_in_place(&nonce.into(), &[], buffer)
+            .map_err(|e| anyhow!("decryption failed: {:?}", e))?;
+
+        Ok(())
+    }
+}
+
+impl crate::key::SecretKey {
+    /// Returns the shared key for communication between this key and `other`.
+    pub fn shared(&self, other: &crate::key::PublicKey) -> SharedSecret {
+        let secret_key = self.secret_crypto_box();
+        let public_key = other.public_crypto_box();
+
+        SharedSecret::new(secret_key, &public_key)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_seal_open_roundtrip() {
+        let key_a = crate::key::SecretKey::generate();
+        let key_b = crate::key::SecretKey::generate();
+
+        seal_open_roundtrip(&key_a, &key_b);
+        seal_open_roundtrip(&key_b, &key_a);
+        seal_open_roundtrip(&key_a, &key_a);
+    }
+
+    fn seal_open_roundtrip(key_a: &crate::key::SecretKey, key_b: &crate::key::SecretKey) {
+        let msg = b"super secret message!!!!".to_vec();
+        let shared_a = key_a.shared(&key_b.public());
+        let mut sealed_message = msg.clone();
+        shared_a.seal(&mut sealed_message);
+        let shared_b = key_b.shared(&key_a.public());
+        let mut decrypted_message = sealed_message.clone();
+        shared_b.open(&mut decrypted_message).unwrap();
+        assert_eq!(&msg[..], &decrypted_message);
+    }
+
+    #[test]
+    fn test_roundtrip_public_key() {
+        let key = crypto_box::SecretKey::generate(&mut rand::thread_rng());
+        let public_bytes = *key.public_key().as_bytes();
+        let public_key_back = crypto_box::PublicKey::from(public_bytes);
+        assert_eq!(key.public_key(), public_key_back);
+    }
+
+    #[test]
+    fn test_same_public_key_api() {
+        let key = crate::key::SecretKey::generate();
+        let public_key1: crypto_box::PublicKey = public_ed_box(&key.public().public());
+        let public_key2: crypto_box::PublicKey = secret_ed_box(&key.secret).public_key();
+
+        assert_eq!(public_key1, public_key2);
+    }
+
+    #[test]
+    fn test_same_public_key_low_level() {
+        let mut rng = rand::thread_rng();
+        let key = ed25519_dalek::SigningKey::generate(&mut rng);
+        let public_key1 = {
+            let m = key.verifying_key().to_montgomery();
+            crypto_box::PublicKey::from(m)
+        };
+
+        let public_key2 = {
+            let s = key.to_scalar();
+            let cs = crypto_box::SecretKey::from(s);
+            cs.public_key()
+        };
+
+        assert_eq!(public_key1, public_key2);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/lib.rs.html b/pr/2992/docs/src/iroh_base/lib.rs.html new file mode 100644 index 0000000000..81c222edfc --- /dev/null +++ b/pr/2992/docs/src/iroh_base/lib.rs.html @@ -0,0 +1,47 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+
//! Base types and utilities for Iroh
+#![cfg_attr(iroh_docsrs, feature(doc_cfg))]
+
+#[cfg(feature = "base32")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "base32")))]
+pub mod base32;
+#[cfg(feature = "hash")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "hash")))]
+pub mod hash;
+#[cfg(feature = "key")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
+pub mod key;
+#[cfg(feature = "key")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
+pub mod node_addr;
+#[cfg(feature = "relay")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "relay")))]
+pub mod relay_map;
+#[cfg(any(feature = "relay", feature = "key"))]
+mod relay_url;
+#[cfg(feature = "base32")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "base32")))]
+pub mod ticket;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/node_addr.rs.html b/pr/2992/docs/src/iroh_base/node_addr.rs.html new file mode 100644 index 0000000000..f5733b906a --- /dev/null +++ b/pr/2992/docs/src/iroh_base/node_addr.rs.html @@ -0,0 +1,401 @@ +node_addr.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+
//! Addressing for iroh nodes.
+//!
+//! This module contains some common addressing types for iroh.  A node is uniquely
+//! identified by the [`NodeId`] but that does not make it addressable on the network layer.
+//! For this the addition of a [`RelayUrl`] and/or direct addresses are required.
+//!
+//! The primary way of addressing a node is by using the [`NodeAddr`].
+
+use std::{collections::BTreeSet, net::SocketAddr};
+
+use serde::{Deserialize, Serialize};
+
+use crate::key::{NodeId, PublicKey};
+pub use crate::relay_url::RelayUrl;
+
+/// Network-level addressing information for an iroh node.
+///
+/// This combines a node's identifier with network-level addressing information of how to
+/// contact the node.
+///
+/// To establish a network connection to a node both the [`NodeId`] and one or more network
+/// paths are needed.  The network paths can come from various sources:
+///
+/// - A [discovery] service which can provide routing information for a given [`NodeId`].
+///
+/// - A [`RelayUrl`] of the node's [home relay], this allows establishing the connection via
+///   the Relay server and is very reliable.
+///
+/// - One or more *direct addresses* on which the node might be reachable.  Depending on the
+///   network location of both nodes it might not be possible to establish a direct
+///   connection without the help of a [Relay server].
+///
+/// This structure will always contain the required [`NodeId`] and will contain an optional
+/// number of network-level addressing information.  It is a generic addressing type used
+/// whenever a connection to other nodes needs to be established.
+///
+/// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery
+/// [home relay]: https://docs.rs/iroh/*/iroh/relay/index.html
+/// [Relay server]: https://docs.rs/iroh/*/iroh/index.html#relay-servers
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
+pub struct NodeAddr {
+    /// The node's identifier.
+    pub node_id: NodeId,
+    /// Addressing information to connect to [`Self::node_id`].
+    pub info: AddrInfo,
+}
+
+impl NodeAddr {
+    /// Creates a new [`NodeAddr`] with empty [`AddrInfo`].
+    pub fn new(node_id: PublicKey) -> Self {
+        NodeAddr {
+            node_id,
+            info: Default::default(),
+        }
+    }
+
+    /// Adds a relay url to the node's [`AddrInfo`].
+    pub fn with_relay_url(mut self, relay_url: RelayUrl) -> Self {
+        self.info.relay_url = Some(relay_url);
+        self
+    }
+
+    /// Adds the given direct addresses to the peer's [`AddrInfo`].
+    pub fn with_direct_addresses(
+        mut self,
+        addresses: impl IntoIterator<Item = SocketAddr>,
+    ) -> Self {
+        self.info.direct_addresses = addresses.into_iter().collect();
+        self
+    }
+
+    /// Creates a new [`NodeAddr`] from its parts.
+    pub fn from_parts(
+        node_id: PublicKey,
+        relay_url: Option<RelayUrl>,
+        direct_addresses: impl IntoIterator<Item = SocketAddr>,
+    ) -> Self {
+        Self {
+            node_id,
+            info: AddrInfo {
+                relay_url,
+                direct_addresses: direct_addresses.into_iter().collect(),
+            },
+        }
+    }
+
+    /// Applies the options to `self`.
+    ///
+    /// This is used to more tightly control the information stored in a [`NodeAddr`]
+    /// received from another API.  E.g. to ensure a [discovery] service is used the
+    /// `AddrInfoOptions::Id`] option could be used to remove all other addressing details.
+    ///
+    /// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery
+    pub fn apply_options(&mut self, opts: AddrInfoOptions) {
+        self.info.apply_options(opts);
+    }
+
+    /// Returns the direct addresses of this peer.
+    pub fn direct_addresses(&self) -> impl Iterator<Item = &SocketAddr> {
+        self.info.direct_addresses.iter()
+    }
+
+    /// Returns the relay url of this peer.
+    pub fn relay_url(&self) -> Option<&RelayUrl> {
+        self.info.relay_url.as_ref()
+    }
+}
+
+impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for NodeAddr {
+    fn from(value: (PublicKey, Option<RelayUrl>, &[SocketAddr])) -> Self {
+        let (node_id, relay_url, direct_addresses_iter) = value;
+        NodeAddr {
+            node_id,
+            info: AddrInfo {
+                relay_url,
+                direct_addresses: direct_addresses_iter.iter().copied().collect(),
+            },
+        }
+    }
+}
+
+impl From<NodeId> for NodeAddr {
+    fn from(node_id: NodeId) -> Self {
+        NodeAddr::new(node_id)
+    }
+}
+
+/// Network paths to contact an iroh node.
+///
+/// This contains zero or more network paths to establish a connection to an iroh node.
+/// Unless a [discovery service] is used at least one path is required to connect to an
+/// other node, see [`NodeAddr`] for details.
+///
+/// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default, PartialOrd, Ord)]
+pub struct AddrInfo {
+    /// The node's home relay url.
+    pub relay_url: Option<RelayUrl>,
+    /// Socket addresses where the peer might be reached directly.
+    pub direct_addresses: BTreeSet<SocketAddr>,
+}
+
+impl AddrInfo {
+    /// Returns whether this addressing information is empty.
+    pub fn is_empty(&self) -> bool {
+        self.relay_url.is_none() && self.direct_addresses.is_empty()
+    }
+
+    /// Applies the options to `self`.
+    ///
+    /// This is used to more tightly control the information stored in ab [`AddrInfo`]
+    /// received from another API.  E.g. to ensure a [discovery] service is used the
+    /// `AddrInfoOptions::Id`] option could be used to remove all other addressing details.
+    ///
+    /// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery
+    pub fn apply_options(&mut self, opts: AddrInfoOptions) {
+        match opts {
+            AddrInfoOptions::Id => {
+                self.direct_addresses.clear();
+                self.relay_url = None;
+            }
+            AddrInfoOptions::RelayAndAddresses => {
+                // nothing to do
+            }
+            AddrInfoOptions::Relay => {
+                self.direct_addresses.clear();
+            }
+            AddrInfoOptions::Addresses => {
+                self.relay_url = None;
+            }
+        }
+    }
+}
+
+/// Options to configure what is included in a [`NodeAddr`] and [`AddrInfo`].
+#[derive(
+    Copy,
+    Clone,
+    PartialEq,
+    Eq,
+    Default,
+    Debug,
+    derive_more::Display,
+    derive_more::FromStr,
+    Serialize,
+    Deserialize,
+)]
+pub enum AddrInfoOptions {
+    /// Only the Node ID is added.
+    ///
+    /// This usually means that iroh-dns discovery is used to find address information.
+    #[default]
+    Id,
+    /// Includes the Node ID and both the relay URL, and the direct addresses.
+    RelayAndAddresses,
+    /// Includes the Node ID and the relay URL.
+    Relay,
+    /// Includes the Node ID and the direct addresses.
+    Addresses,
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/relay_map.rs.html b/pr/2992/docs/src/iroh_base/relay_map.rs.html new file mode 100644 index 0000000000..01f85c78b3 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/relay_map.rs.html @@ -0,0 +1,335 @@ +relay_map.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+
//! based on tailscale/tailcfg/derpmap.go
+
+use std::{collections::BTreeMap, fmt, sync::Arc};
+
+use anyhow::{ensure, Result};
+use serde::{Deserialize, Serialize};
+
+pub use crate::relay_url::RelayUrl;
+
+/// The default STUN port used by the Relay server.
+///
+/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
+pub const DEFAULT_STUN_PORT: u16 = 3478;
+
+/// The default QUIC port used by the Relay server to accept QUIC connections
+/// for QUIC address discovery
+///
+/// The port is "QUIC" typed on a phone keypad.
+pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842;
+
+/// Configuration of all the relay servers that can be used.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct RelayMap {
+    /// A map of the different relay IDs to the [`RelayNode`] information
+    nodes: Arc<BTreeMap<RelayUrl, Arc<RelayNode>>>,
+}
+
+impl RelayMap {
+    /// Returns the sorted relay URLs.
+    pub fn urls(&self) -> impl Iterator<Item = &RelayUrl> {
+        self.nodes.keys()
+    }
+
+    /// Create an empty relay map.
+    pub fn empty() -> Self {
+        Self {
+            nodes: Default::default(),
+        }
+    }
+
+    /// Returns an `Iterator` over all known nodes.
+    pub fn nodes(&self) -> impl Iterator<Item = &Arc<RelayNode>> {
+        self.nodes.values()
+    }
+
+    /// Is this a known node?
+    pub fn contains_node(&self, url: &RelayUrl) -> bool {
+        self.nodes.contains_key(url)
+    }
+
+    /// Get the given node.
+    pub fn get_node(&self, url: &RelayUrl) -> Option<&Arc<RelayNode>> {
+        self.nodes.get(url)
+    }
+
+    /// How many nodes are known?
+    pub fn len(&self) -> usize {
+        self.nodes.len()
+    }
+
+    /// Are there any nodes in this map?
+    pub fn is_empty(&self) -> bool {
+        self.nodes.is_empty()
+    }
+
+    /// Creates a new [`RelayMap`] with a single relay server configured.
+    ///
+    /// Allows to set a custom STUN port and different IP addresses for IPv4 and IPv6.
+    /// If IP addresses are provided, no DNS lookup will be performed.
+    ///
+    /// Sets the port to the default [`DEFAULT_RELAY_QUIC_PORT`].
+    pub fn default_from_node(url: RelayUrl, stun_port: u16) -> Self {
+        let mut nodes = BTreeMap::new();
+        nodes.insert(
+            url.clone(),
+            RelayNode {
+                url,
+                stun_only: false,
+                stun_port,
+                quic: Some(QuicConfig::default()),
+            }
+            .into(),
+        );
+
+        RelayMap {
+            nodes: Arc::new(nodes),
+        }
+    }
+
+    /// Returns a [`RelayMap`] from a [`RelayUrl`].
+    ///
+    /// This will use the default STUN port, the default QUIC port
+    /// (as defined by the `iroh-relay` crate) and IP addresses
+    /// resolved from the URL's host name via DNS.
+    /// relay nodes are specified at <../../docs/relay_nodes.md>
+    pub fn from_url(url: RelayUrl) -> Self {
+        Self::default_from_node(url, DEFAULT_STUN_PORT)
+    }
+
+    /// Constructs the [`RelayMap`] from an iterator of [`RelayNode`]s.
+    pub fn from_nodes<I: Into<Arc<RelayNode>>>(value: impl IntoIterator<Item = I>) -> Result<Self> {
+        let mut map = BTreeMap::new();
+        for node in value.into_iter() {
+            let node = node.into();
+            ensure!(!map.contains_key(&node.url), "Duplicate node url");
+            map.insert(node.url.clone(), node);
+        }
+        Ok(RelayMap { nodes: map.into() })
+    }
+}
+
+impl fmt::Display for RelayMap {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self, f)
+    }
+}
+
+/// Information on a specific relay server.
+///
+/// Includes the Url where it can be dialed.
+// Please note that this is documented in the `iroh.computer` repository under
+// `src/app/docs/reference/config/page.mdx`.  Any changes to this need to be updated there.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
+pub struct RelayNode {
+    /// The [`RelayUrl`] where this relay server can be dialed.
+    pub url: RelayUrl,
+    /// Whether this relay server should only be used for STUN requests.
+    ///
+    /// This essentially allows you to use a normal STUN server as a relay node, no relay
+    /// functionality is used.
+    pub stun_only: bool,
+    /// The stun port of the relay server.
+    ///
+    /// Setting this to `0` means the default STUN port is used.
+    pub stun_port: u16,
+    /// Configuration to speak to the QUIC endpoint on the relay server.
+    ///
+    /// When `None`, we will not attempt to do QUIC address discovery
+    /// with this relay server.
+    #[serde(default = "quic_config")]
+    pub quic: Option<QuicConfig>,
+}
+
+fn quic_config() -> Option<QuicConfig> {
+    Some(QuicConfig::default())
+}
+
+/// Configuration for speaking to the QUIC endpoint on the relay
+/// server to do QUIC address discovery.
+#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
+pub struct QuicConfig {
+    pub port: u16,
+}
+
+impl Default for QuicConfig {
+    fn default() -> Self {
+        Self {
+            port: DEFAULT_RELAY_QUIC_PORT,
+        }
+    }
+}
+
+impl fmt::Display for RelayNode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.url)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/relay_url.rs.html b/pr/2992/docs/src/iroh_base/relay_url.rs.html new file mode 100644 index 0000000000..6e216f722f --- /dev/null +++ b/pr/2992/docs/src/iroh_base/relay_url.rs.html @@ -0,0 +1,243 @@ +relay_url.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+
use std::{fmt, ops::Deref, str::FromStr};
+
+use anyhow::Context;
+use serde::{Deserialize, Serialize};
+use url::Url;
+/// A URL identifying a relay server.
+///
+/// This is but a wrapper around [`Url`], with a few custom tweaks:
+///
+/// - A relay URL is never a relative URL, so an implicit `.` is added at the end of the
+///   domain name if missing.
+///
+/// - [`fmt::Debug`] is implemented so it prints the URL rather than the URL struct fields.
+///   Useful when logging e.g. `Option<RelayUrl>`.
+///
+/// To create a [`RelayUrl`] use the `From<Url>` implementation.
+#[derive(
+    Clone, derive_more::Display, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
+)]
+pub struct RelayUrl(Url);
+
+impl From<Url> for RelayUrl {
+    fn from(mut url: Url) -> Self {
+        if let Some(domain) = url.domain() {
+            if !domain.ends_with('.') {
+                let domain = String::from(domain) + ".";
+
+                // This can fail, though it is unlikely the resulting URL is usable as a
+                // relay URL, probably it has the wrong scheme or is not a base URL or the
+                // like.  We don't do full URL validation however, so just silently leave
+                // this bad URL in place.  Something will fail later.
+                url.set_host(Some(&domain)).ok();
+            }
+        }
+        Self(url)
+    }
+}
+
+/// Support for parsing strings directly.
+///
+/// If you need more control over the error first create a [`Url`] and use [`RelayUrl::from`]
+/// instead.
+impl FromStr for RelayUrl {
+    type Err = anyhow::Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let inner = Url::from_str(s).context("invalid URL")?;
+        Ok(RelayUrl::from(inner))
+    }
+}
+
+impl From<RelayUrl> for Url {
+    fn from(value: RelayUrl) -> Self {
+        value.0
+    }
+}
+
+/// Dereferences to the wrapped [`Url`].
+///
+/// Note that [`DerefMut`] is not implemented on purpose, so this type has more flexibility
+/// to change the inner later.
+///
+/// [`DerefMut`]: std::ops::DerefMut
+impl Deref for RelayUrl {
+    type Target = Url;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Debug for RelayUrl {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("RelayUrl")
+            .field(&DbgStr(self.0.as_str()))
+            .finish()
+    }
+}
+
+/// Helper struct to format a &str without allocating a String.
+///
+/// Maybe this is entirely unneeded and the compiler would be smart enough to never allocate
+/// the String anyway.  Who knows.  Writing this was faster than checking the assembler
+/// output.
+struct DbgStr<'a>(&'a str);
+
+impl fmt::Debug for DbgStr<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, r#""{}""#, self.0)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_relay_url_debug_display() {
+        let url = RelayUrl::from(Url::parse("https://example.com").unwrap());
+
+        assert_eq!(format!("{url:?}"), r#"RelayUrl("https://example.com./")"#);
+
+        assert_eq!(format!("{url}"), "https://example.com./");
+    }
+
+    #[test]
+    fn test_relay_url_absolute() {
+        let url = RelayUrl::from(Url::parse("https://example.com").unwrap());
+
+        assert_eq!(url.domain(), Some("example.com."));
+
+        let url1 = RelayUrl::from(Url::parse("https://example.com.").unwrap());
+        assert_eq!(url, url1);
+
+        let url2 = RelayUrl::from(Url::parse("https://example.com./").unwrap());
+        assert_eq!(url, url2);
+
+        let url3 = RelayUrl::from(Url::parse("https://example.com/").unwrap());
+        assert_eq!(url, url3);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/ticket.rs.html b/pr/2992/docs/src/iroh_base/ticket.rs.html new file mode 100644 index 0000000000..f017c8e692 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/ticket.rs.html @@ -0,0 +1,151 @@ +ticket.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+
use crate::base32;
+
+#[cfg(feature = "key")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
+mod blob;
+#[cfg(feature = "key")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
+mod node;
+#[cfg(feature = "key")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
+pub use self::{blob::BlobTicket, node::NodeTicket};
+
+/// A ticket is a serializable object combining information required for an operation.
+///
+/// Typically tickets contain all information required for an operation, e.g. an iroh blob
+/// ticket would contain the hash of the data as well as information about how to reach the
+/// provider.
+///
+/// Tickets support serialization to a string using base32 encoding. The kind of
+/// ticket will be prepended to the string to make it somewhat self describing.
+///
+/// Versioning is left to the implementer. Some kinds of tickets might need
+/// versioning, others might not.
+///
+/// The serialization format for converting the ticket from and to bytes is left
+/// to the implementer. We recommend using [postcard] for serialization.
+///
+/// [postcard]: https://docs.rs/postcard/latest/postcard/
+pub trait Ticket: Sized {
+    /// String prefix describing the kind of iroh ticket.
+    ///
+    /// This should be lower case ascii characters.
+    const KIND: &'static str;
+
+    /// Serialize to bytes used in the base32 string representation.
+    fn to_bytes(&self) -> Vec<u8>;
+
+    /// Deserialize from the base32 string representation bytes.
+    fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;
+
+    /// Serialize to string.
+    fn serialize(&self) -> String {
+        let mut out = Self::KIND.to_string();
+        base32::fmt_append(self.to_bytes(), &mut out);
+        out
+    }
+
+    /// Deserialize from a string.
+    fn deserialize(str: &str) -> Result<Self, Error> {
+        let expected = Self::KIND;
+        let Some(rest) = str.strip_prefix(expected) else {
+            return Err(Error::Kind { expected });
+        };
+        let bytes = base32::parse_vec(rest)?;
+        let ticket = Self::from_bytes(&bytes)?;
+        Ok(ticket)
+    }
+}
+
+/// An error deserializing an iroh ticket.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    /// Found a ticket of with the wrong prefix, indicating the wrong kind.
+    #[error("wrong prefix, expected {expected}")]
+    Kind { expected: &'static str },
+    /// This looks like a ticket, but postcard deserialization failed.
+    #[error("deserialization failed: {_0}")]
+    Postcard(#[from] postcard::Error),
+    /// This looks like a ticket, but base32 decoding failed.
+    #[error("decoding failed: {_0}")]
+    Encoding(#[from] base32::DecodeError),
+    /// Verification of the deserialized bytes failed.
+    #[error("verification failed: {_0}")]
+    Verify(&'static str),
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/ticket/blob.rs.html b/pr/2992/docs/src/iroh_base/ticket/blob.rs.html new file mode 100644 index 0000000000..38f09b0c25 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/ticket/blob.rs.html @@ -0,0 +1,363 @@ +blob.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+
//! Tickets for blobs.
+use std::str::FromStr;
+
+use anyhow::Result;
+use serde::{Deserialize, Serialize};
+
+use crate::{
+    hash::{BlobFormat, Hash},
+    node_addr::NodeAddr,
+    ticket::{self, Ticket},
+};
+
+/// A token containing everything to get a file from the provider.
+///
+/// It is a single item which can be easily serialized and deserialized.
+#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
+#[display("{}", Ticket::serialize(self))]
+pub struct BlobTicket {
+    /// The provider to get a file from.
+    node: NodeAddr,
+    /// The format of the blob.
+    format: BlobFormat,
+    /// The hash to retrieve.
+    hash: Hash,
+}
+
+/// Wire format for [`BlobTicket`].
+///
+/// In the future we might have multiple variants (not versions, since they
+/// might be both equally valid), so this is a single variant enum to force
+/// postcard to add a discriminator.
+#[derive(Serialize, Deserialize)]
+enum TicketWireFormat {
+    Variant0(BlobTicket),
+}
+
+impl Ticket for BlobTicket {
+    const KIND: &'static str = "blob";
+
+    fn to_bytes(&self) -> Vec<u8> {
+        let data = TicketWireFormat::Variant0(self.clone());
+        postcard::to_stdvec(&data).expect("postcard serialization failed")
+    }
+
+    fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, ticket::Error> {
+        let res: TicketWireFormat = postcard::from_bytes(bytes).map_err(ticket::Error::Postcard)?;
+        let TicketWireFormat::Variant0(res) = res;
+        Ok(res)
+    }
+}
+
+impl FromStr for BlobTicket {
+    type Err = ticket::Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ticket::deserialize(s)
+    }
+}
+
+impl BlobTicket {
+    /// Creates a new ticket.
+    pub fn new(node: NodeAddr, hash: Hash, format: BlobFormat) -> Result<Self> {
+        Ok(Self { hash, format, node })
+    }
+
+    /// The hash of the item this ticket can retrieve.
+    pub fn hash(&self) -> Hash {
+        self.hash
+    }
+
+    /// The [`NodeAddr`] of the provider for this ticket.
+    pub fn node_addr(&self) -> &NodeAddr {
+        &self.node
+    }
+
+    /// The [`BlobFormat`] for this ticket.
+    pub fn format(&self) -> BlobFormat {
+        self.format
+    }
+
+    /// True if the ticket is for a collection and should retrieve all blobs in it.
+    pub fn recursive(&self) -> bool {
+        self.format.is_hash_seq()
+    }
+
+    /// Get the contents of the ticket, consuming it.
+    pub fn into_parts(self) -> (NodeAddr, Hash, BlobFormat) {
+        let BlobTicket { node, hash, format } = self;
+        (node, hash, format)
+    }
+}
+
+impl Serialize for BlobTicket {
+    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        if serializer.is_human_readable() {
+            serializer.serialize_str(&self.to_string())
+        } else {
+            let BlobTicket { node, format, hash } = self;
+            (node, format, hash).serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for BlobTicket {
+    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+        if deserializer.is_human_readable() {
+            let s = String::deserialize(deserializer)?;
+            Self::from_str(&s).map_err(serde::de::Error::custom)
+        } else {
+            let (peer, format, hash) = Deserialize::deserialize(deserializer)?;
+            Self::new(peer, hash, format).map_err(serde::de::Error::custom)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::SocketAddr;
+
+    use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};
+
+    use super::*;
+    use crate::{
+        base32,
+        key::{PublicKey, SecretKey},
+    };
+
+    fn make_ticket() -> BlobTicket {
+        let hash = Hash::new(b"hi there");
+        let peer = SecretKey::generate().public();
+        let addr = SocketAddr::from_str("127.0.0.1:1234").unwrap();
+        let relay_url = None;
+        BlobTicket {
+            hash,
+            node: NodeAddr::from_parts(peer, relay_url, [addr]),
+            format: BlobFormat::HashSeq,
+        }
+    }
+
+    #[test]
+    fn test_ticket_postcard() {
+        let ticket = make_ticket();
+        let bytes = postcard::to_stdvec(&ticket).unwrap();
+        let ticket2: BlobTicket = postcard::from_bytes(&bytes).unwrap();
+        assert_eq!(ticket2, ticket);
+    }
+
+    #[test]
+    fn test_ticket_json() {
+        let ticket = make_ticket();
+        let json = serde_json::to_string(&ticket).unwrap();
+        let ticket2: BlobTicket = serde_json::from_str(&json).unwrap();
+        assert_eq!(ticket2, ticket);
+    }
+
+    #[test]
+    fn test_ticket_base32() {
+        let hash =
+            Hash::from_str("0b84d358e4c8be6c38626b2182ff575818ba6bd3f4b90464994be14cb354a072")
+                .unwrap();
+        let node_id =
+            PublicKey::from_str("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
+                .unwrap();
+
+        let ticket = BlobTicket {
+            node: NodeAddr::from_parts(node_id, None, []),
+            format: BlobFormat::Raw,
+            hash,
+        };
+        let base32 = base32::parse_vec(ticket.to_string().strip_prefix("blob").unwrap()).unwrap();
+        let expected = parse_hexdump("
+            00 # discriminator for variant 0
+            ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6 # node id, 32 bytes, see above
+            00 # relay url
+            00 # number of addresses (0)
+            00 # format (raw)
+            0b84d358e4c8be6c38626b2182ff575818ba6bd3f4b90464994be14cb354a072 # hash, 32 bytes, see above
+        ").unwrap();
+        assert_eq_hex!(base32, expected);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_base/ticket/node.rs.html b/pr/2992/docs/src/iroh_base/ticket/node.rs.html new file mode 100644 index 0000000000..0205516922 --- /dev/null +++ b/pr/2992/docs/src/iroh_base/ticket/node.rs.html @@ -0,0 +1,353 @@ +node.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+
//! Tickets for nodes.
+
+use std::str::FromStr;
+
+use anyhow::Result;
+use serde::{Deserialize, Serialize};
+
+use crate::{
+    node_addr::NodeAddr,
+    ticket::{self, Ticket},
+};
+
+/// A token containing information for establishing a connection to a node.
+///
+/// Contains
+/// - The [`NodeId`] of the node to connect to (a 32-byte ed25519 public key).
+/// - If used, the ['RelayUrl`] of on which the node can be reached.
+/// - Any *direct addresses* on which the node might be reachable.
+///
+/// This allows establishing a connection to the node in most circumstances where it is
+/// possible to do so.
+///
+/// This [`NodeTicket`] is a single item which can be easily serialized and deserialized and
+/// implements the [`Ticket`] trait.  The [`Display`] and [`FromStr`] traits can also be
+/// used to round-trip the ticket to string.
+///
+/// [`NodeId`]: crate::key::NodeId
+/// [`Display`]: std::fmt::Display
+/// [`FromStr`]: std::str::FromStr
+#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
+#[display("{}", Ticket::serialize(self))]
+pub struct NodeTicket {
+    node: NodeAddr,
+}
+
+/// Wire format for [`NodeTicket`].
+#[derive(Serialize, Deserialize)]
+enum TicketWireFormat {
+    Variant0(NodeTicket),
+}
+
+impl Ticket for NodeTicket {
+    const KIND: &'static str = "node";
+
+    fn to_bytes(&self) -> Vec<u8> {
+        let data = TicketWireFormat::Variant0(self.clone());
+        postcard::to_stdvec(&data).expect("postcard serialization failed")
+    }
+
+    fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, ticket::Error> {
+        let res: TicketWireFormat = postcard::from_bytes(bytes).map_err(ticket::Error::Postcard)?;
+        let TicketWireFormat::Variant0(res) = res;
+        Ok(res)
+    }
+}
+
+impl FromStr for NodeTicket {
+    type Err = ticket::Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        ticket::Ticket::deserialize(s)
+    }
+}
+
+impl NodeTicket {
+    /// Creates a new ticket.
+    pub fn new(node: NodeAddr) -> Self {
+        Self { node }
+    }
+
+    /// The [`NodeAddr`] of the provider for this ticket.
+    pub fn node_addr(&self) -> &NodeAddr {
+        &self.node
+    }
+}
+
+impl From<NodeAddr> for NodeTicket {
+    /// Creates a ticket from given addressing info.
+    fn from(addr: NodeAddr) -> Self {
+        Self { node: addr }
+    }
+}
+
+impl From<NodeTicket> for NodeAddr {
+    /// Returns the addressing info from given ticket.
+    fn from(ticket: NodeTicket) -> Self {
+        ticket.node
+    }
+}
+
+impl Serialize for NodeTicket {
+    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        if serializer.is_human_readable() {
+            serializer.serialize_str(&self.to_string())
+        } else {
+            let NodeTicket { node } = self;
+            (node).serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for NodeTicket {
+    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+        if deserializer.is_human_readable() {
+            let s = String::deserialize(deserializer)?;
+            Self::from_str(&s).map_err(serde::de::Error::custom)
+        } else {
+            let peer = Deserialize::deserialize(deserializer)?;
+            Ok(Self::new(peer))
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::{Ipv4Addr, SocketAddr};
+
+    use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};
+
+    use super::*;
+    use crate::{
+        base32,
+        key::{PublicKey, SecretKey},
+    };
+
+    fn make_ticket() -> NodeTicket {
+        let peer = SecretKey::generate().public();
+        let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 1234));
+        let relay_url = None;
+        NodeTicket {
+            node: NodeAddr::from_parts(peer, relay_url, [addr]),
+        }
+    }
+
+    #[test]
+    fn test_ticket_postcard() {
+        let ticket = make_ticket();
+        let bytes = postcard::to_stdvec(&ticket).unwrap();
+        let ticket2: NodeTicket = postcard::from_bytes(&bytes).unwrap();
+        assert_eq!(ticket2, ticket);
+    }
+
+    #[test]
+    fn test_ticket_json() {
+        let ticket = make_ticket();
+        let json = serde_json::to_string(&ticket).unwrap();
+        let ticket2: NodeTicket = serde_json::from_str(&json).unwrap();
+        assert_eq!(ticket2, ticket);
+    }
+
+    #[test]
+    fn test_ticket_base32() {
+        let node_id =
+            PublicKey::from_str("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
+                .unwrap();
+
+        let ticket = NodeTicket {
+            node: NodeAddr::from_parts(
+                node_id,
+                Some("http://derp.me./".parse().unwrap()),
+                ["127.0.0.1:1024".parse().unwrap()],
+            ),
+        };
+        let base32 = base32::parse_vec(ticket.to_string().strip_prefix("node").unwrap()).unwrap();
+        let expected = parse_hexdump("
+            00 # variant
+            ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6 # node id, 32 bytes, see above
+            01 # relay url present
+            10 687474703a2f2f646572702e6d652e2f # relay url, 16 bytes, see above
+            01 # one direct address
+            00 # ipv4
+            7f000001 8008 # address, see above
+        ").unwrap();
+        assert_eq_hex!(base32, expected);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/config.rs.html b/pr/2992/docs/src/iroh_dns_server/config.rs.html new file mode 100644 index 0000000000..3633c4e7af --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/config.rs.html @@ -0,0 +1,391 @@ +config.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+
//! Configuration for the server
+
+use std::{
+    env,
+    net::{IpAddr, Ipv4Addr, SocketAddr},
+    path::{Path, PathBuf},
+};
+
+use anyhow::{anyhow, Context, Result};
+use serde::{Deserialize, Serialize};
+use tracing::info;
+
+use crate::{
+    dns::DnsConfig,
+    http::{CertMode, HttpConfig, HttpsConfig, RateLimitConfig},
+};
+
+const DEFAULT_METRICS_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9117);
+
+/// Server configuration
+///
+/// The config is usually loaded from a file with [`Self::load`].
+///
+/// The struct also implements [`Default`] which creates a config suitable for local development
+/// and testing.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Config {
+    /// Config for the HTTP server
+    ///
+    /// If set to `None` no HTTP server will be started.
+    pub http: Option<HttpConfig>,
+    /// Config for the HTTPS server
+    ///
+    /// If set to `None` no HTTPS server will be started.
+    pub https: Option<HttpsConfig>,
+    /// Config for the DNS server.
+    pub dns: DnsConfig,
+    /// Config for the metrics server.
+    ///
+    /// The metrics server is started by default. To disable the metrics server, set to
+    /// `Some(MetricsConfig::disabled())`.
+    pub metrics: Option<MetricsConfig>,
+
+    /// Config for the mainline lookup.
+    pub mainline: Option<MainlineConfig>,
+
+    /// Config for pkarr rate limit
+    #[serde(default)]
+    pub pkarr_put_rate_limit: RateLimitConfig,
+}
+
+/// The config for the metrics server.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct MetricsConfig {
+    /// Set to true to disable the metrics server.
+    pub disabled: bool,
+    /// Optionally set a custom address to bind to.
+    pub bind_addr: Option<SocketAddr>,
+}
+
+impl MetricsConfig {
+    /// Disable the metrics server.
+    pub fn disabled() -> Self {
+        Self {
+            disabled: true,
+            bind_addr: None,
+        }
+    }
+}
+
+/// The config for the metrics server.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct MainlineConfig {
+    /// Set to true to enable the mainline lookup.
+    pub enabled: bool,
+    /// Set custom bootstrap nodes.
+    ///
+    /// Addresses can either be `domain:port` or `ipv4:port`.
+    ///
+    /// If empty this will use the default bittorrent mainline bootstrap nodes as defined by pkarr.
+    pub bootstrap: Option<Vec<String>>,
+}
+
+/// Configure the bootstrap servers for mainline DHT resolution.
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub enum BootstrapOption {
+    /// Use the default bootstrap servers.
+    #[default]
+    Default,
+    /// Use custom bootstrap servers.
+    Custom(Vec<String>),
+}
+
+#[allow(clippy::derivable_impls)]
+impl Default for MainlineConfig {
+    fn default() -> Self {
+        Self {
+            enabled: false,
+            bootstrap: None,
+        }
+    }
+}
+
+impl Config {
+    /// Load the config from a file.
+    pub async fn load(path: impl AsRef<Path>) -> Result<Config> {
+        info!(
+            "loading config file from {}",
+            path.as_ref().to_string_lossy()
+        );
+        let s = tokio::fs::read_to_string(path.as_ref())
+            .await
+            .with_context(|| format!("failed to read {}", path.as_ref().to_string_lossy()))?;
+        let config: Config = toml::from_str(&s)?;
+        Ok(config)
+    }
+
+    /// Get the data directory.
+    pub fn data_dir() -> Result<PathBuf> {
+        let dir = if let Some(val) = env::var_os("IROH_DNS_DATA_DIR") {
+            PathBuf::from(val)
+        } else {
+            let path = dirs_next::data_dir().ok_or_else(|| {
+                anyhow!("operating environment provides no directory for application data")
+            })?;
+            path.join("iroh-dns")
+        };
+        Ok(dir)
+    }
+
+    /// Get the path to the store database file.
+    pub fn signed_packet_store_path() -> Result<PathBuf> {
+        Ok(Self::data_dir()?.join("signed-packets-1.db"))
+    }
+
+    /// Get the address where the metrics server should be bound, if set.
+    pub(crate) fn metrics_addr(&self) -> Option<SocketAddr> {
+        match &self.metrics {
+            None => Some(DEFAULT_METRICS_ADDR),
+            Some(conf) => match conf.disabled {
+                true => None,
+                false => Some(conf.bind_addr.unwrap_or(DEFAULT_METRICS_ADDR)),
+            },
+        }
+    }
+
+    pub(crate) fn mainline_enabled(&self) -> Option<BootstrapOption> {
+        match self.mainline.as_ref() {
+            None => None,
+            Some(MainlineConfig { enabled: false, .. }) => None,
+            Some(MainlineConfig {
+                bootstrap: Some(bootstrap),
+                ..
+            }) => Some(BootstrapOption::Custom(bootstrap.clone())),
+            Some(MainlineConfig {
+                bootstrap: None, ..
+            }) => Some(BootstrapOption::Default),
+        }
+    }
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            http: Some(HttpConfig {
+                port: 8080,
+                bind_addr: None,
+            }),
+            https: Some(HttpsConfig {
+                port: 8443,
+                bind_addr: None,
+                domains: vec!["localhost".to_string()],
+                cert_mode: CertMode::SelfSigned,
+                letsencrypt_contact: None,
+                letsencrypt_prod: None,
+            }),
+            dns: DnsConfig {
+                port: 5300,
+                bind_addr: None,
+                origins: vec!["irohdns.example.".to_string(), ".".to_string()],
+
+                default_soa: "irohdns.example hostmaster.irohdns.example 0 10800 3600 604800 3600"
+                    .to_string(),
+                default_ttl: 900,
+
+                rr_a: Some(Ipv4Addr::LOCALHOST),
+                rr_aaaa: None,
+                rr_ns: Some("ns1.irohdns.example.".to_string()),
+            },
+            metrics: None,
+            mainline: None,
+            pkarr_put_rate_limit: RateLimitConfig::default(),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/dns.rs.html b/pr/2992/docs/src/iroh_dns_server/dns.rs.html new file mode 100644 index 0000000000..aaf2f0a639 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/dns.rs.html @@ -0,0 +1,545 @@ +dns.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+
//! Implementation of a DNS name server for iroh node announces
+
+use std::{
+    collections::BTreeMap,
+    io,
+    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
+    sync::Arc,
+    time::Duration,
+};
+
+use anyhow::{anyhow, Result};
+use async_trait::async_trait;
+use bytes::Bytes;
+use hickory_server::{
+    authority::{Catalog, MessageResponse, ZoneType},
+    proto::{
+        rr::{
+            rdata::{self},
+            RData, Record, RecordSet, RecordType, RrKey,
+        },
+        serialize::{binary::BinEncoder, txt::RDataParser},
+        {self},
+    },
+    resolver::Name,
+    server::{Request, RequestHandler, ResponseHandler, ResponseInfo},
+    store::in_memory::InMemoryAuthority,
+};
+use iroh_metrics::inc;
+use proto::{op::ResponseCode, rr::LowerName};
+use serde::{Deserialize, Serialize};
+use tokio::{
+    net::{TcpListener, UdpSocket},
+    sync::broadcast,
+};
+use tracing::{debug, info};
+
+use self::node_authority::NodeAuthority;
+use crate::{metrics::Metrics, store::ZoneStore};
+
+mod node_authority;
+
+const DEFAULT_NS_TTL: u32 = 60 * 60 * 12; // 12h
+const DEFAULT_SOA_TTL: u32 = 60 * 60 * 24 * 14; // 14d
+const DEFAULT_A_TTL: u32 = 60 * 60; // 1h
+
+/// DNS server settings
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct DnsConfig {
+    /// The port to serve a local UDP DNS server at
+    pub port: u16,
+    /// The IPv4 or IPv6 address to bind the UDP DNS server.
+    /// Uses `0.0.0.0` if unspecified.
+    pub bind_addr: Option<IpAddr>,
+    /// SOA record data for any authoritative DNS records
+    pub default_soa: String,
+    /// Default time to live for returned DNS records (TXT & SOA)
+    pub default_ttl: u32,
+    /// Domain used for serving the `_iroh_node.<nodeid>.<origin>` DNS TXT entry
+    pub origins: Vec<String>,
+
+    /// `A` record to set for all origins
+    pub rr_a: Option<Ipv4Addr>,
+    /// `AAAA` record to set for all origins
+    pub rr_aaaa: Option<Ipv6Addr>,
+    /// `NS` record to set for all origins
+    pub rr_ns: Option<String>,
+}
+
+/// A DNS server that serves pkarr signed packets.
+pub struct DnsServer {
+    local_addr: SocketAddr,
+    server: hickory_server::ServerFuture<DnsHandler>,
+}
+
+impl DnsServer {
+    /// Spawn the server.
+    pub async fn spawn(config: DnsConfig, dns_handler: DnsHandler) -> Result<Self> {
+        const TCP_TIMEOUT: Duration = Duration::from_millis(1000);
+        let mut server = hickory_server::ServerFuture::new(dns_handler);
+
+        let bind_addr = SocketAddr::new(
+            config.bind_addr.unwrap_or(Ipv4Addr::UNSPECIFIED.into()),
+            config.port,
+        );
+
+        let socket = UdpSocket::bind(bind_addr).await?;
+
+        let socket_addr = socket.local_addr()?;
+
+        server.register_socket(socket);
+        server.register_listener(TcpListener::bind(bind_addr).await?, TCP_TIMEOUT);
+        info!("DNS server listening on {}", bind_addr);
+
+        Ok(Self {
+            server,
+            local_addr: socket_addr,
+        })
+    }
+
+    /// Get the local address of the UDP/TCP socket.
+    pub fn local_addr(&self) -> SocketAddr {
+        self.local_addr
+    }
+
+    /// Shutdown the server an wait for all tasks to complete.
+    pub async fn shutdown(mut self) -> Result<()> {
+        self.server.shutdown_gracefully().await?;
+        Ok(())
+    }
+
+    /// Wait for all tasks to complete.
+    ///
+    /// Runs forever unless tasks fail.
+    pub async fn run_until_done(mut self) -> Result<()> {
+        self.server.block_until_done().await?;
+        Ok(())
+    }
+}
+
+/// State for serving DNS
+#[derive(Clone, derive_more::Debug)]
+pub struct DnsHandler {
+    #[debug("Catalog")]
+    catalog: Arc<Catalog>,
+}
+
+impl DnsHandler {
+    /// Create a DNS server given some settings, a connection to the DB for DID-by-username lookups
+    /// and the server DID to serve under `_did.<origin>`.
+    pub fn new(zone_store: ZoneStore, config: &DnsConfig) -> Result<Self> {
+        let origins = config
+            .origins
+            .iter()
+            .map(Name::from_utf8)
+            .collect::<Result<Vec<_>, _>>()?;
+
+        let (static_authority, serial) = create_static_authority(&origins, config)?;
+        let authority = NodeAuthority::new(zone_store, static_authority, origins, serial)?;
+        let authority = Arc::new(authority);
+
+        let mut catalog = Catalog::new();
+        for origin in authority.origins() {
+            catalog.upsert(LowerName::from(origin), Box::new(Arc::clone(&authority)));
+        }
+
+        Ok(Self {
+            catalog: Arc::new(catalog),
+        })
+    }
+
+    /// Handle a DNS request
+    pub async fn answer_request(&self, request: Request) -> Result<Bytes> {
+        let (tx, mut rx) = broadcast::channel(1);
+        let response_handle = Handle(tx);
+        self.handle_request(&request, response_handle).await;
+        Ok(rx.recv().await?)
+    }
+}
+
+#[async_trait::async_trait]
+impl RequestHandler for DnsHandler {
+    async fn handle_request<R: ResponseHandler>(
+        &self,
+        request: &Request,
+        response_handle: R,
+    ) -> ResponseInfo {
+        inc!(Metrics, dns_requests);
+        match request.protocol() {
+            hickory_server::server::Protocol::Udp => inc!(Metrics, dns_requests_udp),
+            hickory_server::server::Protocol::Https => inc!(Metrics, dns_requests_https),
+            _ => {}
+        }
+        debug!(protocol=%request.protocol(), query=%request.query(), "incoming DNS request");
+
+        let res = self.catalog.handle_request(request, response_handle).await;
+        match &res.response_code() {
+            ResponseCode::NoError => match res.answer_count() {
+                0 => inc!(Metrics, dns_lookup_notfound),
+                _ => inc!(Metrics, dns_lookup_success),
+            },
+            ResponseCode::NXDomain => inc!(Metrics, dns_lookup_notfound),
+            _ => inc!(Metrics, dns_lookup_error),
+        }
+        res
+    }
+}
+
+/// A handle to the channel over which the response to a DNS request will be sent
+#[derive(Debug, Clone)]
+pub struct Handle(pub broadcast::Sender<Bytes>);
+
+#[async_trait]
+impl ResponseHandler for Handle {
+    async fn send_response<'a>(
+        &mut self,
+        response: MessageResponse<
+            '_,
+            'a,
+            impl Iterator<Item = &'a proto::rr::Record> + Send + 'a,
+            impl Iterator<Item = &'a proto::rr::Record> + Send + 'a,
+            impl Iterator<Item = &'a proto::rr::Record> + Send + 'a,
+            impl Iterator<Item = &'a proto::rr::Record> + Send + 'a,
+        >,
+    ) -> io::Result<ResponseInfo> {
+        let mut bytes = Vec::with_capacity(512);
+        let info = {
+            let mut encoder = BinEncoder::new(&mut bytes);
+            response.destructive_emit(&mut encoder)?
+        };
+
+        let bytes = Bytes::from(bytes);
+        self.0.send(bytes).unwrap();
+
+        Ok(info)
+    }
+}
+
+fn create_static_authority(
+    origins: &[Name],
+    config: &DnsConfig,
+) -> Result<(InMemoryAuthority, u32)> {
+    let soa = RData::parse(
+        RecordType::SOA,
+        config.default_soa.split_ascii_whitespace(),
+        None,
+    )?
+    .into_soa()
+    .map_err(|_| anyhow!("Couldn't parse SOA: {}", config.default_soa))?;
+    let serial = soa.serial();
+    let mut records = BTreeMap::new();
+    for name in origins {
+        push_record(
+            &mut records,
+            serial,
+            Record::from_rdata(name.clone(), DEFAULT_SOA_TTL, RData::SOA(soa.clone())),
+        );
+        if let Some(addr) = config.rr_a {
+            push_record(
+                &mut records,
+                serial,
+                Record::from_rdata(name.clone(), DEFAULT_A_TTL, RData::A(addr.into())),
+            );
+        }
+        if let Some(addr) = config.rr_aaaa {
+            push_record(
+                &mut records,
+                serial,
+                Record::from_rdata(name.clone(), DEFAULT_A_TTL, RData::AAAA(addr.into())),
+            );
+        }
+        if let Some(ns) = &config.rr_ns {
+            let ns = Name::parse(ns, Some(&Name::root()))?;
+            push_record(
+                &mut records,
+                serial,
+                Record::from_rdata(name.clone(), DEFAULT_NS_TTL, RData::NS(rdata::NS(ns))),
+            );
+        }
+    }
+
+    let static_authority = InMemoryAuthority::new(Name::root(), records, ZoneType::Primary, false)
+        .map_err(|e| anyhow!(e))?;
+
+    Ok((static_authority, serial))
+}
+
+fn push_record(records: &mut BTreeMap<RrKey, RecordSet>, serial: u32, record: Record) {
+    let key = RrKey::new(record.name().clone().into(), record.record_type());
+    let mut record_set = RecordSet::new(record.name(), record.record_type(), serial);
+    record_set.insert(record, serial);
+    records.insert(key, record_set);
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/dns/node_authority.rs.html b/pr/2992/docs/src/iroh_dns_server/dns/node_authority.rs.html new file mode 100644 index 0000000000..1c0c20191a --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/dns/node_authority.rs.html @@ -0,0 +1,383 @@ +node_authority.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+
use std::{fmt, sync::Arc};
+
+use anyhow::{bail, ensure, Context, Result};
+use async_trait::async_trait;
+use hickory_proto::{
+    op::ResponseCode,
+    rr::{LowerName, Name, RecordType},
+};
+use hickory_server::{
+    authority::{
+        AuthLookup, Authority, LookupError, LookupOptions, LookupRecords, MessageRequest,
+        UpdateResult, ZoneType,
+    },
+    server::RequestInfo,
+    store::in_memory::InMemoryAuthority,
+};
+use tracing::{debug, trace};
+
+use crate::{
+    store::ZoneStore,
+    util::{record_set_append_origin, PublicKeyBytes},
+};
+
+#[derive(derive_more::Debug)]
+pub struct NodeAuthority {
+    serial: u32,
+    origins: Vec<Name>,
+    #[debug("InMemoryAuthority")]
+    static_authority: InMemoryAuthority,
+    zones: ZoneStore,
+    // TODO: This is used by Authority::origin
+    // Find out what exactly this is used for - we don't have a primary origin.
+    first_origin: LowerName,
+}
+
+impl NodeAuthority {
+    pub fn new(
+        zones: ZoneStore,
+        static_authority: InMemoryAuthority,
+        origins: Vec<Name>,
+        serial: u32,
+    ) -> Result<Self> {
+        ensure!(!origins.is_empty(), "at least one origin is required");
+        let first_origin = LowerName::from(&origins[0]);
+        Ok(Self {
+            static_authority,
+            origins,
+            serial,
+            zones,
+            first_origin,
+        })
+    }
+
+    pub fn origins(&self) -> impl Iterator<Item = &Name> {
+        self.origins.iter()
+    }
+
+    pub fn serial(&self) -> u32 {
+        self.serial
+    }
+}
+
+#[async_trait]
+impl Authority for NodeAuthority {
+    type Lookup = AuthLookup;
+
+    fn zone_type(&self) -> ZoneType {
+        ZoneType::Primary
+    }
+
+    fn is_axfr_allowed(&self) -> bool {
+        false
+    }
+
+    async fn update(&self, _update: &MessageRequest) -> UpdateResult<bool> {
+        Err(ResponseCode::NotImp)
+    }
+
+    fn origin(&self) -> &LowerName {
+        &self.first_origin
+    }
+
+    async fn lookup(
+        &self,
+        name: &LowerName,
+        record_type: RecordType,
+        lookup_options: LookupOptions,
+    ) -> Result<Self::Lookup, LookupError> {
+        debug!(name=%name, "lookup in node authority");
+        match record_type {
+            RecordType::SOA | RecordType::NS => {
+                self.static_authority
+                    .lookup(name, record_type, lookup_options)
+                    .await
+            }
+            _ => match parse_name_as_pkarr_with_origin(name, &self.origins) {
+                Err(err) => {
+                    debug!(%name, failed_with=%err, "not a pkarr name, resolve in static authority");
+                    self.static_authority
+                        .lookup(name, record_type, lookup_options)
+                        .await
+                }
+                Ok((name, pubkey, origin)) => {
+                    debug!(%origin, %pubkey, %name, "resolve in pkarr zones");
+                    match self
+                        .zones
+                        .resolve(&pubkey, &name, record_type)
+                        .await
+                        .map_err(err_refused)?
+                    {
+                        Some(pkarr_set) => {
+                            debug!(%origin, %pubkey, %name, "found {} records in pkarr zone", pkarr_set.records_without_rrsigs().count());
+                            let new_origin = Name::parse(&pubkey.to_z32(), Some(&origin))
+                                .map_err(err_refused)?;
+                            let record_set =
+                                record_set_append_origin(&pkarr_set, &new_origin, self.serial())
+                                    .map_err(err_refused)?;
+                            let records = LookupRecords::new(lookup_options, Arc::new(record_set));
+                            let answers = AuthLookup::answers(records, None);
+                            Ok(answers)
+                        }
+                        None => Err(err_nx_domain("not found")),
+                    }
+                }
+            },
+        }
+    }
+
+    async fn search(
+        &self,
+        request_info: RequestInfo<'_>,
+        lookup_options: LookupOptions,
+    ) -> Result<Self::Lookup, LookupError> {
+        debug!("search in node authority for {}", request_info.query);
+        let lookup_name = request_info.query.name();
+        let record_type: RecordType = request_info.query.query_type();
+        match record_type {
+            RecordType::SOA => {
+                self.static_authority
+                    .lookup(self.origin(), record_type, lookup_options)
+                    .await
+            }
+            RecordType::AXFR => Err(LookupError::from(ResponseCode::Refused)),
+            _ => self.lookup(lookup_name, record_type, lookup_options).await,
+        }
+    }
+
+    async fn get_nsec_records(
+        &self,
+        _name: &LowerName,
+        _lookup_options: LookupOptions,
+    ) -> Result<Self::Lookup, LookupError> {
+        Ok(AuthLookup::default())
+    }
+}
+
+fn parse_name_as_pkarr_with_origin(
+    name: impl Into<Name>,
+    allowed_origins: &[Name],
+) -> Result<(Name, PublicKeyBytes, Name)> {
+    let name = name.into();
+    trace!("resolve {name}");
+    for origin in allowed_origins.iter() {
+        trace!("try {origin}");
+        if !origin.zone_of(&name) {
+            continue;
+        }
+        if name.num_labels() < origin.num_labels() + 1 {
+            bail!("not a valid pkarr name: missing pubkey");
+        }
+        trace!("parse {origin}");
+        let labels = name.iter().rev();
+        let mut labels_without_origin = labels.skip(origin.num_labels() as usize);
+        let pkey_label = labels_without_origin.next().expect("length checked above");
+        let pkey_str = std::str::from_utf8(pkey_label)?;
+        let pkey =
+            PublicKeyBytes::from_z32(pkey_str).context("not a valid pkarr name: invalid pubkey")?;
+        let remaining_name = Name::from_labels(labels_without_origin.rev())?;
+        return Ok((remaining_name, pkey, origin.clone()));
+    }
+    bail!("name does not match any allowed origin");
+}
+
+fn err_refused(e: impl fmt::Debug) -> LookupError {
+    trace!("lookup failed (refused): {e:?}");
+    LookupError::from(ResponseCode::Refused)
+}
+fn err_nx_domain(e: impl fmt::Debug) -> LookupError {
+    trace!("lookup failed (nxdomain): {e:?}");
+    LookupError::from(ResponseCode::NXDomain)
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http.rs.html b/pr/2992/docs/src/iroh_dns_server/http.rs.html new file mode 100644 index 0000000000..4fc4350e0a --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http.rs.html @@ -0,0 +1,521 @@ +http.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+
//! HTTP server part of iroh-dns-server
+
+use std::{
+    net::{IpAddr, Ipv4Addr, SocketAddr},
+    time::Instant,
+};
+
+use anyhow::{bail, Context, Result};
+use axum::{
+    extract::{ConnectInfo, Request},
+    handler::Handler,
+    http::Method,
+    middleware::{self, Next},
+    response::IntoResponse,
+    routing::get,
+    Router,
+};
+use iroh_metrics::{inc, inc_by};
+use serde::{Deserialize, Serialize};
+use tokio::{net::TcpListener, task::JoinSet};
+use tower_http::{
+    cors::{self, CorsLayer},
+    trace::TraceLayer,
+};
+use tracing::{info, span, warn, Level};
+
+mod doh;
+mod error;
+mod pkarr;
+mod rate_limiting;
+mod tls;
+
+pub use self::{rate_limiting::RateLimitConfig, tls::CertMode};
+use crate::{config::Config, metrics::Metrics, state::AppState};
+
+/// Config for the HTTP server
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct HttpConfig {
+    /// Port to bind to
+    pub port: u16,
+    /// Optionally set a custom bind address (will use 0.0.0.0 if unset)
+    pub bind_addr: Option<IpAddr>,
+}
+
+/// Config for the HTTPS server
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct HttpsConfig {
+    /// Port to bind to
+    pub port: u16,
+    /// Optionally set a custom bind address (will use 0.0.0.0 if unset)
+    pub bind_addr: Option<IpAddr>,
+    /// The list of domains for which SSL certificates should be created.
+    pub domains: Vec<String>,
+    /// The mode of SSL certificate creation
+    pub cert_mode: CertMode,
+    /// Letsencrypt contact email address (required if using [`CertMode::LetsEncrypt`])
+    pub letsencrypt_contact: Option<String>,
+    /// Whether to use the letsenrypt production servers (only applies to [`CertMode::LetsEncrypt`])
+    pub letsencrypt_prod: Option<bool>,
+}
+
+/// The HTTP(S) server part of iroh-dns-server
+pub struct HttpServer {
+    tasks: JoinSet<std::io::Result<()>>,
+    http_addr: Option<SocketAddr>,
+    https_addr: Option<SocketAddr>,
+}
+
+impl HttpServer {
+    /// Spawn the server
+    pub async fn spawn(
+        http_config: Option<HttpConfig>,
+        https_config: Option<HttpsConfig>,
+        rate_limit_config: RateLimitConfig,
+        state: AppState,
+    ) -> Result<HttpServer> {
+        if http_config.is_none() && https_config.is_none() {
+            bail!("Either http or https config is required");
+        }
+
+        let app = create_app(state, &rate_limit_config);
+
+        let mut tasks = JoinSet::new();
+
+        // launch http
+        let http_addr = if let Some(config) = http_config {
+            let bind_addr = SocketAddr::new(
+                config.bind_addr.unwrap_or(Ipv4Addr::UNSPECIFIED.into()),
+                config.port,
+            );
+            let app = app.clone();
+            let listener = TcpListener::bind(bind_addr).await?.into_std()?;
+            let bound_addr = listener.local_addr()?;
+            let fut = axum_server::from_tcp(listener)
+                .serve(app.into_make_service_with_connect_info::<SocketAddr>());
+            info!("HTTP server listening on {bind_addr}");
+            tasks.spawn(fut);
+            Some(bound_addr)
+        } else {
+            None
+        };
+
+        // launch https
+        let https_addr = if let Some(config) = https_config {
+            let bind_addr = SocketAddr::new(
+                config.bind_addr.unwrap_or(Ipv4Addr::UNSPECIFIED.into()),
+                config.port,
+            );
+            let acceptor = {
+                let cache_path = Config::data_dir()?
+                    .join("cert_cache")
+                    .join(config.cert_mode.to_string());
+                tokio::fs::create_dir_all(&cache_path)
+                    .await
+                    .with_context(|| {
+                        format!("failed to create cert cache dir at {cache_path:?}")
+                    })?;
+                config
+                    .cert_mode
+                    .build(
+                        config.domains,
+                        cache_path,
+                        config.letsencrypt_contact,
+                        config.letsencrypt_prod.unwrap_or(false),
+                    )
+                    .await?
+            };
+            let listener = TcpListener::bind(bind_addr).await?.into_std()?;
+            let bound_addr = listener.local_addr()?;
+            let fut = axum_server::from_tcp(listener)
+                .acceptor(acceptor)
+                .serve(app.into_make_service_with_connect_info::<SocketAddr>());
+            info!("HTTPS server listening on {bind_addr}");
+            tasks.spawn(fut);
+            Some(bound_addr)
+        } else {
+            None
+        };
+
+        Ok(HttpServer {
+            tasks,
+            http_addr,
+            https_addr,
+        })
+    }
+
+    /// Get the bound address of the HTTP socket.
+    pub fn http_addr(&self) -> Option<SocketAddr> {
+        self.http_addr
+    }
+
+    /// Get the bound address of the HTTPS socket.
+    pub fn https_addr(&self) -> Option<SocketAddr> {
+        self.https_addr
+    }
+
+    /// Shutdown the server and wait for all tasks to complete.
+    pub async fn shutdown(mut self) -> Result<()> {
+        // TODO: Graceful cancellation.
+        self.tasks.abort_all();
+        self.run_until_done().await?;
+        Ok(())
+    }
+
+    /// Wait for all tasks to complete.
+    ///
+    /// Runs forever unless tasks fail.
+    pub async fn run_until_done(mut self) -> Result<()> {
+        let mut final_res: anyhow::Result<()> = Ok(());
+        while let Some(res) = self.tasks.join_next().await {
+            match res {
+                Ok(Ok(())) => {}
+                Err(err) if err.is_cancelled() => {}
+                Ok(Err(err)) => {
+                    warn!(?err, "task failed");
+                    final_res = Err(anyhow::Error::from(err));
+                }
+                Err(err) => {
+                    warn!(?err, "task panicked");
+                    final_res = Err(err.into());
+                }
+            }
+        }
+        final_res
+    }
+}
+
+pub(crate) fn create_app(state: AppState, rate_limit_config: &RateLimitConfig) -> Router {
+    // configure cors middleware
+    let cors = CorsLayer::new()
+        // allow `GET` and `POST` when accessing the resource
+        .allow_methods([Method::GET, Method::POST, Method::PUT])
+        // allow requests from any origin
+        .allow_origin(cors::Any);
+
+    // configure tracing middleware
+    let trace = TraceLayer::new_for_http().make_span_with(|request: &http::Request<_>| {
+        let conn_info = request
+            .extensions()
+            .get::<ConnectInfo<SocketAddr>>()
+            .expect("connectinfo extension to be present");
+        let span = span!(
+        Level::DEBUG,
+            "http_request",
+            method = ?request.method(),
+            uri = ?request.uri(),
+            src = %conn_info.0,
+            );
+        span
+    });
+
+    // configure rate limiting middleware
+    let rate_limit = rate_limiting::create(rate_limit_config);
+
+    // configure routes
+    //
+    // only the pkarr::put route gets a rate limit
+    let router = Router::new()
+        .route("/dns-query", get(doh::get).post(doh::post))
+        .route(
+            "/pkarr/:key",
+            if let Some(rate_limit) = rate_limit {
+                get(pkarr::get).put(pkarr::put.layer(rate_limit))
+            } else {
+                get(pkarr::get).put(pkarr::put)
+            },
+        )
+        .route("/healthcheck", get(|| async { "OK" }))
+        .route("/", get(|| async { "Hi!" }))
+        .with_state(state);
+
+    // configure app
+    router
+        .layer(cors)
+        .layer(trace)
+        .route_layer(middleware::from_fn(metrics_middleware))
+}
+
+/// Record request metrics.
+// TODO:
+// * Request duration would be much better tracked as a histogram.
+// * It would be great to attach labels to the metrics, so that the recorded metrics
+// can filter by method etc.
+//
+// See also
+// https://github.com/tokio-rs/axum/blob/main/examples/prometheus-metrics/src/main.rs#L114
+async fn metrics_middleware(req: Request, next: Next) -> impl IntoResponse {
+    let start = Instant::now();
+    let response = next.run(req).await;
+    let latency = start.elapsed().as_millis();
+    let status = response.status();
+    inc_by!(Metrics, http_requests_duration_ms, latency as u64);
+    inc!(Metrics, http_requests);
+    if status.is_success() {
+        inc!(Metrics, http_requests_success);
+    } else {
+        inc!(Metrics, http_requests_error);
+    }
+    response
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/doh.rs.html b/pr/2992/docs/src/iroh_dns_server/http/doh.rs.html new file mode 100644 index 0000000000..e0684d5120 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/doh.rs.html @@ -0,0 +1,159 @@ +doh.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+
//! DNS over HTTPS
+
+// This module is mostly copied from
+// https://github.com/fission-codes/fission-server/blob/main/fission-server/src/routes/doh.rs
+
+use anyhow::anyhow;
+use axum::{
+    extract::State,
+    response::{IntoResponse, Response},
+    Json,
+};
+use hickory_server::proto::{
+    serialize::binary::BinDecodable,
+    {self},
+};
+use http::{
+    header::{CACHE_CONTROL, CONTENT_TYPE},
+    HeaderValue, StatusCode,
+};
+
+use super::error::AppResult;
+use crate::state::AppState;
+
+mod extract;
+mod response;
+
+use self::extract::{DnsMimeType, DnsRequestBody, DnsRequestQuery};
+
+/// GET handler for resolving DoH queries
+pub async fn get(
+    State(state): State<AppState>,
+    DnsRequestQuery(request, accept_type): DnsRequestQuery,
+) -> AppResult<Response> {
+    let message_bytes = state.dns_handler.answer_request(request).await?;
+    let message = proto::op::Message::from_bytes(&message_bytes).map_err(|e| anyhow!(e))?;
+
+    let min_ttl = message.answers().iter().map(|rec| rec.ttl()).min();
+
+    let mut response = match accept_type {
+        DnsMimeType::Message => (StatusCode::OK, message_bytes).into_response(),
+        DnsMimeType::Json => {
+            let response = self::response::DnsResponse::from_message(message)?;
+            (StatusCode::OK, Json(response)).into_response()
+        }
+    };
+
+    response
+        .headers_mut()
+        .insert(CONTENT_TYPE, accept_type.to_header_value());
+
+    if let Some(min_ttl) = min_ttl {
+        let maxage =
+            HeaderValue::from_str(&format!("s-maxage={min_ttl}")).map_err(|e| anyhow!(e))?;
+        response.headers_mut().insert(CACHE_CONTROL, maxage);
+    }
+
+    Ok(response)
+}
+
+/// POST handler for resolvng DoH queries
+pub async fn post(
+    State(state): State<AppState>,
+    DnsRequestBody(request): DnsRequestBody,
+) -> Response {
+    let response = match state.dns_handler.answer_request(request).await {
+        Ok(response) => response,
+        Err(err) => return (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response(),
+    };
+
+    (
+        StatusCode::OK,
+        [(CONTENT_TYPE, DnsMimeType::Message.to_string())],
+        response,
+    )
+        .into_response()
+}
+
+// TODO: Port tests from
+// https://github.com/fission-codes/fission-server/blob/main/fission-server/src/routes/doh.rs
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/doh/extract.rs.html b/pr/2992/docs/src/iroh_dns_server/http/doh/extract.rs.html new file mode 100644 index 0000000000..0defa40c44 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/doh/extract.rs.html @@ -0,0 +1,503 @@ +extract.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+
//! Extractors for DNS-over-HTTPS requests
+
+// This module is mostly copied from
+// https://github.com/fission-codes/fission-server/blob/394de877fad021260c69fdb1edd7bb4b2f98108c/fission-server/src/extract/doh.rs
+
+use std::{
+    fmt::{self, Display, Formatter},
+    net::SocketAddr,
+    str::FromStr,
+};
+
+use async_trait::async_trait;
+use axum::{
+    extract::{ConnectInfo, FromRequest, FromRequestParts, Query},
+    http::Request,
+};
+use bytes::Bytes;
+use hickory_server::{
+    authority::MessageRequest,
+    proto::{
+        serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder},
+        {self},
+    },
+    server::{Protocol, Request as DNSRequest},
+};
+use http::{header, request::Parts, HeaderValue, StatusCode};
+use serde::Deserialize;
+use tracing::info;
+
+use crate::http::error::AppError;
+
+/// A DNS packet encoding type
+#[derive(Debug)]
+pub enum DnsMimeType {
+    /// application/dns-message
+    Message,
+    /// application/dns-json
+    Json,
+}
+
+impl Display for DnsMimeType {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            DnsMimeType::Message => write!(f, "application/dns-message"),
+            DnsMimeType::Json => write!(f, "application/dns-json"),
+        }
+    }
+}
+
+impl DnsMimeType {
+    /// Turn this mime type to an `Accept` HTTP header value
+    pub fn to_header_value(&self) -> HeaderValue {
+        HeaderValue::from_static(match self {
+            Self::Message => "application/dns-message",
+            Self::Json => "application/dns-json",
+        })
+    }
+}
+
+#[derive(Debug, Deserialize)]
+struct DnsMessageQuery {
+    dns: String,
+}
+
+// See: https://developers.google.com/speed/public-dns/docs/doh/json#supported_parameters
+#[derive(Debug, Deserialize)]
+pub struct DnsQuery {
+    /// Record name to look up, e.g. example.com
+    pub name: String,
+    /// Record type, e.g. A/AAAA/TXT, etc.
+    #[serde(rename = "type")]
+    pub record_type: Option<String>,
+    /// Used to disable DNSSEC validation
+    pub cd: Option<bool>,
+    /// Desired content type. E.g. "application/dns-message" or "application/dns-json"
+    #[allow(dead_code)]
+    pub ct: Option<String>,
+    /// Whether to return DNSSEC entries such as RRSIG, NSEC or NSEC3
+    #[serde(rename = "do")]
+    pub dnssec_ok: Option<bool>,
+    /// Privacy setting for how your IP address is forwarded to authoritative nameservers
+    #[allow(dead_code)]
+    pub edns_client_subnet: Option<String>,
+    /// Some url-safe random characters to pad your messages for privacy (to avoid being fingerprinted by encrypted message length)
+    #[allow(dead_code)]
+    pub random_padding: Option<String>,
+    /// Whether to provide answers for all records up to the root
+    #[serde(rename = "rd")]
+    pub recursion_desired: Option<bool>,
+}
+
+/// A DNS request encoded in the query string
+#[derive(Debug)]
+pub struct DnsRequestQuery(pub(crate) DNSRequest, pub(crate) DnsMimeType);
+
+/// A DNS request encoded in the body
+#[derive(Debug)]
+pub struct DnsRequestBody(pub(crate) DNSRequest);
+
+#[async_trait]
+impl<S> FromRequestParts<S> for DnsRequestQuery
+where
+    S: Send + Sync,
+{
+    type Rejection = AppError;
+
+    async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+        let ConnectInfo(src_addr) = ConnectInfo::from_request_parts(parts, state).await?;
+
+        match parts.headers.get(header::ACCEPT) {
+            Some(content_type) if content_type == "application/dns-message" => {
+                handle_dns_message_query(parts, state, src_addr).await
+            }
+            Some(content_type) if content_type == "application/dns-json" => {
+                handle_dns_json_query(parts, state, src_addr).await
+            }
+            Some(content_type) if content_type == "application/x-javascript" => {
+                handle_dns_json_query(parts, state, src_addr).await
+            }
+            None => handle_dns_message_query(parts, state, src_addr).await,
+            _ => Err(AppError::with_status(StatusCode::NOT_ACCEPTABLE)),
+        }
+    }
+}
+
+#[async_trait]
+impl<S> FromRequest<S> for DnsRequestBody
+where
+    S: Send + Sync,
+{
+    type Rejection = AppError;
+
+    async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
+        let (mut parts, body) = req.into_parts();
+
+        let ConnectInfo(src_addr) = ConnectInfo::from_request_parts(&mut parts, state).await?;
+
+        let req = Request::from_parts(parts, body);
+
+        let body = Bytes::from_request(req, state)
+            .await
+            .map_err(|_| AppError::with_status(StatusCode::INTERNAL_SERVER_ERROR))?;
+
+        let request = decode_request(&body, src_addr)?;
+
+        Ok(DnsRequestBody(request))
+    }
+}
+
+async fn handle_dns_message_query<S>(
+    parts: &mut Parts,
+    state: &S,
+    src_addr: SocketAddr,
+) -> Result<DnsRequestQuery, AppError>
+where
+    S: Send + Sync,
+{
+    let Query(params) = Query::<DnsMessageQuery>::from_request_parts(parts, state).await?;
+
+    let buf = base64_url::decode(params.dns.as_bytes())
+        .map_err(|err| AppError::new(StatusCode::BAD_REQUEST, Some(err)))?;
+
+    let request = decode_request(&buf, src_addr)?;
+
+    Ok(DnsRequestQuery(request, DnsMimeType::Message))
+}
+
+async fn handle_dns_json_query<S>(
+    parts: &mut Parts,
+    state: &S,
+    src_addr: SocketAddr,
+) -> Result<DnsRequestQuery, AppError>
+where
+    S: Send + Sync,
+{
+    let Query(dns_query) = Query::<DnsQuery>::from_request_parts(parts, state).await?;
+
+    let request = encode_query_as_request(dns_query, src_addr)?;
+
+    Ok(DnsRequestQuery(request, DnsMimeType::Json))
+}
+
+/// Exposed to make it usable internally...
+pub(crate) fn encode_query_as_request(
+    question: DnsQuery,
+    src_addr: SocketAddr,
+) -> Result<DNSRequest, AppError> {
+    let query_type = if let Some(record_type) = question.record_type {
+        record_type
+            .parse::<u16>()
+            .map(proto::rr::RecordType::from)
+            .or_else(|_| FromStr::from_str(&record_type.to_uppercase()))
+            .map_err(|err| AppError::new(StatusCode::BAD_REQUEST, Some(err)))?
+    } else {
+        proto::rr::RecordType::A
+    };
+
+    let name = proto::rr::Name::from_utf8(question.name)
+        .map_err(|err| AppError::new(StatusCode::BAD_REQUEST, Some(err)))?;
+
+    let query = proto::op::Query::query(name, query_type);
+
+    let mut message = proto::op::Message::new();
+
+    message
+        .add_query(query)
+        .set_message_type(proto::op::MessageType::Query)
+        .set_op_code(proto::op::OpCode::Query)
+        .set_checking_disabled(question.cd.unwrap_or(false))
+        .set_recursion_desired(question.recursion_desired.unwrap_or(true))
+        .set_recursion_available(true)
+        .set_authentic_data(question.dnssec_ok.unwrap_or(false));
+
+    // This is kind of a hack, but the only way I can find to
+    // create a MessageRequest is by decoding a buffer of bytes,
+    // so we encode the message into a buffer and then decode it
+    let mut buf = Vec::with_capacity(4096);
+    let mut encoder = BinEncoder::new(&mut buf);
+
+    message
+        .emit(&mut encoder)
+        .map_err(|err| AppError::new(StatusCode::BAD_REQUEST, Some(err)))?;
+
+    let request = decode_request(&buf, src_addr)?;
+
+    Ok(request)
+}
+
+fn decode_request(bytes: &[u8], src_addr: SocketAddr) -> Result<DNSRequest, AppError> {
+    let mut decoder = BinDecoder::new(bytes);
+
+    match MessageRequest::read(&mut decoder) {
+        Ok(message) => {
+            info!("received message {message:?}");
+            if message.message_type() != proto::op::MessageType::Query {
+                return Err(AppError::new(
+                    StatusCode::BAD_REQUEST,
+                    Some("Invalid message type: expected query"),
+                ));
+            }
+
+            let request = DNSRequest::new(message, src_addr, Protocol::Https);
+
+            Ok(request)
+        }
+        Err(err) => Err(AppError::new(
+            StatusCode::BAD_REQUEST,
+            Some(format!("Invalid DNS message: {}", err)),
+        )),
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/doh/response.rs.html b/pr/2992/docs/src/iroh_dns_server/http/doh/response.rs.html new file mode 100644 index 0000000000..70df7c6f67 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/doh/response.rs.html @@ -0,0 +1,281 @@ +response.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+
//! DNS Response
+
+// This module is mostly copied from
+// https://github.com/fission-codes/fission-server/blob/394de877fad021260c69fdb1edd7bb4b2f98108c/fission-core/src/dns.rs
+
+use anyhow::{ensure, Result};
+use hickory_proto as proto;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize)]
+/// JSON representation of a DNS response
+/// See: <https://developers.google.com/speed/public-dns/docs/doh/json>
+pub struct DnsResponse {
+    /// Standard DNS response code
+    #[serde(rename = "Status")]
+    pub status: u32,
+    /// Whether the response was truncated
+    #[serde(rename = "TC")]
+    pub tc: bool,
+    /// Whether recursion was desired
+    #[serde(rename = "RD")]
+    pub rd: bool,
+    /// Whether recursion was available
+    #[serde(rename = "RA")]
+    pub ra: bool,
+    /// Whether the response was validated with DNSSEC
+    #[serde(rename = "AD")]
+    pub ad: bool,
+    /// Whether the client asked to disable DNSSEC validation
+    #[serde(rename = "CD")]
+    pub cd: bool,
+    /// The questions that this request answers
+    #[serde(rename = "Question")]
+    pub question: Vec<DohQuestionJson>,
+    /// The answers to the request
+    #[serde(rename = "Answer")]
+    #[serde(skip_serializing_if = "Vec::is_empty")]
+    pub answer: Vec<DohRecordJson>,
+    /// An optional comment
+    #[serde(rename = "Comment")]
+    pub comment: Option<String>,
+    /// IP Address / scope prefix-length of the client
+    /// See: <https://tools.ietf.org/html/rfc7871>
+    pub edns_client_subnet: Option<String>,
+}
+
+impl DnsResponse {
+    /// Create a new JSON response from a DNS message
+    pub fn from_message(message: proto::op::Message) -> Result<Self> {
+        ensure!(
+            message.message_type() == proto::op::MessageType::Response,
+            "Expected message type to be response"
+        );
+
+        ensure!(
+            message.query_count() == message.queries().len() as u16,
+            "Query count mismatch"
+        );
+
+        ensure!(
+            message.answer_count() == message.answers().len() as u16,
+            "Answer count mismatch"
+        );
+
+        let status: u32 =
+            <u16 as From<proto::op::ResponseCode>>::from(message.response_code()) as u32;
+
+        let question: Vec<_> = message
+            .queries()
+            .iter()
+            .map(DohQuestionJson::from_query)
+            .collect();
+
+        let answer: Vec<_> = message
+            .answers()
+            .iter()
+            .map(DohRecordJson::from_record)
+            .collect::<Result<_>>()?;
+
+        Ok(DnsResponse {
+            status,
+            tc: message.truncated(),
+            rd: message.recursion_desired(),
+            ra: message.recursion_available(),
+            ad: message.authentic_data(),
+            cd: message.checking_disabled(),
+            question,
+            answer,
+            comment: None,
+            edns_client_subnet: None,
+        })
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+/// JSON representation of a DNS question
+pub struct DohQuestionJson {
+    /// FQDN with trailing dot
+    pub name: String,
+    /// Standard DNS RR type
+    #[serde(rename = "type")]
+    pub question_type: u16,
+}
+
+impl DohQuestionJson {
+    /// Create a new JSON question from a DNS query
+    pub fn from_query(query: &proto::op::Query) -> Self {
+        Self {
+            name: query.name().to_string(),
+            question_type: query.query_type().into(),
+        }
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+/// JSON representation of a DNS record
+pub struct DohRecordJson {
+    /// FQDN with trailing dot
+    pub name: String,
+    /// Standard DNS RR type
+    #[serde(rename = "type")]
+    pub record_type: u16,
+    /// Time-to-live, in seconds
+    #[serde(rename = "TTL")]
+    pub ttl: u32,
+    /// Record data
+    pub data: String,
+}
+
+impl DohRecordJson {
+    /// Create a new JSON record from a DNS record
+    pub fn from_record(record: &proto::rr::Record) -> Result<Self> {
+        Ok(Self {
+            name: record.name().to_string(),
+            record_type: record.record_type().into(),
+            ttl: record.ttl(),
+            data: record.data().to_string(),
+        })
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/error.rs.html b/pr/2992/docs/src/iroh_dns_server/http/error.rs.html new file mode 100644 index 0000000000..2750ab67ac --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/error.rs.html @@ -0,0 +1,203 @@ +error.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+
use axum::{
+    extract::rejection::{ExtensionRejection, QueryRejection},
+    http::StatusCode,
+    response::IntoResponse,
+    Json,
+};
+use serde::{Deserialize, Serialize};
+
+pub type AppResult<T> = Result<T, AppError>;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AppError {
+    #[serde(with = "serde_status_code")]
+    status: StatusCode,
+    detail: Option<String>,
+}
+
+impl Default for AppError {
+    fn default() -> Self {
+        Self {
+            status: StatusCode::INTERNAL_SERVER_ERROR,
+            detail: None,
+        }
+    }
+}
+
+impl AppError {
+    pub fn with_status(status: StatusCode) -> AppError {
+        Self {
+            status,
+            detail: None,
+        }
+    }
+
+    /// Create a new [`AppError`].
+    pub fn new(status_code: StatusCode, message: Option<impl ToString>) -> AppError {
+        Self {
+            status: status_code,
+            // title: Self::canonical_reason_to_string(&status_code),
+            detail: message.map(|m| m.to_string()),
+        }
+    }
+}
+
+impl IntoResponse for AppError {
+    fn into_response(self) -> axum::response::Response {
+        let json = Json(self.clone());
+        (self.status, json).into_response()
+    }
+}
+
+impl From<anyhow::Error> for AppError {
+    fn from(value: anyhow::Error) -> Self {
+        Self {
+            status: StatusCode::INTERNAL_SERVER_ERROR,
+            detail: Some(value.to_string()),
+        }
+    }
+}
+
+impl From<QueryRejection> for AppError {
+    fn from(value: QueryRejection) -> Self {
+        Self::new(StatusCode::BAD_REQUEST, Some(value))
+    }
+}
+
+impl From<ExtensionRejection> for AppError {
+    fn from(value: ExtensionRejection) -> Self {
+        Self::new(StatusCode::BAD_REQUEST, Some(value))
+    }
+}
+
+/// Serialize/Deserializer for status codes.
+///
+/// This is needed because status code according to JSON API spec must
+/// be the status code as a STRING.
+///
+/// We could have used http_serde, but it encodes the status code as a NUMBER.
+pub mod serde_status_code {
+    use http::StatusCode;
+    use serde::{de::Unexpected, Deserialize, Deserializer, Serialize, Serializer};
+
+    /// Serialize [StatusCode]s.
+    pub fn serialize<S: Serializer>(status: &StatusCode, ser: S) -> Result<S::Ok, S::Error> {
+        String::serialize(&status.as_u16().to_string(), ser)
+    }
+
+    /// Deserialize [StatusCode]s.
+    pub fn deserialize<'de, D>(de: D) -> Result<StatusCode, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let str = String::deserialize(de)?;
+        StatusCode::from_bytes(str.as_bytes()).map_err(|_| {
+            serde::de::Error::invalid_value(
+                Unexpected::Str(str.as_str()),
+                &"A valid http status code",
+            )
+        })
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/pkarr.rs.html b/pr/2992/docs/src/iroh_dns_server/http/pkarr.rs.html new file mode 100644 index 0000000000..39fb1153d1 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/pkarr.rs.html @@ -0,0 +1,101 @@ +pkarr.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+
use anyhow::Result;
+use axum::{
+    extract::{Path, State},
+    response::IntoResponse,
+};
+use bytes::Bytes;
+use http::{header, StatusCode};
+use tracing::info;
+
+use super::error::AppError;
+use crate::{state::AppState, store::PacketSource, util::PublicKeyBytes};
+
+pub async fn put(
+    State(state): State<AppState>,
+    Path(key): Path<String>,
+    body: Bytes,
+) -> Result<impl IntoResponse, AppError> {
+    let key = pkarr::PublicKey::try_from(key.as_str())
+        .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, Some(format!("invalid key: {e}"))))?;
+    let label = &key.to_z32()[..10];
+    let signed_packet = pkarr::SignedPacket::from_relay_payload(&key, &body).map_err(|e| {
+        AppError::new(
+            StatusCode::BAD_REQUEST,
+            Some(format!("invalid body payload: {e}")),
+        )
+    })?;
+
+    let updated = state
+        .store
+        .insert(signed_packet, PacketSource::PkarrPublish)
+        .await?;
+    info!(key = %label, ?updated, "pkarr upsert");
+    Ok(StatusCode::NO_CONTENT)
+}
+
+pub async fn get(
+    State(state): State<AppState>,
+    Path(pubkey): Path<String>,
+) -> Result<impl IntoResponse, AppError> {
+    let pubkey = PublicKeyBytes::from_z32(&pubkey)
+        .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, Some(format!("invalid key: {e}"))))?;
+    let signed_packet = state
+        .store
+        .get_signed_packet(&pubkey)
+        .await?
+        .ok_or_else(|| AppError::with_status(StatusCode::NOT_FOUND))?;
+    let body = signed_packet.to_relay_payload();
+    let headers = [(header::CONTENT_TYPE, "application/x-pkarr-signed-packet")];
+    Ok((headers, body))
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/rate_limiting.rs.html b/pr/2992/docs/src/iroh_dns_server/http/rate_limiting.rs.html new file mode 100644 index 0000000000..aa582f1587 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/rate_limiting.rs.html @@ -0,0 +1,167 @@ +rate_limiting.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+
use std::{sync::Arc, time::Duration};
+
+use governor::{clock::QuantaInstant, middleware::NoOpMiddleware};
+use serde::{Deserialize, Serialize};
+use tower_governor::{
+    governor::GovernorConfigBuilder,
+    key_extractor::{PeerIpKeyExtractor, SmartIpKeyExtractor},
+    GovernorLayer,
+};
+
+/// Config for http server rate limit.
+#[derive(Debug, Deserialize, Default, Serialize, Clone)]
+#[serde(rename_all = "lowercase")]
+pub enum RateLimitConfig {
+    /// Disable rate limit.
+    Disabled,
+    /// Enable rate limit based on the connection's peer IP address.
+    ///
+    /// <https://docs.rs/tower_governor/latest/tower_governor/key_extractor/struct.PeerIpKeyExtractor.html>
+    #[default]
+    Simple,
+    /// Enable rate limit based on headers commonly used by reverse proxies.
+    ///
+    /// Uses headers commonly used by reverse proxies to extract the original IP address,
+    /// falling back to the connection's peer IP address.
+    /// <https://docs.rs/tower_governor/latest/tower_governor/key_extractor/struct.SmartIpKeyExtractor.html>
+    Smart,
+}
+
+impl Default for &RateLimitConfig {
+    fn default() -> Self {
+        &RateLimitConfig::Simple
+    }
+}
+
+/// Create the default rate-limiting layer.
+///
+/// This spawns a background thread to clean up the rate limiting cache.
+pub fn create(
+    rate_limit_config: &RateLimitConfig,
+) -> Option<GovernorLayer<PeerIpKeyExtractor, NoOpMiddleware<QuantaInstant>>> {
+    let use_smart_extractor = match rate_limit_config {
+        RateLimitConfig::Disabled => {
+            tracing::info!("Rate limiting disabled");
+            return None;
+        }
+        RateLimitConfig::Simple => false,
+        RateLimitConfig::Smart => true,
+    };
+
+    tracing::info!("Rate limiting enabled ({rate_limit_config:?})");
+
+    // Configure rate limiting:
+    // * allow bursts with up to five requests per IP address
+    // * replenish one element every two seconds
+    let mut governor_conf_builder = GovernorConfigBuilder::default();
+    // governor_conf_builder.use_headers()
+    governor_conf_builder.per_second(4);
+    governor_conf_builder.burst_size(2);
+
+    if use_smart_extractor {
+        governor_conf_builder.key_extractor(SmartIpKeyExtractor);
+    }
+
+    let governor_conf = governor_conf_builder
+        .finish()
+        .expect("failed to build rate-limiting governor");
+
+    let governor_conf = Arc::new(governor_conf);
+
+    // The governor needs a background task for garbage collection (to clear expired records)
+    let gc_interval = Duration::from_secs(60);
+    let governor_limiter = governor_conf.limiter().clone();
+    std::thread::spawn(move || loop {
+        std::thread::sleep(gc_interval);
+        tracing::debug!("rate limiting storage size: {}", governor_limiter.len());
+        governor_limiter.retain_recent();
+    });
+
+    Some(GovernorLayer {
+        config: governor_conf,
+    })
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/http/tls.rs.html b/pr/2992/docs/src/iroh_dns_server/http/tls.rs.html new file mode 100644 index 0000000000..bc5ef2faf8 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/http/tls.rs.html @@ -0,0 +1,369 @@ +tls.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+
use std::{
+    borrow::Cow,
+    io,
+    path::{Path, PathBuf},
+    sync::{Arc, OnceLock},
+};
+
+use anyhow::{bail, Context, Result};
+use axum_server::{
+    accept::Accept,
+    tls_rustls::{RustlsAcceptor, RustlsConfig},
+};
+use futures_lite::{future::Boxed as BoxFuture, FutureExt};
+use serde::{Deserialize, Serialize};
+use tokio::io::{AsyncRead, AsyncWrite};
+use tokio_rustls_acme::{axum::AxumAcceptor, caches::DirCache, AcmeConfig};
+use tokio_stream::StreamExt;
+use tracing::{debug, error, info_span, Instrument};
+
+/// The mode how SSL certificates should be created.
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, strum::Display)]
+#[serde(rename_all = "snake_case")]
+pub enum CertMode {
+    /// Certs are loaded from a the `cert_cache` path
+    Manual,
+    /// ACME with LetsEncrypt servers
+    LetsEncrypt,
+    /// Create self-signed certificates and store them in the `cert_cache` path
+    SelfSigned,
+}
+
+impl CertMode {
+    /// Build the [`TlsAcceptor`] for this mode.
+    pub(crate) async fn build(
+        &self,
+        domains: Vec<String>,
+        cert_cache: PathBuf,
+        letsencrypt_contact: Option<String>,
+        letsencrypt_prod: bool,
+    ) -> Result<TlsAcceptor> {
+        Ok(match self {
+            CertMode::Manual => TlsAcceptor::manual(domains, cert_cache).await?,
+            CertMode::SelfSigned => TlsAcceptor::self_signed(domains).await?,
+            CertMode::LetsEncrypt => {
+                let contact =
+                    letsencrypt_contact.context("contact is required for letsencrypt cert mode")?;
+                TlsAcceptor::letsencrypt(domains, &contact, letsencrypt_prod, cert_cache)?
+            }
+        })
+    }
+}
+
+/// TLS Certificate Authority acceptor.
+#[derive(Clone)]
+pub enum TlsAcceptor {
+    LetsEncrypt(AxumAcceptor),
+    Manual(RustlsAcceptor),
+}
+
+impl<I: AsyncRead + AsyncWrite + Unpin + Send + 'static, S: Send + 'static> Accept<I, S>
+    for TlsAcceptor
+{
+    type Stream = tokio_rustls::server::TlsStream<I>;
+    type Service = S;
+    type Future = BoxFuture<io::Result<(Self::Stream, Self::Service)>>;
+
+    fn accept(&self, stream: I, service: S) -> Self::Future {
+        match self {
+            Self::LetsEncrypt(a) => a.accept(stream, service).boxed(),
+            Self::Manual(a) => a.accept(stream, service).boxed(),
+        }
+    }
+}
+
+impl TlsAcceptor {
+    async fn self_signed(domains: Vec<String>) -> Result<Self> {
+        let rcgen::CertifiedKey { cert, key_pair } = rcgen::generate_simple_self_signed(domains)?;
+        let config =
+            RustlsConfig::from_der(vec![cert.der().to_vec()], key_pair.serialize_der()).await?;
+        let acceptor = RustlsAcceptor::new(config);
+        Ok(Self::Manual(acceptor))
+    }
+
+    async fn manual(domains: Vec<String>, dir: PathBuf) -> Result<Self> {
+        let config = rustls::ServerConfig::builder().with_no_client_auth();
+        if domains.len() != 1 {
+            bail!("Multiple domains in manual mode are not supported");
+        }
+        let keyname = escape_hostname(&domains[0]);
+        let cert_path = dir.join(format!("{keyname}.crt"));
+        let key_path = dir.join(format!("{keyname}.key"));
+
+        let certs = load_certs(cert_path).await?;
+        let secret_key = load_secret_key(key_path).await?;
+
+        let config = config.with_single_cert(certs, secret_key)?;
+        let config = RustlsConfig::from_config(Arc::new(config));
+        let acceptor = RustlsAcceptor::new(config);
+        Ok(Self::Manual(acceptor))
+    }
+
+    fn letsencrypt(
+        domains: Vec<String>,
+        contact: &str,
+        is_production: bool,
+        dir: PathBuf,
+    ) -> Result<Self> {
+        let config = rustls::ServerConfig::builder().with_no_client_auth();
+        let mut state = AcmeConfig::new(domains)
+            .contact([format!("mailto:{contact}")])
+            .cache_option(Some(DirCache::new(dir)))
+            .directory_lets_encrypt(is_production)
+            .state();
+
+        let config = config.with_cert_resolver(state.resolver());
+        let acceptor = state.acceptor();
+
+        tokio::spawn(
+            async move {
+                loop {
+                    match state.next().await.unwrap() {
+                        Ok(ok) => debug!("acme event: {:?}", ok),
+                        Err(err) => error!("error: {:?}", err),
+                    }
+                }
+            }
+            .instrument(info_span!("acme")),
+        );
+        let config = Arc::new(config);
+        let acceptor = AxumAcceptor::new(acceptor, config);
+        Ok(Self::LetsEncrypt(acceptor))
+    }
+}
+
+async fn load_certs(
+    filename: impl AsRef<Path>,
+) -> Result<Vec<rustls::pki_types::CertificateDer<'static>>> {
+    let certfile = tokio::fs::read(filename)
+        .await
+        .context("cannot open certificate file")?;
+    let mut reader = std::io::Cursor::new(certfile);
+    let certs: Result<Vec<_>, std::io::Error> = rustls_pemfile::certs(&mut reader).collect();
+    let certs = certs?;
+
+    Ok(certs)
+}
+
+async fn load_secret_key(
+    filename: impl AsRef<Path>,
+) -> Result<rustls::pki_types::PrivateKeyDer<'static>> {
+    let keyfile = tokio::fs::read(filename.as_ref())
+        .await
+        .context("cannot open secret key file")?;
+    let mut reader = std::io::Cursor::new(keyfile);
+
+    loop {
+        match rustls_pemfile::read_one(&mut reader).context("cannot parse secret key .pem file")? {
+            Some(rustls_pemfile::Item::Pkcs1Key(key)) => {
+                return Ok(rustls::pki_types::PrivateKeyDer::Pkcs1(key));
+            }
+            Some(rustls_pemfile::Item::Pkcs8Key(key)) => {
+                return Ok(rustls::pki_types::PrivateKeyDer::Pkcs8(key));
+            }
+            Some(rustls_pemfile::Item::Sec1Key(key)) => {
+                return Ok(rustls::pki_types::PrivateKeyDer::Sec1(key));
+            }
+            None => break,
+            _ => {}
+        }
+    }
+
+    bail!(
+        "no keys found in {} (encrypted keys not supported)",
+        filename.as_ref().display()
+    );
+}
+
+static UNSAFE_HOSTNAME_CHARACTERS: OnceLock<regex::Regex> = OnceLock::new();
+
+fn escape_hostname(hostname: &str) -> Cow<'_, str> {
+    let regex = UNSAFE_HOSTNAME_CHARACTERS
+        .get_or_init(|| regex::Regex::new(r"[^a-zA-Z0-9-\.]").expect("valid regex"));
+    regex.replace_all(hostname, "")
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/lib.rs.html b/pr/2992/docs/src/iroh_dns_server/lib.rs.html new file mode 100644 index 0000000000..1e90d5994d --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/lib.rs.html @@ -0,0 +1,457 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+
//! A DNS server and pkarr relay
+
+#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
+
+pub mod config;
+pub mod dns;
+pub mod http;
+pub mod metrics;
+pub mod server;
+pub mod state;
+mod store;
+mod util;
+
+#[cfg(test)]
+mod tests {
+    use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
+
+    use anyhow::Result;
+    use hickory_resolver::{
+        config::{NameServerConfig, Protocol, ResolverConfig},
+        AsyncResolver,
+    };
+    use iroh::{
+        discovery::pkarr::PkarrRelayClient,
+        dns::{node_info::NodeInfo, DnsResolver, ResolverExt},
+        key::SecretKey,
+    };
+    use pkarr::{PkarrClient, SignedPacket};
+    use url::Url;
+
+    use crate::{config::BootstrapOption, server::Server};
+
+    #[tokio::test]
+    async fn pkarr_publish_dns_resolve() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+        let (server, nameserver, http_url) = Server::spawn_for_tests().await?;
+        let pkarr_relay_url = {
+            let mut url = http_url.clone();
+            url.set_path("/pkarr");
+            url
+        };
+        let signed_packet = {
+            use pkarr::dns;
+            let keypair = pkarr::Keypair::random();
+            let mut packet = dns::Packet::new_reply(0);
+            // record at root
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::TXT("hi0".try_into()?),
+            ));
+            // record at level one
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("_hello").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::TXT("hi1".try_into()?),
+            ));
+            // record at level two
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("_hello.world").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::TXT("hi2".try_into()?),
+            ));
+            // multiple records for same name
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("multiple").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::TXT("hi3".try_into()?),
+            ));
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("multiple").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::TXT("hi4".try_into()?),
+            ));
+            // record of type A
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::A(Ipv4Addr::LOCALHOST.into()),
+            ));
+            // record of type AAAA
+            packet.answers.push(dns::ResourceRecord::new(
+                dns::Name::new("foo.bar.baz").unwrap(),
+                dns::CLASS::IN,
+                30,
+                dns::rdata::RData::AAAA(Ipv6Addr::LOCALHOST.into()),
+            ));
+            SignedPacket::from_packet(&keypair, &packet)?
+        };
+        let pkarr_client = pkarr::PkarrRelayClient::new(pkarr::RelaySettings {
+            relays: vec![pkarr_relay_url.to_string()],
+            ..Default::default()
+        })?;
+        pkarr_client.as_async().publish(&signed_packet).await?;
+
+        use hickory_proto::rr::Name;
+        let pubkey = signed_packet.public_key().to_z32();
+        let resolver = test_resolver(nameserver);
+
+        // resolve root record
+        let name = Name::from_utf8(format!("{pubkey}."))?;
+        let res = resolver.txt_lookup(name).await?;
+        let records = res.iter().map(|t| t.to_string()).collect::<Vec<_>>();
+        assert_eq!(records, vec!["hi0".to_string()]);
+
+        // resolve level one record
+        let name = Name::from_utf8(format!("_hello.{pubkey}."))?;
+        let res = resolver.txt_lookup(name).await?;
+        let records = res.iter().map(|t| t.to_string()).collect::<Vec<_>>();
+        assert_eq!(records, vec!["hi1".to_string()]);
+
+        // resolve level two record
+        let name = Name::from_utf8(format!("_hello.world.{pubkey}."))?;
+        let res = resolver.txt_lookup(name).await?;
+        let records = res.iter().map(|t| t.to_string()).collect::<Vec<_>>();
+        assert_eq!(records, vec!["hi2".to_string()]);
+
+        // resolve multiple records for same name
+        let name = Name::from_utf8(format!("multiple.{pubkey}."))?;
+        let res = resolver.txt_lookup(name).await?;
+        let records = res.iter().map(|t| t.to_string()).collect::<Vec<_>>();
+        assert_eq!(records, vec!["hi3".to_string(), "hi4".to_string()]);
+
+        // resolve A record
+        let name = Name::from_utf8(format!("{pubkey}."))?;
+        let res = resolver.ipv4_lookup(name).await?;
+        let records = res.iter().map(|t| t.0).collect::<Vec<_>>();
+        assert_eq!(records, vec![Ipv4Addr::LOCALHOST]);
+
+        // resolve AAAA record
+        let name = Name::from_utf8(format!("foo.bar.baz.{pubkey}."))?;
+        let res = resolver.ipv6_lookup(name).await?;
+        let records = res.iter().map(|t| t.0).collect::<Vec<_>>();
+        assert_eq!(records, vec![Ipv6Addr::LOCALHOST]);
+
+        server.shutdown().await?;
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn integration_smoke() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+        let (server, nameserver, http_url) = Server::spawn_for_tests().await?;
+
+        let pkarr_relay = {
+            let mut url = http_url.clone();
+            url.set_path("/pkarr");
+            url
+        };
+
+        let origin = "irohdns.example.";
+
+        let secret_key = SecretKey::generate();
+        let node_id = secret_key.public();
+        let relay_url: Url = "https://relay.example.".parse()?;
+        let pkarr = PkarrRelayClient::new(pkarr_relay);
+        let node_info = NodeInfo::new(node_id, Some(relay_url.clone()), Default::default());
+        let signed_packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;
+
+        pkarr.publish(&signed_packet).await?;
+
+        let resolver = test_resolver(nameserver);
+        let res = resolver.lookup_by_id(&node_id, origin).await?;
+
+        assert_eq!(res.node_id, node_id);
+        assert_eq!(res.info.relay_url.map(Url::from), Some(relay_url));
+
+        server.shutdown().await?;
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn integration_mainline() -> Result<()> {
+        iroh_test::logging::setup_multithreaded();
+
+        // run a mainline testnet
+        let testnet = pkarr::mainline::dht::Testnet::new(5);
+        let bootstrap = testnet.bootstrap.clone();
+
+        // spawn our server with mainline support
+        let (server, nameserver, _http_url) =
+            Server::spawn_for_tests_with_mainline(Some(BootstrapOption::Custom(bootstrap))).await?;
+
+        let origin = "irohdns.example.";
+
+        // create a signed packet
+        let secret_key = SecretKey::generate();
+        let node_id = secret_key.public();
+        let relay_url: Url = "https://relay.example.".parse()?;
+        let node_info = NodeInfo::new(node_id, Some(relay_url.clone()), Default::default());
+        let signed_packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;
+
+        // publish the signed packet to our DHT
+        let pkarr = PkarrClient::builder()
+            .dht_settings(pkarr::mainline::dht::DhtSettings {
+                bootstrap: Some(testnet.bootstrap),
+                ..Default::default()
+            })
+            .build()?;
+        pkarr.publish(&signed_packet)?;
+
+        // resolve via DNS from our server, which will lookup from our DHT
+        let resolver = test_resolver(nameserver);
+        let res = resolver.lookup_by_id(&node_id, origin).await?;
+
+        assert_eq!(res.node_id, node_id);
+        assert_eq!(res.info.relay_url.map(Url::from), Some(relay_url));
+
+        server.shutdown().await?;
+        for mut node in testnet.nodes {
+            node.shutdown()?;
+        }
+        Ok(())
+    }
+
+    fn test_resolver(nameserver: SocketAddr) -> DnsResolver {
+        let mut config = ResolverConfig::new();
+        let nameserver_config = NameServerConfig::new(nameserver, Protocol::Udp);
+        config.add_name_server(nameserver_config);
+        AsyncResolver::tokio(config, Default::default())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/metrics.rs.html b/pr/2992/docs/src/iroh_dns_server/metrics.rs.html new file mode 100644 index 0000000000..1c1a8fc65e --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/metrics.rs.html @@ -0,0 +1,125 @@ +metrics.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
//! Metrics support for the server
+
+use iroh_metrics::core::{Core, Counter, Metric};
+use struct_iterable::Iterable;
+
+/// Metrics for iroh-dns-server
+#[derive(Debug, Clone, Iterable)]
+#[allow(missing_docs)]
+pub struct Metrics {
+    pub pkarr_publish_update: Counter,
+    pub pkarr_publish_noop: Counter,
+    pub dns_requests: Counter,
+    pub dns_requests_udp: Counter,
+    pub dns_requests_https: Counter,
+    pub dns_lookup_success: Counter,
+    pub dns_lookup_notfound: Counter,
+    pub dns_lookup_error: Counter,
+    pub http_requests: Counter,
+    pub http_requests_success: Counter,
+    pub http_requests_error: Counter,
+    pub http_requests_duration_ms: Counter,
+    pub store_packets_inserted: Counter,
+    pub store_packets_removed: Counter,
+    pub store_packets_updated: Counter,
+}
+
+impl Default for Metrics {
+    fn default() -> Self {
+        Self {
+            pkarr_publish_update: Counter::new("Number of pkarr relay puts that updated the state"),
+            pkarr_publish_noop: Counter::new(
+                "Number of pkarr relay puts that did not update the state",
+            ),
+            dns_requests: Counter::new("DNS requests (total)"),
+            dns_requests_udp: Counter::new("DNS requests via UDP"),
+            dns_requests_https: Counter::new("DNS requests via HTTPS (DoH)"),
+            dns_lookup_success: Counter::new("DNS lookup responses with at least one answer"),
+            dns_lookup_notfound: Counter::new("DNS lookup responses with no answers"),
+            dns_lookup_error: Counter::new("DNS lookup responses which failed"),
+            http_requests: Counter::new("Number of HTTP requests"),
+            http_requests_success: Counter::new("Number of HTTP requests with a 2xx status code"),
+            http_requests_error: Counter::new("Number of HTTP requests with a non-2xx status code"),
+            http_requests_duration_ms: Counter::new("Total duration of all HTTP requests"),
+            store_packets_inserted: Counter::new("Signed packets inserted into the store"),
+            store_packets_removed: Counter::new("Signed packets removed from the store"),
+            store_packets_updated: Counter::new("Number of updates to existing packets"),
+        }
+    }
+}
+
+impl Metric for Metrics {
+    fn name() -> &'static str {
+        "dns_server"
+    }
+}
+
+/// Init the metrics collection core.
+pub fn init_metrics() {
+    Core::init(|reg, metrics| {
+        metrics.insert(Metrics::new(reg));
+    });
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/server.rs.html b/pr/2992/docs/src/iroh_dns_server/server.rs.html new file mode 100644 index 0000000000..e4a4e7abe8 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/server.rs.html @@ -0,0 +1,263 @@ +server.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+
//! The main server which combines the DNS and HTTP(S) servers.
+
+use anyhow::Result;
+use iroh_metrics::metrics::start_metrics_server;
+use tracing::info;
+
+use crate::{
+    config::Config,
+    dns::{DnsHandler, DnsServer},
+    http::HttpServer,
+    state::AppState,
+    store::ZoneStore,
+};
+
+/// Spawn the server and run until the `Ctrl-C` signal is received, then shutdown.
+pub async fn run_with_config_until_ctrl_c(config: Config) -> Result<()> {
+    let mut store = ZoneStore::persistent(Config::signed_packet_store_path()?)?;
+    if let Some(bootstrap) = config.mainline_enabled() {
+        info!("mainline fallback enabled");
+        store = store.with_mainline_fallback(bootstrap);
+    };
+    let server = Server::spawn(config, store).await?;
+    tokio::signal::ctrl_c().await?;
+    info!("shutdown");
+    server.shutdown().await?;
+    Ok(())
+}
+
+/// The iroh-dns server.
+pub struct Server {
+    http_server: HttpServer,
+    dns_server: DnsServer,
+    metrics_task: tokio::task::JoinHandle<anyhow::Result<()>>,
+}
+
+impl Server {
+    /// Spawn the server.
+    ///
+    /// This will spawn several background tasks:
+    /// * A DNS server task
+    /// * A HTTP server task, if `config.http` is not empty
+    /// * A HTTPS server task, if `config.https` is not empty
+    pub async fn spawn(config: Config, store: ZoneStore) -> Result<Self> {
+        let dns_handler = DnsHandler::new(store.clone(), &config.dns)?;
+
+        let state = AppState { store, dns_handler };
+
+        let metrics_addr = config.metrics_addr();
+        let metrics_task = tokio::task::spawn(async move {
+            if let Some(addr) = metrics_addr {
+                start_metrics_server(addr).await?;
+            }
+            Ok(())
+        });
+        let http_server = HttpServer::spawn(
+            config.http,
+            config.https,
+            config.pkarr_put_rate_limit,
+            state.clone(),
+        )
+        .await?;
+        let dns_server = DnsServer::spawn(config.dns, state.dns_handler.clone()).await?;
+        Ok(Self {
+            http_server,
+            dns_server,
+            metrics_task,
+        })
+    }
+
+    /// Cancel the server tasks and wait for all tasks to complete.
+    pub async fn shutdown(self) -> Result<()> {
+        self.metrics_task.abort();
+        let (res1, res2) = tokio::join!(self.dns_server.shutdown(), self.http_server.shutdown(),);
+        res1?;
+        res2?;
+        Ok(())
+    }
+
+    /// Wait for all tasks to complete.
+    ///
+    /// This will run forever unless all tasks close with an error, or `Self::cancel` is called.
+    pub async fn run_until_error(self) -> Result<()> {
+        tokio::select! {
+            res = self.dns_server.run_until_done() => res?,
+            res = self.http_server.run_until_done() => res?,
+        }
+        self.metrics_task.abort();
+        Ok(())
+    }
+
+    /// Spawn a server suitable for testing.
+    ///
+    /// This will run the DNS and HTTP servers, but not the HTTPS server.
+    ///
+    /// It returns the server handle, the [`SocketAddr`] of the DNS server and the [`Url`] of the
+    /// HTTP server.
+    #[cfg(test)]
+    pub async fn spawn_for_tests() -> Result<(Self, std::net::SocketAddr, url::Url)> {
+        Self::spawn_for_tests_with_mainline(None).await
+    }
+
+    /// Spawn a server suitable for testing, while optionally enabling mainline with custom
+    /// bootstrap addresses.
+    #[cfg(test)]
+    pub async fn spawn_for_tests_with_mainline(
+        mainline: Option<crate::config::BootstrapOption>,
+    ) -> Result<(Self, std::net::SocketAddr, url::Url)> {
+        use std::net::{IpAddr, Ipv4Addr};
+
+        use crate::config::MetricsConfig;
+
+        let mut config = Config::default();
+        config.dns.port = 0;
+        config.dns.bind_addr = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
+        config.http.as_mut().unwrap().port = 0;
+        config.http.as_mut().unwrap().bind_addr = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
+        config.https = None;
+        config.metrics = Some(MetricsConfig::disabled());
+
+        let mut store = ZoneStore::in_memory()?;
+        if let Some(bootstrap) = mainline {
+            info!("mainline fallback enabled");
+            store = store.with_mainline_fallback(bootstrap);
+        }
+        let server = Self::spawn(config, store).await?;
+        let dns_addr = server.dns_server.local_addr();
+        let http_addr = server.http_server.http_addr().expect("http is set");
+        let http_url = format!("http://{http_addr}").parse()?;
+        Ok((server, dns_addr, http_url))
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/state.rs.html b/pr/2992/docs/src/iroh_dns_server/state.rs.html new file mode 100644 index 0000000000..9a6561ab4d --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/state.rs.html @@ -0,0 +1,25 @@ +state.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+
//! Shared state and store for the iroh-dns-server
+
+use crate::{dns::DnsHandler, store::ZoneStore};
+
+/// The shared app state.
+#[derive(Clone)]
+pub struct AppState {
+    /// The pkarr DNS store
+    pub store: ZoneStore,
+    /// Handler for DNS requests
+    pub dns_handler: DnsHandler,
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/store.rs.html b/pr/2992/docs/src/iroh_dns_server/store.rs.html new file mode 100644 index 0000000000..1004565a97 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/store.rs.html @@ -0,0 +1,529 @@ +store.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+
//! Pkarr packet store used to resolve DNS queries.
+
+use std::{collections::BTreeMap, num::NonZeroUsize, path::Path, sync::Arc, time::Duration};
+
+use anyhow::Result;
+use hickory_proto::rr::{Name, RecordSet, RecordType, RrKey};
+use iroh_metrics::inc;
+use lru::LruCache;
+use parking_lot::Mutex;
+use pkarr::{mainline::dht::DhtSettings, PkarrClient, SignedPacket};
+use tracing::{debug, trace};
+use ttl_cache::TtlCache;
+
+use self::signed_packets::SignedPacketStore;
+use crate::{
+    config::BootstrapOption,
+    metrics::Metrics,
+    util::{signed_packet_to_hickory_records_without_origin, PublicKeyBytes},
+};
+
+mod signed_packets;
+
+/// Cache up to 1 million pkarr zones by default
+pub const DEFAULT_CACHE_CAPACITY: usize = 1024 * 1024;
+/// Default TTL for DHT cache entries
+pub const DHT_CACHE_TTL: Duration = Duration::from_secs(300);
+
+/// Where a new pkarr packet comes from
+pub enum PacketSource {
+    /// Received via HTTPS relay PUT
+    PkarrPublish,
+}
+
+/// A store for pkarr signed packets.
+///
+/// Packets are stored in the persistent [`SignedPacketStore`], and cached on-demand in an in-memory LRU
+/// cache used for resolving DNS queries.
+#[derive(Debug, Clone)]
+pub struct ZoneStore {
+    cache: Arc<Mutex<ZoneCache>>,
+    store: Arc<SignedPacketStore>,
+    pkarr: Option<Arc<PkarrClient>>,
+}
+
+impl ZoneStore {
+    /// Create a persistent store
+    pub fn persistent(path: impl AsRef<Path>) -> Result<Self> {
+        let packet_store = SignedPacketStore::persistent(path)?;
+        Ok(Self::new(packet_store))
+    }
+
+    /// Create an in-memory store.
+    pub fn in_memory() -> Result<Self> {
+        let packet_store = SignedPacketStore::in_memory()?;
+        Ok(Self::new(packet_store))
+    }
+
+    /// Configure a pkarr client for resolution of packets from the bittorrent mainline DHT.
+    ///
+    /// This will be used only as a fallback if there is no local info available.
+    ///
+    /// Optionally set custom bootstrap nodes. If `bootstrap` is empty it will use the default
+    /// mainline bootstrap nodes.
+    pub fn with_mainline_fallback(self, bootstrap: BootstrapOption) -> Self {
+        let pkarr_client = match bootstrap {
+            BootstrapOption::Default => PkarrClient::builder().build().unwrap(),
+            BootstrapOption::Custom(bootstrap) => PkarrClient::builder()
+                .dht_settings(DhtSettings {
+                    bootstrap: Some(bootstrap),
+                    ..Default::default()
+                })
+                .build()
+                .unwrap(),
+        };
+        Self {
+            pkarr: Some(Arc::new(pkarr_client)),
+            ..self
+        }
+    }
+
+    /// Create a new zone store.
+    pub fn new(store: SignedPacketStore) -> Self {
+        let zone_cache = ZoneCache::new(DEFAULT_CACHE_CAPACITY);
+        Self {
+            store: Arc::new(store),
+            cache: Arc::new(Mutex::new(zone_cache)),
+            pkarr: None,
+        }
+    }
+
+    /// Resolve a DNS query.
+    #[allow(clippy::unused_async)]
+    pub async fn resolve(
+        &self,
+        pubkey: &PublicKeyBytes,
+        name: &Name,
+        record_type: RecordType,
+    ) -> Result<Option<Arc<RecordSet>>> {
+        tracing::info!("{} {}", name, record_type);
+        if let Some(rset) = self.cache.lock().resolve(pubkey, name, record_type) {
+            return Ok(Some(rset));
+        }
+
+        if let Some(packet) = self.store.get(pubkey)? {
+            return self
+                .cache
+                .lock()
+                .insert_and_resolve(&packet, name, record_type);
+        };
+
+        if let Some(pkarr) = self.pkarr.as_ref() {
+            let key = pkarr::PublicKey::try_from(pubkey.as_bytes()).expect("valid public key");
+            // use the more expensive `resolve_most_recent` here.
+            //
+            // it will be cached for some time.
+            debug!("DHT resolve {}", key.to_z32());
+            let packet_opt = pkarr.as_ref().clone().as_async().resolve(&key).await?;
+            if let Some(packet) = packet_opt {
+                debug!("DHT resolve successful {:?}", packet.packet());
+                return self
+                    .cache
+                    .lock()
+                    .insert_and_resolve_dht(&packet, name, record_type);
+            } else {
+                debug!("DHT resolve failed");
+            }
+        }
+        Ok(None)
+    }
+
+    /// Get the latest signed packet for a pubkey.
+    // allow unused async: this will be async soon.
+    #[allow(clippy::unused_async)]
+    pub async fn get_signed_packet(&self, pubkey: &PublicKeyBytes) -> Result<Option<SignedPacket>> {
+        self.store.get(pubkey)
+    }
+
+    /// Insert a signed packet into the cache and the store.
+    ///
+    /// Returns whether this produced an update, i.e. whether the packet is the newest for its
+    /// pubkey.
+    // allow unused async: this will be async soon.
+    #[allow(clippy::unused_async)]
+    pub async fn insert(&self, signed_packet: SignedPacket, _source: PacketSource) -> Result<bool> {
+        let pubkey = PublicKeyBytes::from_signed_packet(&signed_packet);
+        if self.store.upsert(signed_packet)? {
+            inc!(Metrics, pkarr_publish_update);
+            self.cache.lock().remove(&pubkey);
+            Ok(true)
+        } else {
+            inc!(Metrics, pkarr_publish_noop);
+            Ok(false)
+        }
+    }
+}
+
+#[derive(derive_more::Debug)]
+struct ZoneCache {
+    /// Cache for explicitly added entries
+    cache: LruCache<PublicKeyBytes, CachedZone>,
+    /// Cache for DHT entries, this must have a finite TTL
+    /// so we don't cache stale entries indefinitely.
+    #[debug("dht_cache")]
+    dht_cache: TtlCache<PublicKeyBytes, CachedZone>,
+}
+
+impl ZoneCache {
+    fn new(cap: usize) -> Self {
+        let cache = LruCache::new(NonZeroUsize::new(cap).expect("capacity must be larger than 0"));
+        let dht_cache = TtlCache::new(cap);
+        Self { cache, dht_cache }
+    }
+
+    fn resolve(
+        &mut self,
+        pubkey: &PublicKeyBytes,
+        name: &Name,
+        record_type: RecordType,
+    ) -> Option<Arc<RecordSet>> {
+        let zone = if let Some(zone) = self.cache.get(pubkey) {
+            trace!("cache hit {}", pubkey.to_z32());
+            zone
+        } else if let Some(zone) = self.dht_cache.get(pubkey) {
+            trace!("dht cache hit {}", pubkey.to_z32());
+            zone
+        } else {
+            return None;
+        };
+        zone.resolve(name, record_type)
+    }
+
+    fn insert_and_resolve(
+        &mut self,
+        signed_packet: &SignedPacket,
+        name: &Name,
+        record_type: RecordType,
+    ) -> Result<Option<Arc<RecordSet>>> {
+        let pubkey = PublicKeyBytes::from_signed_packet(signed_packet);
+        self.insert(signed_packet)?;
+        Ok(self.resolve(&pubkey, name, record_type))
+    }
+
+    fn insert_and_resolve_dht(
+        &mut self,
+        signed_packet: &SignedPacket,
+        name: &Name,
+        record_type: RecordType,
+    ) -> Result<Option<Arc<RecordSet>>> {
+        let pubkey = PublicKeyBytes::from_signed_packet(signed_packet);
+        let zone = CachedZone::from_signed_packet(signed_packet)?;
+        let res = zone.resolve(name, record_type);
+        self.dht_cache.insert(pubkey, zone, DHT_CACHE_TTL);
+        Ok(res)
+    }
+
+    fn insert(&mut self, signed_packet: &SignedPacket) -> Result<()> {
+        let pubkey = PublicKeyBytes::from_signed_packet(signed_packet);
+        if self
+            .cache
+            .peek(&pubkey)
+            .map(|old| old.is_newer_than(signed_packet))
+            .unwrap_or(false)
+        {
+            return Ok(());
+        }
+        self.cache
+            .put(pubkey, CachedZone::from_signed_packet(signed_packet)?);
+        Ok(())
+    }
+
+    fn remove(&mut self, pubkey: &PublicKeyBytes) {
+        self.cache.pop(pubkey);
+        self.dht_cache.remove(pubkey);
+    }
+}
+
+#[derive(Debug)]
+struct CachedZone {
+    timestamp: u64,
+    records: BTreeMap<RrKey, Arc<RecordSet>>,
+}
+
+impl CachedZone {
+    fn from_signed_packet(signed_packet: &SignedPacket) -> Result<Self> {
+        let (_label, records) =
+            signed_packet_to_hickory_records_without_origin(signed_packet, |_| true)?;
+        Ok(Self {
+            records,
+            timestamp: signed_packet.timestamp(),
+        })
+    }
+
+    fn is_newer_than(&self, signed_packet: &SignedPacket) -> bool {
+        self.timestamp > signed_packet.timestamp()
+    }
+
+    fn resolve(&self, name: &Name, record_type: RecordType) -> Option<Arc<RecordSet>> {
+        let key = RrKey::new(name.into(), record_type);
+        for record in self.records.keys() {
+            tracing::info!("record {:?}", record);
+        }
+        self.records.get(&key).cloned()
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/store/signed_packets.rs.html b/pr/2992/docs/src/iroh_dns_server/store/signed_packets.rs.html new file mode 100644 index 0000000000..c1493203b1 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/store/signed_packets.rs.html @@ -0,0 +1,219 @@ +signed_packets.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
use std::path::Path;
+
+use anyhow::{Context, Result};
+use iroh_metrics::inc;
+use pkarr::SignedPacket;
+use redb::{backends::InMemoryBackend, Database, ReadableTable, TableDefinition};
+use tracing::info;
+
+use crate::{metrics::Metrics, util::PublicKeyBytes};
+
+pub type SignedPacketsKey = [u8; 32];
+const SIGNED_PACKETS_TABLE: TableDefinition<&SignedPacketsKey, &[u8]> =
+    TableDefinition::new("signed-packets-1");
+
+#[derive(Debug)]
+pub struct SignedPacketStore {
+    db: Database,
+}
+
+impl SignedPacketStore {
+    pub fn persistent(path: impl AsRef<Path>) -> Result<Self> {
+        let path = path.as_ref();
+        info!("loading packet database from {}", path.to_string_lossy());
+        if let Some(parent) = path.parent() {
+            std::fs::create_dir_all(parent).with_context(|| {
+                format!(
+                    "failed to create database directory at {}",
+                    path.to_string_lossy()
+                )
+            })?;
+        }
+        let db = Database::builder()
+            .create(path)
+            .context("failed to open packet database")?;
+        Self::open(db)
+    }
+
+    pub fn in_memory() -> Result<Self> {
+        info!("using in-memory packet database");
+        let db = Database::builder().create_with_backend(InMemoryBackend::new())?;
+        Self::open(db)
+    }
+
+    pub fn open(db: Database) -> Result<Self> {
+        let write_tx = db.begin_write()?;
+        {
+            let _table = write_tx.open_table(SIGNED_PACKETS_TABLE)?;
+        }
+        write_tx.commit()?;
+        Ok(Self { db })
+    }
+
+    pub fn upsert(&self, packet: SignedPacket) -> Result<bool> {
+        let key = PublicKeyBytes::from_signed_packet(&packet);
+        let tx = self.db.begin_write()?;
+        let mut replaced = false;
+        {
+            let mut table = tx.open_table(SIGNED_PACKETS_TABLE)?;
+            if let Some(existing) = get_packet(&table, &key)? {
+                if existing.more_recent_than(&packet) {
+                    return Ok(false);
+                } else {
+                    replaced = true;
+                }
+            }
+            let value = packet.as_bytes();
+            table.insert(key.as_bytes(), &value[..])?;
+        }
+        tx.commit()?;
+        if replaced {
+            inc!(Metrics, store_packets_updated);
+        } else {
+            inc!(Metrics, store_packets_inserted);
+        }
+        Ok(true)
+    }
+
+    pub fn get(&self, key: &PublicKeyBytes) -> Result<Option<SignedPacket>> {
+        let tx = self.db.begin_read()?;
+        let table = tx.open_table(SIGNED_PACKETS_TABLE)?;
+        get_packet(&table, key)
+    }
+
+    pub fn remove(&self, key: &PublicKeyBytes) -> Result<bool> {
+        let tx = self.db.begin_write()?;
+        let updated = {
+            let mut table = tx.open_table(SIGNED_PACKETS_TABLE)?;
+            let did_remove = table.remove(key.as_bytes())?.is_some();
+            #[allow(clippy::let_and_return)]
+            did_remove
+        };
+        tx.commit()?;
+        if updated {
+            inc!(Metrics, store_packets_removed)
+        }
+        Ok(updated)
+    }
+}
+
+fn get_packet(
+    table: &impl ReadableTable<&'static SignedPacketsKey, &'static [u8]>,
+    key: &PublicKeyBytes,
+) -> Result<Option<SignedPacket>> {
+    let Some(row) = table.get(key.as_ref())? else {
+        return Ok(None);
+    };
+    let packet = SignedPacket::from_bytes(&row.value().to_vec().into())?;
+    Ok(Some(packet))
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_dns_server/util.rs.html b/pr/2992/docs/src/iroh_dns_server/util.rs.html new file mode 100644 index 0000000000..56ef4fe105 --- /dev/null +++ b/pr/2992/docs/src/iroh_dns_server/util.rs.html @@ -0,0 +1,307 @@ +util.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+
use core::fmt;
+use std::{
+    collections::{btree_map, BTreeMap},
+    str::FromStr,
+    sync::Arc,
+};
+
+use anyhow::{anyhow, Result};
+use hickory_proto::{
+    op::Message,
+    rr::{
+        domain::{IntoLabel, Label},
+        Name, Record, RecordSet, RecordType, RrKey,
+    },
+    serialize::binary::BinDecodable,
+};
+use pkarr::SignedPacket;
+
+#[derive(
+    derive_more::From, derive_more::Into, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy,
+)]
+pub struct PublicKeyBytes([u8; 32]);
+
+impl PublicKeyBytes {
+    pub fn from_z32(s: &str) -> Result<Self> {
+        let bytes = z32::decode(s.as_bytes())?;
+        let bytes: [u8; 32] = bytes.try_into().map_err(|_| anyhow!("invalid length"))?;
+        Ok(Self(bytes))
+    }
+
+    pub fn to_z32(self) -> String {
+        z32::encode(&self.0)
+    }
+
+    pub fn to_bytes(self) -> [u8; 32] {
+        self.0
+    }
+
+    pub fn as_bytes(&self) -> &[u8; 32] {
+        &self.0
+    }
+
+    pub fn from_signed_packet(packet: &SignedPacket) -> Self {
+        Self(packet.public_key().to_bytes())
+    }
+}
+
+impl fmt::Display for PublicKeyBytes {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.to_z32())
+    }
+}
+
+impl fmt::Debug for PublicKeyBytes {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "PublicKeyBytes({})", self.to_z32())
+    }
+}
+
+impl From<pkarr::PublicKey> for PublicKeyBytes {
+    fn from(value: pkarr::PublicKey) -> Self {
+        Self(value.to_bytes())
+    }
+}
+
+impl TryFrom<PublicKeyBytes> for pkarr::PublicKey {
+    type Error = anyhow::Error;
+    fn try_from(value: PublicKeyBytes) -> Result<Self, Self::Error> {
+        pkarr::PublicKey::try_from(&value.0).map_err(anyhow::Error::from)
+    }
+}
+
+impl FromStr for PublicKeyBytes {
+    type Err = anyhow::Error;
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Self::from_z32(s)
+    }
+}
+
+impl AsRef<[u8; 32]> for PublicKeyBytes {
+    fn as_ref(&self) -> &[u8; 32] {
+        &self.0
+    }
+}
+
+pub fn signed_packet_to_hickory_message(signed_packet: &SignedPacket) -> Result<Message> {
+    let encoded = signed_packet.encoded_packet();
+    let message = Message::from_bytes(&encoded)?;
+    Ok(message)
+}
+
+pub fn signed_packet_to_hickory_records_without_origin(
+    signed_packet: &SignedPacket,
+    filter: impl Fn(&Record) -> bool,
+) -> Result<(Label, BTreeMap<RrKey, Arc<RecordSet>>)> {
+    let common_zone = Label::from_utf8(&signed_packet.public_key().to_z32())?;
+    let mut message = signed_packet_to_hickory_message(signed_packet)?;
+    let answers = message.take_answers();
+    let mut output: BTreeMap<RrKey, Arc<RecordSet>> = BTreeMap::new();
+    for mut record in answers.into_iter() {
+        // disallow SOA and NS records
+        if matches!(record.record_type(), RecordType::SOA | RecordType::NS) {
+            continue;
+        }
+        // expect the z32 encoded pubkey as root name
+        let name = record.name();
+        if name.num_labels() < 1 {
+            continue;
+        }
+        let zone = name.iter().last().unwrap().into_label()?;
+        if zone != common_zone {
+            continue;
+        }
+        if !filter(&record) {
+            continue;
+        }
+
+        let name_without_zone =
+            Name::from_labels(name.iter().take(name.num_labels() as usize - 1))?;
+        record.set_name(name_without_zone);
+
+        let rrkey = RrKey::new(record.name().into(), record.record_type());
+        match output.entry(rrkey) {
+            btree_map::Entry::Vacant(e) => {
+                let set: RecordSet = record.into();
+                e.insert(Arc::new(set));
+            }
+            btree_map::Entry::Occupied(mut e) => {
+                let set = e.get_mut();
+                let serial = set.serial();
+                // safe because we just created the arc and are sync iterating
+                Arc::get_mut(set).unwrap().insert(record, serial);
+            }
+        }
+    }
+    Ok((common_zone, output))
+}
+
+pub fn record_set_append_origin(
+    input: &RecordSet,
+    origin: &Name,
+    serial: u32,
+) -> Result<RecordSet> {
+    let new_name = input.name().clone().append_name(origin)?;
+    let mut output = RecordSet::new(&new_name, input.record_type(), serial);
+    // TODO: less clones
+    for record in input.records_without_rrsigs() {
+        let mut record = record.clone();
+        record.set_name(new_name.clone());
+        output.insert(record, serial);
+    }
+    Ok(output)
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_bench/iroh.rs.html b/pr/2992/docs/src/iroh_net_bench/iroh.rs.html new file mode 100644 index 0000000000..d427b9f8d4 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_bench/iroh.rs.html @@ -0,0 +1,577 @@ +iroh.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+
use std::{
+    net::SocketAddr,
+    time::{Duration, Instant},
+};
+
+use anyhow::{Context, Result};
+use bytes::Bytes;
+use futures_lite::StreamExt as _;
+use iroh::{
+    endpoint::{Connection, ConnectionError, RecvStream, SendStream, TransportConfig},
+    Endpoint, NodeAddr, RelayMap, RelayMode, RelayUrl,
+};
+use tracing::{trace, warn};
+
+use crate::{
+    client_handler, stats::TransferResult, ClientStats, ConnectionSelector, EndpointSelector, Opt,
+};
+
+pub const ALPN: &[u8] = b"n0/iroh-net-bench/0";
+
+/// Creates a server endpoint which runs on the given runtime
+pub fn server_endpoint(
+    rt: &tokio::runtime::Runtime,
+    relay_url: &Option<RelayUrl>,
+    opt: &Opt,
+) -> (NodeAddr, Endpoint) {
+    let _guard = rt.enter();
+    rt.block_on(async move {
+        let relay_mode = relay_url.clone().map_or(RelayMode::Disabled, |url| {
+            RelayMode::Custom(RelayMap::from_url(url))
+        });
+
+        #[allow(unused_mut)]
+        let mut builder = Endpoint::builder();
+        #[cfg(feature = "local-relay")]
+        {
+            builder = builder.insecure_skip_relay_cert_verify(relay_url.is_some())
+        }
+        let ep = builder
+            .alpns(vec![ALPN.to_vec()])
+            .relay_mode(relay_mode)
+            .transport_config(transport_config(opt.max_streams, opt.initial_mtu))
+            .bind()
+            .await
+            .unwrap();
+
+        if relay_url.is_some() {
+            ep.watch_home_relay().next().await;
+        }
+
+        let addr = ep.bound_sockets();
+        let addr = SocketAddr::new("127.0.0.1".parse().unwrap(), addr.0.port());
+        let mut addr = NodeAddr::new(ep.node_id()).with_direct_addresses([addr]);
+        if let Some(relay_url) = relay_url {
+            addr = addr.with_relay_url(relay_url.clone());
+        }
+        (addr, ep)
+    })
+}
+
+/// Create and run a client
+pub async fn client(
+    server_addr: NodeAddr,
+    relay_url: Option<RelayUrl>,
+    opt: Opt,
+) -> Result<ClientStats> {
+    let client_start = std::time::Instant::now();
+    let (endpoint, connection) = connect_client(server_addr, relay_url, opt).await?;
+    let client_connect_time = client_start.elapsed();
+    let mut res = client_handler(
+        EndpointSelector::Iroh(endpoint),
+        ConnectionSelector::Iroh(connection),
+        opt,
+    )
+    .await?;
+    res.connect_time = client_connect_time;
+    Ok(res)
+}
+
+/// Create a client endpoint and client connection
+pub async fn connect_client(
+    server_addr: NodeAddr,
+    relay_url: Option<RelayUrl>,
+    opt: Opt,
+) -> Result<(Endpoint, Connection)> {
+    let relay_mode = relay_url.clone().map_or(RelayMode::Disabled, |url| {
+        RelayMode::Custom(RelayMap::from_url(url))
+    });
+    #[allow(unused_mut)]
+    let mut builder = Endpoint::builder();
+    #[cfg(feature = "local-relay")]
+    {
+        builder = builder.insecure_skip_relay_cert_verify(relay_url.is_some())
+    }
+    let endpoint = builder
+        .alpns(vec![ALPN.to_vec()])
+        .relay_mode(relay_mode)
+        .transport_config(transport_config(opt.max_streams, opt.initial_mtu))
+        .bind()
+        .await
+        .unwrap();
+
+    if relay_url.is_some() {
+        endpoint.watch_home_relay().next().await;
+    }
+
+    // TODO: We don't support passing client transport config currently
+    // let mut client_config = quinn::ClientConfig::new(Arc::new(crypto));
+    // client_config.transport_config(Arc::new(transport_config(&opt)));
+
+    let connection = endpoint
+        .connect(server_addr, ALPN)
+        .await
+        .context("unable to connect")?;
+    trace!("connected");
+
+    Ok((endpoint, connection))
+}
+
+pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig {
+    // High stream windows are chosen because the amount of concurrent streams
+    // is configurable as a parameter.
+    let mut config = TransportConfig::default();
+    config.max_concurrent_uni_streams(max_streams.try_into().unwrap());
+    config.initial_mtu(initial_mtu);
+
+    // TODO: re-enable when we upgrade quinn version
+    // let mut acks = quinn::AckFrequencyConfig::default();
+    // acks.ack_eliciting_threshold(10u32.into());
+    // config.ack_frequency_config(Some(acks));
+
+    config
+}
+
+async fn drain_stream(
+    stream: &mut RecvStream,
+    read_unordered: bool,
+) -> Result<(usize, Duration, u64)> {
+    let mut read = 0;
+
+    let download_start = Instant::now();
+    let mut first_byte = true;
+    let mut ttfb = download_start.elapsed();
+
+    let mut num_chunks: u64 = 0;
+
+    if read_unordered {
+        while let Some(chunk) = stream.read_chunk(usize::MAX, false).await? {
+            if first_byte {
+                ttfb = download_start.elapsed();
+                first_byte = false;
+            }
+            read += chunk.bytes.len();
+            num_chunks += 1;
+        }
+    } else {
+        // These are 32 buffers, for reading approximately 32kB at once
+        #[rustfmt::skip]
+        let mut bufs = [
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+        ];
+
+        while let Some(n) = stream.read_chunks(&mut bufs[..]).await? {
+            if first_byte {
+                ttfb = download_start.elapsed();
+                first_byte = false;
+            }
+            read += bufs.iter().take(n).map(|buf| buf.len()).sum::<usize>();
+            num_chunks += 1;
+        }
+    }
+
+    Ok((read, ttfb, num_chunks))
+}
+
+async fn send_data_on_stream(stream: &mut SendStream, stream_size: u64) -> Result<()> {
+    const DATA: &[u8] = &[0xAB; 1024 * 1024];
+    let bytes_data = Bytes::from_static(DATA);
+
+    let full_chunks = stream_size / (DATA.len() as u64);
+    let remaining = (stream_size % (DATA.len() as u64)) as usize;
+
+    for _ in 0..full_chunks {
+        stream
+            .write_chunk(bytes_data.clone())
+            .await
+            .context("failed sending data")?;
+    }
+
+    if remaining != 0 {
+        stream
+            .write_chunk(bytes_data.slice(0..remaining))
+            .await
+            .context("failed sending data")?;
+    }
+
+    stream.finish().context("failed finishing stream")?;
+    stream
+        .stopped()
+        .await
+        .context("failed to wait for stream to be stopped")?;
+
+    Ok(())
+}
+
+pub async fn handle_client_stream(
+    connection: &Connection,
+    upload_size: u64,
+    read_unordered: bool,
+) -> Result<(TransferResult, TransferResult)> {
+    let start = Instant::now();
+
+    let (mut send_stream, mut recv_stream) = connection
+        .open_bi()
+        .await
+        .context("failed to open stream")?;
+
+    send_data_on_stream(&mut send_stream, upload_size).await?;
+
+    let upload_result = TransferResult::new(start.elapsed(), upload_size, Duration::default(), 0);
+
+    let start = Instant::now();
+    let (size, ttfb, num_chunks) = drain_stream(&mut recv_stream, read_unordered).await?;
+    let download_result = TransferResult::new(start.elapsed(), size as u64, ttfb, num_chunks);
+
+    Ok((upload_result, download_result))
+}
+
+/// Take the provided endpoint and run the server
+pub async fn server(endpoint: Endpoint, opt: Opt) -> Result<()> {
+    let mut server_tasks = Vec::new();
+
+    // Handle only the expected amount of clients
+    for _ in 0..opt.clients {
+        let incoming = endpoint.accept().await.unwrap();
+        let connecting = match incoming.accept() {
+            Ok(connecting) => connecting,
+            Err(err) => {
+                warn!("incoming connection failed: {err:#}");
+                // we can carry on in these cases:
+                // this can be caused by retransmitted datagrams
+                continue;
+            }
+        };
+        let connection = connecting.await.context("handshake failed")?;
+
+        server_tasks.push(tokio::spawn(async move {
+            loop {
+                let (mut send_stream, mut recv_stream) = match connection.accept_bi().await {
+                    Err(ConnectionError::ApplicationClosed(_)) => break,
+                    Err(e) => {
+                        eprintln!("accepting stream failed: {e:?}");
+                        break;
+                    }
+                    Ok(stream) => stream,
+                };
+                trace!("stream established");
+
+                tokio::spawn(async move {
+                    drain_stream(&mut recv_stream, opt.read_unordered).await?;
+                    send_data_on_stream(&mut send_stream, opt.download_size).await?;
+                    Ok::<_, anyhow::Error>(())
+                });
+            }
+
+            if opt.stats {
+                println!("\nServer connection stats:\n{:#?}", connection.stats());
+            }
+        }));
+    }
+
+    // Await all the tasks. We have to do this to prevent the runtime getting dropped
+    // and all server tasks to be cancelled
+    for handle in server_tasks {
+        if let Err(e) = handle.await {
+            eprintln!("Server task error: {e:?}");
+        };
+    }
+
+    Ok(())
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_bench/lib.rs.html b/pr/2992/docs/src/iroh_net_bench/lib.rs.html new file mode 100644 index 0000000000..cd2856596e --- /dev/null +++ b/pr/2992/docs/src/iroh_net_bench/lib.rs.html @@ -0,0 +1,539 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+
use std::{
+    num::ParseIntError,
+    str::FromStr,
+    sync::{Arc, Mutex},
+    time::Instant,
+};
+
+use anyhow::Result;
+use clap::Parser;
+use stats::Stats;
+use tokio::{
+    runtime::{Builder, Runtime},
+    sync::Semaphore,
+};
+use tracing::info;
+
+pub mod iroh;
+#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+pub mod quinn;
+pub mod s2n;
+pub mod stats;
+
+#[derive(Parser, Debug, Clone, Copy)]
+#[clap(name = "iroh-net-bench")]
+pub enum Commands {
+    Iroh(Opt),
+    #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+    Quinn(Opt),
+    S2n(s2n::Opt),
+}
+
+#[derive(Parser, Debug, Clone, Copy)]
+#[clap(name = "options")]
+pub struct Opt {
+    /// The total number of clients which should be created
+    #[clap(long = "clients", short = 'c', default_value = "1")]
+    pub clients: usize,
+    /// The total number of streams which should be created
+    #[clap(long = "streams", short = 'n', default_value = "1")]
+    pub streams: usize,
+    /// The amount of concurrent streams which should be used
+    #[clap(long = "max_streams", short = 'm', default_value = "1")]
+    pub max_streams: usize,
+    /// Number of bytes to transmit from server to client
+    ///
+    /// This can use SI prefixes for sizes. E.g. 1M will transfer 1MiB, 10G
+    /// will transfer 10GiB.
+    #[clap(long, default_value = "1G", value_parser = parse_byte_size)]
+    pub download_size: u64,
+    /// Number of bytes to transmit from client to server
+    ///
+    /// This can use SI prefixes for sizes. E.g. 1M will transfer 1MiB, 10G
+    /// will transfer 10GiB.
+    #[clap(long, default_value = "0", value_parser = parse_byte_size)]
+    pub upload_size: u64,
+    /// Show connection stats the at the end of the benchmark
+    #[clap(long = "stats")]
+    pub stats: bool,
+    /// Show iroh library counter metrics at the end of the benchmark
+    ///
+    /// These metrics are process-wide, so contain metrics for
+    /// clients and the server all summed up.
+    #[clap(long)]
+    pub metrics: bool,
+    /// Whether to use the unordered read API
+    #[clap(long = "unordered")]
+    pub read_unordered: bool,
+    /// Starting guess for maximum UDP payload size
+    #[clap(long, default_value = "1200")]
+    pub initial_mtu: u16,
+    /// Whether to run a local relay and have the server and clients connect to that.
+    ///
+    /// Can be combined with the `DEV_RELAY_ONLY` environment variable (at compile time)
+    /// to test throughput for relay-only traffic locally.
+    /// (e.g. `DEV_RELAY_ONLY=true cargo run --release -- iroh --with-relay`)
+    #[clap(long, default_value_t = false)]
+    pub with_relay: bool,
+}
+
+pub enum EndpointSelector {
+    Iroh(::iroh::Endpoint),
+    #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+    Quinn(::quinn::Endpoint),
+}
+
+impl EndpointSelector {
+    pub async fn close(self) -> Result<()> {
+        match self {
+            EndpointSelector::Iroh(endpoint) => {
+                endpoint.close().await?;
+            }
+            #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+            EndpointSelector::Quinn(endpoint) => {
+                endpoint.close(0u32.into(), b"");
+            }
+        }
+        Ok(())
+    }
+}
+
+pub enum ConnectionSelector {
+    Iroh(::iroh::endpoint::Connection),
+    #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+    Quinn(::quinn::Connection),
+}
+
+impl ConnectionSelector {
+    pub fn stats(&self) {
+        match self {
+            ConnectionSelector::Iroh(connection) => {
+                println!("{:#?}", connection.stats());
+            }
+            #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+            ConnectionSelector::Quinn(connection) => {
+                println!("{:#?}", connection.stats());
+            }
+        }
+    }
+
+    pub fn close(&self, error_code: u32, reason: &[u8]) {
+        match self {
+            ConnectionSelector::Iroh(connection) => {
+                connection.close(error_code.into(), reason);
+            }
+            #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
+            ConnectionSelector::Quinn(connection) => {
+                connection.close(error_code.into(), reason);
+            }
+        }
+    }
+}
+
+pub fn configure_tracing_subscriber() {
+    tracing::subscriber::set_global_default(
+        tracing_subscriber::FmtSubscriber::builder()
+            .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
+            .finish(),
+    )
+    .unwrap();
+}
+
+pub fn rt() -> Runtime {
+    Builder::new_current_thread().enable_all().build().unwrap()
+}
+
+fn parse_byte_size(s: &str) -> Result<u64, ParseIntError> {
+    let s = s.trim();
+
+    let multiplier = match s.chars().last() {
+        Some('T') => 1024 * 1024 * 1024 * 1024,
+        Some('G') => 1024 * 1024 * 1024,
+        Some('M') => 1024 * 1024,
+        Some('k') => 1024,
+        _ => 1,
+    };
+
+    let s = if multiplier != 1 {
+        &s[..s.len() - 1]
+    } else {
+        s
+    };
+
+    let base: u64 = u64::from_str(s)?;
+
+    Ok(base * multiplier)
+}
+
+#[derive(Default)]
+pub struct ClientStats {
+    upload_stats: Stats,
+    download_stats: Stats,
+    connect_time: std::time::Duration,
+}
+
+impl ClientStats {
+    pub fn print(&self, client_id: usize) {
+        println!();
+        println!("Client {client_id} stats:");
+
+        let ct = self.connect_time.as_nanos() as f64 / 1_000_000.0;
+        println!("Connect time: {ct}ms");
+
+        if self.upload_stats.total_size != 0 {
+            self.upload_stats.print("upload");
+        }
+
+        if self.download_stats.total_size != 0 {
+            self.download_stats.print("download");
+        }
+    }
+}
+
+/// Take the provided endpoint and run the client benchmark
+pub async fn client_handler(
+    endpoint: EndpointSelector,
+    connection: ConnectionSelector,
+    opt: Opt,
+) -> Result<ClientStats> {
+    let start = Instant::now();
+
+    let connection = Arc::new(connection);
+
+    let mut stats = ClientStats::default();
+    let mut first_error = None;
+
+    let sem = Arc::new(Semaphore::new(opt.max_streams));
+    let results = Arc::new(Mutex::new(Vec::new()));
+    for _ in 0..opt.streams {
+        let permit = sem.clone().acquire_owned().await.unwrap();
+        let results = results.clone();
+        let connection = connection.clone();
+        tokio::spawn(async move {
+            let result = match &*connection {
+                ConnectionSelector::Iroh(connection) => {
+                    iroh::handle_client_stream(connection, opt.upload_size, opt.read_unordered)
+                        .await
+                }
+                #[cfg(not(any(
+                    target_os = "freebsd",
+                    target_os = "openbsd",
+                    target_os = "netbsd"
+                )))]
+                ConnectionSelector::Quinn(connection) => {
+                    quinn::handle_client_stream(connection, opt.upload_size, opt.read_unordered)
+                        .await
+                }
+            };
+            // handle_client_stream(connection, opt.upload_size, opt.read_unordered).await;
+            info!("stream finished: {:?}", result);
+            results.lock().unwrap().push(result);
+            drop(permit);
+        });
+    }
+
+    // Wait for remaining streams to finish
+    let _ = sem.acquire_many(opt.max_streams as u32).await.unwrap();
+
+    stats.upload_stats.total_duration = start.elapsed();
+    stats.download_stats.total_duration = start.elapsed();
+
+    for result in results.lock().unwrap().drain(..) {
+        match result {
+            Ok((upload_result, download_result)) => {
+                stats.upload_stats.stream_finished(upload_result);
+                stats.download_stats.stream_finished(download_result);
+            }
+            Err(e) => {
+                if first_error.is_none() {
+                    first_error = Some(e);
+                }
+            }
+        }
+    }
+
+    // Explicit close of the connection, since handles can still be around due
+    // to `Arc`ing them
+    connection.close(0u32, b"Benchmark done");
+
+    endpoint.close().await?;
+
+    if opt.stats {
+        println!("\nClient connection stats:\n{:#?}", connection.stats());
+    }
+
+    match first_error {
+        None => Ok(stats),
+        Some(e) => Err(e),
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_bench/quinn.rs.html b/pr/2992/docs/src/iroh_net_bench/quinn.rs.html new file mode 100644 index 0000000000..94d63d7790 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_bench/quinn.rs.html @@ -0,0 +1,595 @@ +quinn.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+
use std::{
+    net::SocketAddr,
+    sync::Arc,
+    time::{Duration, Instant},
+};
+
+use anyhow::{Context, Result};
+use bytes::Bytes;
+use quinn::{Connection, Endpoint, RecvStream, SendStream, TokioRuntime, TransportConfig};
+use socket2::{Domain, Protocol, Socket, Type};
+use tracing::{trace, warn};
+
+use crate::{
+    client_handler, stats::TransferResult, ClientStats, ConnectionSelector, EndpointSelector, Opt,
+};
+
+/// Derived from the iroh udp SOCKET_BUFFER_SIZE
+const SOCKET_BUFFER_SIZE: usize = 7 << 20;
+pub const ALPN: &[u8] = b"n0/quinn-bench/0";
+
+/// Creates a server endpoint which runs on the given runtime
+pub fn server_endpoint(rt: &tokio::runtime::Runtime, opt: &Opt) -> (SocketAddr, quinn::Endpoint) {
+    let secret_key = iroh::key::SecretKey::generate();
+    let crypto = iroh::tls::make_server_config(&secret_key, vec![ALPN.to_vec()], false).unwrap();
+
+    let transport = transport_config(opt.max_streams, opt.initial_mtu);
+
+    let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(crypto));
+    server_config.transport_config(Arc::new(transport));
+
+    let addr = SocketAddr::new("127.0.0.1".parse().unwrap(), 0);
+
+    let socket = bind_socket(addr).unwrap();
+
+    let _guard = rt.enter();
+    rt.block_on(async move {
+        let ep = quinn::Endpoint::new(
+            Default::default(),
+            Some(server_config),
+            socket,
+            Arc::new(TokioRuntime),
+        )
+        .unwrap();
+        let addr = ep.local_addr().unwrap();
+        (addr, ep)
+    })
+}
+
+/// Create and run a client
+pub async fn client(server_addr: SocketAddr, opt: Opt) -> Result<ClientStats> {
+    let client_start = std::time::Instant::now();
+    let (endpoint, connection) = connect_client(server_addr, opt).await?;
+    let client_connect_time = client_start.elapsed();
+    let mut res = client_handler(
+        EndpointSelector::Quinn(endpoint),
+        ConnectionSelector::Quinn(connection),
+        opt,
+    )
+    .await?;
+    res.connect_time = client_connect_time;
+    Ok(res)
+}
+
+/// Create a client endpoint and client connection
+pub async fn connect_client(
+    server_addr: SocketAddr,
+    opt: Opt,
+) -> Result<(::quinn::Endpoint, Connection)> {
+    let secret_key = iroh::key::SecretKey::generate();
+    let quic_client_config =
+        iroh::tls::make_client_config(&secret_key, None, vec![ALPN.to_vec()], false)?;
+    let mut config = quinn::ClientConfig::new(Arc::new(quic_client_config));
+
+    let transport = transport_config(opt.max_streams, opt.initial_mtu);
+
+    // let mut config = quinn::ClientConfig::new(Arc::new(crypto));
+    config.transport_config(Arc::new(transport));
+
+    let addr = SocketAddr::new("127.0.0.1".parse().unwrap(), 0);
+
+    let socket = bind_socket(addr).unwrap();
+
+    let ep =
+        quinn::Endpoint::new(Default::default(), None, socket, Arc::new(TokioRuntime)).unwrap();
+    let connection = ep
+        .connect_with(config, server_addr, "local")?
+        .await
+        .context("connecting")?;
+    Ok((ep, connection))
+}
+
+pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig {
+    // High stream windows are chosen because the amount of concurrent streams
+    // is configurable as a parameter.
+    let mut config = TransportConfig::default();
+    config.max_concurrent_uni_streams(max_streams.try_into().unwrap());
+    config.initial_mtu(initial_mtu);
+
+    // TODO: re-enable when we upgrade quinn version
+    // let mut acks = quinn::AckFrequencyConfig::default();
+    // acks.ack_eliciting_threshold(10u32.into());
+    // config.ack_frequency_config(Some(acks));
+
+    config
+}
+
+fn bind_socket(addr: SocketAddr) -> Result<std::net::UdpSocket> {
+    let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))
+        .context("create socket")?;
+
+    if addr.is_ipv6() {
+        socket.set_only_v6(false).context("set_only_v6")?;
+    }
+
+    socket
+        .bind(&socket2::SockAddr::from(addr))
+        .context("binding endpoint")?;
+    socket
+        .set_send_buffer_size(SOCKET_BUFFER_SIZE)
+        .context("send buffer size")?;
+    socket
+        .set_recv_buffer_size(SOCKET_BUFFER_SIZE)
+        .context("recv buffer size")?;
+
+    let buf_size = socket.send_buffer_size().context("send buffer size")?;
+    if buf_size < SOCKET_BUFFER_SIZE {
+        warn!(
+            "Unable to set desired send buffer size. Desired: {}, Actual: {}",
+            SOCKET_BUFFER_SIZE, buf_size
+        );
+    }
+
+    let buf_size = socket.recv_buffer_size().context("recv buffer size")?;
+    if buf_size < SOCKET_BUFFER_SIZE {
+        warn!(
+            "Unable to set desired recv buffer size. Desired: {}, Actual: {}",
+            SOCKET_BUFFER_SIZE, buf_size
+        );
+    }
+
+    Ok(socket.into())
+}
+
+async fn drain_stream(
+    stream: &mut RecvStream,
+    read_unordered: bool,
+) -> Result<(usize, Duration, u64)> {
+    let mut read = 0;
+
+    let download_start = Instant::now();
+    let mut first_byte = true;
+    let mut ttfb = download_start.elapsed();
+
+    let mut num_chunks: u64 = 0;
+
+    if read_unordered {
+        while let Some(chunk) = stream.read_chunk(usize::MAX, false).await? {
+            if first_byte {
+                ttfb = download_start.elapsed();
+                first_byte = false;
+            }
+            read += chunk.bytes.len();
+            num_chunks += 1;
+        }
+    } else {
+        // These are 32 buffers, for reading approximately 32kB at once
+        #[rustfmt::skip]
+        let mut bufs = [
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+            Bytes::new(), Bytes::new(), Bytes::new(), Bytes::new(),
+        ];
+
+        while let Some(n) = stream.read_chunks(&mut bufs[..]).await? {
+            if first_byte {
+                ttfb = download_start.elapsed();
+                first_byte = false;
+            }
+            read += bufs.iter().take(n).map(|buf| buf.len()).sum::<usize>();
+            num_chunks += 1;
+        }
+    }
+
+    Ok((read, ttfb, num_chunks))
+}
+
+async fn send_data_on_stream(stream: &mut SendStream, stream_size: u64) -> Result<()> {
+    const DATA: &[u8] = &[0xAB; 1024 * 1024];
+    let bytes_data = Bytes::from_static(DATA);
+
+    let full_chunks = stream_size / (DATA.len() as u64);
+    let remaining = (stream_size % (DATA.len() as u64)) as usize;
+
+    for _ in 0..full_chunks {
+        stream
+            .write_chunk(bytes_data.clone())
+            .await
+            .context("failed sending data")?;
+    }
+
+    if remaining != 0 {
+        stream
+            .write_chunk(bytes_data.slice(0..remaining))
+            .await
+            .context("failed sending data")?;
+    }
+
+    stream.finish().context("failed finishing stream")?;
+    stream
+        .stopped()
+        .await
+        .context("failed to wait for stream to be stopped")?;
+
+    Ok(())
+}
+
+pub async fn handle_client_stream(
+    connection: &Connection,
+    upload_size: u64,
+    read_unordered: bool,
+) -> Result<(TransferResult, TransferResult)> {
+    let start = Instant::now();
+
+    let (mut send_stream, mut recv_stream) = connection
+        .open_bi()
+        .await
+        .context("failed to open stream")?;
+
+    send_data_on_stream(&mut send_stream, upload_size).await?;
+
+    let upload_result = TransferResult::new(start.elapsed(), upload_size, Duration::default(), 0);
+
+    let start = Instant::now();
+    let (size, ttfb, num_chunks) = drain_stream(&mut recv_stream, read_unordered).await?;
+    let download_result = TransferResult::new(start.elapsed(), size as u64, ttfb, num_chunks);
+
+    Ok((upload_result, download_result))
+}
+
+/// Take the provided endpoint and run the server
+pub async fn server(endpoint: Endpoint, opt: Opt) -> Result<()> {
+    let mut server_tasks = Vec::new();
+
+    // Handle only the expected amount of clients
+    for _ in 0..opt.clients {
+        let incoming = endpoint.accept().await.unwrap();
+        let connecting = match incoming.accept() {
+            Ok(connecting) => connecting,
+            Err(err) => {
+                warn!("incoming connection failed: {err:#}");
+                // we can carry on in these cases:
+                // this can be caused by retransmitted datagrams
+                continue;
+            }
+        };
+        let connection = connecting.await.context("handshake failed")?;
+
+        server_tasks.push(tokio::spawn(async move {
+            loop {
+                let (mut send_stream, mut recv_stream) = match connection.accept_bi().await {
+                    Err(::quinn::ConnectionError::ApplicationClosed(_)) => break,
+                    Err(e) => {
+                        eprintln!("accepting stream failed: {e:?}");
+                        break;
+                    }
+                    Ok(stream) => stream,
+                };
+                trace!("stream established");
+
+                tokio::spawn(async move {
+                    drain_stream(&mut recv_stream, opt.read_unordered).await?;
+                    send_data_on_stream(&mut send_stream, opt.download_size).await?;
+                    Ok::<_, anyhow::Error>(())
+                });
+            }
+
+            if opt.stats {
+                println!("\nServer connection stats:\n{:#?}", connection.stats());
+            }
+        }));
+    }
+
+    // Await all the tasks. We have to do this to prevent the runtime getting dropped
+    // and all server tasks to be cancelled
+    for handle in server_tasks {
+        if let Err(e) = handle.await {
+            eprintln!("Server task error: {e:?}");
+        };
+    }
+
+    Ok(())
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_bench/s2n.rs.html b/pr/2992/docs/src/iroh_net_bench/s2n.rs.html new file mode 100644 index 0000000000..a399ba0593 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_bench/s2n.rs.html @@ -0,0 +1,11 @@ +s2n.rs - source
1
+2
+3
+4
+5
+
use clap::Parser;
+
+#[derive(Parser, Debug, Clone, Copy)]
+#[clap(name = "s2n")]
+pub struct Opt {}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_bench/stats.rs.html b/pr/2992/docs/src/iroh_net_bench/stats.rs.html new file mode 100644 index 0000000000..0c4456d8a7 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_bench/stats.rs.html @@ -0,0 +1,271 @@ +stats.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+
use std::time::Duration;
+
+use hdrhistogram::Histogram;
+
+#[derive(Default, Debug)]
+pub struct Stats {
+    pub total_size: u64,
+    pub total_duration: Duration,
+    pub streams: usize,
+    pub stream_stats: StreamStats,
+}
+
+impl Stats {
+    pub fn stream_finished(&mut self, stream_result: TransferResult) {
+        self.total_size += stream_result.size;
+        self.streams += 1;
+
+        self.stream_stats
+            .duration_hist
+            .record(stream_result.duration.as_millis() as u64)
+            .unwrap();
+        self.stream_stats
+            .throughput_hist
+            .record(stream_result.throughput as u64)
+            .unwrap();
+        self.stream_stats
+            .ttfb_hist
+            .record(stream_result.ttfb.as_nanos() as u64)
+            .unwrap();
+        self.stream_stats
+            .chunk_time
+            .record(
+                stream_result.duration.as_nanos() as u64 / std::cmp::max(stream_result.chunks, 1),
+            )
+            .unwrap();
+        self.stream_stats.chunks += stream_result.chunks;
+        self.stream_stats
+            .chunk_size
+            .record(stream_result.avg_chunk_size)
+            .unwrap();
+    }
+
+    pub fn print(&self, stat_name: &str) {
+        println!("Overall {stat_name} stats:\n");
+        println!(
+            "Transferred {} bytes on {} streams in {:4.2?} ({:.2} MiB/s)\n",
+            self.total_size,
+            self.streams,
+            self.total_duration,
+            throughput_bps(self.total_duration, self.total_size) / 1024.0 / 1024.0
+        );
+
+        let avg_ttfb = self.stream_stats.ttfb_hist.mean() / 1_000.0;
+        println!("Time to first byte (TTFB): {avg_ttfb}ms\n");
+
+        let chunks = self.stream_stats.chunks;
+        println!("Total chunks: {chunks}\n");
+        let avg_chunk_time = self.stream_stats.chunk_time.mean() / 1_000.0;
+        println!("Average chunk time: {avg_chunk_time}ms\n");
+        let avg_chunk_size = self.stream_stats.chunk_size.mean() / 1024.0;
+        println!("Average chunk size: {avg_chunk_size:.2}KiB\n");
+
+        println!("Stream {stat_name} metrics:\n");
+
+        println!("      │  Throughput   │ Duration ");
+        println!("──────┼───────────────┼──────────");
+
+        let print_metric = |label: &'static str, get_metric: fn(&Histogram<u64>) -> u64| {
+            println!(
+                " {} │ {:7.2} MiB/s │ {:>9.2?}",
+                label,
+                get_metric(&self.stream_stats.throughput_hist) as f64 / 1024.0 / 1024.0,
+                Duration::from_millis(get_metric(&self.stream_stats.duration_hist))
+            );
+        };
+
+        print_metric("AVG ", |hist| hist.mean() as u64);
+        print_metric("P0  ", |hist| hist.value_at_quantile(0.00));
+        print_metric("P10 ", |hist| hist.value_at_quantile(0.10));
+        print_metric("P50 ", |hist| hist.value_at_quantile(0.50));
+        print_metric("P90 ", |hist| hist.value_at_quantile(0.90));
+        print_metric("P100", |hist| hist.value_at_quantile(1.00));
+    }
+}
+
+#[derive(Debug)]
+pub struct StreamStats {
+    pub duration_hist: Histogram<u64>,
+    pub throughput_hist: Histogram<u64>,
+    pub ttfb_hist: Histogram<u64>,
+    pub chunk_time: Histogram<u64>,
+    pub chunks: u64,
+    pub chunk_size: Histogram<u64>,
+}
+
+impl Default for StreamStats {
+    fn default() -> Self {
+        Self {
+            duration_hist: Histogram::<u64>::new(3).unwrap(),
+            throughput_hist: Histogram::<u64>::new(3).unwrap(),
+            ttfb_hist: Histogram::<u64>::new(3).unwrap(),
+            chunk_time: Histogram::<u64>::new(3).unwrap(),
+            chunks: 0,
+            chunk_size: Histogram::<u64>::new(3).unwrap(),
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct TransferResult {
+    pub duration: Duration,
+    pub size: u64,
+    pub throughput: f64,
+    pub ttfb: Duration,
+    pub chunks: u64,
+    pub avg_chunk_size: u64,
+}
+
+impl TransferResult {
+    pub fn new(duration: Duration, size: u64, ttfb: Duration, chunks: u64) -> Self {
+        let throughput = throughput_bps(duration, size);
+        TransferResult {
+            duration,
+            size,
+            throughput,
+            ttfb,
+            chunks,
+            avg_chunk_size: size / std::cmp::max(chunks, 1),
+        }
+    }
+}
+
+pub fn throughput_bps(duration: Duration, size: u64) -> f64 {
+    (size as f64) / (duration.as_secs_f64())
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/defaults.rs.html b/pr/2992/docs/src/iroh_net_report/defaults.rs.html new file mode 100644 index 0000000000..bbc290cb37 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/defaults.rs.html @@ -0,0 +1,87 @@ +defaults.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+
//! Default values used in net_report.
+
+/// The default STUN port used by the Relay server.
+///
+/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
+pub const DEFAULT_STUN_PORT: u16 = 3478;
+
+/// Contains all timeouts that we use in `iroh-net_report`.
+pub(crate) mod timeouts {
+    use std::time::Duration;
+
+    // Timeouts for net_report
+
+    /// The maximum amount of time net_report will spend gathering a single report.
+    pub(crate) const OVERALL_REPORT_TIMEOUT: Duration = Duration::from_secs(5);
+
+    /// The total time we wait for all the probes.
+    ///
+    /// This includes the STUN, ICMP and HTTPS probes, which will all
+    /// start at different times based on the ProbePlan.
+    pub(crate) const PROBES_TIMEOUT: Duration = Duration::from_secs(3);
+
+    /// How long to await for a captive-portal result.
+    ///
+    /// This delay is chosen so it starts after good-working STUN probes
+    /// would have finished, but not too long so the delay is bearable if
+    /// STUN is blocked.
+    pub(crate) const CAPTIVE_PORTAL_DELAY: Duration = Duration::from_millis(200);
+
+    /// Timeout for captive portal checks
+    ///
+    /// Must be lower than [`OVERALL_REPORT_TIMEOUT`] minus
+    /// [`CAPTIVE_PORTAL_DELAY`].
+    pub(crate) const CAPTIVE_PORTAL_TIMEOUT: Duration = Duration::from_secs(2);
+
+    pub(crate) const DNS_TIMEOUT: Duration = Duration::from_secs(3);
+
+    /// The amount of time we wait for a hairpinned packet to come back.
+    pub(crate) const HAIRPIN_CHECK_TIMEOUT: Duration = Duration::from_millis(100);
+
+    /// Default Pinger timeout
+    pub(crate) const DEFAULT_PINGER_TIMEOUT: Duration = Duration::from_secs(5);
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/dns.rs.html b/pr/2992/docs/src/iroh_net_report/dns.rs.html new file mode 100644 index 0000000000..9db47ae474 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/dns.rs.html @@ -0,0 +1,523 @@ +dns.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+
use std::{fmt::Write, net::IpAddr};
+
+use anyhow::Result;
+use futures_lite::{Future, StreamExt};
+use hickory_resolver::{IntoName, TokioAsyncResolver};
+
+use crate::defaults::timeouts::DNS_TIMEOUT;
+
+/// Delay used to perform staggered dns queries.
+pub(crate) const DNS_STAGGERING_MS: &[u64] = &[200, 300];
+
+/// Extension trait to [`TokioAsyncResolver`].
+pub(crate) trait ResolverExt {
+    /// Perform an ipv4 lookup.
+    fn lookup_ipv4<N: IntoName>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Perform an ipv6 lookup.
+    fn lookup_ipv6<N: IntoName>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Race an ipv4 and ipv6.
+    fn lookup_ipv4_ipv6<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Perform an ipv4 lookup in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// [`DNS_STAGGERING_MS`] with the first call being done immediately. `[200ms, 300ms]` results
+    /// in calls at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually.
+    /// The result of the first successful call is returned, or a summary of all errors otherwise.
+    fn lookup_ipv4_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Perform an ipv6 lookup with a timeout in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// [`DNS_STAGGERING_MS`] with the first call being done immediately. `[200ms, 300ms]` results
+    /// in calls at T+0ms, T+200ms and T+300ms. The `timeout` is applied to each call individually.
+    /// The result of the first successful call is returned, or a summary of all errors otherwise.
+    fn lookup_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+
+    /// Race an ipv4 and ipv6 lookup in a staggered fashion.
+    ///
+    /// From the moment this function is called, each lookup is scheduled after the delays in
+    /// [`DNS_STAGGERING_MS`] with the first call being done immediately. `[200ms, 300ms]` results
+    /// in calls at T+0ms, T+200ms and T+300ms. The [`DNS_TIMEOUT`] is applied as stated in
+    /// [`Self::lookup_ipv4_ipv6`]. The result of the first successful call is returned, or a
+    /// summary of all errors otherwise.
+    fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> impl Future<Output = Result<impl Iterator<Item = IpAddr>>>;
+}
+
+impl ResolverExt for TokioAsyncResolver {
+    async fn lookup_ipv4<N: IntoName>(&self, host: N) -> Result<impl Iterator<Item = IpAddr>> {
+        let addrs = tokio::time::timeout(DNS_TIMEOUT, self.ipv4_lookup(host)).await??;
+        Ok(addrs.into_iter().map(|ip| IpAddr::V4(ip.0)))
+    }
+
+    async fn lookup_ipv6<N: IntoName>(&self, host: N) -> Result<impl Iterator<Item = IpAddr>> {
+        let addrs = tokio::time::timeout(DNS_TIMEOUT, self.ipv6_lookup(host)).await??;
+        Ok(addrs.into_iter().map(|ip| IpAddr::V6(ip.0)))
+    }
+
+    /// Resolve IPv4 and IPv6 in parallel.
+    ///
+    /// `LookupIpStrategy::Ipv4AndIpv6` will wait for ipv6 resolution timeout, even if it is
+    /// not usable on the stack, so we manually query both lookups concurrently and time them out
+    /// individually.
+    ///
+    /// See [`ResolverExt::lookup_ipv4_ipv6`].
+    async fn lookup_ipv4_ipv6<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let res = tokio::join!(self.lookup_ipv4(host.clone()), self.lookup_ipv6(host));
+
+        match res {
+            (Ok(ipv4), Ok(ipv6)) => Ok(LookupIter::Both(ipv4.chain(ipv6))),
+            (Ok(ipv4), Err(_)) => Ok(LookupIter::Ipv4(ipv4)),
+            (Err(_), Ok(ipv6)) => Ok(LookupIter::Ipv6(ipv6)),
+            (Err(ipv4_err), Err(ipv6_err)) => {
+                anyhow::bail!("Ipv4: {:?}, Ipv6: {:?}", ipv4_err, ipv6_err)
+            }
+        }
+    }
+
+    async fn lookup_ipv4_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv4(host.clone());
+        stagger_call(f, DNS_STAGGERING_MS).await
+    }
+
+    async fn lookup_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv6(host.clone());
+        stagger_call(f, DNS_STAGGERING_MS).await
+    }
+
+    async fn lookup_ipv4_ipv6_staggered<N: IntoName + Clone>(
+        &self,
+        host: N,
+    ) -> Result<impl Iterator<Item = IpAddr>> {
+        let f = || self.lookup_ipv4_ipv6(host.clone());
+        stagger_call(f, DNS_STAGGERING_MS).await
+    }
+}
+
+/// Helper enum to give a unified type to the iterators of [`ResolverExt::lookup_ipv4_ipv6`].
+enum LookupIter<A, B> {
+    Ipv4(A),
+    Ipv6(B),
+    Both(std::iter::Chain<A, B>),
+}
+
+impl<A: Iterator<Item = IpAddr>, B: Iterator<Item = IpAddr>> Iterator for LookupIter<A, B> {
+    type Item = IpAddr;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            LookupIter::Ipv4(iter) => iter.next(),
+            LookupIter::Ipv6(iter) => iter.next(),
+            LookupIter::Both(iter) => iter.next(),
+        }
+    }
+}
+
+/// Staggers calls to the future F with the given delays.
+///
+/// The first call is performed immediately. The first call to succeed generates an Ok result
+/// ignoring any previous error. If all calls fail, an error summarizing all errors is returned.
+async fn stagger_call<T, F: Fn() -> Fut, Fut: Future<Output = Result<T>>>(
+    f: F,
+    delays_ms: &[u64],
+) -> Result<T> {
+    let mut calls = futures_buffered::FuturesUnorderedBounded::new(delays_ms.len() + 1);
+    // NOTE: we add the 0 delay here to have a uniform set of futures. This is more performant than
+    // using alternatives that allow futures of different types.
+    for delay in std::iter::once(&0u64).chain(delays_ms) {
+        let delay = std::time::Duration::from_millis(*delay);
+        let fut = f();
+        let staggered_fut = async move {
+            tokio::time::sleep(delay).await;
+            fut.await
+        };
+        calls.push(staggered_fut)
+    }
+
+    let mut errors = vec![];
+    while let Some(call_result) = calls.next().await {
+        match call_result {
+            Ok(t) => return Ok(t),
+            Err(e) => errors.push(e),
+        }
+    }
+
+    anyhow::bail!(
+        "no calls succeed: [ {}]",
+        errors.into_iter().fold(String::new(), |mut summary, e| {
+            write!(summary, "{e} ").expect("infallible");
+            summary
+        })
+    )
+}
+
+#[cfg(test)]
+pub(crate) mod tests {
+    use std::{net::Ipv6Addr, sync::atomic::AtomicUsize};
+
+    use once_cell::sync::Lazy;
+
+    use super::*;
+
+    static DNS_RESOLVER: Lazy<TokioAsyncResolver> =
+        Lazy::new(|| create_default_resolver().expect("unable to create DNS resolver"));
+
+    /// Get a DNS resolver suitable for testing.
+    pub fn resolver() -> &'static TokioAsyncResolver {
+        Lazy::force(&DNS_RESOLVER)
+    }
+
+    /// Deprecated IPv6 site-local anycast addresses still configured by windows.
+    ///
+    /// Windows still configures these site-local addresses as soon even as an IPv6 loopback
+    /// interface is configured.  We do not want to use these DNS servers, the chances of them
+    /// being usable are almost always close to zero, while the chance of DNS configuration
+    /// **only** relying on these servers and not also being configured normally are also almost
+    /// zero.  The chance of the DNS resolver accidentally trying one of these and taking a
+    /// bunch of timeouts to figure out they're no good are on the other hand very high.
+    const WINDOWS_BAD_SITE_LOCAL_DNS_SERVERS: [IpAddr; 3] = [
+        IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 1)),
+        IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 2)),
+        IpAddr::V6(Ipv6Addr::new(0xfec0, 0, 0, 0xffff, 0, 0, 0, 3)),
+    ];
+
+    /// Get resolver to query MX records.
+    ///
+    /// We first try to read the system's resolver from `/etc/resolv.conf`.
+    /// This does not work at least on some Androids, therefore we fallback
+    /// to the default `ResolverConfig` which uses eg. to google's `8.8.8.8` or `8.8.4.4`.
+    fn create_default_resolver() -> Result<TokioAsyncResolver> {
+        let (system_config, mut options) =
+            hickory_resolver::system_conf::read_system_conf().unwrap_or_default();
+
+        // Copy all of the system config, but strip the bad windows nameservers.  Unfortunately
+        // there is no easy way to do this.
+        let mut config = hickory_resolver::config::ResolverConfig::new();
+        if let Some(name) = system_config.domain() {
+            config.set_domain(name.clone());
+        }
+        for name in system_config.search() {
+            config.add_search(name.clone());
+        }
+        for nameserver_cfg in system_config.name_servers() {
+            if !WINDOWS_BAD_SITE_LOCAL_DNS_SERVERS.contains(&nameserver_cfg.socket_addr.ip()) {
+                config.add_name_server(nameserver_cfg.clone());
+            }
+        }
+
+        // see [`ResolverExt::lookup_ipv4_ipv6`] for info on why we avoid `LookupIpStrategy::Ipv4AndIpv6`
+        options.ip_strategy = hickory_resolver::config::LookupIpStrategy::Ipv4thenIpv6;
+
+        let resolver = hickory_resolver::AsyncResolver::tokio(config, options);
+        Ok(resolver)
+    }
+
+    #[tokio::test]
+    async fn stagger_basic() {
+        let _logging = iroh_test::logging::setup();
+        const CALL_RESULTS: &[Result<u8, u8>] = &[Err(2), Ok(3), Ok(5), Ok(7)];
+        static DONE_CALL: AtomicUsize = AtomicUsize::new(0);
+        let f = || {
+            let r_pos = DONE_CALL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
+            async move {
+                tracing::info!(r_pos, "call");
+                CALL_RESULTS[r_pos].map_err(|e| anyhow::anyhow!("{e}"))
+            }
+        };
+
+        let delays = [1000, 15];
+        let result = stagger_call(f, &delays).await.unwrap();
+        assert_eq!(result, 5)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/lib.rs.html b/pr/2992/docs/src/iroh_net_report/lib.rs.html new file mode 100644 index 0000000000..01477230fe --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/lib.rs.html @@ -0,0 +1,2595 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+
//! Checks the network conditions from the current host.
+//!
+//! NetReport is responsible for finding out the network conditions of the current host, like
+//! whether it is connected to the internet via IPv4 and/or IPv6, what the NAT situation is
+//! etc and reachability to the configured relays.
+// Based on <https://github.com/tailscale/tailscale/blob/main/net/netcheck/netcheck.go>
+
+use std::{
+    collections::{BTreeMap, HashMap},
+    fmt::{self, Debug},
+    net::{SocketAddr, SocketAddrV4, SocketAddrV6},
+    sync::Arc,
+};
+
+use anyhow::{anyhow, Context as _, Result};
+use bytes::Bytes;
+use hickory_resolver::TokioAsyncResolver as DnsResolver;
+use iroh_base::relay_map::{RelayMap, RelayNode, RelayUrl};
+#[cfg(feature = "metrics")]
+use iroh_metrics::inc;
+use iroh_relay::protos::stun;
+use netwatch::{IpFamily, UdpSocket};
+use tokio::{
+    sync::{self, mpsc, oneshot},
+    time::{Duration, Instant},
+};
+use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
+use tracing::{debug, error, info_span, trace, warn, Instrument};
+
+mod defaults;
+mod dns;
+#[cfg(feature = "metrics")]
+mod metrics;
+mod ping;
+mod reportgen;
+
+#[cfg(feature = "metrics")]
+pub use metrics::Metrics;
+
+const FULL_REPORT_INTERVAL: Duration = Duration::from_secs(5 * 60);
+
+/// The maximum latency of all nodes, if none are found yet.
+///
+/// Normally the max latency of all nodes is computed, but if we don't yet know any nodes
+/// latencies we return this as default.  This is the value of the initial STUN probe
+/// delays.  It is only used as time to wait for further latencies to arrive, which *should*
+/// never happen unless there already is at least one latency.  Yet here we are, defining a
+/// default which will never be used.
+const DEFAULT_MAX_LATENCY: Duration = Duration::from_millis(100);
+
+/// A net_report report.
+///
+/// Can be obtained by calling [`Client::get_report`].
+#[derive(Default, Debug, PartialEq, Eq, Clone)]
+pub struct Report {
+    /// A UDP STUN round trip completed.
+    pub udp: bool,
+    /// An IPv6 STUN round trip completed.
+    pub ipv6: bool,
+    /// An IPv4 STUN round trip completed.
+    pub ipv4: bool,
+    /// An IPv6 packet was able to be sent
+    pub ipv6_can_send: bool,
+    /// an IPv4 packet was able to be sent
+    pub ipv4_can_send: bool,
+    /// could bind a socket to ::1
+    pub os_has_ipv6: bool,
+    /// An ICMPv4 round trip completed, `None` if not checked.
+    pub icmpv4: Option<bool>,
+    /// An ICMPv6 round trip completed, `None` if not checked.
+    pub icmpv6: Option<bool>,
+    /// Whether STUN results depend on which STUN server you're talking to (on IPv4).
+    pub mapping_varies_by_dest_ip: Option<bool>,
+    /// Whether STUN results depend on which STUN server you're talking to (on IPv6).
+    ///
+    /// Note that we don't really expect this to happen and are merely logging this if
+    /// detecting rather than using it.  For now.
+    pub mapping_varies_by_dest_ipv6: Option<bool>,
+    /// Whether the router supports communicating between two local devices through the NATted
+    /// public IP address (on IPv4).
+    pub hair_pinning: Option<bool>,
+    /// Probe indicating the presence of port mapping protocols on the LAN.
+    pub portmap_probe: Option<portmapper::ProbeOutput>,
+    /// `None` for unknown
+    pub preferred_relay: Option<RelayUrl>,
+    /// keyed by relay Url
+    pub relay_latency: RelayLatencies,
+    /// keyed by relay Url
+    pub relay_v4_latency: RelayLatencies,
+    /// keyed by relay Url
+    pub relay_v6_latency: RelayLatencies,
+    /// ip:port of global IPv4
+    pub global_v4: Option<SocketAddrV4>,
+    /// `[ip]:port` of global IPv6
+    pub global_v6: Option<SocketAddrV6>,
+    /// CaptivePortal is set when we think there's a captive portal that is
+    /// intercepting HTTP traffic.
+    pub captive_portal: Option<bool>,
+}
+
+impl fmt::Display for Report {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self, f)
+    }
+}
+
+/// Latencies per relay node.
+#[derive(Debug, Default, PartialEq, Eq, Clone)]
+pub struct RelayLatencies(BTreeMap<RelayUrl, Duration>);
+
+impl RelayLatencies {
+    fn new() -> Self {
+        Default::default()
+    }
+
+    /// Updates a relay's latency, if it is faster than before.
+    fn update_relay(&mut self, url: RelayUrl, latency: Duration) {
+        let val = self.0.entry(url).or_insert(latency);
+        if latency < *val {
+            *val = latency;
+        }
+    }
+
+    /// Merges another [`RelayLatencies`] into this one.
+    ///
+    /// For each relay the latency is updated using [`RelayLatencies::update_relay`].
+    fn merge(&mut self, other: &RelayLatencies) {
+        for (url, latency) in other.iter() {
+            self.update_relay(url.clone(), latency);
+        }
+    }
+
+    /// Returns the maximum latency for all relays.
+    ///
+    /// If there are not yet any latencies this will return [`DEFAULT_MAX_LATENCY`].
+    fn max_latency(&self) -> Duration {
+        self.0
+            .values()
+            .max()
+            .copied()
+            .unwrap_or(DEFAULT_MAX_LATENCY)
+    }
+
+    /// Returns an iterator over all the relays and their latencies.
+    pub fn iter(&self) -> impl Iterator<Item = (&'_ RelayUrl, Duration)> + '_ {
+        self.0.iter().map(|(k, v)| (k, *v))
+    }
+
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    fn get(&self, url: &RelayUrl) -> Option<Duration> {
+        self.0.get(url).copied()
+    }
+}
+
+/// Client to run net_reports.
+///
+/// Creating this creates a net_report actor which runs in the background.  Most of the time
+/// it is idle unless [`Client::get_report`] is called, which is the main interface.
+///
+/// The [`Client`] struct can be cloned and results multiple handles to the running actor.
+/// If all [`Client`]s are dropped the actor stops running.
+///
+/// While running the net_report actor expects to be passed all received stun packets using
+/// `Addr::receive_stun_packet`.
+#[derive(Debug)]
+pub struct Client {
+    /// Channel to send message to the [`Actor`].
+    ///
+    /// If all senders are dropped, in other words all clones of this struct are dropped,
+    /// the actor will terminate.
+    addr: Addr,
+    /// Ensures the actor is terminated when the client is dropped.
+    _drop_guard: Arc<AbortOnDropHandle<()>>,
+}
+
+#[derive(Debug)]
+struct Reports {
+    /// Do a full relay scan, even if last is `Some`.
+    next_full: bool,
+    /// Some previous reports.
+    prev: HashMap<Instant, Arc<Report>>,
+    /// Most recent report.
+    last: Option<Arc<Report>>,
+    /// Time of last full (non-incremental) report.
+    last_full: Instant,
+}
+
+impl Default for Reports {
+    fn default() -> Self {
+        Self {
+            next_full: Default::default(),
+            prev: Default::default(),
+            last: Default::default(),
+            last_full: Instant::now(),
+        }
+    }
+}
+
+impl Client {
+    /// Creates a new net_report client.
+    ///
+    /// This starts a connected actor in the background.  Once the client is dropped it will
+    /// stop running.
+    pub fn new(port_mapper: Option<portmapper::Client>, dns_resolver: DnsResolver) -> Result<Self> {
+        let mut actor = Actor::new(port_mapper, dns_resolver)?;
+        let addr = actor.addr();
+        let task = tokio::spawn(
+            async move { actor.run().await }.instrument(info_span!("net_report.actor")),
+        );
+        let drop_guard = AbortOnDropHandle::new(task);
+        Ok(Client {
+            addr,
+            _drop_guard: Arc::new(drop_guard),
+        })
+    }
+
+    /// Returns a new address to send messages to this actor.
+    ///
+    /// Unlike the client itself the returned [`Addr`] does not own the actor task, it only
+    /// allows sending messages to the actor.
+    pub fn addr(&self) -> Addr {
+        self.addr.clone()
+    }
+
+    /// Runs a net_report, returning the report.
+    ///
+    /// It may not be called concurrently with itself, `&mut self` takes care of that.
+    ///
+    /// The *stun_conn4* and *stun_conn6* endpoints are bound UDP sockets to use to send out
+    /// STUN packets.  This function **will not read from the sockets**, as they may be
+    /// receiving other traffic as well, normally they are the sockets carrying the real
+    /// traffic. Thus all stun packets received on those sockets should be passed to
+    /// `Addr::receive_stun_packet` in order for this function to receive the stun
+    /// responses and function correctly.
+    ///
+    /// If these are not passed in this will bind sockets for STUN itself, though results
+    /// may not be as reliable.
+    pub async fn get_report(
+        &mut self,
+        dm: RelayMap,
+        stun_conn4: Option<Arc<UdpSocket>>,
+        stun_conn6: Option<Arc<UdpSocket>>,
+    ) -> Result<Arc<Report>> {
+        let rx = self.get_report_channel(dm, stun_conn4, stun_conn6).await?;
+        match rx.await {
+            Ok(res) => res,
+            Err(_) => Err(anyhow!("channel closed, actor awol")),
+        }
+    }
+
+    /// Get report with channel
+    pub async fn get_report_channel(
+        &mut self,
+        dm: RelayMap,
+        stun_conn4: Option<Arc<UdpSocket>>,
+        stun_conn6: Option<Arc<UdpSocket>>,
+    ) -> Result<oneshot::Receiver<Result<Arc<Report>>>> {
+        // TODO: consider if RelayMap should be made to easily clone?  It seems expensive
+        // right now.
+        let (tx, rx) = oneshot::channel();
+        self.addr
+            .send(Message::RunCheck {
+                relay_map: dm,
+                stun_sock_v4: stun_conn4,
+                stun_sock_v6: stun_conn6,
+                response_tx: tx,
+            })
+            .await?;
+        Ok(rx)
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct Inflight {
+    /// The STUN transaction ID.
+    txn: stun::TransactionId,
+    /// The time the STUN probe was sent.
+    start: Instant,
+    /// Response to send STUN results: latency of STUN response and the discovered address.
+    s: sync::oneshot::Sender<(Duration, SocketAddr)>,
+}
+
+/// Messages to send to the [`Actor`].
+#[derive(Debug)]
+pub(crate) enum Message {
+    /// Run a net_report.
+    ///
+    /// Only one net_report can be run at a time, trying to run multiple concurrently will
+    /// fail.
+    RunCheck {
+        /// The relay configuration.
+        relay_map: RelayMap,
+        /// Socket to send IPv4 STUN probes from.
+        ///
+        /// Responses are never read from this socket, they must be passed in via the
+        /// [`Message::StunPacket`] message since the socket is also used to receive
+        /// other packets from in the magicsocket (`MagicSock`).
+        ///
+        /// If not provided this will attempt to bind a suitable socket itself.
+        stun_sock_v4: Option<Arc<UdpSocket>>,
+        /// Socket to send IPv6 STUN probes from.
+        ///
+        /// Like `stun_sock_v4` but for IPv6.
+        stun_sock_v6: Option<Arc<UdpSocket>>,
+        /// Channel to receive the response.
+        response_tx: oneshot::Sender<Result<Arc<Report>>>,
+    },
+    /// A report produced by the [`reportgen`] actor.
+    ReportReady { report: Box<Report> },
+    /// The [`reportgen`] actor failed to produce a report.
+    ReportAborted { err: anyhow::Error },
+    /// An incoming STUN packet to parse.
+    StunPacket {
+        /// The raw UDP payload.
+        payload: Bytes,
+        /// The address this was claimed to be received from.
+        from_addr: SocketAddr,
+    },
+    /// A probe wants to register an in-flight STUN request.
+    ///
+    /// The sender is signalled once the STUN packet is registered with the actor and will
+    /// correctly accept the STUN response.
+    InFlightStun(Inflight, oneshot::Sender<()>),
+}
+
+/// Sender to the main service.
+///
+/// Unlike [`Client`] this is the raw channel to send messages over.  Keeping this alive
+/// will not keep the actor alive, which makes this handy to pass to internal tasks.
+#[derive(Debug, Clone)]
+pub struct Addr {
+    sender: mpsc::Sender<Message>,
+}
+
+impl Addr {
+    /// Pass a received STUN packet to the net_reporter.
+    ///
+    /// Normally the UDP sockets to send STUN messages from are passed in so that STUN
+    /// packets are sent from the sockets that carry the real traffic.  However because
+    /// these sockets carry real traffic they will also receive non-STUN traffic, thus the
+    /// net_report actor does not read from the sockets directly.  If you receive a STUN
+    /// packet on the socket you should pass it to this method.
+    ///
+    /// It is safe to call this even when the net_report actor does not currently have any
+    /// in-flight STUN probes.  The actor will simply ignore any stray STUN packets.
+    ///
+    /// There is an implicit queue here which may drop packets if the actor does not keep up
+    /// consuming them.
+    pub fn receive_stun_packet(&self, payload: Bytes, src: SocketAddr) {
+        if let Err(mpsc::error::TrySendError::Full(_)) = self.sender.try_send(Message::StunPacket {
+            payload,
+            from_addr: src,
+        }) {
+            #[cfg(feature = "metrics")]
+            inc!(Metrics, stun_packets_dropped);
+            warn!("dropping stun packet from {}", src);
+        }
+    }
+
+    async fn send(&self, msg: Message) -> Result<(), mpsc::error::SendError<Message>> {
+        self.sender.send(msg).await.inspect_err(|_| {
+            error!("net_report actor lost");
+        })
+    }
+}
+
+/// The net_report actor.
+///
+/// This actor runs for the entire duration there's a [`Client`] connected.
+#[derive(Debug)]
+struct Actor {
+    // Actor plumbing.
+    /// Actor messages channel.
+    ///
+    /// If there are no more senders the actor stops.
+    receiver: mpsc::Receiver<Message>,
+    /// The sender side of the messages channel.
+    ///
+    /// This allows creating new [`Addr`]s from the actor.
+    sender: mpsc::Sender<Message>,
+    /// A collection of previously generated reports.
+    ///
+    /// Sometimes it is useful to look at past reports to decide what to do.
+    reports: Reports,
+
+    // Actor configuration.
+    /// The port mapper client, if those are requested.
+    ///
+    /// The port mapper is responsible for talking to routers via UPnP and the like to try
+    /// and open ports.
+    port_mapper: Option<portmapper::Client>,
+
+    // Actor state.
+    /// Information about the currently in-flight STUN requests.
+    ///
+    /// This is used to complete the STUN probe when receiving STUN packets.
+    in_flight_stun_requests: HashMap<stun::TransactionId, Inflight>,
+    /// The [`reportgen`] actor currently generating a report.
+    current_report_run: Option<ReportRun>,
+
+    /// The DNS resolver to use for probes that need to perform DNS lookups
+    dns_resolver: DnsResolver,
+}
+
+impl Actor {
+    /// Creates a new actor.
+    ///
+    /// This does not start the actor, see [`Actor::run`] for this.  You should not
+    /// normally create this directly but rather create a [`Client`].
+    fn new(port_mapper: Option<portmapper::Client>, dns_resolver: DnsResolver) -> Result<Self> {
+        // TODO: consider an instrumented flume channel so we have metrics.
+        let (sender, receiver) = mpsc::channel(32);
+        Ok(Self {
+            receiver,
+            sender,
+            reports: Default::default(),
+            port_mapper,
+            in_flight_stun_requests: Default::default(),
+            current_report_run: None,
+            dns_resolver,
+        })
+    }
+
+    /// Returns the channel to send messages to the actor.
+    fn addr(&self) -> Addr {
+        Addr {
+            sender: self.sender.clone(),
+        }
+    }
+
+    /// Run the actor.
+    ///
+    /// It will now run and handle messages.  Once the connected [`Client`] (including all
+    /// its clones) is dropped this will terminate.
+    async fn run(&mut self) {
+        debug!("net_report actor starting");
+        while let Some(msg) = self.receiver.recv().await {
+            trace!(?msg, "handling message");
+            match msg {
+                Message::RunCheck {
+                    relay_map,
+                    stun_sock_v4,
+                    stun_sock_v6,
+                    response_tx,
+                } => {
+                    self.handle_run_check(relay_map, stun_sock_v4, stun_sock_v6, response_tx);
+                }
+                Message::ReportReady { report } => {
+                    self.handle_report_ready(report);
+                }
+                Message::ReportAborted { err } => {
+                    self.handle_report_aborted(err);
+                }
+                Message::StunPacket { payload, from_addr } => {
+                    self.handle_stun_packet(&payload, from_addr);
+                }
+                Message::InFlightStun(inflight, response_tx) => {
+                    self.handle_in_flight_stun(inflight, response_tx);
+                }
+            }
+        }
+    }
+
+    /// Starts a check run as requested by the [`Message::RunCheck`] message.
+    ///
+    /// If *stun_sock_v4* or *stun_sock_v6* are not provided this will bind the sockets
+    /// itself.  This is not ideal since really you want to send STUN probes from the
+    /// sockets you will be using.
+    fn handle_run_check(
+        &mut self,
+        relay_map: RelayMap,
+        stun_sock_v4: Option<Arc<UdpSocket>>,
+        stun_sock_v6: Option<Arc<UdpSocket>>,
+        response_tx: oneshot::Sender<Result<Arc<Report>>>,
+    ) {
+        if self.current_report_run.is_some() {
+            response_tx
+                .send(Err(anyhow!(
+                    "ignoring RunCheck request: reportgen actor already running"
+                )))
+                .ok();
+            return;
+        }
+
+        let now = Instant::now();
+
+        let cancel_token = CancellationToken::new();
+        let stun_sock_v4 = match stun_sock_v4 {
+            Some(sock) => Some(sock),
+            None => bind_local_stun_socket(IpFamily::V4, self.addr(), cancel_token.clone()),
+        };
+        let stun_sock_v6 = match stun_sock_v6 {
+            Some(sock) => Some(sock),
+            None => bind_local_stun_socket(IpFamily::V6, self.addr(), cancel_token.clone()),
+        };
+        let mut do_full = self.reports.next_full
+            || now.duration_since(self.reports.last_full) > FULL_REPORT_INTERVAL;
+
+        // If the last report had a captive portal and reported no UDP access,
+        // it's possible that we didn't get a useful net_report due to the
+        // captive portal blocking us. If so, make this report a full (non-incremental) one.
+        if !do_full {
+            if let Some(ref last) = self.reports.last {
+                do_full = !last.udp && last.captive_portal.unwrap_or_default();
+            }
+        }
+        if do_full {
+            self.reports.last = None; // causes ProbePlan::new below to do a full (initial) plan
+            self.reports.next_full = false;
+            self.reports.last_full = now;
+            #[cfg(feature = "metrics")]
+            inc!(Metrics, reports_full);
+        }
+        #[cfg(feature = "metrics")]
+        inc!(Metrics, reports);
+
+        let actor = reportgen::Client::new(
+            self.addr(),
+            self.reports.last.clone(),
+            self.port_mapper.clone(),
+            relay_map,
+            stun_sock_v4,
+            stun_sock_v6,
+            self.dns_resolver.clone(),
+        );
+
+        self.current_report_run = Some(ReportRun {
+            _reportgen: actor,
+            _drop_guard: cancel_token.drop_guard(),
+            report_tx: response_tx,
+        });
+    }
+
+    fn handle_report_ready(&mut self, report: Box<Report>) {
+        let report = self.finish_and_store_report(*report);
+        self.in_flight_stun_requests.clear();
+        if let Some(ReportRun { report_tx, .. }) = self.current_report_run.take() {
+            report_tx.send(Ok(report)).ok();
+        }
+    }
+
+    fn handle_report_aborted(&mut self, err: anyhow::Error) {
+        self.in_flight_stun_requests.clear();
+        if let Some(ReportRun { report_tx, .. }) = self.current_report_run.take() {
+            report_tx.send(Err(err.context("report aborted"))).ok();
+        }
+    }
+
+    /// Handles [`Message::StunPacket`].
+    ///
+    /// If there are currently no in-flight stun requests registered this is dropped,
+    /// otherwise forwarded to the probe.
+    fn handle_stun_packet(&mut self, pkt: &[u8], src: SocketAddr) {
+        trace!(%src, "received STUN packet");
+        if self.in_flight_stun_requests.is_empty() {
+            return;
+        }
+
+        #[cfg(feature = "metrics")]
+        match &src {
+            SocketAddr::V4(_) => {
+                inc!(Metrics, stun_packets_recv_ipv4);
+            }
+            SocketAddr::V6(_) => {
+                inc!(Metrics, stun_packets_recv_ipv6);
+            }
+        }
+
+        match stun::parse_response(pkt) {
+            Ok((txn, addr_port)) => match self.in_flight_stun_requests.remove(&txn) {
+                Some(inf) => {
+                    debug!(%src, %txn, "received known STUN packet");
+                    let elapsed = inf.start.elapsed();
+                    inf.s.send((elapsed, addr_port)).ok();
+                }
+                None => {
+                    debug!(%src, %txn, "received unexpected STUN message response");
+                }
+            },
+            Err(err) => {
+                match stun::parse_binding_request(pkt) {
+                    Ok(txn) => {
+                        // Is this our hairpin request?
+                        match self.in_flight_stun_requests.remove(&txn) {
+                            Some(inf) => {
+                                debug!(%src, %txn, "received our hairpin STUN request");
+                                let elapsed = inf.start.elapsed();
+                                inf.s.send((elapsed, src)).ok();
+                            }
+                            None => {
+                                debug!(%src, %txn, "unknown STUN request");
+                            }
+                        }
+                    }
+                    Err(_) => {
+                        debug!(%src, "received invalid STUN response: {err:#}");
+                    }
+                }
+            }
+        }
+    }
+
+    /// Handles [`Message::InFlightStun`].
+    ///
+    /// The in-flight request is added to [`Actor::in_flight_stun_requests`] so that
+    /// [`Actor::handle_stun_packet`] can forward packets correctly.
+    ///
+    /// *response_tx* is to signal the actor message has been handled.
+    fn handle_in_flight_stun(&mut self, inflight: Inflight, response_tx: oneshot::Sender<()>) {
+        self.in_flight_stun_requests.insert(inflight.txn, inflight);
+        response_tx.send(()).ok();
+    }
+
+    fn finish_and_store_report(&mut self, report: Report) -> Arc<Report> {
+        let report = self.add_report_history_and_set_preferred_relay(report);
+        debug!("{report:?}");
+        report
+    }
+
+    /// Adds `r` to the set of recent Reports and mutates `r.preferred_relay` to contain the best recent one.
+    /// `r` is stored ref counted and a reference is returned.
+    fn add_report_history_and_set_preferred_relay(&mut self, mut r: Report) -> Arc<Report> {
+        let mut prev_relay = None;
+        if let Some(ref last) = self.reports.last {
+            prev_relay.clone_from(&last.preferred_relay);
+        }
+        let now = Instant::now();
+        const MAX_AGE: Duration = Duration::from_secs(5 * 60);
+
+        // relay ID => its best recent latency in last MAX_AGE
+        let mut best_recent = RelayLatencies::new();
+
+        // chain the current report as we are still mutating it
+        let prevs_iter = self
+            .reports
+            .prev
+            .iter()
+            .map(|(a, b)| -> (&Instant, &Report) { (a, b) })
+            .chain(std::iter::once((&now, &r)));
+
+        let mut to_remove = Vec::new();
+        for (t, pr) in prevs_iter {
+            if now.duration_since(*t) > MAX_AGE {
+                to_remove.push(*t);
+                continue;
+            }
+            best_recent.merge(&pr.relay_latency);
+        }
+
+        for t in to_remove {
+            self.reports.prev.remove(&t);
+        }
+
+        // Then, pick which currently-alive relay server from the
+        // current report has the best latency over the past MAX_AGE.
+        let mut best_any = Duration::default();
+        let mut old_relay_cur_latency = Duration::default();
+        {
+            for (url, duration) in r.relay_latency.iter() {
+                if Some(url) == prev_relay.as_ref() {
+                    old_relay_cur_latency = duration;
+                }
+                if let Some(best) = best_recent.get(url) {
+                    if r.preferred_relay.is_none() || best < best_any {
+                        best_any = best;
+                        r.preferred_relay.replace(url.clone());
+                    }
+                }
+            }
+
+            // If we're changing our preferred relay but the old one's still
+            // accessible and the new one's not much better, just stick with
+            // where we are.
+            if prev_relay.is_some()
+                && r.preferred_relay != prev_relay
+                && !old_relay_cur_latency.is_zero()
+                && best_any > old_relay_cur_latency / 3 * 2
+            {
+                r.preferred_relay = prev_relay;
+            }
+        }
+
+        let r = Arc::new(r);
+        self.reports.prev.insert(now, r.clone());
+        self.reports.last = Some(r.clone());
+
+        r
+    }
+}
+
+/// State the net_report actor needs for an in-progress report generation.
+#[derive(Debug)]
+struct ReportRun {
+    /// The handle of the [`reportgen`] actor, cancels the actor on drop.
+    _reportgen: reportgen::Client,
+    /// Drop guard to optionally kill workers started by net_report to support reportgen.
+    _drop_guard: tokio_util::sync::DropGuard,
+    /// Where to send the completed report.
+    report_tx: oneshot::Sender<Result<Arc<Report>>>,
+}
+
+/// Attempts to bind a local socket to send STUN packets from.
+///
+/// If successful this returns the bound socket and will forward STUN responses to the
+/// provided *actor_addr*.  The *cancel_token* serves to stop the packet forwarding when the
+/// socket is no longer needed.
+fn bind_local_stun_socket(
+    network: IpFamily,
+    actor_addr: Addr,
+    cancel_token: CancellationToken,
+) -> Option<Arc<UdpSocket>> {
+    let sock = match UdpSocket::bind(network, 0) {
+        Ok(sock) => Arc::new(sock),
+        Err(err) => {
+            debug!("failed to bind STUN socket: {}", err);
+            return None;
+        }
+    };
+    let span = info_span!(
+        "stun_udp_listener",
+        local_addr = sock
+            .local_addr()
+            .map(|a| a.to_string())
+            .unwrap_or(String::from("-")),
+    );
+    {
+        let sock = sock.clone();
+        tokio::spawn(
+            async move {
+                debug!("udp stun socket listener started");
+                // TODO: Can we do better for buffers here?  Probably doesn't matter much.
+                let mut buf = vec![0u8; 64 << 10];
+                loop {
+                    tokio::select! {
+                        biased;
+                        _ = cancel_token.cancelled() => break,
+                        res = recv_stun_once(&sock, &mut buf, &actor_addr) => {
+                            if let Err(err) = res {
+                                warn!(%err, "stun recv failed");
+                                break;
+                            }
+                        }
+                    }
+                }
+                debug!("udp stun socket listener stopped");
+            }
+            .instrument(span),
+        );
+    }
+    Some(sock)
+}
+
+/// Receive STUN response from a UDP socket, pass it to the actor.
+async fn recv_stun_once(sock: &UdpSocket, buf: &mut [u8], actor_addr: &Addr) -> Result<()> {
+    let (count, mut from_addr) = sock
+        .recv_from(buf)
+        .await
+        .context("Error reading from stun socket")?;
+    let payload = &buf[..count];
+    from_addr.set_ip(from_addr.ip().to_canonical());
+    let msg = Message::StunPacket {
+        payload: Bytes::from(payload.to_vec()),
+        from_addr,
+    };
+    actor_addr.send(msg).await.context("actor stopped")
+}
+
+/// Test if IPv6 works at all, or if it's been hard disabled at the OS level.
+pub fn os_has_ipv6() -> bool {
+    UdpSocket::bind_local_v6(0).is_ok()
+}
+
+#[cfg(test)]
+mod test_utils {
+    //! Creates a relay server against which to perform tests
+
+    use std::sync::Arc;
+
+    use iroh_base::relay_map::QuicConfig;
+    use iroh_relay::server;
+
+    use crate::RelayNode;
+
+    pub(crate) async fn relay() -> (server::Server, Arc<RelayNode>) {
+        let server = server::Server::spawn(server::testing::server_config())
+            .await
+            .expect("should serve relay");
+        let quic = Some(QuicConfig {
+            port: server.quic_addr().expect("server should run quic").port(),
+        });
+        let node_desc = RelayNode {
+            url: server.https_url().expect("should work as relay"),
+            stun_only: false, // the checks above and below guarantee both stun and relay
+            stun_port: server.stun_addr().expect("server should serve stun").port(),
+            quic,
+        };
+
+        (server, Arc::new(node_desc))
+    }
+
+    /// Create a [`crate::RelayMap`] of the given size.
+    ///
+    /// This function uses [`relay`]. Note that the returned map uses internal order that will
+    /// often _not_ match the order of the servers.
+    pub(crate) async fn relay_map(relays: usize) -> (Vec<server::Server>, crate::RelayMap) {
+        let mut servers = Vec::with_capacity(relays);
+        let mut nodes = Vec::with_capacity(relays);
+        for _ in 0..relays {
+            let (relay_server, node) = relay().await;
+            servers.push(relay_server);
+            nodes.push(node);
+        }
+        let map = crate::RelayMap::from_nodes(nodes).expect("unuque urls");
+        (servers, map)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::Ipv4Addr;
+
+    use bytes::BytesMut;
+    use tokio::time;
+    use tracing::info;
+
+    use super::*;
+    use crate::ping::Pinger;
+
+    mod stun_utils {
+        //! Utils for testing that expose a simple stun server.
+
+        use std::{net::IpAddr, sync::Arc};
+
+        use anyhow::Result;
+        use tokio::{
+            net,
+            sync::{oneshot, Mutex},
+        };
+        use tracing::{debug, trace};
+
+        use super::*;
+        use crate::{RelayMap, RelayNode, RelayUrl};
+
+        /// A drop guard to clean up test infrastructure.
+        ///
+        /// After dropping the test infrastructure will asynchronously shutdown and release its
+        /// resources.
+        // Nightly sees the sender as dead code currently, but we only rely on Drop of the
+        // sender.
+        #[derive(Debug)]
+        pub struct CleanupDropGuard {
+            _guard: oneshot::Sender<()>,
+        }
+
+        // (read_ipv4, read_ipv6)
+        #[derive(Debug, Default, Clone)]
+        pub struct StunStats(Arc<Mutex<(usize, usize)>>);
+
+        impl StunStats {
+            pub async fn total(&self) -> usize {
+                let s = self.0.lock().await;
+                s.0 + s.1
+            }
+        }
+
+        pub fn relay_map_of(stun: impl Iterator<Item = SocketAddr>) -> RelayMap {
+            relay_map_of_opts(stun.map(|addr| (addr, true)))
+        }
+
+        pub fn relay_map_of_opts(stun: impl Iterator<Item = (SocketAddr, bool)>) -> RelayMap {
+            let nodes = stun.map(|(addr, stun_only)| {
+                let host = addr.ip();
+                let port = addr.port();
+
+                let url: RelayUrl = format!("http://{host}:{port}").parse().unwrap();
+                RelayNode {
+                    url,
+                    stun_port: port,
+                    stun_only,
+                    quic: None,
+                }
+            });
+            RelayMap::from_nodes(nodes).expect("generated invalid nodes")
+        }
+
+        /// Sets up a simple STUN server binding to `0.0.0.0:0`.
+        ///
+        /// See [`serve`] for more details.
+        pub(crate) async fn serve_v4() -> Result<(SocketAddr, StunStats, CleanupDropGuard)> {
+            serve(std::net::Ipv4Addr::UNSPECIFIED.into()).await
+        }
+
+        /// Sets up a simple STUN server.
+        pub(crate) async fn serve(ip: IpAddr) -> Result<(SocketAddr, StunStats, CleanupDropGuard)> {
+            let stats = StunStats::default();
+
+            let pc = net::UdpSocket::bind((ip, 0)).await?;
+            let mut addr = pc.local_addr()?;
+            match addr.ip() {
+                IpAddr::V4(ip) => {
+                    if ip.octets() == [0, 0, 0, 0] {
+                        addr.set_ip("127.0.0.1".parse().unwrap());
+                    }
+                }
+                _ => unreachable!("using ipv4"),
+            }
+
+            println!("STUN listening on {}", addr);
+            let (_guard, r) = oneshot::channel();
+            let stats_c = stats.clone();
+            tokio::task::spawn(async move {
+                run_stun(pc, stats_c, r).await;
+            });
+
+            Ok((addr, stats, CleanupDropGuard { _guard }))
+        }
+
+        async fn run_stun(pc: net::UdpSocket, stats: StunStats, mut done: oneshot::Receiver<()>) {
+            let mut buf = vec![0u8; 64 << 10];
+            loop {
+                trace!("read loop");
+                tokio::select! {
+                    _ = &mut done => {
+                        debug!("shutting down");
+                        break;
+                    }
+                    res = pc.recv_from(&mut buf) => match res {
+                        Ok((n, addr)) => {
+                            trace!("read packet {}bytes from {}", n, addr);
+                            let pkt = &buf[..n];
+                            if !stun::is(pkt) {
+                                debug!("received non STUN pkt");
+                                continue;
+                            }
+                            if let Ok(txid) = stun::parse_binding_request(pkt) {
+                                debug!("received binding request");
+                                let mut s = stats.0.lock().await;
+                                if addr.is_ipv4() {
+                                    s.0 += 1;
+                                } else {
+                                    s.1 += 1;
+                                }
+                                drop(s);
+
+                                let res = stun::response(txid, addr);
+                                if let Err(err) = pc.send_to(&res, addr).await {
+                                    eprintln!("STUN server write failed: {:?}", err);
+                                }
+                            }
+                        }
+                        Err(err) => {
+                            eprintln!("failed to read: {:?}", err);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    #[tokio::test]
+    async fn test_basic() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+        let (stun_addr, stun_stats, _cleanup_guard) =
+            stun_utils::serve("127.0.0.1".parse().unwrap()).await?;
+
+        let resolver = crate::dns::tests::resolver();
+        let mut client = Client::new(None, resolver.clone())?;
+        let dm = stun_utils::relay_map_of([stun_addr].into_iter());
+
+        // Note that the ProbePlan will change with each iteration.
+        for i in 0..5 {
+            println!("--round {}", i);
+            let r = client.get_report(dm.clone(), None, None).await?;
+
+            assert!(r.udp, "want UDP");
+            assert_eq!(
+                r.relay_latency.len(),
+                1,
+                "expected 1 key in RelayLatency; got {}",
+                r.relay_latency.len()
+            );
+            assert!(
+                r.relay_latency.iter().next().is_some(),
+                "expected key 1 in RelayLatency; got {:?}",
+                r.relay_latency
+            );
+            assert!(r.global_v4.is_some(), "expected globalV4 set");
+            assert!(r.preferred_relay.is_some(),);
+        }
+
+        assert!(
+            stun_stats.total().await >= 5,
+            "expected at least 5 stun, got {}",
+            stun_stats.total().await,
+        );
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_udp_blocked() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        // Create a "STUN server", which will never respond to anything.  This is how UDP to
+        // the STUN server being blocked will look like from the client's perspective.
+        let blackhole = tokio::net::UdpSocket::bind("127.0.0.1:0").await?;
+        let stun_addr = blackhole.local_addr()?;
+        let dm = stun_utils::relay_map_of_opts([(stun_addr, false)].into_iter());
+
+        // Now create a client and generate a report.
+        let resolver = crate::dns::tests::resolver();
+        let mut client = Client::new(None, resolver.clone())?;
+
+        let r = client.get_report(dm, None, None).await?;
+        let mut r: Report = (*r).clone();
+        r.portmap_probe = None;
+
+        // This test wants to ensure that the ICMP part of the probe works when UDP is
+        // blocked.  Unfortunately on some systems we simply don't have permissions to
+        // create raw ICMP pings and we'll have to silently accept this test is useless (if
+        // we could, this would be a skip instead).
+        let pinger = Pinger::new();
+        let can_ping = pinger.send(Ipv4Addr::LOCALHOST.into(), b"aa").await.is_ok();
+        let want_icmpv4 = match can_ping {
+            true => Some(true),
+            false => None,
+        };
+
+        let want = Report {
+            // The ICMP probe sets the can_ping flag.
+            ipv4_can_send: can_ping,
+            // OS IPv6 test is irrelevant here, accept whatever the current machine has.
+            os_has_ipv6: r.os_has_ipv6,
+            // Captive portal test is irrelevant; accept what the current report has.
+            captive_portal: r.captive_portal,
+            // If we can ping we expect to have this.
+            icmpv4: want_icmpv4,
+            // If we had a pinger, we'll have some latencies filled in and a preferred relay
+            relay_latency: can_ping
+                .then(|| r.relay_latency.clone())
+                .unwrap_or_default(),
+            preferred_relay: can_ping
+                .then_some(r.preferred_relay.clone())
+                .unwrap_or_default(),
+            ..Default::default()
+        };
+
+        assert_eq!(r, want);
+
+        Ok(())
+    }
+
+    #[tokio::test(flavor = "current_thread", start_paused = true)]
+    async fn test_add_report_history_set_preferred_relay() -> Result<()> {
+        fn relay_url(i: u16) -> RelayUrl {
+            format!("http://{i}.com").parse().unwrap()
+        }
+
+        // report returns a *Report from (relay host, Duration)+ pairs.
+        fn report(a: impl IntoIterator<Item = (&'static str, u64)>) -> Option<Arc<Report>> {
+            let mut report = Report::default();
+            for (s, d) in a {
+                assert!(s.starts_with('d'), "invalid relay server key");
+                let id: u16 = s[1..].parse().unwrap();
+                report
+                    .relay_latency
+                    .0
+                    .insert(relay_url(id), Duration::from_secs(d));
+            }
+
+            Some(Arc::new(report))
+        }
+        struct Step {
+            /// Delay in seconds
+            after: u64,
+            r: Option<Arc<Report>>,
+        }
+        struct Test {
+            name: &'static str,
+            steps: Vec<Step>,
+            /// want PreferredRelay on final step
+            want_relay: Option<RelayUrl>,
+            // wanted len(c.prev)
+            want_prev_len: usize,
+        }
+
+        let tests = [
+            Test {
+                name: "first_reading",
+                steps: vec![Step {
+                    after: 0,
+                    r: report([("d1", 2), ("d2", 3)]),
+                }],
+                want_prev_len: 1,
+                want_relay: Some(relay_url(1)),
+            },
+            Test {
+                name: "with_two",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 2), ("d2", 3)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 4), ("d2", 3)]),
+                    },
+                ],
+                want_prev_len: 2,
+                want_relay: Some(relay_url(1)), // t0's d1 of 2 is still best
+            },
+            Test {
+                name: "but_now_d1_gone",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 2), ("d2", 3)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 4), ("d2", 3)]),
+                    },
+                    Step {
+                        after: 2,
+                        r: report([("d2", 3)]),
+                    },
+                ],
+                want_prev_len: 3,
+                want_relay: Some(relay_url(2)), // only option
+            },
+            Test {
+                name: "d1_is_back",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 2), ("d2", 3)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 4), ("d2", 3)]),
+                    },
+                    Step {
+                        after: 2,
+                        r: report([("d2", 3)]),
+                    },
+                    Step {
+                        after: 3,
+                        r: report([("d1", 4), ("d2", 3)]),
+                    }, // same as 2 seconds ago
+                ],
+                want_prev_len: 4,
+                want_relay: Some(relay_url(1)), // t0's d1 of 2 is still best
+            },
+            Test {
+                name: "things_clean_up",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 1), ("d2", 2)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 1), ("d2", 2)]),
+                    },
+                    Step {
+                        after: 2,
+                        r: report([("d1", 1), ("d2", 2)]),
+                    },
+                    Step {
+                        after: 3,
+                        r: report([("d1", 1), ("d2", 2)]),
+                    },
+                    Step {
+                        after: 10 * 60,
+                        r: report([("d3", 3)]),
+                    },
+                ],
+                want_prev_len: 1, // t=[0123]s all gone. (too old, older than 10 min)
+                want_relay: Some(relay_url(3)), // only option
+            },
+            Test {
+                name: "preferred_relay_hysteresis_no_switch",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 4), ("d2", 5)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 4), ("d2", 3)]),
+                    },
+                ],
+                want_prev_len: 2,
+                want_relay: Some(relay_url(1)), // 2 didn't get fast enough
+            },
+            Test {
+                name: "preferred_relay_hysteresis_do_switch",
+                steps: vec![
+                    Step {
+                        after: 0,
+                        r: report([("d1", 4), ("d2", 5)]),
+                    },
+                    Step {
+                        after: 1,
+                        r: report([("d1", 4), ("d2", 1)]),
+                    },
+                ],
+                want_prev_len: 2,
+                want_relay: Some(relay_url(2)), // 2 got fast enough
+            },
+        ];
+        let resolver = crate::dns::tests::resolver();
+        for mut tt in tests {
+            println!("test: {}", tt.name);
+            let mut actor = Actor::new(None, resolver.clone()).unwrap();
+            for s in &mut tt.steps {
+                // trigger the timer
+                time::advance(Duration::from_secs(s.after)).await;
+                let r = Arc::try_unwrap(s.r.take().unwrap()).unwrap();
+                s.r = Some(actor.add_report_history_and_set_preferred_relay(r));
+            }
+            let last_report = tt.steps.last().unwrap().r.clone().unwrap();
+            let got = actor.reports.prev.len();
+            let want = tt.want_prev_len;
+            assert_eq!(got, want, "prev length");
+            let got = &last_report.preferred_relay;
+            let want = &tt.want_relay;
+            assert_eq!(got, want, "preferred_relay");
+        }
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_hairpin() -> Result<()> {
+        // Hairpinning is initiated after we discover our own IPv4 socket address (IP +
+        // port) via STUN, so the test needs to have a STUN server and perform STUN over
+        // IPv4 first.  Hairpinning detection works by sending a STUN *request* to **our own
+        // public socket address** (IP + port).  If the router supports hairpinning the STUN
+        // request is returned back to us and received on our public address.  This doesn't
+        // need to be a STUN request, but STUN already has a unique transaction ID which we
+        // can easily use to identify the packet.
+
+        // Setup STUN server and create relay_map.
+        let (stun_addr, _stun_stats, _done) = stun_utils::serve_v4().await?;
+        let dm = stun_utils::relay_map_of([stun_addr].into_iter());
+        dbg!(&dm);
+
+        let resolver = crate::dns::tests::resolver().clone();
+        let mut client = Client::new(None, resolver)?;
+
+        // Set up an external socket to send STUN requests from, this will be discovered as
+        // our public socket address by STUN.  We send back any packets received on this
+        // socket to the net_report client using Client::receive_stun_packet.  Once we sent
+        // the hairpin STUN request (from a different randomly bound socket) we are sending
+        // it to this socket, which is forwarnding it back to our net_report client, because
+        // this dumb implementation just forwards anything even if it would be garbage.
+        // Thus hairpinning detection will declare hairpinning to work.
+        let sock = UdpSocket::bind_local(IpFamily::V4, 0)?;
+        let sock = Arc::new(sock);
+        info!(addr=?sock.local_addr().unwrap(), "Using local addr");
+        let task = {
+            let sock = sock.clone();
+            let addr = client.addr.clone();
+            tokio::spawn(
+                async move {
+                    let mut buf = BytesMut::zeroed(64 << 10);
+                    loop {
+                        let (count, src) = sock.recv_from(&mut buf).await.unwrap();
+                        info!(
+                            addr=?sock.local_addr().unwrap(),
+                            %count,
+                            "Forwarding payload to net_report client",
+                        );
+                        let payload = buf.split_to(count).freeze();
+                        addr.receive_stun_packet(payload, src);
+                    }
+                }
+                .instrument(info_span!("pkt-fwd")),
+            )
+        };
+
+        let r = client.get_report(dm, Some(sock), None).await?;
+        dbg!(&r);
+        assert_eq!(r.hair_pinning, Some(true));
+
+        task.abort();
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/metrics.rs.html b/pr/2992/docs/src/iroh_net_report/metrics.rs.html new file mode 100644 index 0000000000..0f9c381094 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/metrics.rs.html @@ -0,0 +1,83 @@ +metrics.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
use iroh_metrics::{
+    core::{Counter, Metric},
+    struct_iterable::Iterable,
+};
+
+/// Enum of metrics for the module
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Iterable)]
+pub struct Metrics {
+    pub stun_packets_dropped: Counter,
+    pub stun_packets_sent_ipv4: Counter,
+    pub stun_packets_sent_ipv6: Counter,
+    pub stun_packets_recv_ipv4: Counter,
+    pub stun_packets_recv_ipv6: Counter,
+    pub reports: Counter,
+    pub reports_full: Counter,
+}
+
+impl Default for Metrics {
+    fn default() -> Self {
+        Self {
+            stun_packets_dropped: Counter::new(
+                "Incoming STUN packets dropped due to a full receiving queue.",
+            ),
+            stun_packets_sent_ipv4: Counter::new("Number of IPv4 STUN packets sent"),
+            stun_packets_sent_ipv6: Counter::new("Number of IPv6 STUN packets sent"),
+            stun_packets_recv_ipv4: Counter::new("Number of IPv4 STUN packets received"),
+            stun_packets_recv_ipv6: Counter::new("Number of IPv6 STUN packets received"),
+            reports: Counter::new(
+                "Number of reports executed by net_report, including full reports",
+            ),
+            reports_full: Counter::new("Number of full reports executed by net_report"),
+        }
+    }
+}
+
+impl Metric for Metrics {
+    fn name() -> &'static str {
+        "net_report"
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/ping.rs.html b/pr/2992/docs/src/iroh_net_report/ping.rs.html new file mode 100644 index 0000000000..3a73f145b9 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/ping.rs.html @@ -0,0 +1,387 @@ +ping.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+
//! Allows sending ICMP echo requests to a host in order to determine network latency.
+
+use std::{
+    fmt::Debug,
+    net::IpAddr,
+    sync::{Arc, Mutex},
+    time::Duration,
+};
+
+use anyhow::{Context, Result};
+use surge_ping::{Client, Config, IcmpPacket, PingIdentifier, PingSequence, ICMP};
+use tracing::debug;
+
+use crate::defaults::timeouts::DEFAULT_PINGER_TIMEOUT as DEFAULT_TIMEOUT;
+
+/// Whether this error was because we couldn't create a client or a send error.
+#[derive(Debug, thiserror::Error)]
+pub enum PingError {
+    /// Could not create client, probably bind error.
+    #[error("Error creating ping client")]
+    Client(#[from] anyhow::Error),
+    /// Could not send ping.
+    #[error("Error sending ping")]
+    Ping(#[from] surge_ping::SurgeError),
+}
+
+/// Allows sending ICMP echo requests to a host in order to determine network latency.
+/// Will gracefully handle both IPv4 and IPv6.
+#[derive(Debug, Clone, Default)]
+pub struct Pinger(Arc<Inner>);
+
+impl Debug for Inner {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Inner").finish()
+    }
+}
+
+#[derive(Default)]
+struct Inner {
+    client_v6: Mutex<Option<Client>>,
+    client_v4: Mutex<Option<Client>>,
+}
+
+impl Pinger {
+    /// Create a new [Pinger].
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    /// Lazily create the ping client.
+    ///
+    /// We do this because it means we do not bind a socket until we really try to send a
+    /// ping.  It makes it more transparent to use the pinger.
+    fn get_client(&self, kind: ICMP) -> Result<Client> {
+        let client = match kind {
+            ICMP::V4 => {
+                let mut opt_client = self.0.client_v4.lock().unwrap();
+                match *opt_client {
+                    Some(ref client) => client.clone(),
+                    None => {
+                        let cfg = Config::builder().kind(kind).build();
+                        let client = Client::new(&cfg).context("failed to create IPv4 pinger")?;
+                        *opt_client = Some(client.clone());
+                        client
+                    }
+                }
+            }
+            ICMP::V6 => {
+                let mut opt_client = self.0.client_v6.lock().unwrap();
+                match *opt_client {
+                    Some(ref client) => client.clone(),
+                    None => {
+                        let cfg = Config::builder().kind(kind).build();
+                        let client = Client::new(&cfg).context("failed to create IPv6 pinger")?;
+                        *opt_client = Some(client.clone());
+                        client
+                    }
+                }
+            }
+        };
+        Ok(client)
+    }
+
+    /// Send a ping request with associated data, returning the perceived latency.
+    pub async fn send(&self, addr: IpAddr, data: &[u8]) -> Result<Duration, PingError> {
+        let client = match addr {
+            IpAddr::V4(_) => self.get_client(ICMP::V4).map_err(PingError::Client)?,
+            IpAddr::V6(_) => self.get_client(ICMP::V6).map_err(PingError::Client)?,
+        };
+        let ident = PingIdentifier(rand::random());
+        debug!(%addr, %ident, "Creating pinger");
+        let mut pinger = client.pinger(addr, ident).await;
+        pinger.timeout(DEFAULT_TIMEOUT); // todo: timeout too large for net_report
+        match pinger.ping(PingSequence(0), data).await? {
+            (IcmpPacket::V4(packet), dur) => {
+                debug!(
+                    "{} bytes from {}: icmp_seq={} ttl={:?} time={:0.2?}",
+                    packet.get_size(),
+                    packet.get_source(),
+                    packet.get_sequence(),
+                    packet.get_ttl(),
+                    dur
+                );
+                Ok(dur)
+            }
+
+            (IcmpPacket::V6(packet), dur) => {
+                debug!(
+                    "{} bytes from {}: icmp_seq={} hlim={} time={:0.2?}",
+                    packet.get_size(),
+                    packet.get_source(),
+                    packet.get_sequence(),
+                    packet.get_max_hop_limit(),
+                    dur
+                );
+                Ok(dur)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::{Ipv4Addr, Ipv6Addr};
+
+    use tracing::error;
+
+    use super::*;
+
+    #[tokio::test]
+    #[ignore] // Doesn't work in CI
+    async fn test_ping_google() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        // Public DNS addrs from google based on
+        // https://developers.google.com/speed/public-dns/docs/using
+
+        let pinger = Pinger::new();
+
+        // IPv4
+        let dur = pinger.send("8.8.8.8".parse()?, &[1u8; 8]).await?;
+        assert!(!dur.is_zero());
+
+        // IPv6
+        match pinger
+            .send("2001:4860:4860:0:0:0:0:8888".parse()?, &[1u8; 8])
+            .await
+        {
+            Ok(dur) => {
+                assert!(!dur.is_zero());
+            }
+            Err(err) => {
+                tracing::error!("IPv6 is not available: {:?}", err);
+            }
+        }
+
+        Ok(())
+    }
+
+    // See net_report::reportgen::tests::test_icmp_probe_eu_relay for permissions to ping.
+    #[tokio::test]
+    async fn test_ping_localhost() {
+        let _guard = iroh_test::logging::setup();
+
+        let pinger = Pinger::new();
+
+        match pinger.send(Ipv4Addr::LOCALHOST.into(), b"data").await {
+            Ok(duration) => {
+                assert!(!duration.is_zero());
+            }
+            Err(PingError::Client(err)) => {
+                // We don't have permission, too bad.
+                error!("no ping permissions: {err:#}");
+            }
+            Err(PingError::Ping(err)) => {
+                panic!("ping failed: {err:#}");
+            }
+        }
+
+        match pinger.send(Ipv6Addr::LOCALHOST.into(), b"data").await {
+            Ok(duration) => {
+                assert!(!duration.is_zero());
+            }
+            Err(PingError::Client(err)) => {
+                // We don't have permission, too bad.
+                error!("no ping permissions: {err:#}");
+            }
+            Err(PingError::Ping(err)) => {
+                error!("ping failed, probably no IPv6 stack: {err:#}");
+            }
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/reportgen.rs.html b/pr/2992/docs/src/iroh_net_report/reportgen.rs.html new file mode 100644 index 0000000000..b3cacd7547 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/reportgen.rs.html @@ -0,0 +1,2935 @@ +reportgen.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+
//! The reportgen actor is responsible for generating a single net_report report.
+//!
+//! It is implemented as an actor with [`Client`] as handle.
+//!
+//! The actor starts generating the report as soon as it is created, it does not receive any
+//! messages from the client.  It follows roughly these steps:
+//!
+//! - Determines host IPv6 support.
+//! - Creates hairpin actor.
+//! - Creates portmapper future.
+//! - Creates captive portal detection future.
+//! - Creates Probe Set futures.
+//!   - These send messages to the reportgen actor.
+//! - Loops driving the futures and handling actor messages:
+//!   - Disables futures as they are completed or aborted.
+//!   - Stop if there are no outstanding tasks/futures, or on timeout.
+//! - Sends the completed report to the net_report actor.
+
+use std::{
+    future::Future,
+    net::{IpAddr, SocketAddr},
+    pin::Pin,
+    sync::Arc,
+    task::{Context, Poll},
+    time::Duration,
+};
+
+use anyhow::{anyhow, bail, Context as _, Result};
+use hickory_resolver::TokioAsyncResolver as DnsResolver;
+#[cfg(feature = "metrics")]
+use iroh_metrics::inc;
+use iroh_relay::{http::RELAY_PROBE_PATH, protos::stun};
+use netwatch::{interfaces, UdpSocket};
+use rand::seq::IteratorRandom;
+use tokio::{
+    sync::{mpsc, oneshot},
+    task::JoinSet,
+    time::{self, Instant},
+};
+use tokio_util::task::AbortOnDropHandle;
+use tracing::{debug, debug_span, error, info_span, trace, warn, Instrument, Span};
+use url::Host;
+
+#[cfg(feature = "metrics")]
+use crate::Metrics;
+use crate::{
+    self as net_report,
+    defaults::DEFAULT_STUN_PORT,
+    dns::ResolverExt,
+    ping::{PingError, Pinger},
+    RelayMap, RelayNode, RelayUrl, Report,
+};
+
+mod hairpin;
+mod probes;
+
+use probes::{Probe, ProbePlan, ProbeProto};
+
+use crate::defaults::timeouts::{
+    CAPTIVE_PORTAL_DELAY, CAPTIVE_PORTAL_TIMEOUT, OVERALL_REPORT_TIMEOUT, PROBES_TIMEOUT,
+};
+
+const ENOUGH_NODES: usize = 3;
+
+/// Holds the state for a single invocation of [`net_report::Client::get_report`].
+///
+/// Dropping this will cancel the actor and stop the report generation.
+#[derive(Debug)]
+pub(super) struct Client {
+    // Addr is currently only used by child actors, so not yet exposed here.
+    _drop_guard: AbortOnDropHandle<()>,
+}
+
+impl Client {
+    /// Creates a new actor generating a single report.
+    ///
+    /// The actor starts running immediately and only generates a single report, after which
+    /// it shuts down.  Dropping this handle will abort the actor.
+    pub(super) fn new(
+        net_report: net_report::Addr,
+        last_report: Option<Arc<Report>>,
+        port_mapper: Option<portmapper::Client>,
+        relay_map: RelayMap,
+        stun_sock4: Option<Arc<UdpSocket>>,
+        stun_sock6: Option<Arc<UdpSocket>>,
+        dns_resolver: DnsResolver,
+    ) -> Self {
+        let (msg_tx, msg_rx) = mpsc::channel(32);
+        let addr = Addr {
+            sender: msg_tx.clone(),
+        };
+        let mut actor = Actor {
+            msg_tx,
+            msg_rx,
+            net_report: net_report.clone(),
+            last_report,
+            port_mapper,
+            relay_map,
+            stun_sock4,
+            stun_sock6,
+            report: Report::default(),
+            hairpin_actor: hairpin::Client::new(net_report, addr),
+            outstanding_tasks: OutstandingTasks::default(),
+            dns_resolver,
+        };
+        let task = tokio::spawn(
+            async move { actor.run().await }.instrument(info_span!("reportgen.actor")),
+        );
+        Self {
+            _drop_guard: AbortOnDropHandle::new(task),
+        }
+    }
+}
+
+/// The address of the reportstate [`Actor`].
+///
+/// Unlike the [`Client`] struct itself this is the raw channel to send message over.
+/// Keeping this alive will not keep the actor alive, which makes this handy to pass to
+/// internal tasks.
+#[derive(Debug, Clone)]
+pub(super) struct Addr {
+    sender: mpsc::Sender<Message>,
+}
+
+impl Addr {
+    /// Blocking send to the actor, to be used from a non-actor future.
+    async fn send(&self, msg: Message) -> Result<(), mpsc::error::SendError<Message>> {
+        trace!(
+            "sending {:?} to channel with cap {}",
+            msg,
+            self.sender.capacity()
+        );
+        self.sender.send(msg).await
+    }
+}
+
+/// Messages to send to the reportstate [`Actor`].
+#[derive(Debug)]
+enum Message {
+    /// Set the hairpinning availability in the report.
+    HairpinResult(bool),
+    /// Check whether executing a probe would still help.
+    // TODO: Ideally we remove the need for this message and the logic is inverted: once we
+    // get a probe result we cancel all probes that are no longer needed.  But for now it's
+    // this way around to ease conversion.
+    ProbeWouldHelp(Probe, Arc<RelayNode>, oneshot::Sender<bool>),
+    /// Abort all remaining probes.
+    AbortProbes,
+}
+
+/// The reportstate actor.
+///
+/// This actor starts, generates a single report and exits.
+#[derive(Debug)]
+struct Actor {
+    /// The sender of the message channel, so we can give out [`Addr`].
+    msg_tx: mpsc::Sender<Message>,
+    /// The receiver of the message channel.
+    msg_rx: mpsc::Receiver<Message>,
+    /// The address of the net_report actor.
+    net_report: super::Addr,
+
+    // Provided state
+    /// The previous report, if it exists.
+    last_report: Option<Arc<Report>>,
+    /// The portmapper client, if there is one.
+    port_mapper: Option<portmapper::Client>,
+    /// The relay configuration.
+    relay_map: RelayMap,
+    /// Socket to send IPv4 STUN requests from.
+    stun_sock4: Option<Arc<UdpSocket>>,
+    /// Socket so send IPv6 STUN requests from.
+    stun_sock6: Option<Arc<UdpSocket>>,
+
+    // Internal state.
+    /// The report being built.
+    report: Report,
+    /// The hairpin actor.
+    hairpin_actor: hairpin::Client,
+    /// Which tasks the [`Actor`] is still waiting on.
+    ///
+    /// This is essentially the summary of all the work the [`Actor`] is doing.
+    outstanding_tasks: OutstandingTasks,
+    /// The DNS resolver to use for probes that need to resolve DNS records.
+    dns_resolver: DnsResolver,
+}
+
+impl Actor {
+    fn addr(&self) -> Addr {
+        Addr {
+            sender: self.msg_tx.clone(),
+        }
+    }
+
+    async fn run(&mut self) {
+        match self.run_inner().await {
+            Ok(_) => debug!("reportgen actor finished"),
+            Err(err) => {
+                self.net_report
+                    .send(net_report::Message::ReportAborted { err })
+                    .await
+                    .ok();
+            }
+        }
+    }
+
+    /// Runs the main reportgen actor logic.
+    ///
+    /// This actor runs by:
+    ///
+    /// - Creates a hairpin actor.
+    /// - Creates a captive portal future.
+    /// - Creates ProbeSet futures in a group of futures.
+    /// - Runs a main loop:
+    ///   - Drives all the above futures.
+    ///   - Receives actor messages (sent by those futures).
+    ///   - Updates the report, cancels unneeded futures.
+    /// - Sends the report to the net_report actor.
+    async fn run_inner(&mut self) -> Result<()> {
+        debug!(
+            port_mapper = %self.port_mapper.is_some(),
+            "reportstate actor starting",
+        );
+
+        self.report.os_has_ipv6 = super::os_has_ipv6();
+
+        let mut port_mapping = self.prepare_portmapper_task();
+        let mut captive_task = self.prepare_captive_portal_task();
+        let mut probes = self.spawn_probes_task().await?;
+
+        let total_timer = tokio::time::sleep(OVERALL_REPORT_TIMEOUT);
+        tokio::pin!(total_timer);
+        let probe_timer = tokio::time::sleep(PROBES_TIMEOUT);
+        tokio::pin!(probe_timer);
+
+        loop {
+            trace!(awaiting = ?self.outstanding_tasks, "tick; awaiting tasks");
+            if self.outstanding_tasks.all_done() {
+                debug!("all tasks done");
+                break;
+            }
+            tokio::select! {
+                biased;
+                _ = &mut total_timer => {
+                    trace!("tick: total_timer expired");
+                    bail!("report timed out");
+                }
+
+                _ = &mut probe_timer => {
+                    warn!("tick: probes timed out");
+                    // Set new timeout to not go into this branch multiple times.  We need
+                    // the abort to finish all probes normally.  PROBES_TIMEOUT is
+                    // sufficiently far in the future.
+                    probe_timer.as_mut().reset(Instant::now() + PROBES_TIMEOUT);
+                    probes.abort_all();
+                    self.handle_abort_probes();
+                }
+
+                // Drive the portmapper.
+                pm = &mut port_mapping, if self.outstanding_tasks.port_mapper => {
+                    debug!(report=?pm, "tick: portmapper probe report");
+                    self.report.portmap_probe = pm;
+                    port_mapping.inner = None;
+                    self.outstanding_tasks.port_mapper = false;
+                }
+
+                // Check for probes finishing.
+                set_result = probes.join_next(), if self.outstanding_tasks.probes => {
+                    trace!("tick: probes done: {:?}", set_result);
+                    match set_result {
+                        Some(Ok(Ok(report))) => self.handle_probe_report(report),
+                        Some(Ok(Err(_))) => (),
+                        Some(Err(e)) => {
+                            warn!("probes task error: {:?}", e);
+                        }
+                        None => {
+                            self.handle_abort_probes();
+                        }
+                    }
+                    trace!("tick: probes handled");
+                }
+
+                // Drive the captive task.
+                found = &mut captive_task, if self.outstanding_tasks.captive_task => {
+                    trace!("tick: captive portal task done");
+                    self.report.captive_portal = found;
+                    captive_task.inner = None;
+                    self.outstanding_tasks.captive_task = false;
+                }
+
+                // Handle actor messages.
+                msg = self.msg_rx.recv() => {
+                    trace!("tick: msg recv: {:?}", msg);
+                    match msg {
+                        Some(msg) => self.handle_message(msg),
+                        None => bail!("msg_rx closed, reportgen client must be dropped"),
+                    }
+                }
+            }
+        }
+
+        if !probes.is_empty() {
+            debug!(
+                "aborting {} probe sets, already have enough reports",
+                probes.len()
+            );
+            drop(probes);
+        }
+
+        debug!("Sending report to net_report actor");
+        self.net_report
+            .send(net_report::Message::ReportReady {
+                report: Box::new(self.report.clone()),
+            })
+            .await?;
+
+        Ok(())
+    }
+
+    /// Handles an actor message.
+    ///
+    /// Returns `true` if all the probes need to be aborted.
+    fn handle_message(&mut self, msg: Message) {
+        trace!(?msg, "handling message");
+        match msg {
+            Message::HairpinResult(works) => {
+                self.report.hair_pinning = Some(works);
+                self.outstanding_tasks.hairpin = false;
+            }
+            Message::ProbeWouldHelp(probe, relay_node, response_tx) => {
+                let res = self.probe_would_help(probe, relay_node);
+                if response_tx.send(res).is_err() {
+                    debug!("probe dropped before ProbeWouldHelp response sent");
+                }
+            }
+            Message::AbortProbes => {
+                self.handle_abort_probes();
+            }
+        }
+    }
+
+    fn handle_probe_report(&mut self, probe_report: ProbeReport) {
+        debug!(?probe_report, "finished probe");
+        update_report(&mut self.report, probe_report);
+
+        // When we discover the first IPv4 address we want to start the hairpin actor.
+        if let Some(ref addr) = self.report.global_v4 {
+            if !self.hairpin_actor.has_started() {
+                self.hairpin_actor.start_check(*addr);
+                self.outstanding_tasks.hairpin = true;
+            }
+        }
+
+        // Once we've heard from enough relay servers (3), start a timer to give up on the other
+        // probes. The timer's duration is a function of whether this is our initial full
+        // probe or an incremental one. For incremental ones, wait for the duration of the
+        // slowest relay. For initial ones, double that.
+        let enough_relays = std::cmp::min(self.relay_map.len(), ENOUGH_NODES);
+        if self.report.relay_latency.len() == enough_relays {
+            let timeout = self.report.relay_latency.max_latency();
+            let timeout = match self.last_report.is_some() {
+                true => timeout,
+                false => timeout * 2,
+            };
+            let reportcheck = self.addr();
+            debug!(
+                reports=self.report.relay_latency.len(),
+                delay=?timeout,
+                "Have enough probe reports, aborting further probes soon",
+            );
+            tokio::spawn(
+                async move {
+                    time::sleep(timeout).await;
+                    // Because we do this after a timeout it is entirely normal that the
+                    // actor is no longer there by the time we send this message.
+                    reportcheck
+                        .send(Message::AbortProbes)
+                        .await
+                        .map_err(|err| trace!("Failed to abort all probes: {err:#}"))
+                        .ok();
+                }
+                .instrument(Span::current()),
+            );
+        }
+    }
+
+    /// Whether running this probe would still improve our report.
+    fn probe_would_help(&mut self, probe: Probe, relay_node: Arc<RelayNode>) -> bool {
+        // If the probe is for a relay we don't yet know about, that would help.
+        if self.report.relay_latency.get(&relay_node.url).is_none() {
+            return true;
+        }
+
+        // If the probe is for IPv6 and we don't yet have an IPv6 report, that would help.
+        if probe.proto() == ProbeProto::StunIpv6 && self.report.relay_v6_latency.is_empty() {
+            return true;
+        }
+
+        // For IPv4, we need at least two IPv4 results overall to
+        // determine whether we're behind a NAT that shows us as
+        // different source IPs and/or ports depending on who we're
+        // talking to. If we don't yet have two results yet
+        // (`mapping_varies_by_dest_ip` is blank), then another IPv4 probe
+        // would be good.
+        if probe.proto() == ProbeProto::StunIpv4 && self.report.mapping_varies_by_dest_ip.is_none()
+        {
+            return true;
+        }
+
+        // Otherwise not interesting.
+        false
+    }
+
+    /// Stops further probes.
+    ///
+    /// This makes sure that no further probes are run and also cancels the captive portal
+    /// and portmapper tasks if there were successful probes.  Be sure to only handle this
+    /// after all the required [`ProbeReport`]s have been processed.
+    fn handle_abort_probes(&mut self) {
+        trace!("handle abort probes");
+        self.outstanding_tasks.probes = false;
+        if self.report.udp {
+            self.outstanding_tasks.port_mapper = false;
+            self.outstanding_tasks.captive_task = false;
+        }
+    }
+
+    /// Creates the future which will perform the portmapper task.
+    ///
+    /// The returned future will run the portmapper, if enabled, resolving to it's result.
+    fn prepare_portmapper_task(
+        &mut self,
+    ) -> MaybeFuture<Pin<Box<impl Future<Output = Option<portmapper::ProbeOutput>>>>> {
+        let mut port_mapping = MaybeFuture::default();
+        if let Some(port_mapper) = self.port_mapper.clone() {
+            port_mapping.inner = Some(Box::pin(async move {
+                match port_mapper.probe().await {
+                    Ok(Ok(res)) => Some(res),
+                    Ok(Err(err)) => {
+                        debug!("skipping port mapping: {err:?}");
+                        None
+                    }
+                    Err(recv_err) => {
+                        warn!("skipping port mapping: {recv_err:?}");
+                        None
+                    }
+                }
+            }));
+            self.outstanding_tasks.port_mapper = true;
+        }
+        port_mapping
+    }
+
+    /// Creates the future which will perform the captive portal check.
+    fn prepare_captive_portal_task(
+        &mut self,
+    ) -> MaybeFuture<Pin<Box<impl Future<Output = Option<bool>>>>> {
+        // If we're doing a full probe, also check for a captive portal. We
+        // delay by a bit to wait for UDP STUN to finish, to avoid the probe if
+        // it's unnecessary.
+        if self.last_report.is_none() {
+            // Even if we're doing a non-incremental update, we may want to try our
+            // preferred relay for captive portal detection.
+            let preferred_relay = self
+                .last_report
+                .as_ref()
+                .and_then(|l| l.preferred_relay.clone());
+
+            let dns_resolver = self.dns_resolver.clone();
+            let dm = self.relay_map.clone();
+            self.outstanding_tasks.captive_task = true;
+            MaybeFuture {
+                inner: Some(Box::pin(async move {
+                    tokio::time::sleep(CAPTIVE_PORTAL_DELAY).await;
+                    debug!("Captive portal check started after {CAPTIVE_PORTAL_DELAY:?}");
+                    let captive_portal_check = tokio::time::timeout(
+                        CAPTIVE_PORTAL_TIMEOUT,
+                        check_captive_portal(&dns_resolver, &dm, preferred_relay)
+                            .instrument(debug_span!("captive-portal")),
+                    );
+                    match captive_portal_check.await {
+                        Ok(Ok(found)) => Some(found),
+                        Ok(Err(err)) => {
+                            let err: Result<reqwest::Error, _> = err.downcast();
+                            match err {
+                                Ok(req_err) if req_err.is_connect() => {
+                                    debug!("check_captive_portal failed: {req_err:#}");
+                                }
+                                Ok(req_err) => warn!("check_captive_portal error: {req_err:#}"),
+                                Err(any_err) => warn!("check_captive_portal error: {any_err:#}"),
+                            }
+                            None
+                        }
+                        Err(_) => {
+                            warn!("check_captive_portal timed out");
+                            None
+                        }
+                    }
+                })),
+            }
+        } else {
+            self.outstanding_tasks.captive_task = false;
+            MaybeFuture::default()
+        }
+    }
+
+    /// Prepares the future which will run all the probes as per generated ProbePlan.
+    ///
+    /// Probes operate like the following:
+    ///
+    /// - A future is created for each probe in all probe sets.
+    /// - All probes in a set are grouped in [`JoinSet`].
+    /// - All those probe sets are grouped in one overall [`JoinSet`].
+    ///   - This future is polled by the main actor loop to make progress.
+    /// - Once a probe future is polled:
+    ///   - Many probes start with a delay, they sleep during this time.
+    ///   - When a probe starts it first asks the reportgen [`Actor`] if it is still useful
+    ///     to run.  If not it aborts the entire probe set.
+    ///   - When a probe finishes, its [`ProbeReport`] is yielded to the reportgen actor.
+    /// - Probes get aborted in several ways:
+    ///   - A running it can fail and abort the entire probe set if it deems the
+    ///     failure permanent.  Probes in a probe set are essentially retries.
+    ///   - Once there are [`ProbeReport`]s from enough nodes, all remaining probes are
+    ///     aborted.  That is, the main actor loop stops polling them.
+    async fn spawn_probes_task(&mut self) -> Result<JoinSet<Result<ProbeReport>>> {
+        let if_state = interfaces::State::new().await;
+        debug!(%if_state, "Local interfaces");
+        let plan = match self.last_report {
+            Some(ref report) => ProbePlan::with_last_report(&self.relay_map, &if_state, report),
+            None => ProbePlan::initial(&self.relay_map, &if_state),
+        };
+        trace!(%plan, "probe plan");
+
+        // The pinger is created here so that any sockets that might be bound for it are
+        // shared between the probes that use it.  It binds sockets lazily, so we can always
+        // create it.
+        let pinger = Pinger::new();
+
+        // A collection of futures running probe sets.
+        let mut probes = JoinSet::default();
+        for probe_set in plan.iter() {
+            let mut set = JoinSet::default();
+            for probe in probe_set {
+                let reportstate = self.addr();
+                let stun_sock4 = self.stun_sock4.clone();
+                let stun_sock6 = self.stun_sock6.clone();
+                let relay_node = probe.node().clone();
+                let probe = probe.clone();
+                let net_report = self.net_report.clone();
+                let pinger = pinger.clone();
+                let dns_resolver = self.dns_resolver.clone();
+
+                set.spawn(
+                    run_probe(
+                        reportstate,
+                        stun_sock4,
+                        stun_sock6,
+                        relay_node,
+                        probe.clone(),
+                        net_report,
+                        pinger,
+                        dns_resolver,
+                    )
+                    .instrument(debug_span!("run_probe", %probe)),
+                );
+            }
+
+            // Add the probe set to all futures of probe sets.  Handle aborting a probe set
+            // if needed, only normal errors means the set continues.
+            probes.spawn(
+                async move {
+                    // Hack because ProbeSet is not it's own type yet.
+                    let mut probe_proto = None;
+                    while let Some(res) = set.join_next().await {
+                        match res {
+                            Ok(Ok(report)) => return Ok(report),
+                            Ok(Err(ProbeError::Error(err, probe))) => {
+                                probe_proto = Some(probe.proto());
+                                warn!(?probe, "probe failed: {:#}", err);
+                                continue;
+                            }
+                            Ok(Err(ProbeError::AbortSet(err, probe))) => {
+                                debug!(?probe, "probe set aborted: {:#}", err);
+                                set.abort_all();
+                                return Err(err);
+                            }
+                            Err(err) => {
+                                warn!("fatal probe set error, aborting: {:#}", err);
+                                continue;
+                            }
+                        }
+                    }
+                    warn!(?probe_proto, "no successful probes in ProbeSet");
+                    Err(anyhow!("All probes in ProbeSet failed"))
+                }
+                .instrument(info_span!("probe")),
+            );
+        }
+        self.outstanding_tasks.probes = true;
+
+        Ok(probes)
+    }
+}
+
+/// Tasks on which the reportgen [`Actor`] is still waiting.
+///
+/// There is no particular progression, e.g. hairpin starts `false`, moves to `true` when a
+/// check is started and then becomes `false` again once it is finished.
+#[derive(Debug, Default)]
+struct OutstandingTasks {
+    probes: bool,
+    port_mapper: bool,
+    captive_task: bool,
+    hairpin: bool,
+}
+
+impl OutstandingTasks {
+    fn all_done(&self) -> bool {
+        !(self.probes || self.port_mapper || self.captive_task || self.hairpin)
+    }
+}
+
+/// The success result of [`run_probe`].
+#[derive(Debug, Clone)]
+struct ProbeReport {
+    /// Whether we can send IPv4 UDP packets.
+    ipv4_can_send: bool,
+    /// Whether we can send IPv6 UDP packets.
+    ipv6_can_send: bool,
+    /// Whether we can send ICMPv4 packets, `None` if not checked.
+    icmpv4: Option<bool>,
+    /// Whether we can send ICMPv6 packets, `None` if not checked.
+    icmpv6: Option<bool>,
+    /// The latency to the relay node.
+    latency: Option<Duration>,
+    /// The probe that generated this report.
+    probe: Probe,
+    /// The discovered public address.
+    addr: Option<SocketAddr>,
+}
+
+impl ProbeReport {
+    fn new(probe: Probe) -> Self {
+        ProbeReport {
+            probe,
+            ipv4_can_send: false,
+            ipv6_can_send: false,
+            icmpv4: None,
+            icmpv6: None,
+            latency: None,
+            addr: None,
+        }
+    }
+}
+
+/// Errors for [`run_probe`].
+///
+/// The main purpose is to signal whether other probes in this probe set should still be
+/// run.  Recall that a probe set is normally a set of identical probes with delays,
+/// effectively creating retries, and the first successful probe of a probe set will cancel
+/// the others in the set.  So this allows an unsuccessful probe to cancel the remainder of
+/// the set or not.
+#[derive(Debug)]
+enum ProbeError {
+    /// Abort the current set.
+    AbortSet(anyhow::Error, Probe),
+    /// Continue the other probes in the set.
+    Error(anyhow::Error, Probe),
+}
+
+/// Executes a particular [`Probe`], including using a delayed start if needed.
+///
+/// If *stun_sock4* and *stun_sock6* are `None` the STUN probes are disabled.
+#[allow(clippy::too_many_arguments)]
+async fn run_probe(
+    reportstate: Addr,
+    stun_sock4: Option<Arc<UdpSocket>>,
+    stun_sock6: Option<Arc<UdpSocket>>,
+    relay_node: Arc<RelayNode>,
+    probe: Probe,
+    net_report: net_report::Addr,
+    pinger: Pinger,
+    dns_resolver: DnsResolver,
+) -> Result<ProbeReport, ProbeError> {
+    if !probe.delay().is_zero() {
+        trace!("delaying probe");
+        tokio::time::sleep(probe.delay()).await;
+    }
+    debug!("starting probe");
+
+    let (would_help_tx, would_help_rx) = oneshot::channel();
+    if let Err(err) = reportstate
+        .send(Message::ProbeWouldHelp(
+            probe.clone(),
+            relay_node.clone(),
+            would_help_tx,
+        ))
+        .await
+    {
+        // this happens on shutdown or if the report is already finished
+        debug!("Failed to check if probe would help: {err:#}");
+        return Err(ProbeError::AbortSet(err.into(), probe.clone()));
+    }
+
+    if !would_help_rx.await.map_err(|_| {
+        ProbeError::AbortSet(
+            anyhow!("ReportCheck actor dropped sender while waiting for ProbeWouldHelp response"),
+            probe.clone(),
+        )
+    })? {
+        return Err(ProbeError::AbortSet(
+            anyhow!("ReportCheck says probe set no longer useful"),
+            probe,
+        ));
+    }
+
+    let relay_addr = get_relay_addr(&dns_resolver, &relay_node, probe.proto())
+        .await
+        .context("no relay node addr")
+        .map_err(|e| ProbeError::AbortSet(e, probe.clone()))?;
+
+    let mut result = ProbeReport::new(probe.clone());
+    match probe {
+        Probe::StunIpv4 { .. } | Probe::StunIpv6 { .. } => {
+            let maybe_sock = if matches!(probe, Probe::StunIpv4 { .. }) {
+                stun_sock4.as_ref()
+            } else {
+                stun_sock6.as_ref()
+            };
+            match maybe_sock {
+                Some(sock) => {
+                    result = run_stun_probe(sock, relay_addr, net_report, probe).await?;
+                }
+                None => {
+                    return Err(ProbeError::AbortSet(
+                        anyhow!("No socket for {}, aborting probeset", probe.proto()),
+                        probe.clone(),
+                    ));
+                }
+            }
+        }
+        Probe::IcmpV4 { .. } | Probe::IcmpV6 { .. } => {
+            result = run_icmp_probe(probe, relay_addr, pinger).await?
+        }
+        Probe::Https { ref node, .. } => {
+            debug!("sending probe HTTPS");
+            match measure_https_latency(&dns_resolver, node, None).await {
+                Ok((latency, ip)) => {
+                    result.latency = Some(latency);
+                    // We set these IPv4 and IPv6 but they're not really used
+                    // and we don't necessarily set them both. If UDP is blocked
+                    // and both IPv4 and IPv6 are available over TCP, it's basically
+                    // random which fields end up getting set here.
+                    // Since they're not needed, that's fine for now.
+                    match ip {
+                        IpAddr::V4(_) => result.ipv4_can_send = true,
+                        IpAddr::V6(_) => result.ipv6_can_send = true,
+                    }
+                }
+                Err(err) => {
+                    warn!("https latency measurement failed: {:?}", err);
+                }
+            }
+        }
+    }
+
+    trace!("probe successful");
+    Ok(result)
+}
+
+/// Run a STUN IPv4 or IPv6 probe.
+async fn run_stun_probe(
+    sock: &Arc<UdpSocket>,
+    relay_addr: SocketAddr,
+    net_report: net_report::Addr,
+    probe: Probe,
+) -> Result<ProbeReport, ProbeError> {
+    match probe.proto() {
+        ProbeProto::StunIpv4 => debug_assert!(relay_addr.is_ipv4()),
+        ProbeProto::StunIpv6 => debug_assert!(relay_addr.is_ipv6()),
+        _ => debug_assert!(false, "wrong probe"),
+    }
+    let txid = stun::TransactionId::default();
+    let req = stun::request(txid);
+
+    // Setup net_report to give us back the incoming STUN response.
+    let (stun_tx, stun_rx) = oneshot::channel();
+    let (inflight_ready_tx, inflight_ready_rx) = oneshot::channel();
+    net_report
+        .send(net_report::Message::InFlightStun(
+            net_report::Inflight {
+                txn: txid,
+                start: Instant::now(),
+                s: stun_tx,
+            },
+            inflight_ready_tx,
+        ))
+        .await
+        .map_err(|e| ProbeError::Error(e.into(), probe.clone()))?;
+    inflight_ready_rx
+        .await
+        .map_err(|e| ProbeError::Error(e.into(), probe.clone()))?;
+
+    // Send the probe.
+    match sock.send_to(&req, relay_addr).await {
+        Ok(n) if n == req.len() => {
+            debug!(%relay_addr, %txid, "sending {} probe", probe.proto());
+            let mut result = ProbeReport::new(probe.clone());
+
+            if matches!(probe, Probe::StunIpv4 { .. }) {
+                result.ipv4_can_send = true;
+                #[cfg(feature = "metrics")]
+                inc!(Metrics, stun_packets_sent_ipv4);
+            } else {
+                result.ipv6_can_send = true;
+                #[cfg(feature = "metrics")]
+                inc!(Metrics, stun_packets_sent_ipv6);
+            }
+            let (delay, addr) = stun_rx
+                .await
+                .map_err(|e| ProbeError::Error(e.into(), probe.clone()))?;
+            result.latency = Some(delay);
+            result.addr = Some(addr);
+            Ok(result)
+        }
+        Ok(n) => {
+            let err = anyhow!("Failed to send full STUN request: {}", probe.proto());
+            error!(%relay_addr, sent_len=n, req_len=req.len(), "{err:#}");
+            Err(ProbeError::Error(err, probe.clone()))
+        }
+        Err(err) => {
+            let kind = err.kind();
+            let err = anyhow::Error::new(err)
+                .context(format!("Failed to send STUN request: {}", probe.proto()));
+
+            // It is entirely normal that we are on a dual-stack machine with no
+            // routed IPv6 network.  So silence that case.
+            // NetworkUnreachable and HostUnreachable are still experimental (io_error_more
+            // #86442) but it is already emitted.  So hack around this.
+            match format!("{kind:?}").as_str() {
+                "NetworkUnreachable" | "HostUnreachable" => {
+                    debug!(%relay_addr, "{err:#}");
+                    Err(ProbeError::AbortSet(err, probe.clone()))
+                }
+                _ => {
+                    // No need to log this, our caller does already log this.
+                    Err(ProbeError::Error(err, probe.clone()))
+                }
+            }
+        }
+    }
+}
+
+/// Reports whether or not we think the system is behind a
+/// captive portal, detected by making a request to a URL that we know should
+/// return a "204 No Content" response and checking if that's what we get.
+///
+/// The boolean return is whether we think we have a captive portal.
+async fn check_captive_portal(
+    dns_resolver: &DnsResolver,
+    dm: &RelayMap,
+    preferred_relay: Option<RelayUrl>,
+) -> Result<bool> {
+    // If we have a preferred relay node and we can use it for non-STUN requests, try that;
+    // otherwise, pick a random one suitable for non-STUN requests.
+    let preferred_relay = preferred_relay.and_then(|url| match dm.get_node(&url) {
+        Some(node) if node.stun_only => Some(url),
+        _ => None,
+    });
+
+    let url = match preferred_relay {
+        Some(url) => url,
+        None => {
+            let urls: Vec<_> = dm
+                .nodes()
+                .filter(|n| !n.stun_only)
+                .map(|n| n.url.clone())
+                .collect();
+            if urls.is_empty() {
+                debug!("No suitable relay node for captive portal check");
+                return Ok(false);
+            }
+
+            let i = (0..urls.len())
+                .choose(&mut rand::thread_rng())
+                .unwrap_or_default();
+            urls[i].clone()
+        }
+    };
+
+    let mut builder = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none());
+    if let Some(Host::Domain(domain)) = url.host() {
+        // Use our own resolver rather than getaddrinfo
+        //
+        // Be careful, a non-zero port will override the port in the URI.
+        //
+        // Ideally we would try to resolve **both** IPv4 and IPv6 rather than purely race
+        // them.  But our resolver doesn't support that yet.
+        let addrs: Vec<_> = dns_resolver
+            .lookup_ipv4_ipv6_staggered(domain)
+            .await?
+            .map(|ipaddr| SocketAddr::new(ipaddr, 0))
+            .collect();
+        builder = builder.resolve_to_addrs(domain, &addrs);
+    }
+    let client = builder.build()?;
+
+    // Note: the set of valid characters in a challenge and the total
+    // length is limited; see is_challenge_char in bin/iroh-relay for more
+    // details.
+
+    let host_name = url.host_str().unwrap_or_default();
+    let challenge = format!("ts_{}", host_name);
+    let portal_url = format!("http://{}/generate_204", host_name);
+    let res = client
+        .request(reqwest::Method::GET, portal_url)
+        .header("X-Tailscale-Challenge", &challenge)
+        .send()
+        .await?;
+
+    let expected_response = format!("response {challenge}");
+    let is_valid_response = res
+        .headers()
+        .get("X-Tailscale-Response")
+        .map(|s| s.to_str().unwrap_or_default())
+        == Some(&expected_response);
+
+    debug!(
+        "check_captive_portal url={} status_code={} valid_response={}",
+        res.url(),
+        res.status(),
+        is_valid_response,
+    );
+    let has_captive = res.status() != 204 || !is_valid_response;
+
+    Ok(has_captive)
+}
+
+/// Returns the IP address to use to communicate to this relay node.
+///
+/// *proto* specifies the protocol of the probe.  Depending on the protocol we may return
+/// different results.  Obviously IPv4 vs IPv6 but a [`RelayNode`] may also have disabled
+/// some protocols.
+async fn get_relay_addr(
+    dns_resolver: &DnsResolver,
+    relay_node: &RelayNode,
+    proto: ProbeProto,
+) -> Result<SocketAddr> {
+    let port = if relay_node.stun_port == 0 {
+        DEFAULT_STUN_PORT
+    } else {
+        relay_node.stun_port
+    };
+
+    if relay_node.stun_only && !matches!(proto, ProbeProto::StunIpv4 | ProbeProto::StunIpv6) {
+        bail!("Relay node not suitable for non-STUN probes");
+    }
+
+    match proto {
+        ProbeProto::StunIpv4 | ProbeProto::IcmpV4 => match relay_node.url.host() {
+            Some(url::Host::Domain(hostname)) => {
+                debug!(?proto, %hostname, "Performing DNS A lookup for relay addr");
+                match dns_resolver.lookup_ipv4_staggered(hostname).await {
+                    Ok(mut addrs) => addrs
+                        .next()
+                        .map(|ip| ip.to_canonical())
+                        .map(|addr| SocketAddr::new(addr, port))
+                        .ok_or(anyhow!("No suitable relay addr found")),
+                    Err(err) => Err(err.context("No suitable relay addr found")),
+                }
+            }
+            Some(url::Host::Ipv4(addr)) => Ok(SocketAddr::new(addr.into(), port)),
+            Some(url::Host::Ipv6(_addr)) => Err(anyhow!("No suitable relay addr found")),
+            None => Err(anyhow!("No valid hostname in RelayUrl")),
+        },
+
+        ProbeProto::StunIpv6 | ProbeProto::IcmpV6 => match relay_node.url.host() {
+            Some(url::Host::Domain(hostname)) => {
+                debug!(?proto, %hostname, "Performing DNS AAAA lookup for relay addr");
+                match dns_resolver.lookup_ipv6_staggered(hostname).await {
+                    Ok(mut addrs) => addrs
+                        .next()
+                        .map(|ip| ip.to_canonical())
+                        .map(|addr| SocketAddr::new(addr, port))
+                        .ok_or(anyhow!("No suitable relay addr found")),
+                    Err(err) => Err(err.context("No suitable relay addr found")),
+                }
+            }
+            Some(url::Host::Ipv4(_addr)) => Err(anyhow!("No suitable relay addr found")),
+            Some(url::Host::Ipv6(addr)) => Ok(SocketAddr::new(addr.into(), port)),
+            None => Err(anyhow!("No valid hostname in RelayUrl")),
+        },
+
+        ProbeProto::Https => Err(anyhow!("Not implemented")),
+    }
+}
+
+/// Runs an ICMP IPv4 or IPv6 probe.
+///
+/// The `pinger` is passed in so the ping sockets are only bound once
+/// for the probe set.
+async fn run_icmp_probe(
+    probe: Probe,
+    relay_addr: SocketAddr,
+    pinger: Pinger,
+) -> Result<ProbeReport, ProbeError> {
+    match probe.proto() {
+        ProbeProto::IcmpV4 => debug_assert!(relay_addr.is_ipv4()),
+        ProbeProto::IcmpV6 => debug_assert!(relay_addr.is_ipv6()),
+        _ => debug_assert!(false, "wrong probe"),
+    }
+    const DATA: &[u8; 15] = b"iroh icmp probe";
+    debug!(dst = %relay_addr, len = DATA.len(), "ICMP Ping started");
+    let latency = pinger
+        .send(relay_addr.ip(), DATA)
+        .await
+        .map_err(|err| match err {
+            PingError::Client(err) => ProbeError::AbortSet(
+                anyhow!("Failed to create pinger ({err:#}), aborting probeset"),
+                probe.clone(),
+            ),
+            PingError::Ping(err) => ProbeError::Error(err.into(), probe.clone()),
+        })?;
+    debug!(dst = %relay_addr, len = DATA.len(), ?latency, "ICMP ping done");
+    let mut report = ProbeReport::new(probe);
+    report.latency = Some(latency);
+    match relay_addr {
+        SocketAddr::V4(_) => {
+            report.ipv4_can_send = true;
+            report.icmpv4 = Some(true);
+        }
+        SocketAddr::V6(_) => {
+            report.ipv6_can_send = true;
+            report.icmpv6 = Some(true);
+        }
+    }
+    Ok(report)
+}
+
+/// Executes an HTTPS probe.
+///
+/// If `certs` is provided they will be added to the trusted root certificates, allowing the
+/// use of self-signed certificates for servers.  Currently this is used for testing.
+#[allow(clippy::unused_async)]
+async fn measure_https_latency(
+    dns_resolver: &DnsResolver,
+    node: &RelayNode,
+    certs: Option<Vec<rustls::pki_types::CertificateDer<'static>>>,
+) -> Result<(Duration, IpAddr)> {
+    let url = node.url.join(RELAY_PROBE_PATH)?;
+
+    // This should also use same connection establishment as relay client itself, which
+    // needs to be more configurable so users can do more crazy things:
+    // https://github.com/n0-computer/iroh/issues/2901
+    let mut builder = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none());
+    if let Some(Host::Domain(domain)) = url.host() {
+        // Use our own resolver rather than getaddrinfo
+        //
+        // Be careful, a non-zero port will override the port in the URI.
+        //
+        // The relay Client uses `.lookup_ipv4_ipv6` to connect, so use the same function
+        // but staggered for reliability.  Ideally this tries to resolve **both** IPv4 and
+        // IPv6 though.  But our resolver does not have a function for that yet.
+        let addrs: Vec<_> = dns_resolver
+            .lookup_ipv4_ipv6_staggered(domain)
+            .await?
+            .map(|ipaddr| SocketAddr::new(ipaddr, 0))
+            .collect();
+        builder = builder.resolve_to_addrs(domain, &addrs);
+    }
+    if let Some(certs) = certs {
+        for cert in certs {
+            let cert = reqwest::Certificate::from_der(&cert)?;
+            builder = builder.add_root_certificate(cert);
+        }
+    }
+    let client = builder.build()?;
+
+    let start = Instant::now();
+    let mut response = client.request(reqwest::Method::GET, url).send().await?;
+    let latency = start.elapsed();
+    if response.status().is_success() {
+        // Drain the response body to be nice to the server, up to a limit.
+        const MAX_BODY_SIZE: usize = 8 << 10; // 8 KiB
+        let mut body_size = 0;
+        while let Some(chunk) = response.chunk().await? {
+            body_size += chunk.len();
+            if body_size >= MAX_BODY_SIZE {
+                break;
+            }
+        }
+
+        // Only `None` if a different hyper HttpConnector in the request.
+        let remote_ip = response
+            .remote_addr()
+            .context("missing HttpInfo from HttpConnector")?
+            .ip();
+        Ok((latency, remote_ip))
+    } else {
+        Err(anyhow!(
+            "Error response from server: '{}'",
+            response.status().canonical_reason().unwrap_or_default()
+        ))
+    }
+}
+
+/// Updates a net_report [`Report`] with a new [`ProbeReport`].
+fn update_report(report: &mut Report, probe_report: ProbeReport) {
+    let relay_node = probe_report.probe.node();
+    if let Some(latency) = probe_report.latency {
+        report
+            .relay_latency
+            .update_relay(relay_node.url.clone(), latency);
+
+        if matches!(
+            probe_report.probe.proto(),
+            ProbeProto::StunIpv4 | ProbeProto::StunIpv6
+        ) {
+            report.udp = true;
+
+            match probe_report.addr {
+                Some(SocketAddr::V4(ipp)) => {
+                    report.ipv4 = true;
+                    report
+                        .relay_v4_latency
+                        .update_relay(relay_node.url.clone(), latency);
+                    if report.global_v4.is_none() {
+                        report.global_v4 = Some(ipp);
+                    } else if report.global_v4 != Some(ipp) {
+                        report.mapping_varies_by_dest_ip = Some(true);
+                    } else if report.mapping_varies_by_dest_ip.is_none() {
+                        report.mapping_varies_by_dest_ip = Some(false);
+                    }
+                }
+                Some(SocketAddr::V6(ipp)) => {
+                    report.ipv6 = true;
+                    report
+                        .relay_v6_latency
+                        .update_relay(relay_node.url.clone(), latency);
+                    if report.global_v6.is_none() {
+                        report.global_v6 = Some(ipp);
+                    } else if report.global_v6 != Some(ipp) {
+                        report.mapping_varies_by_dest_ipv6 = Some(true);
+                        warn!("IPv6 Address detected by STUN varies by destination");
+                    } else if report.mapping_varies_by_dest_ipv6.is_none() {
+                        report.mapping_varies_by_dest_ipv6 = Some(false);
+                    }
+                }
+                None => {
+                    // If we are here we had a relay server latency reported from a STUN probe.
+                    // Thus we must have a reported address.
+                    debug_assert!(probe_report.addr.is_some());
+                }
+            }
+        }
+    }
+    report.ipv4_can_send |= probe_report.ipv4_can_send;
+    report.ipv6_can_send |= probe_report.ipv6_can_send;
+    report.icmpv4 = report
+        .icmpv4
+        .map(|val| val || probe_report.icmpv4.unwrap_or_default())
+        .or(probe_report.icmpv4);
+    report.icmpv6 = report
+        .icmpv6
+        .map(|val| val || probe_report.icmpv6.unwrap_or_default())
+        .or(probe_report.icmpv6);
+}
+
+/// Resolves to pending if the inner is `None`.
+#[derive(Debug)]
+pub(crate) struct MaybeFuture<T> {
+    /// Future to be polled.
+    pub inner: Option<T>,
+}
+
+// NOTE: explicit implementation to bypass derive unnecessary bounds
+impl<T> Default for MaybeFuture<T> {
+    fn default() -> Self {
+        MaybeFuture { inner: None }
+    }
+}
+
+impl<T: Future + Unpin> Future for MaybeFuture<T> {
+    type Output = T::Output;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        match self.inner {
+            Some(ref mut t) => Pin::new(t).poll(cx),
+            None => Poll::Pending,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::{Ipv4Addr, Ipv6Addr};
+
+    use testresult::TestResult;
+
+    use super::{super::test_utils, *};
+
+    #[tokio::test]
+    async fn test_update_report_stun_working() {
+        let _logging = iroh_test::logging::setup();
+        let (_server_a, relay_a) = test_utils::relay().await;
+        let (_server_b, relay_b) = test_utils::relay().await;
+
+        let mut report = Report::default();
+
+        // A STUN IPv4 probe from the the first relay server.
+        let probe_report_a = ProbeReport {
+            ipv4_can_send: true,
+            ipv6_can_send: false,
+            icmpv4: None,
+            icmpv6: None,
+            latency: Some(Duration::from_millis(5)),
+            probe: Probe::StunIpv4 {
+                delay: Duration::ZERO,
+                node: relay_a.clone(),
+            },
+            addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
+        };
+        update_report(&mut report, probe_report_a.clone());
+
+        assert!(report.udp);
+        assert_eq!(
+            report.relay_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(5)
+        );
+        assert_eq!(
+            report.relay_v4_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(5)
+        );
+        assert!(report.ipv4_can_send);
+        assert!(!report.ipv6_can_send);
+
+        // A second STUN IPv4 probe, same external IP detected but slower.
+        let probe_report_b = ProbeReport {
+            latency: Some(Duration::from_millis(8)),
+            probe: Probe::StunIpv4 {
+                delay: Duration::ZERO,
+                node: relay_b.clone(),
+            },
+            ..probe_report_a
+        };
+        update_report(&mut report, probe_report_b);
+
+        assert!(report.udp);
+        assert_eq!(
+            report.relay_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(5)
+        );
+        assert_eq!(
+            report.relay_v4_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(5)
+        );
+        assert!(report.ipv4_can_send);
+        assert!(!report.ipv6_can_send);
+
+        // A STUN IPv6 probe, this one is faster.
+        let probe_report_a_ipv6 = ProbeReport {
+            ipv4_can_send: false,
+            ipv6_can_send: true,
+            icmpv4: None,
+            icmpv6: None,
+            latency: Some(Duration::from_millis(4)),
+            probe: Probe::StunIpv6 {
+                delay: Duration::ZERO,
+                node: relay_a.clone(),
+            },
+            addr: Some((Ipv6Addr::new(2001, 0xdb8, 0, 0, 0, 0, 0, 1), 1234).into()),
+        };
+        update_report(&mut report, probe_report_a_ipv6);
+
+        assert!(report.udp);
+        assert_eq!(
+            report.relay_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(4)
+        );
+        assert_eq!(
+            report.relay_v6_latency.get(&relay_a.url).unwrap(),
+            Duration::from_millis(4)
+        );
+        assert!(report.ipv4_can_send);
+        assert!(report.ipv6_can_send);
+    }
+
+    #[tokio::test]
+    async fn test_update_report_icmp() {
+        let _logging = iroh_test::logging::setup();
+        let (_server_a, relay_a) = test_utils::relay().await;
+        let (_server_b, relay_b) = test_utils::relay().await;
+
+        let mut report = Report::default();
+
+        // An ICMPv4 probe from the EU relay server.
+        let probe_report_eu = ProbeReport {
+            ipv4_can_send: true,
+            ipv6_can_send: false,
+            icmpv4: Some(true),
+            icmpv6: None,
+            latency: Some(Duration::from_millis(5)),
+            probe: Probe::IcmpV4 {
+                delay: Duration::ZERO,
+                node: relay_a.clone(),
+            },
+            addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
+        };
+        update_report(&mut report, probe_report_eu.clone());
+
+        assert!(!report.udp);
+        assert!(report.ipv4_can_send);
+        assert_eq!(report.icmpv4, Some(true));
+
+        // A second ICMPv4 probe which did not work.
+        let probe_report_na = ProbeReport {
+            ipv4_can_send: false,
+            ipv6_can_send: false,
+            icmpv4: Some(false),
+            icmpv6: None,
+            latency: None,
+            probe: Probe::IcmpV4 {
+                delay: Duration::ZERO,
+                node: relay_b.clone(),
+            },
+            addr: None,
+        };
+        update_report(&mut report, probe_report_na);
+
+        assert_eq!(report.icmpv4, Some(true));
+
+        // Behold, a STUN probe arrives!
+        let probe_report_eu_stun = ProbeReport {
+            ipv4_can_send: true,
+            ipv6_can_send: false,
+            icmpv4: None,
+            icmpv6: None,
+            latency: Some(Duration::from_millis(5)),
+            probe: Probe::StunIpv4 {
+                delay: Duration::ZERO,
+                node: relay_a.clone(),
+            },
+            addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
+        };
+        update_report(&mut report, probe_report_eu_stun);
+
+        assert!(report.udp);
+        assert_eq!(report.icmpv4, Some(true));
+    }
+
+    // # ICMP permissions on Linux
+    //
+    // ## Using capabilities: CAP_NET_RAW
+    //
+    // To run ICMP tests on Linux you need CAP_NET_RAW capabilities.  When running tests
+    // this means you first need to build the binary, set the capabilities and finally run
+    // the tests.
+    //
+    // Build the test binary:
+    //
+    //    cargo nextest run -p iroh net_report::reportgen::tests --no-run
+    //
+    // Find out the test binary location:
+    //
+    //    cargo nextest list --message-format json -p iroh net_report::reportgen::tests \
+    //       | jq '."rust-suites"."iroh"."binary-path"' | tr -d \"
+    //
+    // Set the CAP_NET_RAW permission, note that nextest runs each test in a child process
+    // so the capabilities need to be inherited:
+    //
+    //    sudo setcap CAP_NET_RAW=eip target/debug/deps/iroh-abc123
+    //
+    // Finally run the test:
+    //
+    //    cargo nextest run -p iroh net_report::reportgen::tests
+    //
+    // This allows the pinger to create a SOCK_RAW socket for IPPROTO_ICMP.
+    //
+    //
+    // ## Using sysctl
+    //
+    // Now you know the hard way, you can also get this permission a little easier, but
+    // slightly less secure, by allowing any process running with your group ID to create a
+    // SOCK_DGRAM for IPPROTO_ICMP.
+    //
+    // First find out your group ID:
+    //
+    //    id --group
+    //
+    // Then allow this group to send pings.  Note that this is an inclusive range:
+    //
+    //    sudo sysctl net.ipv4.ping_group_range="1234 1234"
+    //
+    // Note that this does not survive a reboot usually, commonly you need to edit
+    // /etc/sysctl.conf or /etc/sysctl.d/* to persist this across reboots.
+    //
+    // TODO: Not sure what about IPv6 pings using sysctl.
+    #[tokio::test]
+    async fn test_icmpk_probe() {
+        let _logging_guard = iroh_test::logging::setup();
+        let pinger = Pinger::new();
+        let (server, node) = test_utils::relay().await;
+        let addr = server.stun_addr().expect("test relay serves stun");
+        let probe = Probe::IcmpV4 {
+            delay: Duration::from_secs(0),
+            node,
+        };
+
+        // A single ICMP packet might get lost.  Try several and take the first.
+        let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
+        let mut tasks = JoinSet::new();
+        for i in 0..8 {
+            let probe = probe.clone();
+            let pinger = pinger.clone();
+            let tx = tx.clone();
+            tasks.spawn(async move {
+                time::sleep(Duration::from_millis(i * 100)).await;
+                let res = run_icmp_probe(probe, addr, pinger).await;
+                tx.send(res).ok();
+            });
+        }
+        let mut last_err = None;
+        while let Some(res) = rx.recv().await {
+            match res {
+                Ok(report) => {
+                    dbg!(&report);
+                    assert_eq!(report.icmpv4, Some(true));
+                    assert!(
+                        report.latency.expect("should have a latency") > Duration::from_secs(0)
+                    );
+                    break;
+                }
+                Err(ProbeError::Error(err, _probe)) => {
+                    last_err = Some(err);
+                }
+                Err(ProbeError::AbortSet(_err, _probe)) => {
+                    // We don't have permission, too bad.
+                    // panic!("no ping permission: {err:#}");
+                    break;
+                }
+            }
+        }
+        if let Some(err) = last_err {
+            panic!("Ping error: {err:#}");
+        }
+    }
+
+    #[tokio::test]
+    async fn test_measure_https_latency() -> TestResult {
+        let _logging_guard = iroh_test::logging::setup();
+        let (server, relay) = test_utils::relay().await;
+        let dns_resolver = crate::dns::tests::resolver();
+        tracing::info!(relay_url = ?relay.url , "RELAY_URL");
+        let (latency, ip) =
+            measure_https_latency(dns_resolver, &relay, server.certificates()).await?;
+
+        assert!(latency > Duration::ZERO);
+
+        let relay_url_ip = relay
+            .url
+            .host_str()
+            .context("host")?
+            .parse::<std::net::IpAddr>()?;
+        assert_eq!(ip, relay_url_ip);
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/reportgen/hairpin.rs.html b/pr/2992/docs/src/iroh_net_report/reportgen/hairpin.rs.html new file mode 100644 index 0000000000..3ebcceb593 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/reportgen/hairpin.rs.html @@ -0,0 +1,607 @@ +hairpin.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+
//! Actor to run hairpinning check.
+//!
+//! This actor works as follows:
+//!
+//! - After starting prepares the haircheck:
+//!   - binds socket
+//!   - sends traffic from it's socket to trick some routers
+//! - When requested performs the hairpin probe.
+//!   - result is sent to net_report actor addr.
+//! - Shuts down
+//!
+//! Note it will only perform a single hairpin check before shutting down.  Any further
+//! requests to it will fail which is intentional.
+
+use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+
+use anyhow::{bail, Context, Result};
+use iroh_relay::protos::stun;
+use netwatch::UdpSocket;
+use tokio::{sync::oneshot, time::Instant};
+use tokio_util::task::AbortOnDropHandle;
+use tracing::{debug, error, info_span, trace, warn, Instrument};
+
+use crate::{self as net_report, defaults::timeouts::HAIRPIN_CHECK_TIMEOUT, reportgen, Inflight};
+
+/// Handle to the hairpin actor.
+///
+/// Dropping it will abort the actor.
+#[derive(Debug)]
+pub(super) struct Client {
+    addr: Option<oneshot::Sender<Message>>,
+    _drop_guard: AbortOnDropHandle<()>,
+}
+
+impl Client {
+    pub(super) fn new(net_report: net_report::Addr, reportgen: reportgen::Addr) -> Self {
+        let (addr, msg_rx) = oneshot::channel();
+
+        let actor = Actor {
+            msg_rx,
+            net_report,
+            reportgen,
+        };
+
+        let task =
+            tokio::spawn(async move { actor.run().await }.instrument(info_span!("hairpin.actor")));
+        Self {
+            addr: Some(addr),
+            _drop_guard: AbortOnDropHandle::new(task),
+        }
+    }
+
+    /// Returns `true` if we have started a hairpin check before.
+    pub(super) fn has_started(&self) -> bool {
+        self.addr.is_none()
+    }
+
+    /// Starts the hairpin check.
+    ///
+    /// *dst* should be our own address as discovered by STUN.  Hairpin detection works by
+    /// sending a new STUN request to our own public address, if we receive this request
+    /// back then hairpinning works, otherwise it does not.
+    ///
+    /// Will do nothing if this actor is already finished or a check has already started.
+    pub(super) fn start_check(&mut self, dst: SocketAddrV4) {
+        if let Some(addr) = self.addr.take() {
+            addr.send(Message::StartCheck(dst)).ok();
+        }
+    }
+}
+
+#[derive(Debug)]
+enum Message {
+    /// Performs the hairpin check.
+    ///
+    /// The STUN request will be sent to the provided [`SocketAddrV4`] which should be our
+    /// own address discovered using STUN.
+    StartCheck(SocketAddrV4),
+}
+
+#[derive(Debug)]
+struct Actor {
+    msg_rx: oneshot::Receiver<Message>,
+    net_report: net_report::Addr,
+    reportgen: reportgen::Addr,
+}
+
+impl Actor {
+    async fn run(self) {
+        match self.run_inner().await {
+            Ok(_) => trace!("hairpin actor finished successfully"),
+            Err(err) => error!("Hairpin actor failed: {err:#}"),
+        }
+    }
+
+    async fn run_inner(self) -> Result<()> {
+        let socket = UdpSocket::bind_v4(0).context("Failed to bind hairpin socket on 0.0.0.0:0")?;
+
+        if let Err(err) = Self::prepare_hairpin(&socket).await {
+            warn!("unable to send hairpin prep: {err:#}");
+            // Continue anyway, most routers are fine.
+        }
+
+        // We only have one message to handle
+        let Ok(Message::StartCheck(dst)) = self.msg_rx.await else {
+            return Ok(());
+        };
+
+        let txn = stun::TransactionId::default();
+        trace!(%txn, "Sending hairpin with transaction ID");
+        let (stun_tx, stun_rx) = oneshot::channel();
+        let inflight = Inflight {
+            txn,
+            start: Instant::now(), // ignored by hairping probe
+            s: stun_tx,
+        };
+        let (msg_response_tx, msg_response_rx) = oneshot::channel();
+        self.net_report
+            .send(net_report::Message::InFlightStun(inflight, msg_response_tx))
+            .await
+            .context("net_report actor gone")?;
+        msg_response_rx.await.context("net_report actor died")?;
+
+        if let Err(err) = socket.send_to(&stun::request(txn), dst.into()).await {
+            warn!(%dst, "failed to send hairpin check");
+            return Err(err.into());
+        }
+
+        let now = Instant::now();
+        let hairpinning_works = match tokio::time::timeout(HAIRPIN_CHECK_TIMEOUT, stun_rx).await {
+            Ok(Ok(_)) => true,
+            Ok(Err(_)) => bail!("net_report actor dropped stun response channel"),
+            Err(_) => false, // Elapsed
+        };
+        debug!(
+            "hairpinning done in {:?}, res: {:?}",
+            now.elapsed(),
+            hairpinning_works
+        );
+
+        self.reportgen
+            .send(super::Message::HairpinResult(hairpinning_works))
+            .await
+            .context("Failed to send hairpin result to reportgen actor")?;
+
+        trace!("reportgen notified");
+
+        Ok(())
+    }
+
+    async fn prepare_hairpin(socket: &UdpSocket) -> Result<()> {
+        // At least the Apple Airport Extreme doesn't allow hairpin
+        // sends from a private socket until it's seen traffic from
+        // that src IP:port to something else out on the internet.
+        //
+        // See https://github.com/tailscale/tailscale/issues/188#issuecomment-600728643
+        //
+        // And it seems that even sending to a likely-filtered RFC 5737
+        // documentation-only IPv4 range is enough to set up the mapping.
+        // So do that for now. In the future we might want to classify networks
+        // that do and don't require this separately. But for now help it.
+        let documentation_ip = SocketAddr::from((Ipv4Addr::new(203, 0, 113, 1), 12345));
+
+        socket
+            .send_to(
+                b"net_report; see https://github.com/tailscale/tailscale/issues/188",
+                documentation_ip,
+            )
+            .await?;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::time::Duration;
+
+    use bytes::BytesMut;
+    use tokio::sync::mpsc;
+    use tracing::info;
+
+    use super::*;
+
+    #[tokio::test]
+    async fn test_hairpin_success() {
+        for i in 0..100 {
+            let now = Instant::now();
+            test_hairpin(true).await;
+            println!("done round {} in {:?}", i + 1, now.elapsed());
+        }
+    }
+
+    #[tokio::test]
+    async fn test_hairpin_failure() {
+        test_hairpin(false).await;
+    }
+
+    async fn test_hairpin(hairpinning_works: bool) {
+        let _guard = iroh_test::logging::setup();
+
+        // Setup fake net_report and reportstate actors, hairpinning interacts with them.
+        let (net_report_tx, mut net_report_rx) = mpsc::channel(32);
+        let net_report_addr = net_report::Addr {
+            sender: net_report_tx,
+        };
+        let (reportstate_tx, mut reportstate_rx) = mpsc::channel(32);
+        let reportstate_addr = reportgen::Addr {
+            sender: reportstate_tx,
+        };
+
+        // Create hairpin actor
+        let mut actor = Client::new(net_report_addr, reportstate_addr);
+
+        // Hairpinning works by asking the hairpin actor to send a STUN request to our
+        // discovered public address.  If the router returns it hairpinning works.  We
+        // emulate this by binding a random socket which we pretend is our publicly
+        // discovered address.  The hairpin actor will send it a request and we return it
+        // via the inflight channel.
+        let public_sock = UdpSocket::bind_local_v4(0).unwrap();
+        let ipp_v4 = match public_sock.local_addr().unwrap() {
+            SocketAddr::V4(ipp) => ipp,
+            SocketAddr::V6(_) => unreachable!(),
+        };
+        actor.start_check(ipp_v4);
+
+        // This bit is our dummy net_report actor: it handles the inflight request and sends
+        // back the STUN request once it arrives.
+        let dummy_net_report = tokio::spawn(
+            async move {
+                let net_report::Message::InFlightStun(inflight, resp_tx) =
+                    net_report_rx.recv().await.unwrap()
+                else {
+                    panic!("Wrong message received");
+                };
+                resp_tx.send(()).unwrap();
+
+                let mut buf = BytesMut::zeroed(64 << 10);
+                let (count, addr) = public_sock.recv_from(&mut buf).await.unwrap();
+                info!(
+                    addr=?public_sock.local_addr().unwrap(),
+                    %count,
+                    "Forwarding payload to hairpin actor",
+                );
+                let payload = buf.split_to(count).freeze();
+                let txn = stun::parse_binding_request(&payload).unwrap();
+                assert_eq!(txn, inflight.txn);
+
+                if hairpinning_works {
+                    // We want hairpinning to work, send back the STUN request.
+                    inflight.s.send((Duration::new(0, 1), addr)).unwrap();
+                } else {
+                    // We want hairpinning to fail, just wait but do not drop the STUN response
+                    // channel because that would make the hairpin actor detect an error.
+                    info!("Received hairpin request, not sending response");
+                    tokio::time::sleep(HAIRPIN_CHECK_TIMEOUT * 8).await;
+                }
+            }
+            .instrument(info_span!("dummy-net_report")),
+        );
+
+        // Next we expect our dummy reportstate to receive the result.
+        match reportstate_rx.recv().await {
+            Some(reportgen::Message::HairpinResult(val)) => assert_eq!(val, hairpinning_works),
+            Some(msg) => panic!("Unexpected reportstate message: {msg:?}"),
+            None => panic!("reportstate mpsc has no senders"),
+        }
+
+        // Cleanup: our dummy net_report actor should finish
+        dummy_net_report
+            .await
+            .expect("error in dummy net_report actor");
+    }
+
+    #[tokio::test]
+    async fn test_client_drop() {
+        let _guard = iroh_test::logging::setup();
+
+        // Setup fake net_report and reportstate actors, hairpinning interacts with them.
+        let (net_report_tx, _net_report_rx) = mpsc::channel(32);
+        let net_report_addr = net_report::Addr {
+            sender: net_report_tx,
+        };
+        let (reportstate_tx, _reportstate_rx) = mpsc::channel(32);
+        let reportstate_addr = reportgen::Addr {
+            sender: reportstate_tx,
+        };
+
+        // Create hairpin actor
+        let mut client = Client::new(net_report_addr, reportstate_addr);
+
+        // Save the addr, drop the client
+        let addr = client.addr.take();
+        drop(client);
+        tokio::task::yield_now().await;
+
+        // Check the actor is gone
+        let ipp_v4 = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 10);
+        match addr.unwrap().send(Message::StartCheck(ipp_v4)) {
+            Err(_) => (),
+            _ => panic!("actor still running"),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_net_report/reportgen/probes.rs.html b/pr/2992/docs/src/iroh_net_report/reportgen/probes.rs.html new file mode 100644 index 0000000000..828fad1d65 --- /dev/null +++ b/pr/2992/docs/src/iroh_net_report/reportgen/probes.rs.html @@ -0,0 +1,1651 @@ +probes.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+
//! The relay probes.
+//!
+//! All the probes try and establish the latency to the relay servers.  Preferably the STUN
+//! probes work and we also learn about our public IP addresses and ports.  But fallback
+//! probes for HTTPS and ICMP exist as well.
+
+use std::{collections::BTreeSet, fmt, sync::Arc};
+
+use anyhow::{ensure, Result};
+use netwatch::interfaces;
+use tokio::time::Duration;
+
+use crate::{RelayMap, RelayNode, RelayUrl, Report};
+
+/// The retransmit interval used when net_report first runs.
+///
+/// We have no past context to work with, and we want answers relatively quickly, so it's
+/// biased slightly more aggressive than [`DEFAULT_ACTIVE_RETRANSMIT_DELAY`]. A few extra
+/// packets at startup is fine.
+const DEFAULT_INITIAL_RETRANSMIT: Duration = Duration::from_millis(100);
+
+/// The retransmit interval used when a previous report exists but is missing latency.
+///
+/// When in an active steady-state, i.e. a previous report exists, we use the latency of the
+/// previous report to determine the retransmit interval.  However when this previous relay
+/// latency is missing this default is used.
+///
+/// This is a somewhat conservative guess because if we have no data, likely the relay node
+/// is very far away and we have no data because we timed out the last time we probed it.
+const DEFAULT_ACTIVE_RETRANSMIT_DELAY: Duration = Duration::from_millis(200);
+
+/// The extra time to add to retransmits if a previous report exists.
+///
+/// When in an active steady-state, i.e. a previous report exists, we add this delay
+/// multiplied with the attempt to probe retries to give later attempts increasingly more
+/// time.
+const ACTIVE_RETRANSMIT_EXTRA_DELAY: Duration = Duration::from_millis(50);
+
+/// The number of fastest relays to periodically re-query during incremental net_report
+/// reports. (During a full report, all relay servers are scanned.)
+const NUM_INCREMENTAL_RELAYS: usize = 3;
+
+/// The protocol used to time a node's latency.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, derive_more::Display)]
+#[repr(u8)]
+pub(super) enum ProbeProto {
+    /// STUN IPv4
+    StunIpv4,
+    /// STUN IPv6
+    StunIpv6,
+    /// HTTPS
+    Https,
+    /// ICMP IPv4
+    IcmpV4,
+    /// ICMP IPv6
+    IcmpV6,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, derive_more::Display)]
+pub(super) enum Probe {
+    #[display("STUN Ipv4 after {delay:?} to {node}")]
+    StunIpv4 {
+        /// When the probe is started, relative to the time that `get_report` is called.
+        /// One probe in each `ProbePlan` should have a delay of 0. Non-zero values
+        /// are for retries on UDP loss or timeout.
+        delay: Duration,
+
+        /// The relay server to send this probe to.
+        node: Arc<RelayNode>,
+    },
+    #[display("STUN Ipv6 after {delay:?} to {node}")]
+    StunIpv6 {
+        delay: Duration,
+        node: Arc<RelayNode>,
+    },
+    #[display("HTTPS after {delay:?} to {node}")]
+    Https {
+        delay: Duration,
+        node: Arc<RelayNode>,
+    },
+    #[display("ICMPv4 after {delay:?} to {node}")]
+    IcmpV4 {
+        delay: Duration,
+        node: Arc<RelayNode>,
+    },
+    #[display("ICMPv6 after {delay:?} to {node}")]
+    IcmpV6 {
+        delay: Duration,
+        node: Arc<RelayNode>,
+    },
+}
+
+impl Probe {
+    pub(super) fn delay(&self) -> Duration {
+        match self {
+            Probe::StunIpv4 { delay, .. }
+            | Probe::StunIpv6 { delay, .. }
+            | Probe::Https { delay, .. }
+            | Probe::IcmpV4 { delay, .. }
+            | Probe::IcmpV6 { delay, .. } => *delay,
+        }
+    }
+
+    pub(super) fn proto(&self) -> ProbeProto {
+        match self {
+            Probe::StunIpv4 { .. } => ProbeProto::StunIpv4,
+            Probe::StunIpv6 { .. } => ProbeProto::StunIpv6,
+            Probe::Https { .. } => ProbeProto::Https,
+            Probe::IcmpV4 { .. } => ProbeProto::IcmpV4,
+            Probe::IcmpV6 { .. } => ProbeProto::IcmpV6,
+        }
+    }
+
+    pub(super) fn node(&self) -> &Arc<RelayNode> {
+        match self {
+            Probe::StunIpv4 { node, .. }
+            | Probe::StunIpv6 { node, .. }
+            | Probe::Https { node, .. }
+            | Probe::IcmpV4 { node, .. }
+            | Probe::IcmpV6 { node, .. } => node,
+        }
+    }
+}
+
+/// A probe set is a sequence of similar [`Probe`]s with delays between them.
+///
+/// The probes are to the same Relayer and of the same [`ProbeProto`] but will have different
+/// delays.  The delays are effectively retries, though they do not wait for the previous
+/// probe to be finished.  The first successful probe will cancel all other probes in the
+/// set.
+///
+/// This is a lot of type-safety by convention.  It would be so much nicer to have this
+/// compile-time checked but that introduces a giant mess of generics and traits and
+/// associated exploding types.
+///
+/// A [`ProbeSet`] implements [`IntoIterator`] similar to how [`Vec`] does.
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub(super) struct ProbeSet {
+    /// The [`ProbeProto`] all the probes in this set have.
+    proto: ProbeProto,
+    /// The probes in the set.
+    probes: Vec<Probe>,
+}
+
+impl ProbeSet {
+    fn new(proto: ProbeProto) -> Self {
+        Self {
+            probes: Vec::new(),
+            proto,
+        }
+    }
+
+    fn push(&mut self, probe: Probe) -> Result<()> {
+        ensure!(probe.proto() == self.proto, "mismatching probe proto");
+        self.probes.push(probe);
+        Ok(())
+    }
+
+    fn is_empty(&self) -> bool {
+        self.probes.is_empty()
+    }
+}
+
+impl<'a> IntoIterator for &'a ProbeSet {
+    type Item = &'a Probe;
+
+    type IntoIter = std::slice::Iter<'a, Probe>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.probes.iter()
+    }
+}
+
+impl fmt::Display for ProbeSet {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        writeln!(f, r#"ProbeSet("{}") {{"#, self.proto)?;
+        for probe in self.probes.iter() {
+            writeln!(f, "        {probe},")?;
+        }
+        writeln!(f, "}}")
+    }
+}
+
+/// A probe plan.
+///
+/// A probe plan contains a number of [`ProbeSet`]s containing probes to be executed.
+/// Generally the first probe of of a set which completes aborts the remaining probes of a
+/// set.  Sometimes a failing probe can also abort the remaining probes of a set.
+///
+/// The [`reportgen`] actor will also abort all the remaining [`ProbeSet`]s once it has
+/// sufficient information for a report.
+///
+/// [`reportgen`]: crate::reportgen
+#[derive(Debug, PartialEq, Eq)]
+pub(super) struct ProbePlan(BTreeSet<ProbeSet>);
+
+impl ProbePlan {
+    /// Creates an initial probe plan.
+    pub(super) fn initial(relay_map: &RelayMap, if_state: &interfaces::State) -> Self {
+        let mut plan = Self(BTreeSet::new());
+
+        // The first time we need add probes after the STUN we record this delay, so that
+        // further relay server can reuse this delay.
+        let mut max_stun_delay: Option<Duration> = None;
+
+        for relay_node in relay_map.nodes() {
+            let mut stun_ipv4_probes = ProbeSet::new(ProbeProto::StunIpv4);
+            let mut stun_ipv6_probes = ProbeSet::new(ProbeProto::StunIpv6);
+
+            for attempt in 0..3 {
+                let delay = DEFAULT_INITIAL_RETRANSMIT * attempt as u32;
+
+                if if_state.have_v4 {
+                    stun_ipv4_probes
+                        .push(Probe::StunIpv4 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("adding StunIpv4 probe to a StunIpv4 probe set");
+                }
+                if if_state.have_v6 {
+                    stun_ipv6_probes
+                        .push(Probe::StunIpv6 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("adding StunIpv6 probe to a StunIpv6 probe set");
+                }
+            }
+            plan.add(stun_ipv4_probes);
+            plan.add(stun_ipv6_probes);
+
+            // The HTTP and ICMP probes only start after the STUN probes have had a chance.
+            let mut https_probes = ProbeSet::new(ProbeProto::Https);
+            let mut icmp_probes_ipv4 = ProbeSet::new(ProbeProto::IcmpV4);
+            let mut icmp_probes_ipv6 = ProbeSet::new(ProbeProto::IcmpV6);
+            for attempt in 0..3 {
+                let start = *max_stun_delay.get_or_insert_with(|| plan.max_delay())
+                    + DEFAULT_INITIAL_RETRANSMIT;
+                let delay = start + DEFAULT_INITIAL_RETRANSMIT * attempt as u32;
+
+                https_probes
+                    .push(Probe::Https {
+                        delay,
+                        node: relay_node.clone(),
+                    })
+                    .expect("adding Https probe to a Https probe set");
+                if if_state.have_v4 {
+                    icmp_probes_ipv4
+                        .push(Probe::IcmpV4 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("adding Icmp probe to an Icmp probe set");
+                }
+                if if_state.have_v6 {
+                    icmp_probes_ipv6
+                        .push(Probe::IcmpV6 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("adding IcmpIpv6 probe to and IcmpIpv6 probe set");
+                }
+            }
+            plan.add(https_probes);
+            plan.add(icmp_probes_ipv4);
+            plan.add(icmp_probes_ipv6);
+        }
+        plan
+    }
+
+    /// Creates a follow up probe plan using a previous net_report report.
+    pub(super) fn with_last_report(
+        relay_map: &RelayMap,
+        if_state: &interfaces::State,
+        last_report: &Report,
+    ) -> Self {
+        if last_report.relay_latency.is_empty() {
+            return Self::initial(relay_map, if_state);
+        }
+        let mut plan = Self(Default::default());
+
+        // The first time we need add probes after the STUN we record this delay, so that
+        // further relay servers can reuse this delay.
+        let mut max_stun_delay: Option<Duration> = None;
+
+        let had_stun_ipv4 = !last_report.relay_v4_latency.is_empty();
+        let had_stun_ipv6 = !last_report.relay_v6_latency.is_empty();
+        let had_both = if_state.have_v6 && had_stun_ipv4 && had_stun_ipv6;
+        let sorted_relays = sort_relays(relay_map, last_report);
+        for (ri, (url, relay_node)) in sorted_relays.into_iter().enumerate() {
+            if ri == NUM_INCREMENTAL_RELAYS {
+                break;
+            }
+            let mut do4 = if_state.have_v4;
+            let mut do6 = if_state.have_v6;
+
+            // By default, each node only gets one STUN packet sent,
+            // except the fastest two from the previous round.
+            let mut attempts = 1;
+            let is_fastest_two = ri < 2;
+
+            if is_fastest_two {
+                attempts = 2;
+            } else if had_both {
+                // For dual stack machines, make the 3rd & slower nodes alternate between
+                // IPv4 and IPv6 for STUN and ICMP probes.
+                if ri % 2 == 0 {
+                    (do4, do6) = (true, false);
+                } else {
+                    (do4, do6) = (false, true);
+                }
+            }
+            if !is_fastest_two && !had_stun_ipv6 {
+                do6 = false;
+            }
+            if Some(url) == last_report.preferred_relay.as_ref() {
+                // But if we already had a relay home, try extra hard to
+                // make sure it's there so we don't flip flop around.
+                attempts = 4;
+            }
+            let retransmit_delay = last_report
+                .relay_latency
+                .get(url)
+                .map(|l| l * 120 / 100) // increases latency by 20%, why?
+                .unwrap_or(DEFAULT_ACTIVE_RETRANSMIT_DELAY);
+
+            let mut stun_ipv4_probes = ProbeSet::new(ProbeProto::StunIpv4);
+            let mut stun_ipv6_probes = ProbeSet::new(ProbeProto::StunIpv6);
+
+            for attempt in 0..attempts {
+                let delay = (retransmit_delay * attempt as u32)
+                    + (ACTIVE_RETRANSMIT_EXTRA_DELAY * attempt as u32);
+                if do4 {
+                    stun_ipv4_probes
+                        .push(Probe::StunIpv4 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("Pushing StunIpv4 Probe to StunIpv4 ProbeSet");
+                }
+                if do6 {
+                    stun_ipv6_probes
+                        .push(Probe::StunIpv6 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("Pushing StunIpv6 Probe to StunIpv6 ProbeSet");
+                }
+            }
+            plan.add(stun_ipv4_probes);
+            plan.add(stun_ipv6_probes);
+
+            // The HTTP and ICMP probes only start after the STUN probes have had a chance.
+            let mut https_probes = ProbeSet::new(ProbeProto::Https);
+            let mut icmp_v4_probes = ProbeSet::new(ProbeProto::IcmpV4);
+            let mut icmp_v6_probes = ProbeSet::new(ProbeProto::IcmpV6);
+            let start = *max_stun_delay.get_or_insert_with(|| plan.max_delay());
+            for attempt in 0..attempts {
+                let delay = start
+                    + (retransmit_delay * attempt as u32)
+                    + (ACTIVE_RETRANSMIT_EXTRA_DELAY * (attempt as u32 + 1));
+                https_probes
+                    .push(Probe::Https {
+                        delay,
+                        node: relay_node.clone(),
+                    })
+                    .expect("Pushing Https Probe to an Https ProbeSet");
+                if do4 {
+                    icmp_v4_probes
+                        .push(Probe::IcmpV4 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("Pushing IcmpV4 Probe to an Icmp ProbeSet");
+                }
+                if do6 {
+                    icmp_v6_probes
+                        .push(Probe::IcmpV6 {
+                            delay,
+                            node: relay_node.clone(),
+                        })
+                        .expect("Pusying IcmpV6 Probe to an IcmpV6 ProbeSet");
+                }
+            }
+            plan.add(https_probes);
+            plan.add(icmp_v4_probes);
+            plan.add(icmp_v6_probes);
+        }
+        plan
+    }
+
+    /// Returns an iterator over the [`ProbeSet`]s in this plan.
+    pub(super) fn iter(&self) -> impl Iterator<Item = &ProbeSet> {
+        self.0.iter()
+    }
+
+    /// Adds a [`ProbeSet`] if it contains probes.
+    fn add(&mut self, set: ProbeSet) {
+        if !set.is_empty() {
+            self.0.insert(set);
+        }
+    }
+
+    /// Returns the delay of the last probe in the probe plan.
+    fn max_delay(&self) -> Duration {
+        self.0
+            .iter()
+            .flatten()
+            .map(|probe| probe.delay())
+            .max()
+            .unwrap_or_default()
+    }
+}
+
+impl fmt::Display for ProbePlan {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        writeln!(f, "ProbePlan {{")?;
+        for probe_set in self.0.iter() {
+            writeln!(f, r#"    ProbeSet("{}") {{"#, probe_set.proto)?;
+            for probe in probe_set.probes.iter() {
+                writeln!(f, "        {probe},")?;
+            }
+            writeln!(f, "    }}")?;
+        }
+        writeln!(f, "}}")
+    }
+}
+
+impl FromIterator<ProbeSet> for ProbePlan {
+    fn from_iter<T: IntoIterator<Item = ProbeSet>>(iter: T) -> Self {
+        Self(iter.into_iter().collect())
+    }
+}
+
+/// Sorts the nodes in the [`RelayMap`] from fastest to slowest.
+///
+/// This uses the latencies from the last report to determine the order. Relay Nodes with no
+/// data are at the end.
+fn sort_relays<'a>(
+    relay_map: &'a RelayMap,
+    last_report: &Report,
+) -> Vec<(&'a RelayUrl, &'a Arc<RelayNode>)> {
+    let mut prev: Vec<_> = relay_map.nodes().collect();
+    prev.sort_by(|a, b| {
+        let latencies_a = last_report.relay_latency.get(&a.url);
+        let latencies_b = last_report.relay_latency.get(&b.url);
+        match (latencies_a, latencies_b) {
+            (Some(_), None) => {
+                // Non-zero sorts before zero.
+                std::cmp::Ordering::Less
+            }
+            (None, Some(_)) => {
+                // Zero can't sort before anything else.
+                std::cmp::Ordering::Greater
+            }
+            (None, None) => {
+                // For both empty latencies sort by relay_id.
+                a.url.cmp(&b.url)
+            }
+            (Some(_), Some(_)) => match latencies_a.cmp(&latencies_b) {
+                std::cmp::Ordering::Equal => a.url.cmp(&b.url),
+                x => x,
+            },
+        }
+    });
+
+    prev.into_iter().map(|n| (&n.url, n)).collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use pretty_assertions::assert_eq;
+
+    use super::*;
+    use crate::{test_utils, RelayLatencies};
+
+    /// Shorthand which declares a new ProbeSet.
+    ///
+    /// `$kind`: The `ProbeProto`.
+    /// `$node`: Expression which will be an `Arc<RelayNode>`.
+    /// `$delays`: A `Vec` of the delays for this probe.
+    macro_rules! probeset {
+        (proto: ProbeProto::$kind:ident, relay: $node:expr, delays: $delays:expr,) => {
+            ProbeSet {
+                proto: ProbeProto::$kind,
+                probes: $delays
+                    .iter()
+                    .map(|delay| Probe::$kind {
+                        delay: *delay,
+                        node: $node,
+                    })
+                    .collect(),
+            }
+        };
+    }
+
+    #[tokio::test]
+    async fn test_initial_probeplan() {
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let relay_node_1 = relay_map.nodes().next().unwrap();
+        let relay_node_2 = relay_map.nodes().nth(1).unwrap();
+        let if_state = interfaces::State::fake();
+        let plan = ProbePlan::initial(&relay_map, &if_state);
+
+        let expected_plan: ProbePlan = [
+            probeset! {
+                proto: ProbeProto::StunIpv4,
+                relay: relay_node_1.clone(),
+                delays: [Duration::ZERO,
+                         Duration::from_millis(100),
+                         Duration::from_millis(200)],
+            },
+            probeset! {
+                proto: ProbeProto::StunIpv6,
+                relay: relay_node_1.clone(),
+                delays: [Duration::ZERO,
+                         Duration::from_millis(100),
+                         Duration::from_millis(200)],
+            },
+            probeset! {
+                proto: ProbeProto::Https,
+                relay: relay_node_1.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+            probeset! {
+                proto: ProbeProto::IcmpV4,
+                relay: relay_node_1.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+            probeset! {
+                proto: ProbeProto::IcmpV6,
+                relay: relay_node_1.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+            probeset! {
+                proto: ProbeProto::StunIpv4,
+                relay: relay_node_2.clone(),
+                delays: [Duration::ZERO,
+                         Duration::from_millis(100),
+                         Duration::from_millis(200)],
+            },
+            probeset! {
+                proto: ProbeProto::StunIpv6,
+                relay: relay_node_2.clone(),
+                delays: [Duration::ZERO,
+                         Duration::from_millis(100),
+                         Duration::from_millis(200)],
+            },
+            probeset! {
+                proto: ProbeProto::Https,
+                relay: relay_node_2.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+            probeset! {
+                proto: ProbeProto::IcmpV4,
+                relay: relay_node_2.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+            probeset! {
+                proto: ProbeProto::IcmpV6,
+                relay: relay_node_2.clone(),
+                delays: [Duration::from_millis(300),
+                         Duration::from_millis(400),
+                         Duration::from_millis(500)],
+            },
+        ]
+        .into_iter()
+        .collect();
+
+        println!("expected:");
+        println!("{expected_plan}");
+        println!("actual:");
+        println!("{plan}");
+        // The readable error:
+        assert_eq!(plan.to_string(), expected_plan.to_string());
+        // Just in case there's a bug in the Display impl:
+        assert_eq!(plan, expected_plan);
+    }
+
+    #[tokio::test]
+    async fn test_plan_with_report() {
+        let _logging = iroh_test::logging::setup();
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let relay_node_1 = relay_map.nodes().next().unwrap().clone();
+        let relay_node_2 = relay_map.nodes().nth(1).unwrap().clone();
+        let if_state = interfaces::State::fake();
+
+        for i in 0..10 {
+            println!("round {}", i);
+            let mut latencies = RelayLatencies::new();
+            latencies.update_relay(relay_node_1.url.clone(), Duration::from_millis(2));
+            latencies.update_relay(relay_node_2.url.clone(), Duration::from_millis(2));
+            let last_report = Report {
+                udp: true,
+                ipv6: true,
+                ipv4: true,
+                ipv6_can_send: true,
+                ipv4_can_send: true,
+                os_has_ipv6: true,
+                icmpv4: None,
+                icmpv6: None,
+                mapping_varies_by_dest_ip: Some(false),
+                mapping_varies_by_dest_ipv6: Some(false),
+                hair_pinning: Some(true),
+                portmap_probe: None,
+                preferred_relay: Some(relay_node_1.url.clone()),
+                relay_latency: latencies.clone(),
+                relay_v4_latency: latencies.clone(),
+                relay_v6_latency: latencies.clone(),
+                global_v4: None,
+                global_v6: None,
+                captive_portal: None,
+            };
+            let plan = ProbePlan::with_last_report(&relay_map, &if_state, &last_report);
+            let expected_plan: ProbePlan = [
+                probeset! {
+                    proto: ProbeProto::StunIpv4,
+                    relay: relay_node_1.clone(),
+                    delays: [Duration::ZERO,
+                             Duration::from_micros(52_400),
+                             Duration::from_micros(104_800),
+                             Duration::from_micros(157_200)],
+                },
+                probeset! {
+                    proto: ProbeProto::StunIpv6,
+                    relay: relay_node_1.clone(),
+                    delays: [Duration::ZERO,
+                             Duration::from_micros(52_400),
+                             Duration::from_micros(104_800),
+                             Duration::from_micros(157_200)],
+                },
+                probeset! {
+                    proto: ProbeProto::Https,
+                    relay: relay_node_1.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600),
+                             Duration::from_micros(312_000),
+                             Duration::from_micros(364_400)],
+                },
+                probeset! {
+                    proto: ProbeProto::IcmpV4,
+                    relay: relay_node_1.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600),
+                             Duration::from_micros(312_000),
+                             Duration::from_micros(364_400)],
+                },
+                probeset! {
+                    proto: ProbeProto::IcmpV6,
+                    relay: relay_node_1.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600),
+                             Duration::from_micros(312_000),
+                             Duration::from_micros(364_400)],
+                },
+                probeset! {
+                    proto: ProbeProto::StunIpv4,
+                    relay: relay_node_2.clone(),
+                    delays: [Duration::ZERO,
+                             Duration::from_micros(52_400)],
+                },
+                probeset! {
+                    proto: ProbeProto::StunIpv6,
+                    relay: relay_node_2.clone(),
+                    delays: [Duration::ZERO,
+                             Duration::from_micros(52_400)],
+                },
+                probeset! {
+                    proto: ProbeProto::Https,
+                    relay: relay_node_2.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600)],
+                },
+                probeset! {
+                    proto: ProbeProto::IcmpV4,
+                    relay: relay_node_2.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600)],
+                },
+                probeset! {
+                    proto: ProbeProto::IcmpV6,
+                    relay: relay_node_2.clone(),
+                    delays: [Duration::from_micros(207_200),
+                             Duration::from_micros(259_600)],
+                },
+            ]
+            .into_iter()
+            .collect();
+
+            println!("{} round", i);
+            println!("expected:");
+            println!("{expected_plan}");
+            println!("actual:");
+            println!("{plan}");
+            // The readable error:
+            assert_eq!(plan.to_string(), expected_plan.to_string(), "{}", i);
+            // Just in case there's a bug in the Display impl:
+            assert_eq!(plan, expected_plan, "{}", i);
+        }
+    }
+
+    fn create_last_report(
+        url_1: &RelayUrl,
+        latency_1: Option<Duration>,
+        url_2: &RelayUrl,
+        latency_2: Option<Duration>,
+    ) -> Report {
+        let mut latencies = RelayLatencies::new();
+        if let Some(latency_1) = latency_1 {
+            latencies.update_relay(url_1.clone(), latency_1);
+        }
+        if let Some(latency_2) = latency_2 {
+            latencies.update_relay(url_2.clone(), latency_2);
+        }
+        Report {
+            udp: true,
+            ipv6: true,
+            ipv4: true,
+            ipv6_can_send: true,
+            ipv4_can_send: true,
+            os_has_ipv6: true,
+            icmpv4: None,
+            icmpv6: None,
+            mapping_varies_by_dest_ip: Some(false),
+            mapping_varies_by_dest_ipv6: Some(false),
+            hair_pinning: Some(true),
+            portmap_probe: None,
+            preferred_relay: Some(url_1.clone()),
+            relay_latency: latencies.clone(),
+            relay_v4_latency: latencies.clone(),
+            relay_v6_latency: latencies.clone(),
+            global_v4: None,
+            global_v6: None,
+            captive_portal: None,
+        }
+    }
+
+    #[tokio::test]
+    async fn test_relay_sort_two_latencies() {
+        let _logging = iroh_test::logging::setup();
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let r1 = relay_map.nodes().next().unwrap();
+        let r2 = relay_map.nodes().nth(1).unwrap();
+        let last_report = create_last_report(
+            &r1.url,
+            Some(Duration::from_millis(1)),
+            &r2.url,
+            Some(Duration::from_millis(2)),
+        );
+        let sorted: Vec<_> = sort_relays(&relay_map, &last_report)
+            .iter()
+            .map(|(url, _reg)| *url)
+            .collect();
+        assert_eq!(sorted, vec![&r1.url, &r2.url]);
+    }
+
+    #[tokio::test]
+    async fn test_relay_sort_equal_latencies() {
+        let _logging = iroh_test::logging::setup();
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let r1 = relay_map.nodes().next().unwrap();
+        let r2 = relay_map.nodes().nth(1).unwrap();
+        let last_report = create_last_report(
+            &r1.url,
+            Some(Duration::from_millis(2)),
+            &r2.url,
+            Some(Duration::from_millis(2)),
+        );
+        let sorted: Vec<_> = sort_relays(&relay_map, &last_report)
+            .iter()
+            .map(|(url, _)| *url)
+            .collect();
+        assert_eq!(sorted, vec![&r1.url, &r2.url]);
+    }
+
+    #[tokio::test]
+    async fn test_relay_sort_missing_latency() {
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let r1 = relay_map.nodes().next().unwrap();
+        let r2 = relay_map.nodes().nth(1).unwrap();
+
+        let last_report =
+            create_last_report(&r1.url, None, &r2.url, Some(Duration::from_millis(2)));
+        let sorted: Vec<_> = sort_relays(&relay_map, &last_report)
+            .iter()
+            .map(|(url, _)| *url)
+            .collect();
+        assert_eq!(sorted, vec![&r2.url, &r1.url]);
+
+        let last_report =
+            create_last_report(&r1.url, Some(Duration::from_millis(2)), &r2.url, None);
+        let sorted: Vec<_> = sort_relays(&relay_map, &last_report)
+            .iter()
+            .map(|(url, _)| *url)
+            .collect();
+        assert_eq!(sorted, vec![&r1.url, &r2.url]);
+    }
+
+    #[tokio::test]
+    async fn test_relay_sort_no_latency() {
+        let _logging = iroh_test::logging::setup();
+        let (_servers, relay_map) = test_utils::relay_map(2).await;
+        let r1 = relay_map.nodes().next().unwrap();
+        let r2 = relay_map.nodes().nth(1).unwrap();
+
+        let last_report = create_last_report(&r1.url, None, &r2.url, None);
+        let sorted: Vec<_> = sort_relays(&relay_map, &last_report)
+            .iter()
+            .map(|(url, _)| *url)
+            .collect();
+        // sorted by relay url only
+        assert_eq!(sorted, vec![&r1.url, &r2.url]);
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/cli.rs.html b/pr/2992/docs/src/iroh_node_util/cli.rs.html new file mode 100644 index 0000000000..ac3e36a84c --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/cli.rs.html @@ -0,0 +1,7 @@ +cli.rs - source
1
+2
+3
+
//! Cli commands.
+pub mod net;
+pub mod node;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/cli/net.rs.html b/pr/2992/docs/src/iroh_node_util/cli/net.rs.html new file mode 100644 index 0000000000..a5ab6dd694 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/cli/net.rs.html @@ -0,0 +1,485 @@ +net.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+
//! Define the net subcommands.
+use std::{net::SocketAddr, time::Duration};
+
+use anyhow::Result;
+use clap::Subcommand;
+use colored::Colorize;
+use comfy_table::{presets::NOTHING, Cell, Table};
+use futures_lite::{Stream, StreamExt};
+use human_time::ToHumanTimeString;
+use iroh::{
+    endpoint::{DirectAddrInfo, RemoteInfo},
+    NodeAddr, NodeId, RelayUrl,
+};
+
+/// Commands to manage the iroh network.
+#[derive(Subcommand, Debug, Clone)]
+#[allow(clippy::large_enum_variant, missing_docs)]
+pub enum NetCommands {
+    /// Get information about the different remote nodes.
+    RemoteList,
+    /// Get information about a particular remote node.
+    Remote { node_id: NodeId },
+    /// Get the node addr of this node.
+    NodeAddr,
+    /// Add this node addr to the known nodes.
+    AddNodeAddr {
+        node_id: NodeId,
+        relay: Option<RelayUrl>,
+        addresses: Vec<SocketAddr>,
+    },
+    /// Get the relay server we are connected to.
+    HomeRelay,
+}
+
+impl NetCommands {
+    /// Runs the net command given the iroh client.
+    pub async fn run(self, client: &crate::rpc::client::net::Client) -> Result<()> {
+        match self {
+            Self::RemoteList => {
+                let connections = client.remote_info_iter().await?;
+                let timestamp = time::OffsetDateTime::now_utc()
+                    .format(&time::format_description::well_known::Rfc2822)
+                    .unwrap_or_else(|_| String::from("failed to get current time"));
+
+                println!(
+                    " {}: {}\n\n{}",
+                    "current time".bold(),
+                    timestamp,
+                    fmt_remote_infos(connections).await
+                );
+            }
+            Self::Remote { node_id } => {
+                let info = client.remote_info(node_id).await?;
+                match info {
+                    Some(info) => println!("{}", fmt_info(info)),
+                    None => println!("Not Found"),
+                }
+            }
+            Self::NodeAddr => {
+                let addr = client.node_addr().await?;
+                println!("Node ID: {}", addr.node_id);
+                let relay = addr
+                    .info
+                    .relay_url
+                    .map(|s| s.to_string())
+                    .unwrap_or_else(|| "Not Available".to_string());
+                println!("Home Relay: {}", relay);
+                println!("Direct Addresses ({}):", addr.info.direct_addresses.len());
+                for da in &addr.info.direct_addresses {
+                    println!(" {}", da);
+                }
+            }
+            Self::AddNodeAddr {
+                node_id,
+                relay,
+                addresses,
+            } => {
+                let mut addr = NodeAddr::new(node_id).with_direct_addresses(addresses);
+                if let Some(relay) = relay {
+                    addr = addr.with_relay_url(relay);
+                }
+                client.add_node_addr(addr).await?;
+            }
+            Self::HomeRelay => {
+                let relay = client.home_relay().await?;
+                let relay = relay
+                    .map(|s| s.to_string())
+                    .unwrap_or_else(|| "Not Available".to_string());
+                println!("Home Relay: {}", relay);
+            }
+        }
+        Ok(())
+    }
+}
+
+/// Formats the remote information into a `Table`.
+async fn fmt_remote_infos(
+    mut infos: impl Stream<Item = Result<RemoteInfo, anyhow::Error>> + Unpin,
+) -> String {
+    let mut table = Table::new();
+    table.load_preset(NOTHING).set_header(
+        ["node id", "relay", "conn type", "latency", "last used"]
+            .into_iter()
+            .map(bold_cell),
+    );
+    while let Some(Ok(info)) = infos.next().await {
+        let node_id: Cell = info.node_id.to_string().into();
+        let relay_url = info
+            .relay_url
+            .map_or(String::new(), |url_info| url_info.relay_url.to_string())
+            .into();
+        let conn_type = info.conn_type.to_string().into();
+        let latency = match info.latency {
+            Some(latency) => latency.to_human_time_string(),
+            None => String::from("unknown"),
+        }
+        .into();
+        let last_used = info
+            .last_used
+            .map(fmt_how_long_ago)
+            .map(Cell::new)
+            .unwrap_or_else(never);
+        table.add_row([node_id, relay_url, conn_type, latency, last_used]);
+    }
+    table.to_string()
+}
+
+/// Formats the remote information into a `String`.
+fn fmt_info(info: RemoteInfo) -> String {
+    let RemoteInfo {
+        node_id,
+        relay_url,
+        addrs,
+        conn_type,
+        latency,
+        last_used,
+    } = info;
+    let timestamp = time::OffsetDateTime::now_utc()
+        .format(&time::format_description::well_known::Rfc2822)
+        .unwrap_or_else(|_| String::from("failed to get current time"));
+    let mut table = Table::new();
+    table.load_preset(NOTHING);
+    table.add_row([bold_cell("current time"), timestamp.into()]);
+    table.add_row([bold_cell("node id"), node_id.to_string().into()]);
+    let relay_url = relay_url
+        .map(|r| r.relay_url.to_string())
+        .unwrap_or_else(|| String::from("unknown"));
+    table.add_row([bold_cell("relay url"), relay_url.into()]);
+    table.add_row([bold_cell("connection type"), conn_type.to_string().into()]);
+    table.add_row([bold_cell("latency"), fmt_latency(latency).into()]);
+    table.add_row([
+        bold_cell("last used"),
+        last_used
+            .map(fmt_how_long_ago)
+            .map(Cell::new)
+            .unwrap_or_else(never),
+    ]);
+    table.add_row([bold_cell("known addresses"), addrs.len().into()]);
+
+    let general_info = table.to_string();
+
+    let addrs_info = fmt_addrs(addrs);
+
+    format!("{general_info}\n\n{addrs_info}")
+}
+
+/// Formats the [`DirectAddrInfo`] into a [`Table`].
+fn direct_addr_row(info: DirectAddrInfo) -> comfy_table::Row {
+    let DirectAddrInfo {
+        addr,
+        latency,
+        last_control,
+        last_payload,
+        last_alive,
+        ..
+    } = info;
+
+    let last_control = match last_control {
+        None => never(),
+        Some((how_long_ago, kind)) => {
+            format!("{kind} ( {} )", fmt_how_long_ago(how_long_ago)).into()
+        }
+    };
+    let last_payload = last_payload
+        .map(fmt_how_long_ago)
+        .map(Cell::new)
+        .unwrap_or_else(never);
+
+    let last_alive = last_alive
+        .map(fmt_how_long_ago)
+        .map(Cell::new)
+        .unwrap_or_else(never);
+
+    [
+        addr.into(),
+        fmt_latency(latency).into(),
+        last_control,
+        last_payload,
+        last_alive,
+    ]
+    .into()
+}
+
+/// Formats a collection o [`DirectAddrInfo`] into a [`Table`].
+fn fmt_addrs(addrs: Vec<DirectAddrInfo>) -> comfy_table::Table {
+    let mut table = Table::new();
+    table.load_preset(NOTHING).set_header(
+        vec!["addr", "latency", "last control", "last data", "last alive"]
+            .into_iter()
+            .map(bold_cell),
+    );
+    table.add_rows(addrs.into_iter().map(direct_addr_row));
+    table
+}
+
+/// Creates a cell with the dimmed text "never".
+fn never() -> Cell {
+    Cell::new("never").add_attribute(comfy_table::Attribute::Dim)
+}
+
+/// Formats a [`Duration`] into a human-readable `String`.
+fn fmt_how_long_ago(duration: Duration) -> String {
+    duration
+        .to_human_time_string()
+        .split_once(',')
+        .map(|(first, _rest)| first)
+        .unwrap_or("-")
+        .to_string()
+}
+
+/// Formats the latency into a human-readable `String`.
+fn fmt_latency(latency: Option<Duration>) -> String {
+    match latency {
+        Some(latency) => latency.to_human_time_string(),
+        None => String::from("unknown"),
+    }
+}
+
+/// Creates a bold cell with the given text.
+fn bold_cell(s: &str) -> Cell {
+    Cell::new(s).add_attribute(comfy_table::Attribute::Bold)
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/cli/node.rs.html b/pr/2992/docs/src/iroh_node_util/cli/node.rs.html new file mode 100644 index 0000000000..18ea1edf81 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/cli/node.rs.html @@ -0,0 +1,111 @@ +node.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+
//! Node commands
+use clap::Subcommand;
+
+use crate::rpc::client::node;
+
+/// Commands to manage the iroh RPC.
+#[derive(Subcommand, Debug, Clone)]
+#[allow(clippy::large_enum_variant)]
+pub enum NodeCommands {
+    /// Get statistics and metrics from the running node.
+    Stats,
+    /// Get status of the running node.
+    Status,
+    /// Shutdown the running node.
+    Shutdown {
+        /// Shutdown mode.
+        ///
+        /// Hard shutdown will immediately terminate the process, soft shutdown will wait
+        /// for all connections to close.
+        #[clap(long, default_value_t = false)]
+        force: bool,
+    },
+}
+
+impl NodeCommands {
+    /// Run the RPC command given the iroh client and the console environment.
+    pub async fn run(self, node: &node::Client) -> anyhow::Result<()> {
+        match self {
+            Self::Stats => {
+                let stats = node.stats().await?;
+                for (name, details) in stats.iter() {
+                    println!(
+                        "{:23} : {:>6}    ({})",
+                        name, details.value, details.description
+                    );
+                }
+                Ok(())
+            }
+            Self::Shutdown { force } => {
+                node.shutdown(force).await?;
+                Ok(())
+            }
+            Self::Status => {
+                let response = node.status().await?;
+                println!("Listening addresses: {:#?}", response.listen_addrs);
+                println!("Node ID: {}", response.addr.node_id);
+                println!("Version: {}", response.version);
+                if let Some(addr) = response.rpc_addr {
+                    println!("RPC Addr: {}", addr);
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/config.rs.html b/pr/2992/docs/src/iroh_node_util/config.rs.html new file mode 100644 index 0000000000..025715d75a --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/config.rs.html @@ -0,0 +1,171 @@ +config.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+
//! Utilities to get default paths for configuration, data, and cache directories.
+use std::{env, path::PathBuf};
+
+use anyhow::{anyhow, Result};
+
+/// Returns the path to the user's config directory for the given binary.
+///
+/// This is determined by the following steps:
+/// - If the environment variable `<BIN>_CONFIG_DIR` is set, return that.
+/// - If the operating environment provides a config directory, return `$CONFIG_DIR/<bin>`.
+/// - Otherwise, return an error.
+///
+/// The default directories are as follows:
+///
+/// | Platform | Value                                 | Example                          |
+/// | -------- | ------------------------------------- | -------------------------------- |
+/// | Linux    | `$XDG_CONFIG_HOME` or `$HOME`/.config/iroh | /home/alice/.config/iroh              |
+/// | macOS    | `$HOME`/Library/Application Support/iroh   | /Users/Alice/Library/Application Support/iroh |
+/// | Windows  | `{FOLDERID_RoamingAppData}`/iroh           | C:\Users\Alice\AppData\Roaming\iroh   |
+pub fn config_root(bin: &'static str) -> Result<PathBuf> {
+    let env_config_dir = format!("{}_CONFIG_DIR", bin.to_uppercase());
+    if let Some(val) = env::var_os(env_config_dir) {
+        return Ok(PathBuf::from(val));
+    }
+    let cfg = dirs_next::config_dir()
+        .ok_or_else(|| anyhow!("operating environment provides no directory for configuration"))?;
+    Ok(cfg.join(bin))
+}
+
+/// Returns the path to the user's data directory for the given binary.
+///
+/// This is determined by the following steps:
+/// - If the environment variable `<BIN>_DATA_DIR` is set, return that.
+/// - If the operating environment provides a data directory, return `$DATA_DIR/<bin>`.
+/// - Otherwise, return an error.
+///
+/// The default directories are as follows:
+///
+/// | Platform | Value                                         | Example                                  |
+/// | -------- | --------------------------------------------- | ---------------------------------------- |
+/// | Linux    | `$XDG_DATA_HOME`/iroh or `$HOME`/.local/share/iroh | /home/alice/.local/share/iroh                 |
+/// | macOS    | `$HOME`/Library/Application Support/iroh      | /Users/Alice/Library/Application Support/iroh |
+/// | Windows  | `{FOLDERID_RoamingAppData}/iroh`              | C:\Users\Alice\AppData\Roaming\iroh           |
+pub fn data_root(bin: &'static str) -> Result<PathBuf> {
+    let env_data_dir = format!("{}_DATA_DIR", bin.to_uppercase());
+    let path = if let Some(val) = env::var_os(env_data_dir) {
+        PathBuf::from(val)
+    } else {
+        let path = dirs_next::data_dir().ok_or_else(|| {
+            anyhow!("operating environment provides no directory for application data")
+        })?;
+        path.join(bin)
+    };
+    let path = if !path.is_absolute() {
+        std::env::current_dir()?.join(path)
+    } else {
+        path
+    };
+    Ok(path)
+}
+
+/// Returns the path to the user's cache directory for the given binary.
+///
+/// This is determined by the following steps:
+/// - If the environment variable `<BIN>_CACHE_DIR` is set, return that.
+/// - If the operating environment provides a cache directory, return `$CACHE_DIR/<bin>`.
+/// - Otherwise, return an error.
+///
+/// The default directories are as follows:
+///
+/// | Platform | Value                                         | Example                                  |
+/// | -------- | --------------------------------------------- | ---------------------------------------- |
+/// | Linux    | `$XDG_CACHE_HOME`/iroh or `$HOME`/.cache/iroh | /home/.cache/iroh                        |
+/// | macOS    | `$HOME`/Library/Caches/iroh                   | /Users/Alice/Library/Caches/iroh         |
+/// | Windows  | `{FOLDERID_LocalAppData}/iroh`                | C:\Users\Alice\AppData\Roaming\iroh      |
+pub fn cache_root(bin: &'static str) -> Result<PathBuf> {
+    let env_cache_dir = format!("{}_CACHE_DIR", bin.to_uppercase());
+    if let Some(val) = env::var_os(env_cache_dir) {
+        return Ok(PathBuf::from(val));
+    }
+    let path = dirs_next::cache_dir().ok_or_else(|| {
+        anyhow!("operating environment provides no directory for application data")
+    })?;
+    Ok(path.join(bin))
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/fs.rs.html b/pr/2992/docs/src/iroh_node_util/fs.rs.html new file mode 100644 index 0000000000..09d19e4a8b --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/fs.rs.html @@ -0,0 +1,91 @@ +fs.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
//! Utilities for filesystem operations.
+
+use std::path::PathBuf;
+
+use anyhow::Context;
+use iroh::key::SecretKey;
+use tokio::io::AsyncWriteExt;
+
+/// Loads a [`SecretKey`] from the provided file, or stores a newly generated one
+/// at the given location.
+pub async fn load_secret_key(key_path: PathBuf) -> anyhow::Result<SecretKey> {
+    if key_path.exists() {
+        let keystr = tokio::fs::read(key_path).await?;
+        let secret_key = SecretKey::try_from_openssh(keystr).context("invalid keyfile")?;
+        Ok(secret_key)
+    } else {
+        let secret_key = SecretKey::generate();
+        let ser_key = secret_key.to_openssh()?;
+
+        // Try to canonicalize if possible
+        let key_path = key_path.canonicalize().unwrap_or(key_path);
+        let key_path_parent = key_path.parent().ok_or_else(|| {
+            anyhow::anyhow!("no parent directory found for '{}'", key_path.display())
+        })?;
+        tokio::fs::create_dir_all(&key_path_parent).await?;
+
+        // write to tempfile
+        let (file, temp_file_path) = tempfile::NamedTempFile::new_in(key_path_parent)
+            .context("unable to create tempfile")?
+            .into_parts();
+        let mut file = tokio::fs::File::from_std(file);
+        file.write_all(ser_key.as_bytes())
+            .await
+            .context("unable to write keyfile")?;
+        file.flush().await?;
+        drop(file);
+
+        // move file
+        tokio::fs::rename(temp_file_path, key_path)
+            .await
+            .context("failed to rename keyfile")?;
+
+        Ok(secret_key)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/lib.rs.html b/pr/2992/docs/src/iroh_node_util/lib.rs.html new file mode 100644 index 0000000000..730cccd5f4 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/lib.rs.html @@ -0,0 +1,119 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+
//! Utilities for building iroh nodes.
+#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
+#![cfg_attr(iroh_docsrs, feature(doc_cfg))]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "cli")))]
+#[cfg(feature = "cli")]
+pub mod cli;
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "config")))]
+#[cfg(feature = "config")]
+pub mod config;
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "logging")))]
+#[cfg(feature = "logging")]
+pub mod logging;
+pub mod rpc;
+
+pub mod fs;
+
+use std::path::PathBuf;
+
+use anyhow::Context;
+use iroh::key::SecretKey;
+use tokio::io::AsyncWriteExt;
+
+/// Loads a [`SecretKey`] from the provided file, or stores a newly generated one
+/// at the given location.
+pub async fn load_secret_key(key_path: PathBuf) -> anyhow::Result<SecretKey> {
+    if key_path.exists() {
+        let keystr = tokio::fs::read(key_path).await?;
+        let secret_key = SecretKey::try_from_openssh(keystr).context("invalid keyfile")?;
+        Ok(secret_key)
+    } else {
+        let secret_key = SecretKey::generate();
+        let ser_key = secret_key.to_openssh()?;
+
+        // Try to canonicalize if possible
+        let key_path = key_path.canonicalize().unwrap_or(key_path);
+        let key_path_parent = key_path.parent().ok_or_else(|| {
+            anyhow::anyhow!("no parent directory found for '{}'", key_path.display())
+        })?;
+        tokio::fs::create_dir_all(&key_path_parent).await?;
+
+        // write to tempfile
+        let (file, temp_file_path) = tempfile::NamedTempFile::new_in(key_path_parent)
+            .context("unable to create tempfile")?
+            .into_parts();
+        let mut file = tokio::fs::File::from_std(file);
+        file.write_all(ser_key.as_bytes())
+            .await
+            .context("unable to write keyfile")?;
+        file.flush().await?;
+        drop(file);
+
+        // move file
+        tokio::fs::rename(temp_file_path, key_path)
+            .await
+            .context("failed to rename keyfile")?;
+
+        Ok(secret_key)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/logging.rs.html b/pr/2992/docs/src/iroh_node_util/logging.rs.html new file mode 100644 index 0000000000..bbec690be9 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/logging.rs.html @@ -0,0 +1,385 @@ +logging.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+
//! Utilities for logging
+use std::{env, path::Path};
+
+use derive_more::FromStr;
+use serde::{Deserialize, Serialize};
+use serde_with::{DeserializeFromStr, SerializeDisplay};
+use tracing_appender::{non_blocking, rolling};
+use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, Layer};
+
+/// `RUST_LOG` statement used by default in file logging.
+// rustyline is annoying
+pub(crate) const DEFAULT_FILE_RUST_LOG: &str = "rustyline=warn,debug";
+
+/// Parse `<bin>_FILE_RUST_LOG` as [`tracing_subscriber::EnvFilter`]. Returns `None` if not
+/// present.
+pub fn env_file_rust_log(bin: &'static str) -> Option<anyhow::Result<EnvFilter>> {
+    let env_file_rust_log = format!("{}_FILE_RUST_LOG", bin.to_uppercase());
+    match env::var(env_file_rust_log) {
+        Ok(s) => Some(crate::logging::EnvFilter::from_str(&s).map_err(Into::into)),
+        Err(e) => match e {
+            env::VarError::NotPresent => None,
+            e @ env::VarError::NotUnicode(_) => Some(Err(e.into())),
+        },
+    }
+}
+
+/// Initialize logging both in the terminal and file based.
+///
+/// The terminal based logging layer will:
+/// - use the default [`fmt::format::Format`].
+/// - log to [`std::io::Stderr`]
+///
+/// The file base logging layer will:
+/// - use the default [`fmt::format::Format`] save for:
+///   - including line numbers.
+///   - not using ansi colors.
+/// - create log files in the [`FileLogging::dir`] directory. If not provided, the `logs` dir
+///   inside the given `logs_root` is used.
+/// - rotate files every [`FileLogging::rotation`].
+/// - keep at most [`FileLogging::max_files`] log files.
+/// - use the filtering defined by [`FileLogging::rust_log`]. When not provided, the default
+///   `DEFAULT_FILE_RUST_LOG` is used.
+/// - create log files with the name `iroh-<ROTATION_BASED_NAME>.log` (ex: iroh-2024-02-02.log)
+pub fn init_terminal_and_file_logging(
+    file_log_config: &FileLogging,
+    logs_root: &Path,
+) -> anyhow::Result<non_blocking::WorkerGuard> {
+    let terminal_layer = fmt::layer()
+        .with_writer(std::io::stderr)
+        .with_filter(tracing_subscriber::EnvFilter::from_default_env());
+    let (file_layer, guard) = {
+        let FileLogging {
+            rust_log,
+            max_files,
+            rotation,
+            dir,
+        } = file_log_config;
+
+        let filter = rust_log.layer();
+
+        let (file_logger, guard) = {
+            let file_appender = if *max_files == 0 || &filter.to_string() == "off" {
+                fmt::writer::OptionalWriter::none()
+            } else {
+                let rotation = match rotation {
+                    Rotation::Hourly => rolling::Rotation::HOURLY,
+                    Rotation::Daily => rolling::Rotation::DAILY,
+                    Rotation::Never => rolling::Rotation::NEVER,
+                };
+
+                // prefer the directory set in the config file over the default
+                let logs_path = dir.clone().unwrap_or_else(|| logs_root.join("logs"));
+
+                let file_appender = rolling::Builder::new()
+                    .rotation(rotation)
+                    .max_log_files(*max_files)
+                    .filename_prefix("iroh")
+                    .filename_suffix("log")
+                    .build(logs_path)?;
+                fmt::writer::OptionalWriter::some(file_appender)
+            };
+            non_blocking(file_appender)
+        };
+
+        let layer = fmt::Layer::new()
+            .with_ansi(false)
+            .with_line_number(true)
+            .with_writer(file_logger)
+            .with_filter(filter);
+        (layer, guard)
+    };
+    tracing_subscriber::registry()
+        .with(file_layer)
+        .with(terminal_layer)
+        .try_init()?;
+    Ok(guard)
+}
+
+/// Initialize logging in the terminal.
+///
+/// This will:
+/// - use the default [`fmt::format::Format`].
+/// - log to [`std::io::Stderr`]
+pub fn init_terminal_logging() -> anyhow::Result<()> {
+    let terminal_layer = fmt::layer()
+        .with_writer(std::io::stderr)
+        .with_filter(tracing_subscriber::EnvFilter::from_default_env());
+    tracing_subscriber::registry()
+        .with(terminal_layer)
+        .try_init()?;
+    Ok(())
+}
+
+/// Configuration for the logfiles.
+// Please note that this is documented in the `iroh.computer` repository under
+// `src/app/docs/reference/config/page.mdx`.  Any changes to this need to be updated there.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(default, deny_unknown_fields)]
+pub struct FileLogging {
+    /// RUST_LOG directive to filter file logs.
+    pub rust_log: EnvFilter,
+    /// Maximum number of files to keep.
+    pub max_files: usize,
+    /// How often should a new log file be produced.
+    pub rotation: Rotation,
+    /// Where to store log files.
+    pub dir: Option<std::path::PathBuf>,
+}
+
+impl Default for FileLogging {
+    fn default() -> Self {
+        Self {
+            rust_log: EnvFilter::default(),
+            max_files: 4,
+            rotation: Rotation::default(),
+            dir: None,
+        }
+    }
+}
+
+/// Wrapper to obtain a [`tracing_subscriber::EnvFilter`] that satisfies required bounds.
+#[derive(
+    Debug, Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr, derive_more::Display,
+)]
+#[display("{_0}")]
+pub struct EnvFilter(String);
+
+impl FromStr for EnvFilter {
+    type Err = <tracing_subscriber::EnvFilter as FromStr>::Err;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        // validate the RUST_LOG statement
+        let _valid_env = tracing_subscriber::EnvFilter::from_str(s)?;
+        Ok(EnvFilter(s.into()))
+    }
+}
+
+impl Default for EnvFilter {
+    fn default() -> Self {
+        Self(DEFAULT_FILE_RUST_LOG.into())
+    }
+}
+
+impl EnvFilter {
+    pub(crate) fn layer(&self) -> tracing_subscriber::EnvFilter {
+        tracing_subscriber::EnvFilter::from_str(&self.0).expect("validated RUST_LOG statement")
+    }
+}
+
+/// How often should a new file be created for file logs.
+///
+/// Akin to [`tracing_appender::rolling::Rotation`].
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Default)]
+#[serde(rename_all = "lowercase")]
+#[allow(missing_docs)]
+pub enum Rotation {
+    #[default]
+    Hourly,
+    Daily,
+    Never,
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// Tests that the default file logging `RUST_LOG` statement produces a valid layer.
+    #[test]
+    fn test_default_file_rust_log() {
+        let _ = EnvFilter::default().layer();
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc.rs.html b/pr/2992/docs/src/iroh_node_util/rpc.rs.html new file mode 100644 index 0000000000..2b181bef3d --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc.rs.html @@ -0,0 +1,9 @@ +rpc.rs - source
1
+2
+3
+4
+
//! RPC client, server and protocol to control iroh endpoints and iroh nodes
+pub mod client;
+pub mod proto;
+pub mod server;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/client.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/client.rs.html new file mode 100644 index 0000000000..12a848302f --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/client.rs.html @@ -0,0 +1,41 @@ +client.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+
//! Client to interact with iroh nodes and endpoints.
+use anyhow::Result;
+use futures_lite::{Stream, StreamExt};
+
+pub mod net;
+pub mod node;
+
+fn flatten<T, E1, E2>(
+    s: impl Stream<Item = Result<Result<T, E1>, E2>>,
+) -> impl Stream<Item = Result<T>>
+where
+    E1: std::error::Error + Send + Sync + 'static,
+    E2: std::error::Error + Send + Sync + 'static,
+{
+    s.map(|res| match res {
+        Ok(Ok(res)) => Ok(res),
+        Ok(Err(err)) => Err(err.into()),
+        Err(err) => Err(err.into()),
+    })
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/client/net.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/client/net.rs.html new file mode 100644 index 0000000000..141ceef451 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/client/net.rs.html @@ -0,0 +1,221 @@ +net.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+
//! API to manage the iroh networking stack.
+//!
+//! The main entry point is the [`Client`].
+//!
+//! The client can be used to get information about the node, such as the
+//! [node id](Client::node_id) or [node address](Client::node_addr).
+//!
+//! It can also be used to provide additional information to the node, e.g.
+//! using the [add_node_addr](Client::add_node_addr) method.
+use std::net::SocketAddr;
+
+use anyhow::Result;
+use futures_lite::{Stream, StreamExt};
+use iroh::{endpoint::RemoteInfo, relay::RelayUrl, NodeAddr, NodeId};
+use quic_rpc::RpcClient;
+use serde::{Deserialize, Serialize};
+
+use super::flatten;
+use crate::rpc::proto::{
+    net::{
+        AddAddrRequest, AddrRequest, IdRequest, RelayRequest, RemoteInfoRequest,
+        RemoteInfoResponse, RemoteInfosIterRequest,
+    },
+    RpcService,
+};
+
+/// Iroh net Client.
+///
+/// Cheaply clonable and threadsafe. Use the iroh `net::Client` to access the
+/// iroh net methods from a different thread, process, or remote machine.
+///
+/// The `node::Client` api allows you to get information *about* the iroh node,
+/// its status, and connection status to other nodes. It also allows you to
+/// provide address information about *other* nodes to your node.
+#[derive(Debug, Clone)]
+#[repr(transparent)]
+pub struct Client {
+    pub(super) rpc: RpcClient<RpcService>,
+}
+
+impl Client {
+    /// Creates a new net client
+    pub fn new(rpc: RpcClient<RpcService>) -> Self {
+        Self { rpc }
+    }
+
+    /// Fetches information about currently known remote nodes.
+    ///
+    /// This streams a *current snapshot*. It does not keep the stream open after finishing
+    /// transferring the snapshot.
+    ///
+    /// See also [`Endpoint::remote_info_iter`](iroh::Endpoint::remote_info_iter).
+    pub async fn remote_info_iter(&self) -> Result<impl Stream<Item = Result<RemoteInfo>>> {
+        let stream = self.rpc.server_streaming(RemoteInfosIterRequest {}).await?;
+        Ok(flatten(stream).map(|res| res.map(|res| res.info)))
+    }
+
+    /// Fetches node information about a remote iroh node identified by its [`NodeId`].
+    ///
+    /// See also [`Endpoint::remote_info`](iroh::Endpoint::remote_info).
+    pub async fn remote_info(&self, node_id: NodeId) -> Result<Option<RemoteInfo>> {
+        let RemoteInfoResponse { info } = self.rpc.rpc(RemoteInfoRequest { node_id }).await??;
+        Ok(info)
+    }
+
+    /// Fetches the node id of this node.
+    ///
+    /// See also [`Endpoint::node_id`](iroh::Endpoint::node_id).
+    pub async fn node_id(&self) -> Result<NodeId> {
+        let id = self.rpc.rpc(IdRequest).await??;
+        Ok(id)
+    }
+
+    /// Fetches the [`NodeAddr`] for this node.
+    ///
+    /// See also [`Endpoint::node_addr`](iroh::Endpoint::node_addr).
+    pub async fn node_addr(&self) -> Result<NodeAddr> {
+        let addr = self.rpc.rpc(AddrRequest).await??;
+        Ok(addr)
+    }
+
+    /// Adds a known node address to this node.
+    ///
+    /// See also [`Endpoint::add_node_addr`](iroh::Endpoint::add_node_addr).
+    pub async fn add_node_addr(&self, addr: NodeAddr) -> Result<()> {
+        self.rpc.rpc(AddAddrRequest { addr }).await??;
+        Ok(())
+    }
+
+    /// Returns the relay server we are connected to.
+    ///
+    /// See also [`Endpoint::home_relay`](iroh::Endpoint::home_relay).
+    pub async fn home_relay(&self) -> Result<Option<RelayUrl>> {
+        let relay = self.rpc.rpc(RelayRequest).await??;
+        Ok(relay)
+    }
+}
+
+/// The response to a version request
+#[derive(Debug, Serialize, Deserialize)]
+pub struct NodeStatus {
+    /// The node id and socket addresses of this node.
+    pub addr: NodeAddr,
+    /// The bound listening addresses of the node
+    pub listen_addrs: Vec<SocketAddr>,
+    /// The version of the node
+    pub version: String,
+    /// RPC address, if currently listening.
+    pub rpc_addr: Option<SocketAddr>,
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/client/node.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/client/node.rs.html new file mode 100644 index 0000000000..c028bd3cd7 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/client/node.rs.html @@ -0,0 +1,91 @@ +node.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
//! Client to interact with an iroh node.
+//!
+//! The main entry point is [`Client`].
+use std::collections::BTreeMap;
+
+use anyhow::Result;
+use quic_rpc::RpcClient;
+
+use super::net::NodeStatus;
+use crate::rpc::proto::{node::*, RpcService};
+
+/// Client to interact with an iroh node.
+#[derive(Debug, Clone)]
+#[repr(transparent)]
+pub struct Client {
+    pub(super) rpc: RpcClient<RpcService>,
+}
+
+impl Client {
+    /// Creates a new node client
+    pub fn new(rpc: RpcClient<RpcService>) -> Self {
+        Self { rpc }
+    }
+
+    /// Shuts down the node.
+    ///
+    /// If `force` is true, the node will be shut down instantly without
+    /// waiting for things to stop gracefully.
+    pub async fn shutdown(&self, force: bool) -> Result<()> {
+        self.rpc.rpc(ShutdownRequest { force }).await?;
+        Ok(())
+    }
+
+    /// Fetches statistics of the running node.
+    pub async fn stats(&self) -> Result<BTreeMap<String, CounterStats>> {
+        let res = self.rpc.rpc(StatsRequest {}).await??;
+        Ok(res.stats)
+    }
+
+    /// Fetches status information about this node.
+    pub async fn status(&self) -> Result<NodeStatus> {
+        let response = self.rpc.rpc(StatusRequest).await??;
+        Ok(response)
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/proto.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/proto.rs.html new file mode 100644 index 0000000000..e30f51f8aa --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/proto.rs.html @@ -0,0 +1,73 @@ +proto.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+
//! RPC protocol definitions for controlling iroh endpoints and iroh nodes
+use nested_enum_utils::enum_conversions;
+use serde::{Deserialize, Serialize};
+
+pub mod net;
+pub mod node;
+
+pub(crate) type RpcError = serde_error::Error;
+pub(crate) type RpcResult<T> = Result<T, RpcError>;
+
+/// Request, either net or node
+#[derive(Debug, Serialize, Deserialize)]
+#[enum_conversions]
+#[allow(missing_docs)]
+pub enum Request {
+    Net(net::Request),
+    Node(node::Request),
+}
+
+/// Response, either net or node
+#[derive(Debug, Serialize, Deserialize)]
+#[enum_conversions]
+#[allow(missing_docs)]
+pub enum Response {
+    Net(net::Response),
+    Node(node::Response),
+}
+
+/// The RPC service
+#[derive(Debug, Clone, Copy)]
+pub struct RpcService {}
+
+impl quic_rpc::Service for RpcService {
+    type Req = Request;
+    type Res = Response;
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/proto/net.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/proto/net.rs.html new file mode 100644 index 0000000000..62e97eb38c --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/proto/net.rs.html @@ -0,0 +1,193 @@ +net.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+
//! RPC calls to control an iroh endpoint.
+#![allow(missing_docs)]
+use iroh::{endpoint::RemoteInfo, key::PublicKey, relay::RelayUrl, NodeAddr, NodeId};
+use nested_enum_utils::enum_conversions;
+use quic_rpc_derive::rpc_requests;
+use serde::{Deserialize, Serialize};
+
+use super::{RpcResult, RpcService};
+
+#[derive(strum::Display, Debug, Serialize, Deserialize)]
+#[enum_conversions(super::Request)]
+#[rpc_requests(RpcService)]
+pub enum Request {
+    #[rpc(response = RpcResult<NodeId>)]
+    Id(IdRequest),
+    #[rpc(response = RpcResult<NodeAddr>)]
+    Addr(AddrRequest),
+    #[rpc(response = RpcResult<()>)]
+    AddAddr(AddAddrRequest),
+    #[rpc(response = RpcResult<Option<RelayUrl>>)]
+    Relay(RelayRequest),
+    #[server_streaming(response = RpcResult<RemoteInfosIterResponse>)]
+    RemoteInfosIter(RemoteInfosIterRequest),
+    #[rpc(response = RpcResult<RemoteInfoResponse>)]
+    RemoteInfo(RemoteInfoRequest),
+    #[server_streaming(response = WatchResponse)]
+    Watch(NodeWatchRequest),
+}
+
+#[allow(missing_docs)]
+#[derive(strum::Display, Debug, Serialize, Deserialize)]
+#[enum_conversions(super::Response)]
+pub enum Response {
+    Id(RpcResult<NodeId>),
+    Addr(RpcResult<NodeAddr>),
+    Relay(RpcResult<Option<RelayUrl>>),
+    RemoteInfosIter(RpcResult<RemoteInfosIterResponse>),
+    RemoteInfo(RpcResult<RemoteInfoResponse>),
+    Watch(WatchResponse),
+    Unit(RpcResult<()>),
+}
+
+/// List network path information about all the remote nodes known by this node.
+///
+/// There may never have been connections to these nodes, and connections may not even be
+/// possible. Nodes can also become known due to discovery mechanisms
+/// or be added manually.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct RemoteInfosIterRequest;
+
+/// A response to a [`Request::RemoteInfosIter`].
+#[derive(Debug, Serialize, Deserialize)]
+pub struct RemoteInfosIterResponse {
+    /// Information about a node.
+    pub info: RemoteInfo,
+}
+
+/// Get information about a specific remote node.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct RemoteInfoRequest {
+    /// The node identifier
+    pub node_id: PublicKey,
+}
+
+/// A response to a [`Request::RemoteInfo`] request
+#[derive(Debug, Serialize, Deserialize)]
+pub struct RemoteInfoResponse {
+    /// Information about a node
+    pub info: Option<RemoteInfo>,
+}
+
+/// A request to get information the identity of the node.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct IdRequest;
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct AddrRequest;
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct AddAddrRequest {
+    pub addr: NodeAddr,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct RelayRequest;
+
+/// A request to watch for the node status
+#[derive(Serialize, Deserialize, Debug)]
+pub struct NodeWatchRequest;
+
+/// The response to a watch request
+#[derive(Serialize, Deserialize, Debug)]
+pub struct WatchResponse {
+    /// The version of the node
+    pub version: String,
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/proto/node.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/proto/node.rs.html new file mode 100644 index 0000000000..9aeb98bd5a --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/proto/node.rs.html @@ -0,0 +1,125 @@ +node.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
//! RPC calls to control a generic node.
+use std::collections::BTreeMap;
+
+use nested_enum_utils::enum_conversions;
+use quic_rpc_derive::rpc_requests;
+use serde::{Deserialize, Serialize};
+
+use super::{RpcResult, RpcService};
+use crate::rpc::client::net::NodeStatus;
+
+#[allow(missing_docs)]
+#[derive(strum::Display, Debug, Serialize, Deserialize)]
+#[enum_conversions(super::Request)]
+#[rpc_requests(RpcService)]
+pub enum Request {
+    #[rpc(response = RpcResult<NodeStatus>)]
+    Status(StatusRequest),
+    #[rpc(response = RpcResult<StatsResponse>)]
+    Stats(StatsRequest),
+    #[rpc(response = ())]
+    Shutdown(ShutdownRequest),
+}
+
+#[allow(missing_docs)]
+#[derive(strum::Display, Debug, Serialize, Deserialize)]
+#[enum_conversions(super::Response)]
+pub enum Response {
+    Status(RpcResult<NodeStatus>),
+    Stats(RpcResult<StatsResponse>),
+    Shutdown(()),
+}
+
+/// A request to shutdown the node
+#[derive(Serialize, Deserialize, Debug)]
+pub struct ShutdownRequest {
+    /// Force shutdown
+    pub force: bool,
+}
+
+/// A request to get information about the status of the node.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct StatusRequest;
+
+/// Get stats for the running Iroh node
+#[derive(Serialize, Deserialize, Debug)]
+pub struct StatsRequest {}
+
+/// Counter stats
+#[derive(Serialize, Deserialize, Debug)]
+pub struct CounterStats {
+    /// The counter value
+    pub value: u64,
+    /// The counter description
+    pub description: String,
+}
+
+/// Response to [`StatsRequest`]
+#[derive(Serialize, Deserialize, Debug)]
+pub struct StatsResponse {
+    /// Map of statistics
+    pub stats: BTreeMap<String, CounterStats>,
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_node_util/rpc/server.rs.html b/pr/2992/docs/src/iroh_node_util/rpc/server.rs.html new file mode 100644 index 0000000000..c4b812ad38 --- /dev/null +++ b/pr/2992/docs/src/iroh_node_util/rpc/server.rs.html @@ -0,0 +1,397 @@ +server.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+
//! Server implementation to handle node and net rpc requests
+use std::{collections::BTreeMap, net::SocketAddr, sync::Arc, time::Duration};
+
+use anyhow::{anyhow, Result};
+use futures_lite::{Stream, StreamExt};
+use iroh::{Endpoint, NodeAddr, NodeId, RelayUrl};
+use quic_rpc::server::{ChannelTypes, RpcChannel, RpcServerError};
+use tracing::{debug, info};
+
+use super::proto::{net, node::CounterStats, Request};
+use crate::rpc::{
+    client::net::NodeStatus,
+    proto::{
+        node::{self, ShutdownRequest, StatsRequest, StatsResponse, StatusRequest},
+        RpcError, RpcResult, RpcService,
+    },
+};
+
+/// Trait that provides fields used by the rpc handler for the net and node requests.
+pub trait AbstractNode: Send + Sync + 'static {
+    /// Get the endpoint of the node
+    fn endpoint(&self) -> &Endpoint;
+
+    /// Shutdown the node, used by the node shutdown rpc call
+    fn shutdown(&self);
+
+    /// Rpc address of the node, used by the node status rpc call
+    fn rpc_addr(&self) -> Option<SocketAddr> {
+        None
+    }
+
+    /// Stats for the node stats rpc call
+    fn stats(&self) -> anyhow::Result<BTreeMap<String, CounterStats>> {
+        anyhow::bail!("metrics are disabled");
+    }
+}
+
+struct Handler(Arc<dyn AbstractNode>);
+
+/// Handle rpc requests for the node and net services
+pub async fn handle_rpc_request<C: ChannelTypes<RpcService>>(
+    node: Arc<dyn AbstractNode>,
+    msg: Request,
+    chan: RpcChannel<RpcService, C>,
+) -> Result<(), RpcServerError<C>> {
+    use Request::*;
+    match msg {
+        Node(msg) => Handler(node).handle_node_request(msg, chan).await,
+        Net(msg) => Handler(node).handle_net_request(msg, chan).await,
+    }
+}
+
+impl Handler {
+    fn endpoint(&self) -> &Endpoint {
+        self.0.endpoint()
+    }
+
+    async fn handle_node_request<C: ChannelTypes<RpcService>>(
+        self,
+        msg: node::Request,
+        chan: RpcChannel<RpcService, C>,
+    ) -> Result<(), RpcServerError<C>> {
+        use node::Request::*;
+        debug!("handling node request: {msg}");
+        match msg {
+            Status(msg) => chan.rpc(msg, self, Self::node_status).await,
+            Shutdown(msg) => chan.rpc(msg, self, Self::node_shutdown).await,
+            Stats(msg) => chan.rpc(msg, self, Self::node_stats).await,
+        }
+    }
+
+    async fn handle_net_request<C: ChannelTypes<RpcService>>(
+        self,
+        msg: net::Request,
+        chan: RpcChannel<RpcService, C>,
+    ) -> Result<(), RpcServerError<C>> {
+        use net::Request::*;
+        debug!("handling net request: {msg}");
+        match msg {
+            Watch(msg) => chan.server_streaming(msg, self, Self::node_watch).await,
+            Id(msg) => chan.rpc(msg, self, Self::node_id).await,
+            Addr(msg) => chan.rpc(msg, self, Self::node_addr).await,
+            Relay(msg) => chan.rpc(msg, self, Self::node_relay).await,
+            RemoteInfosIter(msg) => {
+                chan.server_streaming(msg, self, Self::remote_infos_iter)
+                    .await
+            }
+            RemoteInfo(msg) => chan.rpc(msg, self, Self::remote_info).await,
+            AddAddr(msg) => chan.rpc(msg, self, Self::node_add_addr).await,
+        }
+    }
+
+    #[allow(clippy::unused_async)]
+    async fn node_shutdown(self, request: ShutdownRequest) {
+        if request.force {
+            info!("hard shutdown requested");
+            std::process::exit(0);
+        } else {
+            // trigger a graceful shutdown
+            info!("graceful shutdown requested");
+            self.0.shutdown();
+        }
+    }
+
+    #[allow(clippy::unused_async)]
+    async fn node_stats(self, _req: StatsRequest) -> RpcResult<StatsResponse> {
+        Ok(StatsResponse {
+            stats: self.0.stats().map_err(|e| RpcError::new(&*e))?,
+        })
+    }
+
+    async fn node_status(self, _: StatusRequest) -> RpcResult<NodeStatus> {
+        Ok(NodeStatus {
+            addr: self
+                .endpoint()
+                .node_addr()
+                .await
+                .map_err(|e| RpcError::new(&*e))?,
+            listen_addrs: self.local_endpoint_addresses().await.unwrap_or_default(),
+            version: env!("CARGO_PKG_VERSION").to_string(),
+            rpc_addr: self.0.rpc_addr(),
+        })
+    }
+
+    async fn local_endpoint_addresses(&self) -> Result<Vec<SocketAddr>> {
+        let endpoints = self
+            .endpoint()
+            .direct_addresses()
+            .next()
+            .await
+            .ok_or(anyhow!("no endpoints found"))?;
+        Ok(endpoints.into_iter().map(|x| x.addr).collect())
+    }
+
+    async fn node_addr(self, _: net::AddrRequest) -> RpcResult<NodeAddr> {
+        let addr = self
+            .endpoint()
+            .node_addr()
+            .await
+            .map_err(|e| RpcError::new(&*e))?;
+        Ok(addr)
+    }
+
+    fn remote_infos_iter(
+        self,
+        _: net::RemoteInfosIterRequest,
+    ) -> impl Stream<Item = RpcResult<net::RemoteInfosIterResponse>> + Send + 'static {
+        let mut infos: Vec<_> = self.endpoint().remote_info_iter().collect();
+        infos.sort_by_key(|n| n.node_id.to_string());
+        futures_lite::stream::iter(
+            infos
+                .into_iter()
+                .map(|info| Ok(net::RemoteInfosIterResponse { info })),
+        )
+    }
+
+    #[allow(clippy::unused_async)]
+    async fn node_id(self, _: net::IdRequest) -> RpcResult<NodeId> {
+        Ok(self.endpoint().secret_key().public())
+    }
+
+    // This method is called as an RPC method, which have to be async
+    #[allow(clippy::unused_async)]
+    async fn remote_info(self, req: net::RemoteInfoRequest) -> RpcResult<net::RemoteInfoResponse> {
+        let net::RemoteInfoRequest { node_id } = req;
+        let info = self.endpoint().remote_info(node_id);
+        Ok(net::RemoteInfoResponse { info })
+    }
+
+    // This method is called as an RPC method, which have to be async
+    #[allow(clippy::unused_async)]
+    async fn node_add_addr(self, req: net::AddAddrRequest) -> RpcResult<()> {
+        let net::AddAddrRequest { addr } = req;
+        self.endpoint()
+            .add_node_addr(addr)
+            .map_err(|e| RpcError::new(&*e))?;
+        Ok(())
+    }
+
+    #[allow(clippy::unused_async)]
+    async fn node_relay(self, _: net::RelayRequest) -> RpcResult<Option<RelayUrl>> {
+        Ok(self.endpoint().home_relay())
+    }
+
+    fn node_watch(self, _: net::NodeWatchRequest) -> impl Stream<Item = net::WatchResponse> + Send {
+        futures_lite::stream::unfold((), |()| async move {
+            tokio::time::sleep(HEALTH_POLL_WAIT).await;
+            Some((
+                net::WatchResponse {
+                    version: env!("CARGO_PKG_VERSION").to_string(),
+                },
+                (),
+            ))
+        })
+    }
+}
+
+const HEALTH_POLL_WAIT: Duration = Duration::from_secs(1);
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/client.rs.html b/pr/2992/docs/src/iroh_relay/client.rs.html new file mode 100644 index 0000000000..5a3440d024 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/client.rs.html @@ -0,0 +1,2467 @@ +client.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+
//! Exposes [`Client`], which allows to establish connections to a relay server.
+//!
+//! Based on tailscale/derp/derphttp/derphttp_client.go
+
+use std::{
+    collections::HashMap,
+    future,
+    net::{IpAddr, SocketAddr},
+    sync::Arc,
+    time::Duration,
+};
+
+use base64::{engine::general_purpose::URL_SAFE, Engine as _};
+use bytes::Bytes;
+use conn::{Conn, ConnBuilder, ConnReader, ConnReceiver, ConnWriter, ReceivedMessage};
+use futures_lite::future::Boxed as BoxFuture;
+use futures_util::StreamExt;
+use hickory_resolver::TokioAsyncResolver as DnsResolver;
+use http_body_util::Empty;
+use hyper::{
+    body::Incoming,
+    header::{HOST, UPGRADE},
+    upgrade::Parts,
+    Request,
+};
+use hyper_util::rt::TokioIo;
+use iroh_base::key::{NodeId, PublicKey, SecretKey};
+use rand::Rng;
+use rustls::client::Resumption;
+use streams::{downcast_upgrade, MaybeTlsStream, ProxyStream};
+use tokio::{
+    io::{AsyncRead, AsyncWrite},
+    net::TcpStream,
+    sync::{mpsc, oneshot},
+    task::JoinSet,
+    time::Instant,
+};
+use tokio_util::{
+    codec::{FramedRead, FramedWrite},
+    task::AbortOnDropHandle,
+};
+use tracing::{debug, error, event, info_span, trace, warn, Instrument, Level};
+use url::Url;
+
+use crate::{
+    defaults::timeouts::*,
+    http::{Protocol, RELAY_PATH},
+    protos::relay::DerpCodec,
+    RelayUrl,
+};
+
+pub(crate) mod conn;
+pub(crate) mod streams;
+mod util;
+
+/// Possible connection errors on the [`Client`]
+#[derive(Debug, thiserror::Error)]
+pub enum ClientError {
+    /// The client is closed
+    #[error("client is closed")]
+    Closed,
+    /// There no underlying relay [`super::client::Client`] client exists for this http relay [`Client`]
+    #[error("no relay client")]
+    NoClient,
+    /// There was an error sending a packet
+    #[error("error sending a packet")]
+    Send,
+    /// There was an error receiving a packet
+    #[error("error receiving a packet: {0:?}")]
+    Receive(anyhow::Error),
+    /// There was a connection timeout error
+    #[error("connect timeout")]
+    ConnectTimeout,
+    /// No relay nodes are available
+    #[error("Relay node is not available")]
+    RelayNodeNotAvail,
+    /// No relay nodes are available with that name
+    #[error("no nodes available for {0}")]
+    NoNodeForTarget(String),
+    /// The relay node specified only allows STUN requests
+    #[error("no relay nodes found for {0}, only are stun_only nodes")]
+    StunOnlyNodesFound(String),
+    /// There was an error dialing
+    #[error("dial error")]
+    DialIO(#[from] std::io::Error),
+    /// There was an error from the task doing the dialing
+    #[error("dial error")]
+    DialTask(#[from] tokio::task::JoinError),
+    /// Both IPv4 and IPv6 are disabled for this relay node
+    #[error("both IPv4 and IPv6 are explicitly disabled for this node")]
+    IPDisabled,
+    /// No local addresses exist
+    #[error("no local addr: {0}")]
+    NoLocalAddr(String),
+    /// There was http server [`hyper::Error`]
+    #[error("http connection error")]
+    Hyper(#[from] hyper::Error),
+    /// There was an http error [`http::Error`].
+    #[error("http error")]
+    Http(#[from] http::Error),
+    /// There was an unexpected status code
+    #[error("unexpected status code: expected {0}, got {1}")]
+    UnexpectedStatusCode(hyper::StatusCode, hyper::StatusCode),
+    /// The connection failed to upgrade
+    #[error("failed to upgrade connection: {0}")]
+    Upgrade(String),
+    /// The connection failed to proxy
+    #[error("failed to proxy connection: {0}")]
+    Proxy(String),
+    /// The relay [`super::client::Client`] failed to build
+    #[error("failed to build relay client: {0}")]
+    Build(String),
+    /// The ping request timed out
+    #[error("ping timeout")]
+    PingTimeout,
+    /// The ping request was aborted
+    #[error("ping aborted")]
+    PingAborted,
+    /// This [`Client`] cannot acknowledge pings
+    #[error("cannot acknowledge pings")]
+    CannotAckPings,
+    /// The given [`Url`] is invalid
+    #[error("invalid url: {0}")]
+    InvalidUrl(String),
+    /// There was an error with DNS resolution
+    #[error("dns: {0:?}")]
+    Dns(Option<anyhow::Error>),
+    /// There was a timeout resolving DNS.
+    #[error("dns timeout")]
+    DnsTimeout,
+    /// The inner actor is gone, likely means things are shutdown.
+    #[error("actor gone")]
+    ActorGone,
+    /// An error related to websockets, either errors with parsing ws messages or the handshake
+    #[error("websocket error: {0}")]
+    WebsocketError(#[from] tokio_tungstenite_wasm::Error),
+}
+
+/// An HTTP Relay client.
+///
+/// Cheaply clonable.
+#[derive(Clone, Debug)]
+pub struct Client {
+    inner: mpsc::Sender<ActorMessage>,
+    public_key: PublicKey,
+    #[allow(dead_code)]
+    recv_loop: Arc<AbortOnDropHandle<()>>,
+}
+
+#[derive(Debug)]
+enum ActorMessage {
+    Connect(oneshot::Sender<Result<Conn, ClientError>>),
+    NotePreferred(bool),
+    LocalAddr(oneshot::Sender<Result<Option<SocketAddr>, ClientError>>),
+    Ping(oneshot::Sender<Result<Duration, ClientError>>),
+    Pong([u8; 8], oneshot::Sender<Result<(), ClientError>>),
+    Send(PublicKey, Bytes, oneshot::Sender<Result<(), ClientError>>),
+    Close(oneshot::Sender<Result<(), ClientError>>),
+    CloseForReconnect(oneshot::Sender<Result<(), ClientError>>),
+    IsConnected(oneshot::Sender<Result<bool, ClientError>>),
+}
+
+/// Receiving end of a [`Client`].
+#[derive(Debug)]
+pub struct ClientReceiver {
+    msg_receiver: mpsc::Receiver<Result<ReceivedMessage, ClientError>>,
+}
+
+#[derive(derive_more::Debug)]
+struct Actor {
+    secret_key: SecretKey,
+    can_ack_pings: bool,
+    is_preferred: bool,
+    relay_conn: Option<(Conn, ConnReceiver)>,
+    is_closed: bool,
+    #[debug("address family selector callback")]
+    address_family_selector: Option<Box<dyn Fn() -> BoxFuture<bool> + Send + Sync + 'static>>,
+    url: RelayUrl,
+    protocol: Protocol,
+    #[debug("TlsConnector")]
+    tls_connector: tokio_rustls::TlsConnector,
+    pings: PingTracker,
+    ping_tasks: JoinSet<()>,
+    dns_resolver: DnsResolver,
+    proxy_url: Option<Url>,
+}
+
+#[derive(Default, Debug)]
+struct PingTracker(HashMap<[u8; 8], oneshot::Sender<()>>);
+
+impl PingTracker {
+    /// Note that we have sent a ping, and store the [`oneshot::Sender`] we
+    /// must notify when the pong returns
+    fn register(&mut self) -> ([u8; 8], oneshot::Receiver<()>) {
+        let data = rand::thread_rng().gen::<[u8; 8]>();
+        let (send, recv) = oneshot::channel();
+        self.0.insert(data, send);
+        (data, recv)
+    }
+
+    /// Remove the associated [`oneshot::Sender`] for `data` & return it.
+    ///
+    /// If there is no [`oneshot::Sender`] in the tracker, return `None`.
+    fn unregister(&mut self, data: [u8; 8], why: &'static str) -> Option<oneshot::Sender<()>> {
+        trace!("removing ping {}: {}", hex::encode(data), why);
+        self.0.remove(&data)
+    }
+}
+
+/// Build a Client.
+#[derive(derive_more::Debug)]
+pub struct ClientBuilder {
+    /// Default is false
+    can_ack_pings: bool,
+    /// Default is false
+    is_preferred: bool,
+    /// Default is None
+    #[debug("address family selector callback")]
+    address_family_selector: Option<Box<dyn Fn() -> BoxFuture<bool> + Send + Sync + 'static>>,
+    /// Default is false
+    is_prober: bool,
+    /// Expected PublicKey of the server
+    server_public_key: Option<PublicKey>,
+    /// Server url.
+    url: RelayUrl,
+    /// Relay protocol
+    protocol: Protocol,
+    /// Allow self-signed certificates from relay servers
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    insecure_skip_cert_verify: bool,
+    /// HTTP Proxy
+    proxy_url: Option<Url>,
+}
+
+impl ClientBuilder {
+    /// Create a new [`ClientBuilder`]
+    pub fn new(url: impl Into<RelayUrl>) -> Self {
+        ClientBuilder {
+            can_ack_pings: false,
+            is_preferred: false,
+            address_family_selector: None,
+            is_prober: false,
+            server_public_key: None,
+            url: url.into(),
+            protocol: Protocol::Relay,
+            #[cfg(any(test, feature = "test-utils"))]
+            insecure_skip_cert_verify: false,
+            proxy_url: None,
+        }
+    }
+
+    /// Sets the server url
+    pub fn server_url(mut self, url: impl Into<RelayUrl>) -> Self {
+        self.url = url.into();
+        self
+    }
+
+    /// Sets whether to connect to the relay via websockets or not.
+    /// Set to use non-websocket, normal relaying by default.
+    pub fn protocol(mut self, protocol: Protocol) -> Self {
+        self.protocol = protocol;
+        self
+    }
+
+    /// Returns if we should prefer ipv6
+    /// it replaces the relayhttp.AddressFamilySelector we pass
+    /// It provides the hint as to whether in an IPv4-vs-IPv6 race that
+    /// IPv4 should be held back a bit to give IPv6 a better-than-50/50
+    /// chance of winning. We only return true when we believe IPv6 will
+    /// work anyway, so we don't artificially delay the connection speed.
+    pub fn address_family_selector<S>(mut self, selector: S) -> Self
+    where
+        S: Fn() -> BoxFuture<bool> + Send + Sync + 'static,
+    {
+        self.address_family_selector = Some(Box::new(selector));
+        self
+    }
+
+    /// Enable this [`Client`] to acknowledge pings.
+    pub fn can_ack_pings(mut self, can: bool) -> Self {
+        self.can_ack_pings = can;
+        self
+    }
+
+    /// Indicate this client is the preferred way to communicate
+    /// to the peer with this client's [`PublicKey`]
+    pub fn is_preferred(mut self, is: bool) -> Self {
+        self.is_preferred = is;
+        self
+    }
+
+    /// Indicates this client is a prober
+    pub fn is_prober(mut self, is: bool) -> Self {
+        self.is_prober = is;
+        self
+    }
+
+    /// Skip the verification of the relay server's SSL certificates.
+    ///
+    /// May only be used in tests.
+    #[cfg(any(test, feature = "test-utils"))]
+    #[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+    pub fn insecure_skip_cert_verify(mut self, skip: bool) -> Self {
+        self.insecure_skip_cert_verify = skip;
+        self
+    }
+
+    /// Set an explicit proxy url to proxy all HTTP(S) traffic through.
+    pub fn proxy_url(mut self, url: Url) -> Self {
+        self.proxy_url.replace(url);
+        self
+    }
+
+    /// Build the [`Client`]
+    pub fn build(self, key: SecretKey, dns_resolver: DnsResolver) -> (Client, ClientReceiver) {
+        // TODO: review TLS config
+        let roots = rustls::RootCertStore {
+            roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
+        };
+        let mut config = rustls::client::ClientConfig::builder_with_provider(Arc::new(
+            rustls::crypto::ring::default_provider(),
+        ))
+        .with_safe_default_protocol_versions()
+        .expect("protocols supported by ring")
+        .with_root_certificates(roots)
+        .with_no_client_auth();
+        #[cfg(any(test, feature = "test-utils"))]
+        if self.insecure_skip_cert_verify {
+            warn!("Insecure config: SSL certificates from relay servers will be trusted without verification");
+            config
+                .dangerous()
+                .set_certificate_verifier(Arc::new(NoCertVerifier));
+        }
+
+        config.resumption = Resumption::default();
+
+        let tls_connector: tokio_rustls::TlsConnector = Arc::new(config).into();
+        let public_key = key.public();
+
+        let inner = Actor {
+            secret_key: key,
+            can_ack_pings: self.can_ack_pings,
+            is_preferred: self.is_preferred,
+            relay_conn: None,
+            is_closed: false,
+            address_family_selector: self.address_family_selector,
+            pings: PingTracker::default(),
+            ping_tasks: Default::default(),
+            url: self.url,
+            protocol: self.protocol,
+            tls_connector,
+            dns_resolver,
+            proxy_url: self.proxy_url,
+        };
+
+        let (msg_sender, inbox) = mpsc::channel(64);
+        let (s, r) = mpsc::channel(64);
+        let recv_loop = tokio::task::spawn(
+            async move { inner.run(inbox, s).await }.instrument(info_span!("client")),
+        );
+
+        (
+            Client {
+                public_key,
+                inner: msg_sender,
+                recv_loop: Arc::new(AbortOnDropHandle::new(recv_loop)),
+            },
+            ClientReceiver { msg_receiver: r },
+        )
+    }
+
+    /// The expected [`PublicKey`] of the relay server we are connecting to.
+    pub fn server_public_key(mut self, server_public_key: PublicKey) -> Self {
+        self.server_public_key = Some(server_public_key);
+        self
+    }
+}
+
+#[cfg(test)]
+/// Creates a client config that trusts any servers without verifying their TLS certificate.
+///
+/// Should be used for testing local relay setups only.
+pub(crate) fn make_dangerous_client_config() -> rustls::ClientConfig {
+    warn!(
+        "Insecure config: SSL certificates from relay servers will be trusted without verification"
+    );
+    rustls::client::ClientConfig::builder_with_provider(Arc::new(
+        rustls::crypto::ring::default_provider(),
+    ))
+    .with_protocol_versions(&[&rustls::version::TLS13])
+    .expect("protocols supported by ring")
+    .dangerous()
+    .with_custom_certificate_verifier(Arc::new(NoCertVerifier))
+    .with_no_client_auth()
+}
+
+impl ClientReceiver {
+    /// Reads a message from the server.
+    pub async fn recv(&mut self) -> Option<Result<ReceivedMessage, ClientError>> {
+        self.msg_receiver.recv().await
+    }
+}
+
+impl Client {
+    /// The public key for this client
+    pub fn public_key(&self) -> PublicKey {
+        self.public_key
+    }
+
+    async fn send_actor<F, T>(&self, msg_create: F) -> Result<T, ClientError>
+    where
+        F: FnOnce(oneshot::Sender<Result<T, ClientError>>) -> ActorMessage,
+    {
+        let (s, r) = oneshot::channel();
+        let msg = msg_create(s);
+        match self.inner.send(msg).await {
+            Ok(_) => {
+                let res = r.await.map_err(|_| ClientError::ActorGone)??;
+                Ok(res)
+            }
+            Err(_) => Err(ClientError::ActorGone),
+        }
+    }
+
+    /// Connects to a relay Server and returns the underlying relay connection.
+    ///
+    /// Returns [`ClientError::Closed`] if the [`Client`] is closed.
+    ///
+    /// If there is already an active relay connection, returns the already
+    /// connected [`crate::RelayConn`].
+    pub async fn connect(&self) -> Result<Conn, ClientError> {
+        self.send_actor(ActorMessage::Connect).await
+    }
+
+    /// Let the server know that this client is the preferred client
+    pub async fn note_preferred(&self, is_preferred: bool) {
+        self.inner
+            .send(ActorMessage::NotePreferred(is_preferred))
+            .await
+            .ok();
+    }
+
+    /// Get the local addr of the connection. If there is no current underlying relay connection
+    /// or the [`Client`] is closed, returns `None`.
+    pub async fn local_addr(&self) -> Option<SocketAddr> {
+        self.send_actor(ActorMessage::LocalAddr)
+            .await
+            .ok()
+            .flatten()
+    }
+
+    /// Send a ping to the server. Return once we get an expected pong.
+    ///
+    /// There must be a task polling `recv_detail` to process the `pong` response.
+    pub async fn ping(&self) -> Result<Duration, ClientError> {
+        self.send_actor(ActorMessage::Ping).await
+    }
+
+    /// Send a pong back to the server.
+    ///
+    /// If there is no underlying active relay connection, it creates one before attempting to
+    /// send the pong message.
+    ///
+    /// If there is an error sending pong, it closes the underlying relay connection before
+    /// returning.
+    pub async fn send_pong(&self, data: [u8; 8]) -> Result<(), ClientError> {
+        self.send_actor(|s| ActorMessage::Pong(data, s)).await
+    }
+
+    /// Send a packet to the server.
+    ///
+    /// If there is no underlying active relay connection, it creates one before attempting to
+    /// send the message.
+    ///
+    /// If there is an error sending the packet, it closes the underlying relay connection before
+    /// returning.
+    pub async fn send(&self, dst_key: PublicKey, b: Bytes) -> Result<(), ClientError> {
+        self.send_actor(|s| ActorMessage::Send(dst_key, b, s)).await
+    }
+
+    /// Close the http relay connection.
+    pub async fn close(self) -> Result<(), ClientError> {
+        self.send_actor(ActorMessage::Close).await
+    }
+
+    /// Disconnect the http relay connection.
+    pub async fn close_for_reconnect(&self) -> Result<(), ClientError> {
+        self.send_actor(ActorMessage::CloseForReconnect).await
+    }
+
+    /// Returns `true` if the underlying relay connection is established.
+    pub async fn is_connected(&self) -> Result<bool, ClientError> {
+        self.send_actor(ActorMessage::IsConnected).await
+    }
+}
+
+impl Actor {
+    async fn run(
+        mut self,
+        mut inbox: mpsc::Receiver<ActorMessage>,
+        msg_sender: mpsc::Sender<Result<ReceivedMessage, ClientError>>,
+    ) {
+        // Add an initial connection attempt.
+        if let Err(err) = self.connect("initial connect").await {
+            msg_sender.send(Err(err)).await.ok();
+        }
+
+        loop {
+            tokio::select! {
+                res = self.recv_detail() => {
+                    if let Ok(ReceivedMessage::Pong(ping)) = res {
+                        match self.pings.unregister(ping, "pong") {
+                            Some(chan) => {
+                                if chan.send(()).is_err() {
+                                    warn!("pong received for ping {ping:?}, but the receiving channel was closed");
+                                }
+                            }
+                            None => {
+                                warn!("pong received for ping {ping:?}, but not registered");
+                            }
+                        }
+                        continue;
+                    }
+                    msg_sender.send(res).await.ok();
+                }
+                msg = inbox.recv() => {
+                    let Some(msg) = msg else {
+                        // Shutting down
+                        self.close().await;
+                        break;
+                    };
+
+                    match msg {
+                        ActorMessage::Connect(s) => {
+                            let res = self.connect("actor msg").await.map(|(client, _)| (client));
+                            s.send(res).ok();
+                        },
+                        ActorMessage::NotePreferred(is_preferred) => {
+                            self.note_preferred(is_preferred).await;
+                        },
+                        ActorMessage::LocalAddr(s) => {
+                            let res = self.local_addr();
+                            s.send(Ok(res)).ok();
+                        },
+                        ActorMessage::Ping(s) => {
+                            self.ping(s).await;
+                        },
+                        ActorMessage::Pong(data, s) => {
+                            let res = self.send_pong(data).await;
+                            s.send(res).ok();
+                        },
+                        ActorMessage::Send(key, data, s) => {
+                            let res = self.send(key, data).await;
+                            s.send(res).ok();
+                        },
+                        ActorMessage::Close(s) => {
+                            let res = self.close().await;
+                            s.send(Ok(res)).ok();
+                            // shutting down
+                            break;
+                        },
+                        ActorMessage::CloseForReconnect(s) => {
+                            let res = self.close_for_reconnect().await;
+                            s.send(Ok(res)).ok();
+                        },
+                        ActorMessage::IsConnected(s) => {
+                            let res = self.is_connected();
+                            s.send(Ok(res)).ok();
+                        },
+                    }
+                }
+            }
+        }
+    }
+
+    /// Returns a connection to the relay.
+    ///
+    /// If the client is currently connected, the existing connection is returned; otherwise,
+    /// a new connection is made.
+    ///
+    /// Returns:
+    /// - A clonable connection object which can send DISCO messages to the relay.
+    /// - A reference to a channel receiving DISCO messages from the relay.
+    async fn connect(
+        &mut self,
+        why: &'static str,
+    ) -> Result<(Conn, &'_ mut ConnReceiver), ClientError> {
+        if self.is_closed {
+            return Err(ClientError::Closed);
+        }
+        let url = self.url.clone();
+        async move {
+            if self.relay_conn.is_none() {
+                trace!("no connection, trying to connect");
+                let (conn, receiver) = tokio::time::timeout(CONNECT_TIMEOUT, self.connect_0())
+                    .await
+                    .map_err(|_| ClientError::ConnectTimeout)??;
+
+                self.relay_conn = Some((conn, receiver));
+            } else {
+                trace!("already had connection");
+            }
+            let (conn, receiver) = self
+                .relay_conn
+                .as_mut()
+                .map(|(c, r)| (c.clone(), r))
+                .expect("just checked");
+
+            Ok((conn, receiver))
+        }
+        .instrument(info_span!("connect", %url, %why))
+        .await
+    }
+
+    async fn connect_0(&self) -> Result<(Conn, ConnReceiver), ClientError> {
+        let (reader, writer, local_addr) = match self.protocol {
+            Protocol::Websocket => {
+                let (reader, writer) = self.connect_ws().await?;
+                let local_addr = None;
+                (reader, writer, local_addr)
+            }
+            Protocol::Relay => {
+                let (reader, writer, local_addr) = self.connect_derp().await?;
+                (reader, writer, Some(local_addr))
+            }
+        };
+
+        let (conn, receiver) =
+            ConnBuilder::new(self.secret_key.clone(), local_addr, reader, writer)
+                .build()
+                .await
+                .map_err(|e| ClientError::Build(e.to_string()))?;
+
+        if self.is_preferred && conn.note_preferred(true).await.is_err() {
+            conn.close().await;
+            return Err(ClientError::Send);
+        }
+
+        event!(
+            target: "events.net.relay.connected",
+            Level::DEBUG,
+            home = self.is_preferred,
+            url = %self.url,
+        );
+
+        trace!("connect_0 done");
+        Ok((conn, receiver))
+    }
+
+    async fn connect_ws(&self) -> Result<(ConnReader, ConnWriter), ClientError> {
+        let mut dial_url = (*self.url).clone();
+        dial_url.set_path(RELAY_PATH);
+        // The relay URL is exchanged with the http(s) scheme in tickets and similar.
+        // We need to use the ws:// or wss:// schemes when connecting with websockets, though.
+        dial_url
+            .set_scheme(if self.use_tls() { "wss" } else { "ws" })
+            .map_err(|()| ClientError::InvalidUrl(self.url.to_string()))?;
+
+        debug!(%dial_url, "Dialing relay by websocket");
+
+        let (writer, reader) = tokio_tungstenite_wasm::connect(dial_url).await?.split();
+
+        let reader = ConnReader::Ws(reader);
+        let writer = ConnWriter::Ws(writer);
+
+        Ok((reader, writer))
+    }
+
+    async fn connect_derp(&self) -> Result<(ConnReader, ConnWriter, SocketAddr), ClientError> {
+        let url = self.url.clone();
+        let tcp_stream = self.dial_url().await?;
+
+        let local_addr = tcp_stream
+            .local_addr()
+            .map_err(|e| ClientError::NoLocalAddr(e.to_string()))?;
+
+        debug!(server_addr = ?tcp_stream.peer_addr(), %local_addr, "TCP stream connected");
+
+        let response = if self.use_tls() {
+            debug!("Starting TLS handshake");
+            let hostname = self
+                .tls_servername()
+                .ok_or_else(|| ClientError::InvalidUrl("No tls servername".into()))?;
+            let hostname = hostname.to_owned();
+            let tls_stream = self.tls_connector.connect(hostname, tcp_stream).await?;
+            debug!("tls_connector connect success");
+            Self::start_upgrade(tls_stream, url).await?
+        } else {
+            debug!("Starting handshake");
+            Self::start_upgrade(tcp_stream, url).await?
+        };
+
+        if response.status() != hyper::StatusCode::SWITCHING_PROTOCOLS {
+            error!(
+                "expected status 101 SWITCHING_PROTOCOLS, got: {}",
+                response.status()
+            );
+            return Err(ClientError::UnexpectedStatusCode(
+                hyper::StatusCode::SWITCHING_PROTOCOLS,
+                response.status(),
+            ));
+        }
+
+        debug!("starting upgrade");
+        let upgraded = match hyper::upgrade::on(response).await {
+            Ok(upgraded) => upgraded,
+            Err(err) => {
+                warn!("upgrade failed: {:#}", err);
+                return Err(ClientError::Hyper(err));
+            }
+        };
+
+        debug!("connection upgraded");
+        let (reader, writer) =
+            downcast_upgrade(upgraded).map_err(|e| ClientError::Upgrade(e.to_string()))?;
+
+        let reader = ConnReader::Derp(FramedRead::new(reader, DerpCodec));
+        let writer = ConnWriter::Derp(FramedWrite::new(writer, DerpCodec));
+
+        Ok((reader, writer, local_addr))
+    }
+
+    /// Sends the HTTP upgrade request to the relay server.
+    async fn start_upgrade<T>(
+        io: T,
+        relay_url: RelayUrl,
+    ) -> Result<hyper::Response<Incoming>, ClientError>
+    where
+        T: AsyncRead + AsyncWrite + Send + Unpin + 'static,
+    {
+        let host_header_value = host_header_value(relay_url)?;
+
+        let io = hyper_util::rt::TokioIo::new(io);
+        let (mut request_sender, connection) = hyper::client::conn::http1::Builder::new()
+            .handshake(io)
+            .await?;
+        tokio::spawn(
+            // This task drives the HTTP exchange, completes once connection is upgraded.
+            async move {
+                debug!("HTTP upgrade driver started");
+                if let Err(err) = connection.with_upgrades().await {
+                    error!("HTTP upgrade error: {err:#}");
+                }
+                debug!("HTTP upgrade driver finished");
+            }
+            .instrument(info_span!("http-driver")),
+        );
+        debug!("Sending upgrade request");
+        let req = Request::builder()
+            .uri(RELAY_PATH)
+            .header(UPGRADE, Protocol::Relay.upgrade_header())
+            // https://datatracker.ietf.org/doc/html/rfc2616#section-14.23
+            // > A client MUST include a Host header field in all HTTP/1.1 request messages.
+            // This header value helps reverse proxies identify how to forward requests.
+            .header(HOST, host_header_value)
+            .body(http_body_util::Empty::<hyper::body::Bytes>::new())?;
+        request_sender.send_request(req).await.map_err(From::from)
+    }
+
+    async fn note_preferred(&mut self, is_preferred: bool) {
+        let old = &mut self.is_preferred;
+        if *old == is_preferred {
+            return;
+        }
+        *old = is_preferred;
+
+        // only send the preference if we already have a connection
+        let res = {
+            if let Some((ref conn, _)) = self.relay_conn {
+                conn.note_preferred(is_preferred).await
+            } else {
+                return;
+            }
+        };
+        // need to do this outside the above closure because they rely on the same lock
+        // if there was an error sending, close the underlying relay connection
+        if res.is_err() {
+            self.close_for_reconnect().await;
+        }
+    }
+
+    fn local_addr(&self) -> Option<SocketAddr> {
+        if self.is_closed {
+            return None;
+        }
+        if let Some((ref conn, _)) = self.relay_conn {
+            conn.local_addr()
+        } else {
+            None
+        }
+    }
+
+    async fn ping(&mut self, s: oneshot::Sender<Result<Duration, ClientError>>) {
+        let connect_res = self.connect("ping").await.map(|(c, _)| c);
+        let (ping, recv) = self.pings.register();
+        trace!("ping: {}", hex::encode(ping));
+
+        self.ping_tasks.spawn(async move {
+            let res = match connect_res {
+                Ok(conn) => {
+                    let start = Instant::now();
+                    if let Err(err) = conn.send_ping(ping).await {
+                        warn!("failed to send ping: {:?}", err);
+                        Err(ClientError::Send)
+                    } else {
+                        match tokio::time::timeout(PING_TIMEOUT, recv).await {
+                            Ok(Ok(())) => Ok(start.elapsed()),
+                            Err(_) => Err(ClientError::PingTimeout),
+                            Ok(Err(_)) => Err(ClientError::PingAborted),
+                        }
+                    }
+                }
+                Err(err) => Err(err),
+            };
+            s.send(res).ok();
+        });
+    }
+
+    async fn send(&mut self, remote_node: NodeId, payload: Bytes) -> Result<(), ClientError> {
+        trace!(remote_node = %remote_node.fmt_short(), len = payload.len(), "send");
+        let (conn, _) = self.connect("send").await?;
+        if conn.send(remote_node, payload).await.is_err() {
+            self.close_for_reconnect().await;
+            return Err(ClientError::Send);
+        }
+        Ok(())
+    }
+
+    async fn send_pong(&mut self, data: [u8; 8]) -> Result<(), ClientError> {
+        debug!("send_pong");
+        if self.can_ack_pings {
+            let (conn, _) = self.connect("send_pong").await?;
+            if conn.send_pong(data).await.is_err() {
+                self.close_for_reconnect().await;
+                return Err(ClientError::Send);
+            }
+            Ok(())
+        } else {
+            Err(ClientError::CannotAckPings)
+        }
+    }
+
+    async fn close(mut self) {
+        if !self.is_closed {
+            self.is_closed = true;
+            self.close_for_reconnect().await;
+        }
+    }
+
+    fn is_connected(&self) -> bool {
+        if self.is_closed {
+            return false;
+        }
+        self.relay_conn.is_some()
+    }
+
+    fn tls_servername(&self) -> Option<rustls::pki_types::ServerName> {
+        self.url
+            .host_str()
+            .and_then(|s| rustls::pki_types::ServerName::try_from(s).ok())
+    }
+
+    fn use_tls(&self) -> bool {
+        // only disable tls if we are explicitly dialing a http url
+        #[allow(clippy::match_like_matches_macro)]
+        match self.url.scheme() {
+            "http" => false,
+            "ws" => false,
+            _ => true,
+        }
+    }
+
+    async fn dial_url(&self) -> Result<ProxyStream, ClientError> {
+        if let Some(ref proxy) = self.proxy_url {
+            let stream = self.dial_url_proxy(proxy.clone()).await?;
+            Ok(ProxyStream::Proxied(stream))
+        } else {
+            let stream = self.dial_url_direct().await?;
+            Ok(ProxyStream::Raw(stream))
+        }
+    }
+
+    async fn dial_url_direct(&self) -> Result<TcpStream, ClientError> {
+        debug!(%self.url, "dial url");
+        let prefer_ipv6 = self.prefer_ipv6().await;
+        let dst_ip = self
+            .dns_resolver
+            .resolve_host(&self.url, prefer_ipv6)
+            .await?;
+
+        let port = url_port(&self.url)
+            .ok_or_else(|| ClientError::InvalidUrl("missing url port".into()))?;
+        let addr = SocketAddr::new(dst_ip, port);
+
+        debug!("connecting to {}", addr);
+        let tcp_stream =
+            tokio::time::timeout(
+                DIAL_NODE_TIMEOUT,
+                async move { TcpStream::connect(addr).await },
+            )
+            .await
+            .map_err(|_| ClientError::ConnectTimeout)?
+            .map_err(ClientError::DialIO)?;
+
+        tcp_stream.set_nodelay(true)?;
+
+        Ok(tcp_stream)
+    }
+
+    async fn dial_url_proxy(
+        &self,
+        proxy_url: Url,
+    ) -> Result<util::Chain<std::io::Cursor<Bytes>, MaybeTlsStream>, ClientError> {
+        debug!(%self.url, %proxy_url, "dial url via proxy");
+
+        // Resolve proxy DNS
+        let prefer_ipv6 = self.prefer_ipv6().await;
+        let proxy_ip = self
+            .dns_resolver
+            .resolve_host(&proxy_url, prefer_ipv6)
+            .await?;
+
+        let proxy_port = url_port(&proxy_url)
+            .ok_or_else(|| ClientError::Proxy("missing proxy url port".into()))?;
+        let proxy_addr = SocketAddr::new(proxy_ip, proxy_port);
+
+        debug!(%proxy_addr, "connecting to proxy");
+
+        let tcp_stream = tokio::time::timeout(DIAL_NODE_TIMEOUT, async move {
+            TcpStream::connect(proxy_addr).await
+        })
+        .await
+        .map_err(|_| ClientError::ConnectTimeout)?
+        .map_err(ClientError::DialIO)?;
+
+        tcp_stream.set_nodelay(true)?;
+
+        // Setup TLS if necessary
+        let io = if proxy_url.scheme() == "http" {
+            MaybeTlsStream::Raw(tcp_stream)
+        } else {
+            let hostname = proxy_url
+                .host_str()
+                .and_then(|s| rustls::pki_types::ServerName::try_from(s.to_string()).ok())
+                .ok_or_else(|| ClientError::InvalidUrl("No tls servername for proxy url".into()))?;
+            let tls_stream = self.tls_connector.connect(hostname, tcp_stream).await?;
+            MaybeTlsStream::Tls(tls_stream)
+        };
+        let io = TokioIo::new(io);
+
+        let target_host = self
+            .url
+            .host_str()
+            .ok_or_else(|| ClientError::Proxy("missing proxy host".into()))?;
+
+        let port =
+            url_port(&self.url).ok_or_else(|| ClientError::Proxy("invalid target port".into()))?;
+
+        // Establish Proxy Tunnel
+        let mut req_builder = Request::builder()
+            .uri(format!("{}:{}", target_host, port))
+            .method("CONNECT")
+            .header("Host", target_host)
+            .header("Proxy-Connection", "Keep-Alive");
+        if !proxy_url.username().is_empty() {
+            // Passthrough authorization
+            // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization
+            debug!(
+                "setting proxy-authorization: username={}",
+                proxy_url.username()
+            );
+            let to_encode = format!(
+                "{}:{}",
+                proxy_url.username(),
+                proxy_url.password().unwrap_or_default()
+            );
+            let encoded = URL_SAFE.encode(to_encode);
+            req_builder = req_builder.header("Proxy-Authorization", format!("Basic {}", encoded));
+        }
+        let req = req_builder.body(Empty::<Bytes>::new())?;
+
+        debug!("Sending proxy request: {:?}", req);
+
+        let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;
+        tokio::task::spawn(async move {
+            if let Err(err) = conn.with_upgrades().await {
+                error!("Proxy connection failed: {:?}", err);
+            }
+        });
+
+        let res = sender.send_request(req).await?;
+        if !res.status().is_success() {
+            return Err(ClientError::Proxy(format!(
+                "failed to connect to proxy: {}",
+                res.status(),
+            )));
+        }
+
+        let upgraded = hyper::upgrade::on(res).await?;
+        let Ok(Parts { io, read_buf, .. }) = upgraded.downcast::<TokioIo<MaybeTlsStream>>() else {
+            return Err(ClientError::Proxy("invalid upgrade".to_string()));
+        };
+
+        let res = util::chain(std::io::Cursor::new(read_buf), io.into_inner());
+
+        Ok(res)
+    }
+
+    /// Reports whether IPv4 dials should be slightly
+    /// delayed to give IPv6 a better chance of winning dial races.
+    /// Implementations should only return true if IPv6 is expected
+    /// to succeed. (otherwise delaying IPv4 will delay the connection
+    /// overall)
+    async fn prefer_ipv6(&self) -> bool {
+        match self.address_family_selector {
+            Some(ref selector) => selector().await,
+            None => false,
+        }
+    }
+
+    async fn recv_detail(&mut self) -> Result<ReceivedMessage, ClientError> {
+        if let Some((_conn, conn_receiver)) = self.relay_conn.as_mut() {
+            trace!("recv_detail tick");
+            match conn_receiver.recv().await {
+                Ok(msg) => {
+                    return Ok(msg);
+                }
+                Err(e) => {
+                    self.close_for_reconnect().await;
+                    if self.is_closed {
+                        return Err(ClientError::Closed);
+                    }
+                    // TODO(ramfox): more specific error?
+                    return Err(ClientError::Receive(e));
+                }
+            }
+        }
+        future::pending().await
+    }
+
+    /// Close the underlying relay connection. The next time the client takes some action that
+    /// requires a connection, it will call `connect`.
+    async fn close_for_reconnect(&mut self) {
+        debug!("close for reconnect");
+        if let Some((conn, _)) = self.relay_conn.take() {
+            conn.close().await
+        }
+    }
+}
+
+fn host_header_value(relay_url: RelayUrl) -> Result<String, ClientError> {
+    // grab the host, turns e.g. https://example.com:8080/xyz -> example.com.
+    let relay_url_host = relay_url
+        .host_str()
+        .ok_or_else(|| ClientError::InvalidUrl(relay_url.to_string()))?;
+    // strip the trailing dot, if present: example.com. -> example.com
+    let relay_url_host = relay_url_host.strip_suffix('.').unwrap_or(relay_url_host);
+    // build the host header value (reserve up to 6 chars for the ":" and port digits):
+    let mut host_header_value = String::with_capacity(relay_url_host.len() + 6);
+    host_header_value += relay_url_host;
+    if let Some(port) = relay_url.port() {
+        host_header_value += ":";
+        host_header_value += &port.to_string();
+    }
+    Ok(host_header_value)
+}
+
+trait DnsExt {
+    fn lookup_ipv4<N: hickory_resolver::IntoName>(
+        &self,
+        host: N,
+    ) -> impl future::Future<Output = anyhow::Result<Option<IpAddr>>>;
+
+    fn lookup_ipv6<N: hickory_resolver::IntoName>(
+        &self,
+        host: N,
+    ) -> impl future::Future<Output = anyhow::Result<Option<IpAddr>>>;
+
+    fn resolve_host(
+        &self,
+        url: &Url,
+        prefer_ipv6: bool,
+    ) -> impl future::Future<Output = Result<IpAddr, ClientError>>;
+}
+
+impl DnsExt for DnsResolver {
+    async fn lookup_ipv4<N: hickory_resolver::IntoName>(
+        &self,
+        host: N,
+    ) -> anyhow::Result<Option<IpAddr>> {
+        let addrs = tokio::time::timeout(DNS_TIMEOUT, self.ipv4_lookup(host)).await??;
+        Ok(addrs.into_iter().next().map(|ip| IpAddr::V4(ip.0)))
+    }
+
+    async fn lookup_ipv6<N: hickory_resolver::IntoName>(
+        &self,
+        host: N,
+    ) -> anyhow::Result<Option<IpAddr>> {
+        let addrs = tokio::time::timeout(DNS_TIMEOUT, self.ipv6_lookup(host)).await??;
+        Ok(addrs.into_iter().next().map(|ip| IpAddr::V6(ip.0)))
+    }
+
+    async fn resolve_host(&self, url: &Url, prefer_ipv6: bool) -> Result<IpAddr, ClientError> {
+        let host = url
+            .host()
+            .ok_or_else(|| ClientError::InvalidUrl("missing host".into()))?;
+        match host {
+            url::Host::Domain(domain) => {
+                // Need to do a DNS lookup
+                let lookup = tokio::join!(self.lookup_ipv4(domain), self.lookup_ipv6(domain));
+                let (v4, v6) = match lookup {
+                    (Err(ipv4_err), Err(ipv6_err)) => {
+                        let err = anyhow::anyhow!("Ipv4: {:?}, Ipv6: {:?}", ipv4_err, ipv6_err);
+                        return Err(ClientError::Dns(Some(err)));
+                    }
+                    (Err(_), Ok(v6)) => (None, v6),
+                    (Ok(v4), Err(_)) => (v4, None),
+                    (Ok(v4), Ok(v6)) => (v4, v6),
+                };
+                if prefer_ipv6 { v6.or(v4) } else { v4.or(v6) }
+                    .ok_or_else(|| ClientError::Dns(None))
+            }
+            url::Host::Ipv4(ip) => Ok(IpAddr::V4(ip)),
+            url::Host::Ipv6(ip) => Ok(IpAddr::V6(ip)),
+        }
+    }
+}
+
+/// Used to allow self signed certificates in tests
+#[cfg(any(test, feature = "test-utils"))]
+#[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
+#[derive(Debug)]
+struct NoCertVerifier;
+
+#[cfg(any(test, feature = "test-utils"))]
+impl rustls::client::danger::ServerCertVerifier for NoCertVerifier {
+    fn verify_server_cert(
+        &self,
+        _end_entity: &rustls::pki_types::CertificateDer,
+        _intermediates: &[rustls::pki_types::CertificateDer],
+        _server_name: &rustls::pki_types::ServerName,
+        _ocsp_response: &[u8],
+        _now: rustls::pki_types::UnixTime,
+    ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
+        Ok(rustls::client::danger::ServerCertVerified::assertion())
+    }
+    fn verify_tls12_signature(
+        &self,
+        _message: &[u8],
+        _cert: &rustls::pki_types::CertificateDer<'_>,
+        _dss: &rustls::DigitallySignedStruct,
+    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
+        Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
+    }
+
+    fn verify_tls13_signature(
+        &self,
+        _message: &[u8],
+        _cert: &rustls::pki_types::CertificateDer<'_>,
+        _dss: &rustls::DigitallySignedStruct,
+    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
+        Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
+    }
+
+    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
+        rustls::crypto::ring::default_provider()
+            .signature_verification_algorithms
+            .supported_schemes()
+    }
+}
+
+fn url_port(url: &Url) -> Option<u16> {
+    if let Some(port) = url.port() {
+        return Some(port);
+    }
+
+    match url.scheme() {
+        "http" => Some(80),
+        "https" => Some(443),
+        _ => None,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::str::FromStr;
+
+    use anyhow::{bail, Result};
+
+    use super::*;
+    use crate::dns::default_resolver;
+
+    #[tokio::test]
+    async fn test_recv_detail_connect_error() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        let key = SecretKey::generate();
+        let bad_url: Url = "https://bad.url".parse().unwrap();
+        let dns_resolver = default_resolver();
+
+        let (_client, mut client_receiver) =
+            ClientBuilder::new(bad_url).build(key.clone(), dns_resolver.clone());
+
+        // ensure that the client will bubble up any connection error & not
+        // just loop ad infinitum attempting to connect
+        if client_receiver.recv().await.and_then(|s| s.ok()).is_some() {
+            bail!("expected client with bad relay node detail to return with an error");
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn test_host_header_value() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        let cases = [
+            (
+                "https://euw1-1.relay.iroh.network.",
+                "euw1-1.relay.iroh.network",
+            ),
+            ("http://localhost:8080", "localhost:8080"),
+        ];
+
+        for (url, expected_host) in cases {
+            let relay_url = RelayUrl::from_str(url)?;
+            let host = host_header_value(relay_url)?;
+            assert_eq!(host, expected_host);
+        }
+
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/client/conn.rs.html b/pr/2992/docs/src/iroh_relay/client/conn.rs.html new file mode 100644 index 0000000000..705d835623 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/client/conn.rs.html @@ -0,0 +1,1101 @@ +conn.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+
//! Manages client-side connections to the relay server.
+//!
+//! based on tailscale/derp/derp_client.go
+
+use std::{
+    net::SocketAddr,
+    num::NonZeroU32,
+    pin::Pin,
+    sync::Arc,
+    task::{Context, Poll},
+    time::Duration,
+};
+
+use anyhow::{anyhow, bail, ensure, Context as _, Result};
+use bytes::Bytes;
+use futures_lite::Stream;
+use futures_sink::Sink;
+use futures_util::{
+    stream::{SplitSink, SplitStream, StreamExt},
+    SinkExt,
+};
+use iroh_base::key::{NodeId, SecretKey};
+use tokio::sync::mpsc;
+use tokio_tungstenite_wasm::WebSocketStream;
+use tokio_util::{
+    codec::{FramedRead, FramedWrite},
+    task::AbortOnDropHandle,
+};
+use tracing::{debug, info_span, trace, Instrument};
+
+use crate::{
+    client::streams::{MaybeTlsStreamReader, MaybeTlsStreamWriter},
+    defaults::timeouts::CLIENT_RECV_TIMEOUT,
+    protos::relay::{
+        write_frame, ClientInfo, DerpCodec, Frame, MAX_PACKET_SIZE, PER_CLIENT_READ_QUEUE_DEPTH,
+        PER_CLIENT_SEND_QUEUE_DEPTH, PROTOCOL_VERSION,
+    },
+};
+
+impl PartialEq for Conn {
+    fn eq(&self, other: &Self) -> bool {
+        Arc::ptr_eq(&self.inner, &other.inner)
+    }
+}
+
+impl Eq for Conn {}
+
+/// A connection to a relay server.
+///
+/// Cheaply clonable.
+/// Call `close` to shut down the write loop and read functionality.
+#[derive(Debug, Clone)]
+pub struct Conn {
+    inner: Arc<ConnTasks>,
+}
+
+/// The channel on which a relay connection sends received messages.
+///
+/// The [`Conn`] to a relay is easily clonable but can only send DISCO messages to a relay
+/// server.  This is the counterpart which receives DISCO messages from the relay server for
+/// a connection.  It is not clonable.
+#[derive(Debug)]
+pub struct ConnReceiver {
+    /// The reader channel, receiving incoming messages.
+    reader_channel: mpsc::Receiver<Result<ReceivedMessage>>,
+}
+
+impl ConnReceiver {
+    /// Reads a messages from a relay server.
+    ///
+    /// Once it returns an error, the [`Conn`] is dead forever.
+    pub async fn recv(&mut self) -> Result<ReceivedMessage> {
+        let msg = self
+            .reader_channel
+            .recv()
+            .await
+            .ok_or(anyhow!("shut down"))??;
+        Ok(msg)
+    }
+}
+
+#[derive(derive_more::Debug)]
+pub struct ConnTasks {
+    /// Our local address, if known.
+    ///
+    /// Is `None` in tests or when using websockets (because we don't control connection establishment in browsers).
+    local_addr: Option<SocketAddr>,
+    /// Channel on which to communicate to the server. The associated [`mpsc::Receiver`] will close
+    /// if there is ever an error writing to the server.
+    writer_channel: mpsc::Sender<ConnWriterMessage>,
+    /// JoinHandle for the [`ConnWriter`] task
+    writer_task: AbortOnDropHandle<Result<()>>,
+    reader_task: AbortOnDropHandle<()>,
+}
+
+impl Conn {
+    /// Sends a packet to the node identified by `dstkey`
+    ///
+    /// Errors if the packet is larger than [`MAX_PACKET_SIZE`]
+    pub async fn send(&self, dst: NodeId, packet: Bytes) -> Result<()> {
+        trace!(%dst, len = packet.len(), "[RELAY] send");
+
+        self.inner
+            .writer_channel
+            .send(ConnWriterMessage::Packet((dst, packet)))
+            .await?;
+        Ok(())
+    }
+
+    /// Send a ping with 8 bytes of random data.
+    pub async fn send_ping(&self, data: [u8; 8]) -> Result<()> {
+        self.inner
+            .writer_channel
+            .send(ConnWriterMessage::Ping(data))
+            .await?;
+        Ok(())
+    }
+
+    /// Respond to a ping request. The `data` field should be filled
+    /// by the 8 bytes of random data send by the ping.
+    pub async fn send_pong(&self, data: [u8; 8]) -> Result<()> {
+        self.inner
+            .writer_channel
+            .send(ConnWriterMessage::Pong(data))
+            .await?;
+        Ok(())
+    }
+
+    /// Sends a packet that tells the server whether this
+    /// connection is to the user's preferred server. This is only
+    /// used in the server for stats.
+    pub async fn note_preferred(&self, preferred: bool) -> Result<()> {
+        self.inner
+            .writer_channel
+            .send(ConnWriterMessage::NotePreferred(preferred))
+            .await?;
+        Ok(())
+    }
+
+    /// The local address that the [`Conn`] is listening on.
+    ///
+    /// `None`, when run in a testing environment or when using websockets.
+    pub fn local_addr(&self) -> Option<SocketAddr> {
+        self.inner.local_addr
+    }
+
+    /// Whether or not this [`Conn`] is closed.
+    ///
+    /// The [`Conn`] is considered closed if the write side of the connection is no longer running.
+    pub fn is_closed(&self) -> bool {
+        self.inner.writer_task.is_finished()
+    }
+
+    /// Close the connection
+    ///
+    /// Shuts down the write loop directly and marks the connection as closed. The [`Conn`] will
+    /// check if the it is closed before attempting to read from it.
+    pub async fn close(&self) {
+        if self.inner.writer_task.is_finished() && self.inner.reader_task.is_finished() {
+            return;
+        }
+
+        self.inner
+            .writer_channel
+            .send(ConnWriterMessage::Shutdown)
+            .await
+            .ok();
+        self.inner.reader_task.abort();
+    }
+}
+
+fn process_incoming_frame(frame: Frame) -> Result<ReceivedMessage> {
+    match frame {
+        Frame::KeepAlive => {
+            // A one-way keep-alive message that doesn't require an ack.
+            // This predated FrameType::Ping/FrameType::Pong.
+            Ok(ReceivedMessage::KeepAlive)
+        }
+        Frame::NodeGone { node_id } => Ok(ReceivedMessage::NodeGone(node_id)),
+        Frame::RecvPacket { src_key, content } => {
+            let packet = ReceivedMessage::ReceivedPacket {
+                source: src_key,
+                data: content,
+            };
+            Ok(packet)
+        }
+        Frame::Ping { data } => Ok(ReceivedMessage::Ping(data)),
+        Frame::Pong { data } => Ok(ReceivedMessage::Pong(data)),
+        Frame::Health { problem } => {
+            let problem = std::str::from_utf8(&problem)?.to_owned();
+            let problem = Some(problem);
+            Ok(ReceivedMessage::Health { problem })
+        }
+        Frame::Restarting {
+            reconnect_in,
+            try_for,
+        } => {
+            let reconnect_in = Duration::from_millis(reconnect_in as u64);
+            let try_for = Duration::from_millis(try_for as u64);
+            Ok(ReceivedMessage::ServerRestarting {
+                reconnect_in,
+                try_for,
+            })
+        }
+        _ => bail!("unexpected packet: {:?}", frame.typ()),
+    }
+}
+
+/// The kinds of messages we can send to the [`Server`](crate::server::Server)
+#[derive(Debug)]
+enum ConnWriterMessage {
+    /// Send a packet (addressed to the [`NodeId`]) to the server
+    Packet((NodeId, Bytes)),
+    /// Send a pong to the server
+    Pong([u8; 8]),
+    /// Send a ping to the server
+    Ping([u8; 8]),
+    /// Tell the server whether or not this client is the user's preferred client
+    NotePreferred(bool),
+    /// Shutdown the writer
+    Shutdown,
+}
+
+/// Call [`ConnWriterTasks::run`] to listen for messages to send to the connection.
+/// Should be used by the [`Conn`]
+///
+/// Shutsdown when you send a [`ConnWriterMessage::Shutdown`], or if there is an error writing to
+/// the server.
+struct ConnWriterTasks {
+    recv_msgs: mpsc::Receiver<ConnWriterMessage>,
+    writer: ConnWriter,
+    rate_limiter: Option<RateLimiter>,
+}
+
+impl ConnWriterTasks {
+    async fn run(mut self) -> Result<()> {
+        while let Some(msg) = self.recv_msgs.recv().await {
+            match msg {
+                ConnWriterMessage::Packet((key, bytes)) => {
+                    send_packet(&mut self.writer, &self.rate_limiter, key, bytes).await?;
+                }
+                ConnWriterMessage::Pong(data) => {
+                    write_frame(&mut self.writer, Frame::Pong { data }, None).await?;
+                    self.writer.flush().await?;
+                }
+                ConnWriterMessage::Ping(data) => {
+                    write_frame(&mut self.writer, Frame::Ping { data }, None).await?;
+                    self.writer.flush().await?;
+                }
+                ConnWriterMessage::NotePreferred(preferred) => {
+                    write_frame(&mut self.writer, Frame::NotePreferred { preferred }, None).await?;
+                    self.writer.flush().await?;
+                }
+                ConnWriterMessage::Shutdown => {
+                    return Ok(());
+                }
+            }
+        }
+
+        bail!("channel unexpectedly closed");
+    }
+}
+
+/// The Builder returns a [`Conn`] and a [`ConnReceiver`] and
+/// runs a [`ConnWriterTasks`] in the background.
+pub struct ConnBuilder {
+    secret_key: SecretKey,
+    reader: ConnReader,
+    writer: ConnWriter,
+    local_addr: Option<SocketAddr>,
+}
+
+pub(crate) enum ConnReader {
+    Derp(FramedRead<MaybeTlsStreamReader, DerpCodec>),
+    Ws(SplitStream<WebSocketStream>),
+}
+
+pub(crate) enum ConnWriter {
+    Derp(FramedWrite<MaybeTlsStreamWriter, DerpCodec>),
+    Ws(SplitSink<WebSocketStream, tokio_tungstenite_wasm::Message>),
+}
+
+fn tung_wasm_to_io_err(e: tokio_tungstenite_wasm::Error) -> std::io::Error {
+    match e {
+        tokio_tungstenite_wasm::Error::Io(io_err) => io_err,
+        _ => std::io::Error::new(std::io::ErrorKind::Other, e.to_string()),
+    }
+}
+
+impl Stream for ConnReader {
+    type Item = Result<Frame>;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        match *self {
+            Self::Derp(ref mut ws) => Pin::new(ws).poll_next(cx),
+            Self::Ws(ref mut ws) => match Pin::new(ws).poll_next(cx) {
+                Poll::Ready(Some(Ok(tokio_tungstenite_wasm::Message::Binary(vec)))) => {
+                    Poll::Ready(Some(Frame::decode_from_ws_msg(vec)))
+                }
+                Poll::Ready(Some(Ok(msg))) => {
+                    tracing::warn!(?msg, "Got websocket message of unsupported type, skipping.");
+                    Poll::Pending
+                }
+                Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e.into()))),
+                Poll::Ready(None) => Poll::Ready(None),
+                Poll::Pending => Poll::Pending,
+            },
+        }
+    }
+}
+
+impl Sink<Frame> for ConnWriter {
+    type Error = std::io::Error;
+
+    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut ws) => Pin::new(ws).poll_ready(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_ready(cx).map_err(tung_wasm_to_io_err),
+        }
+    }
+
+    fn start_send(mut self: Pin<&mut Self>, item: Frame) -> Result<(), Self::Error> {
+        match *self {
+            Self::Derp(ref mut ws) => Pin::new(ws).start_send(item),
+            Self::Ws(ref mut ws) => Pin::new(ws)
+                .start_send(tokio_tungstenite_wasm::Message::binary(
+                    item.encode_for_ws_msg(),
+                ))
+                .map_err(tung_wasm_to_io_err),
+        }
+    }
+
+    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut ws) => Pin::new(ws).poll_flush(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_flush(cx).map_err(tung_wasm_to_io_err),
+        }
+    }
+
+    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut ws) => Pin::new(ws).poll_close(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_close(cx).map_err(tung_wasm_to_io_err),
+        }
+    }
+}
+
+impl ConnBuilder {
+    pub fn new(
+        secret_key: SecretKey,
+        local_addr: Option<SocketAddr>,
+        reader: ConnReader,
+        writer: ConnWriter,
+    ) -> Self {
+        Self {
+            secret_key,
+            reader,
+            writer,
+            local_addr,
+        }
+    }
+
+    async fn server_handshake(&mut self) -> Result<Option<RateLimiter>> {
+        debug!("server_handshake: started");
+        let client_info = ClientInfo {
+            version: PROTOCOL_VERSION,
+        };
+        debug!("server_handshake: sending client_key: {:?}", &client_info);
+        crate::protos::relay::send_client_key(&mut self.writer, &self.secret_key, &client_info)
+            .await?;
+
+        // TODO: add some actual configuration
+        let rate_limiter = RateLimiter::new(0, 0)?;
+
+        debug!("server_handshake: done");
+        Ok(rate_limiter)
+    }
+
+    pub async fn build(mut self) -> Result<(Conn, ConnReceiver)> {
+        // exchange information with the server
+        let rate_limiter = self.server_handshake().await?;
+
+        // create task to handle writing to the server
+        let (writer_sender, writer_recv) = mpsc::channel(PER_CLIENT_SEND_QUEUE_DEPTH);
+        let writer_task = tokio::task::spawn(
+            ConnWriterTasks {
+                rate_limiter,
+                writer: self.writer,
+                recv_msgs: writer_recv,
+            }
+            .run()
+            .instrument(info_span!("conn.writer")),
+        );
+
+        let (reader_sender, reader_recv) = mpsc::channel(PER_CLIENT_READ_QUEUE_DEPTH);
+        let reader_task = tokio::task::spawn({
+            let writer_sender = writer_sender.clone();
+            async move {
+                loop {
+                    let frame = tokio::time::timeout(CLIENT_RECV_TIMEOUT, self.reader.next()).await;
+                    let res = match frame {
+                        Ok(Some(Ok(frame))) => process_incoming_frame(frame),
+                        Ok(Some(Err(err))) => {
+                            // Error processing incoming messages
+                            Err(err)
+                        }
+                        Ok(None) => {
+                            // EOF
+                            Err(anyhow::anyhow!("EOF: reader stream ended"))
+                        }
+                        Err(err) => {
+                            // Timeout
+                            Err(err.into())
+                        }
+                    };
+                    if res.is_err() {
+                        // shutdown
+                        writer_sender.send(ConnWriterMessage::Shutdown).await.ok();
+                        break;
+                    }
+                    if reader_sender.send(res).await.is_err() {
+                        // shutdown, as the reader is gone
+                        writer_sender.send(ConnWriterMessage::Shutdown).await.ok();
+                        break;
+                    }
+                }
+            }
+            .instrument(info_span!("conn.reader"))
+        });
+
+        let conn = Conn {
+            inner: Arc::new(ConnTasks {
+                local_addr: self.local_addr,
+                writer_channel: writer_sender,
+                writer_task: AbortOnDropHandle::new(writer_task),
+                reader_task: AbortOnDropHandle::new(reader_task),
+            }),
+        };
+
+        let conn_receiver = ConnReceiver {
+            reader_channel: reader_recv,
+        };
+
+        Ok((conn, conn_receiver))
+    }
+}
+
+#[derive(derive_more::Debug, Clone)]
+/// The type of message received by the [`Conn`] from a relay server.
+pub enum ReceivedMessage {
+    /// Represents an incoming packet.
+    ReceivedPacket {
+        /// The [`NodeId`] of the packet sender.
+        source: NodeId,
+        /// The received packet bytes.
+        #[debug(skip)]
+        data: Bytes, // TODO: ref
+    },
+    /// Indicates that the client identified by the underlying public key had previously sent you a
+    /// packet but has now disconnected from the server.
+    NodeGone(NodeId),
+    /// Request from a client or server to reply to the
+    /// other side with a [`ReceivedMessage::Pong`] with the given payload.
+    Ping([u8; 8]),
+    /// Reply to a [`ReceivedMessage::Ping`] from a client or server
+    /// with the payload sent previously in the ping.
+    Pong([u8; 8]),
+    /// A one-way empty message from server to client, just to
+    /// keep the connection alive. It's like a [`ReceivedMessage::Ping`], but doesn't solicit
+    /// a reply from the client.
+    KeepAlive,
+    /// A one-way message from server to client, declaring the connection health state.
+    Health {
+        /// If set, is a description of why the connection is unhealthy.
+        ///
+        /// If `None` means the connection is healthy again.
+        ///
+        /// The default condition is healthy, so the server doesn't broadcast a [`ReceivedMessage::Health`]
+        /// until a problem exists.
+        problem: Option<String>,
+    },
+    /// A one-way message from server to client, advertising that the server is restarting.
+    ServerRestarting {
+        /// An advisory duration that the client should wait before attempting to reconnect.
+        /// It might be zero. It exists for the server to smear out the reconnects.
+        reconnect_in: Duration,
+        /// An advisory duration for how long the client should attempt to reconnect
+        /// before giving up and proceeding with its normal connection failure logic. The interval
+        /// between retries is undefined for now. A server should not send a TryFor duration more
+        /// than a few seconds.
+        try_for: Duration,
+    },
+}
+
+pub(crate) async fn send_packet<S: Sink<Frame, Error = std::io::Error> + Unpin>(
+    mut writer: S,
+    rate_limiter: &Option<RateLimiter>,
+    dst: NodeId,
+    packet: Bytes,
+) -> Result<()> {
+    ensure!(
+        packet.len() <= MAX_PACKET_SIZE,
+        "packet too big: {}",
+        packet.len()
+    );
+
+    let frame = Frame::SendPacket {
+        dst_key: dst,
+        packet,
+    };
+    if let Some(rate_limiter) = rate_limiter {
+        if rate_limiter.check_n(frame.len()).is_err() {
+            tracing::debug!("dropping send: rate limit reached");
+            return Ok(());
+        }
+    }
+    writer.send(frame).await?;
+    writer.flush().await?;
+
+    Ok(())
+}
+
+pub(crate) struct RateLimiter {
+    inner: governor::DefaultDirectRateLimiter,
+}
+
+impl RateLimiter {
+    pub(crate) fn new(bytes_per_second: usize, bytes_burst: usize) -> Result<Option<Self>> {
+        if bytes_per_second == 0 || bytes_burst == 0 {
+            return Ok(None);
+        }
+        let bytes_per_second = NonZeroU32::new(u32::try_from(bytes_per_second)?)
+            .context("bytes_per_second not non-zero")?;
+        let bytes_burst =
+            NonZeroU32::new(u32::try_from(bytes_burst)?).context("bytes_burst not non-zero")?;
+        Ok(Some(Self {
+            inner: governor::RateLimiter::direct(
+                governor::Quota::per_second(bytes_per_second).allow_burst(bytes_burst),
+            ),
+        }))
+    }
+
+    pub(crate) fn check_n(&self, n: usize) -> Result<()> {
+        let n = NonZeroU32::new(u32::try_from(n)?).context("n not non-zero")?;
+        match self.inner.check_n(n) {
+            Ok(_) => Ok(()),
+            Err(_) => bail!("batch cannot go through"),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/client/streams.rs.html b/pr/2992/docs/src/iroh_relay/client/streams.rs.html new file mode 100644 index 0000000000..95b33d5e2a --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/client/streams.rs.html @@ -0,0 +1,585 @@ +streams.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+
use std::{
+    net::SocketAddr,
+    pin::Pin,
+    task::{Context, Poll},
+};
+
+use anyhow::{bail, Result};
+use bytes::Bytes;
+use hyper::upgrade::{Parts, Upgraded};
+use hyper_util::rt::TokioIo;
+use tokio::{
+    io::{AsyncRead, AsyncWrite},
+    net::TcpStream,
+};
+
+use super::util;
+
+pub enum MaybeTlsStreamReader {
+    Raw(util::Chain<std::io::Cursor<Bytes>, tokio::io::ReadHalf<ProxyStream>>),
+    Tls(
+        util::Chain<
+            std::io::Cursor<Bytes>,
+            tokio::io::ReadHalf<tokio_rustls::client::TlsStream<ProxyStream>>,
+        >,
+    ),
+    #[cfg(all(test, feature = "server"))]
+    Mem(tokio::io::ReadHalf<tokio::io::DuplexStream>),
+}
+
+impl AsyncRead for MaybeTlsStreamReader {
+    fn poll_read(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut tokio::io::ReadBuf<'_>,
+    ) -> Poll<std::io::Result<()>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf),
+            Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf),
+            #[cfg(all(test, feature = "server"))]
+            Self::Mem(stream) => Pin::new(stream).poll_read(cx, buf),
+        }
+    }
+}
+
+pub enum MaybeTlsStreamWriter {
+    Raw(tokio::io::WriteHalf<ProxyStream>),
+    Tls(tokio::io::WriteHalf<tokio_rustls::client::TlsStream<ProxyStream>>),
+    #[cfg(all(test, feature = "server"))]
+    Mem(tokio::io::WriteHalf<tokio::io::DuplexStream>),
+}
+
+impl AsyncWrite for MaybeTlsStreamWriter {
+    fn poll_write(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &[u8],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf),
+            Self::Tls(stream) => Pin::new(stream).poll_write(cx, buf),
+            #[cfg(all(test, feature = "server"))]
+            Self::Mem(stream) => Pin::new(stream).poll_write(cx, buf),
+        }
+    }
+
+    fn poll_flush(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_flush(cx),
+            Self::Tls(stream) => Pin::new(stream).poll_flush(cx),
+            #[cfg(all(test, feature = "server"))]
+            Self::Mem(stream) => Pin::new(stream).poll_flush(cx),
+        }
+    }
+
+    fn poll_shutdown(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx),
+            Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx),
+            #[cfg(all(test, feature = "server"))]
+            Self::Mem(stream) => Pin::new(stream).poll_shutdown(cx),
+        }
+    }
+
+    fn poll_write_vectored(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        bufs: &[std::io::IoSlice<'_>],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+            Self::Tls(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+            #[cfg(all(test, feature = "server"))]
+            Self::Mem(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+        }
+    }
+}
+
+pub fn downcast_upgrade(
+    upgraded: Upgraded,
+) -> Result<(MaybeTlsStreamReader, MaybeTlsStreamWriter)> {
+    match upgraded.downcast::<TokioIo<ProxyStream>>() {
+        Ok(Parts { read_buf, io, .. }) => {
+            let inner = io.into_inner();
+            let (reader, writer) = tokio::io::split(inner);
+            // Prepend data to the reader to avoid data loss
+            let reader = util::chain(std::io::Cursor::new(read_buf), reader);
+            Ok((
+                MaybeTlsStreamReader::Raw(reader),
+                MaybeTlsStreamWriter::Raw(writer),
+            ))
+        }
+        Err(upgraded) => {
+            if let Ok(Parts { read_buf, io, .. }) =
+                upgraded.downcast::<TokioIo<tokio_rustls::client::TlsStream<ProxyStream>>>()
+            {
+                let inner = io.into_inner();
+                let (reader, writer) = tokio::io::split(inner);
+                // Prepend data to the reader to avoid data loss
+                let reader = util::chain(std::io::Cursor::new(read_buf), reader);
+
+                return Ok((
+                    MaybeTlsStreamReader::Tls(reader),
+                    MaybeTlsStreamWriter::Tls(writer),
+                ));
+            }
+
+            bail!(
+                "could not downcast the upgraded connection to a TcpStream or client::TlsStream<TcpStream>"
+            )
+        }
+    }
+}
+
+pub enum ProxyStream {
+    Raw(TcpStream),
+    Proxied(util::Chain<std::io::Cursor<Bytes>, MaybeTlsStream>),
+}
+
+impl AsyncRead for ProxyStream {
+    fn poll_read(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut tokio::io::ReadBuf<'_>,
+    ) -> Poll<std::io::Result<()>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf),
+            Self::Proxied(stream) => Pin::new(stream).poll_read(cx, buf),
+        }
+    }
+}
+
+impl AsyncWrite for ProxyStream {
+    fn poll_write(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &[u8],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf),
+            Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_write(cx, buf),
+        }
+    }
+
+    fn poll_flush(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_flush(cx),
+            Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_flush(cx),
+        }
+    }
+
+    fn poll_shutdown(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx),
+            Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_shutdown(cx),
+        }
+    }
+    fn poll_write_vectored(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        bufs: &[std::io::IoSlice<'_>],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+            Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_write_vectored(cx, bufs),
+        }
+    }
+}
+
+impl ProxyStream {
+    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
+        match self {
+            Self::Raw(s) => s.local_addr(),
+            Self::Proxied(s) => s.get_ref().1.local_addr(),
+        }
+    }
+
+    pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
+        match self {
+            Self::Raw(s) => s.peer_addr(),
+            Self::Proxied(s) => s.get_ref().1.peer_addr(),
+        }
+    }
+}
+
+pub enum MaybeTlsStream {
+    Raw(TcpStream),
+    Tls(tokio_rustls::client::TlsStream<TcpStream>),
+}
+
+impl AsyncRead for MaybeTlsStream {
+    fn poll_read(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut tokio::io::ReadBuf<'_>,
+    ) -> Poll<std::io::Result<()>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf),
+            Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf),
+        }
+    }
+}
+
+impl AsyncWrite for MaybeTlsStream {
+    fn poll_write(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &[u8],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf),
+            Self::Tls(stream) => Pin::new(stream).poll_write(cx, buf),
+        }
+    }
+
+    fn poll_flush(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_flush(cx),
+            Self::Tls(stream) => Pin::new(stream).poll_flush(cx),
+        }
+    }
+
+    fn poll_shutdown(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Result<(), std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx),
+            Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx),
+        }
+    }
+    fn poll_write_vectored(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        bufs: &[std::io::IoSlice<'_>],
+    ) -> Poll<Result<usize, std::io::Error>> {
+        match &mut *self {
+            Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+            Self::Tls(stream) => Pin::new(stream).poll_write_vectored(cx, bufs),
+        }
+    }
+}
+
+impl MaybeTlsStream {
+    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
+        match self {
+            Self::Raw(s) => s.local_addr(),
+            Self::Tls(s) => s.get_ref().0.local_addr(),
+        }
+    }
+
+    pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
+        match self {
+            Self::Raw(s) => s.peer_addr(),
+            Self::Tls(s) => s.get_ref().0.peer_addr(),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/client/util.rs.html b/pr/2992/docs/src/iroh_relay/client/util.rs.html new file mode 100644 index 0000000000..87da6b8022 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/client/util.rs.html @@ -0,0 +1,247 @@ +util.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+
//! IO utility to chain `AsyncRead`s together.
+
+// Based on tokios chain implementation, that doesn't make the concrete type public.
+
+use std::{
+    fmt, io,
+    pin::Pin,
+    task::{ready, Context, Poll},
+};
+
+use pin_project::pin_project;
+use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf};
+
+/// Stream for the [`chain`] method.
+#[must_use = "streams do nothing unless polled"]
+#[pin_project]
+pub(crate) struct Chain<T, U> {
+    #[pin]
+    first: T,
+    #[pin]
+    second: U,
+    done_first: bool,
+}
+
+/// Chain two `AsyncRead`s together.
+pub(crate) fn chain<T, U>(first: T, second: U) -> Chain<T, U>
+where
+    T: AsyncRead,
+    U: AsyncRead,
+{
+    Chain {
+        first,
+        second,
+        done_first: false,
+    }
+}
+
+impl<T, U> Chain<T, U>
+where
+    T: AsyncRead,
+    U: AsyncRead,
+{
+    /// Gets references to the underlying readers in this `Chain`.
+    pub(crate) fn get_ref(&self) -> (&T, &U) {
+        (&self.first, &self.second)
+    }
+
+    /// Gets mutable references to the underlying readers in this `Chain`.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying readers as doing so may corrupt the internal state of this
+    /// `Chain`.
+    pub(crate) fn get_mut(&mut self) -> (&mut T, &mut U) {
+        (&mut self.first, &mut self.second)
+    }
+}
+
+impl<T, U> fmt::Debug for Chain<T, U>
+where
+    T: fmt::Debug,
+    U: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Chain")
+            .field("t", &self.first)
+            .field("u", &self.second)
+            .finish()
+    }
+}
+
+impl<T, U> AsyncRead for Chain<T, U>
+where
+    T: AsyncRead,
+    U: AsyncRead,
+{
+    fn poll_read(
+        self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut ReadBuf<'_>,
+    ) -> Poll<io::Result<()>> {
+        let me = self.project();
+
+        if !*me.done_first {
+            let rem = buf.remaining();
+            ready!(me.first.poll_read(cx, buf))?;
+            if buf.remaining() == rem {
+                *me.done_first = true;
+            } else {
+                return Poll::Ready(Ok(()));
+            }
+        }
+        me.second.poll_read(cx, buf)
+    }
+}
+
+impl<T, U> AsyncBufRead for Chain<T, U>
+where
+    T: AsyncBufRead,
+    U: AsyncBufRead,
+{
+    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
+        let me = self.project();
+
+        if !*me.done_first {
+            match ready!(me.first.poll_fill_buf(cx)?) {
+                [] => {
+                    *me.done_first = true;
+                }
+                buf => return Poll::Ready(Ok(buf)),
+            }
+        }
+        me.second.poll_fill_buf(cx)
+    }
+
+    fn consume(self: Pin<&mut Self>, amt: usize) {
+        let me = self.project();
+        if !*me.done_first {
+            me.first.consume(amt)
+        } else {
+            me.second.consume(amt)
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/defaults.rs.html b/pr/2992/docs/src/iroh_relay/defaults.rs.html new file mode 100644 index 0000000000..ea4b15377c --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/defaults.rs.html @@ -0,0 +1,77 @@ +defaults.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+
//! Default values used in the relay.
+
+pub use iroh_base::relay_map::{DEFAULT_RELAY_QUIC_PORT, DEFAULT_STUN_PORT};
+
+/// The default HTTP port used by the Relay server.
+pub const DEFAULT_HTTP_PORT: u16 = 80;
+
+/// The default HTTPS port used by the Relay server.
+pub const DEFAULT_HTTPS_PORT: u16 = 443;
+
+/// The default metrics port used by the Relay server.
+pub const DEFAULT_METRICS_PORT: u16 = 9090;
+
+/// Contains all timeouts that we use in `iroh`.
+pub(crate) mod timeouts {
+    use std::time::Duration;
+
+    /// Timeout used by the relay client while connecting to the relay server,
+    /// using `TcpStream::connect`
+    pub(crate) const DIAL_NODE_TIMEOUT: Duration = Duration::from_millis(1500);
+    /// Timeout for expecting a pong from the relay server
+    pub(crate) const PING_TIMEOUT: Duration = Duration::from_secs(5);
+    /// Timeout for the entire relay connection, which includes dns, dialing
+    /// the server, upgrading the connection, and completing the handshake
+    pub(crate) const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
+    /// Timeout for our async dns resolver
+    pub(crate) const DNS_TIMEOUT: Duration = Duration::from_secs(1);
+
+    /// Maximum time the client will wait to receive on the connection, since
+    /// the last message. Longer than this time and the client will consider
+    /// the connection dead.
+    pub(crate) const CLIENT_RECV_TIMEOUT: Duration = Duration::from_secs(120);
+
+    /// Maximum time the server will attempt to get a successful write to the connection.
+    #[cfg(feature = "server")]
+    #[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+    pub(crate) const SERVER_WRITE_TIMEOUT: Duration = Duration::from_secs(2);
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/http.rs.html b/pr/2992/docs/src/iroh_relay/http.rs.html new file mode 100644 index 0000000000..dfe08658a6 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/http.rs.html @@ -0,0 +1,103 @@ +http.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+
//! HTTP-specific constants for the relay server and client.
+
+pub(crate) const HTTP_UPGRADE_PROTOCOL: &str = "iroh derp http";
+pub(crate) const WEBSOCKET_UPGRADE_PROTOCOL: &str = "websocket";
+#[cfg(feature = "server")] // only used in the server for now
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) const SUPPORTED_WEBSOCKET_VERSION: &str = "13";
+
+/// The HTTP path under which the relay accepts relaying connections
+/// (over websockets and a custom upgrade protocol).
+pub const RELAY_PATH: &str = "/relay";
+/// The HTTP path under which the relay allows doing latency queries for testing.
+pub const RELAY_PROBE_PATH: &str = "/ping";
+/// The legacy HTTP path under which the relay used to accept relaying connections.
+/// We keep this for backwards compatibility.
+#[cfg(feature = "server")] // legacy paths only used on server-side for backwards compat
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) const LEGACY_RELAY_PATH: &str = "/derp";
+
+/// The HTTP upgrade protocol used for relaying.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Protocol {
+    /// Relays over the custom relaying protocol with a custom HTTP upgrade header.
+    Relay,
+    /// Relays over websockets.
+    ///
+    /// Originally introduced to support browser connections.
+    Websocket,
+}
+
+impl Protocol {
+    /// The HTTP upgrade header used or expected.
+    pub const fn upgrade_header(&self) -> &'static str {
+        match self {
+            Protocol::Relay => HTTP_UPGRADE_PROTOCOL,
+            Protocol::Websocket => WEBSOCKET_UPGRADE_PROTOCOL,
+        }
+    }
+
+    /// Tries to match the value of an HTTP upgrade header to figure out which protocol should be initiated.
+    pub fn parse_header(header: &http::HeaderValue) -> Option<Self> {
+        let header_bytes = header.as_bytes();
+        if header_bytes == Protocol::Relay.upgrade_header().as_bytes() {
+            Some(Protocol::Relay)
+        } else if header_bytes == Protocol::Websocket.upgrade_header().as_bytes() {
+            Some(Protocol::Websocket)
+        } else {
+            None
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/lib.rs.html b/pr/2992/docs/src/iroh_relay/lib.rs.html new file mode 100644 index 0000000000..88f3e98915 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/lib.rs.html @@ -0,0 +1,87 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+
//! Iroh's relay is a feature within [iroh](https://github.com/n0-computer/iroh), a peer-to-peer
+//! networking system designed to facilitate direct, encrypted connections between devices. Iroh
+//! aims to simplify decentralized communication by automatically handling connections through
+//! "relays" when direct connections aren't immediately possible. The relay server helps establish
+//! connections by temporarily routing encrypted traffic until a direct, P2P connection is
+//! feasible. Once this direct path is set up, the relay server steps back, and the data flows
+//! directly between devices. This approach allows Iroh to maintain a secure, low-latency
+//! connection, even in challenging network situations.
+//!
+//! This crate provides a complete setup for creating and interacting with iroh relays, including:
+//! - [`protos::relay`]: The protocol used to communicate between relay servers and clients. It's a
+//!   revised version of the Designated Encrypted Relay for Packets (DERP) protocol written by
+//!   Tailscale.
+//! - [`server`]: A fully-fledged iroh-relay server over HTTP or HTTPS. Optionally will also
+//!   expose a stun endpoint and metrics.
+//! - [`client`]: A client for establishing connections to the relay.
+//! - *Server Binary*: A CLI for running your own relay server. It can be configured to also offer
+//!   STUN support and expose metrics.
+// Based on tailscale/derp/derp.go
+
+#![cfg_attr(iroh_docsrs, feature(doc_cfg))]
+#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
+
+pub mod client;
+pub mod defaults;
+pub mod http;
+pub mod protos;
+pub mod quic;
+#[cfg(feature = "server")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub mod server;
+
+#[cfg(test)]
+mod dns;
+
+pub use iroh_base::node_addr::RelayUrl;
+pub use protos::relay::MAX_PACKET_SIZE;
+
+pub use self::client::{
+    conn::{Conn as RelayConn, ReceivedMessage},
+    Client as HttpClient, ClientBuilder as HttpClientBuilder, ClientError as HttpClientError,
+    ClientReceiver as HttpClientReceiver,
+};
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/protos.rs.html b/pr/2992/docs/src/iroh_relay/protos.rs.html new file mode 100644 index 0000000000..4be8642029 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/protos.rs.html @@ -0,0 +1,11 @@ +protos.rs - source
1
+2
+3
+4
+5
+
//! Protocols used by the iroh-relay
+
+pub mod disco;
+pub mod relay;
+pub mod stun;
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/protos/disco.rs.html b/pr/2992/docs/src/iroh_relay/protos/disco.rs.html new file mode 100644 index 0000000000..969e2c960d --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/protos/disco.rs.html @@ -0,0 +1,43 @@ +disco.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
//! This module exports [`looks_like_disco_wrapper`] as the only disco-related relay
+//! functionality.
+//!
+//! Despite the relay not being able to read disco messages by design, it does attempt to
+//! identify this traffic to ensure hole-punching messages are not lost do to congestion.
+
+/// The 6 byte header of all discovery messages.
+pub const MAGIC: &str = "TS💬"; // 6 bytes: 0x54 53 f0 9f 92 ac
+pub(crate) const MAGIC_LEN: usize = MAGIC.as_bytes().len();
+pub(crate) const KEY_LEN: usize = 32;
+
+const MESSAGE_HEADER_LEN: usize = MAGIC_LEN + KEY_LEN;
+
+/// Reports whether p looks like it's a packet containing an encrypted disco message.
+pub fn looks_like_disco_wrapper(p: &[u8]) -> bool {
+    if p.len() < MESSAGE_HEADER_LEN {
+        return false;
+    }
+
+    &p[..MAGIC_LEN] == MAGIC.as_bytes()
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/protos/relay.rs.html b/pr/2992/docs/src/iroh_relay/protos/relay.rs.html new file mode 100644 index 0000000000..c365367a52 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/protos/relay.rs.html @@ -0,0 +1,1655 @@ +relay.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+
//! This module implements the relaying protocol used the [`crate::server`] and [`crate::client`].
+//!
+//! Protocol flow:
+//!
+//! Login:
+//!  * client connects
+//!  * -> client sends `FrameType::ClientInfo`
+//!
+//!  Steady state:
+//!  * server occasionally sends `FrameType::KeepAlive` (or `FrameType::Ping`)
+//!  * client responds to any `FrameType::Ping` with a `FrameType::Pong`
+//!  * clients sends `FrameType::SendPacket`
+//!  * server then sends `FrameType::RecvPacket` to recipient
+
+use std::time::Duration;
+
+use anyhow::{bail, ensure};
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+#[cfg(feature = "server")]
+use futures_lite::{Stream, StreamExt};
+use futures_sink::Sink;
+use futures_util::SinkExt;
+use iroh_base::key::{PublicKey, SecretKey, Signature, PUBLIC_KEY_LENGTH};
+use postcard::experimental::max_size::MaxSize;
+use serde::{Deserialize, Serialize};
+use tokio_util::codec::{Decoder, Encoder};
+
+/// The maximum size of a packet sent over relay.
+/// (This only includes the data bytes visible to magicsock, not
+/// including its on-wire framing overhead)
+pub const MAX_PACKET_SIZE: usize = 64 * 1024;
+
+/// The maximum frame size.
+///
+/// This is also the minimum burst size that a rate-limiter has to accept.
+const MAX_FRAME_SIZE: usize = 1024 * 1024;
+
+/// The Relay magic number, sent in the FrameType::ClientInfo frame upon initial connection.
+const MAGIC: &str = "RELAY🔑";
+
+#[cfg(feature = "server")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) const KEEP_ALIVE: Duration = Duration::from_secs(60);
+// TODO: what should this be?
+#[cfg(feature = "server")]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) const SERVER_CHANNEL_SIZE: usize = 1024 * 100;
+/// The number of packets buffered for sending per client
+pub(crate) const PER_CLIENT_SEND_QUEUE_DEPTH: usize = 512; //32;
+pub(crate) const PER_CLIENT_READ_QUEUE_DEPTH: usize = 512;
+
+/// ProtocolVersion is bumped whenever there's a wire-incompatible change.
+///  - version 1 (zero on wire): consistent box headers, in use by employee dev nodes a bit
+///  - version 2: received packets have src addrs in FrameType::RecvPacket at beginning.
+///
+/// NOTE: we are technically running a modified version of the protocol.
+/// `FrameType::PeerPresent`, `FrameType::WatchConn`, `FrameType::ClosePeer`, have been removed.
+/// The server will error on that connection if a client sends one of these frames.
+/// We have split with the DERP protocol significantly starting with our relay protocol 3
+/// `FrameType::PeerPresent`, `FrameType::WatchConn`, `FrameType::ClosePeer`, `FrameType::ServerKey`, and `FrameType::ServerInfo` have been removed.
+/// The server will error on that connection if a client sends one of these frames.
+/// This materially affects the handshake protocol, and so relay nodes on version 3 will be unable to communicate
+/// with nodes running earlier protocol versions.
+pub(crate) const PROTOCOL_VERSION: usize = 3;
+
+/// Indicates this IS the client's home node
+const PREFERRED: u8 = 1u8;
+/// Indicates this IS NOT the client's home node
+const NOT_PREFERRED: u8 = 0u8;
+
+/// The one byte frame type at the beginning of the frame
+/// header. The second field is a big-endian u32 describing the
+/// length of the remaining frame (not including the initial 5 bytes)
+#[derive(Debug, PartialEq, Eq, num_enum::IntoPrimitive, num_enum::FromPrimitive, Clone, Copy)]
+#[repr(u8)]
+pub(crate) enum FrameType {
+    /// magic + 32b pub key + 24B nonce + bytes
+    ClientInfo = 2,
+    /// 32B dest pub key + packet bytes
+    SendPacket = 4,
+    /// v0/1 packet bytes, v2: 32B src pub key + packet bytes
+    RecvPacket = 5,
+    /// no payload, no-op (to be replaced with ping/pong)
+    KeepAlive = 6,
+    /// 1 byte payload: 0x01 or 0x00 for whether this is client's home node
+    NotePreferred = 7,
+    /// Sent from server to client to signal that a previous sender is no longer connected.
+    ///
+    /// That is, if A sent to B, and then if A disconnects, the server sends `FrameType::PeerGone`
+    /// to B so B can forget that a reverse path exists on that connection to get back to A
+    ///
+    /// 32B pub key of peer that's gone
+    PeerGone = 8,
+    /// Frames 9-11 concern meshing, which we have eliminated from our version of the protocol.
+    /// Messages with these frames will be ignored.
+    /// 8 byte ping payload, to be echoed back in FrameType::Pong
+    Ping = 12,
+    /// 8 byte payload, the contents of ping being replied to
+    Pong = 13,
+    /// Sent from server to client to tell the client if their connection is
+    /// unhealthy somehow. Currently the only unhealthy state is whether the
+    /// connection is detected as a duplicate.
+    /// The entire frame body is the text of the error message. An empty message
+    /// clears the error state.
+    Health = 14,
+
+    /// Sent from server to client for the server to declare that it's restarting.
+    /// Payload is two big endian u32 durations in milliseconds: when to reconnect,
+    /// and how long to try total.
+    ///
+    /// Handled on the `[relay::Client]`, but currently never sent on the `[relay::Server]`
+    Restarting = 15,
+    #[num_enum(default)]
+    Unknown = 255,
+}
+
+impl std::fmt::Display for FrameType {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "{self:?}")
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize, MaxSize, PartialEq, Eq)]
+pub(crate) struct ClientInfo {
+    /// The relay protocol version that the client was built with.
+    pub(crate) version: usize,
+}
+
+/// Writes complete frame, errors if it is unable to write within the given `timeout`.
+/// Ignores the timeout if `None`
+///
+/// Does not flush.
+pub(crate) async fn write_frame<S: Sink<Frame, Error = std::io::Error> + Unpin>(
+    mut writer: S,
+    frame: Frame,
+    timeout: Option<Duration>,
+) -> anyhow::Result<()> {
+    if let Some(duration) = timeout {
+        tokio::time::timeout(duration, writer.send(frame)).await??;
+    } else {
+        writer.send(frame).await?;
+    }
+
+    Ok(())
+}
+
+/// Writes a `FrameType::ClientInfo`, including the client's [`PublicKey`],
+/// and the client's [`ClientInfo`], sealed using the server's [`PublicKey`].
+///
+/// Flushes after writing.
+pub(crate) async fn send_client_key<S: Sink<Frame, Error = std::io::Error> + Unpin>(
+    mut writer: S,
+    client_secret_key: &SecretKey,
+    client_info: &ClientInfo,
+) -> anyhow::Result<()> {
+    let msg = postcard::to_stdvec(client_info)?;
+    let signature = client_secret_key.sign(&msg);
+
+    writer
+        .send(Frame::ClientInfo {
+            client_public_key: client_secret_key.public(),
+            message: msg.into(),
+            signature,
+        })
+        .await?;
+    writer.flush().await?;
+    Ok(())
+}
+
+/// Reads the `FrameType::ClientInfo` frame from the client (its proof of identity)
+/// upon it's initial connection.
+#[cfg(any(test, feature = "server"))]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) async fn recv_client_key<S: Stream<Item = anyhow::Result<Frame>> + Unpin>(
+    stream: S,
+) -> anyhow::Result<(PublicKey, ClientInfo)> {
+    use anyhow::Context;
+    // the client is untrusted at this point, limit the input size even smaller than our usual
+    // maximum frame size, and give a timeout
+
+    // TODO: variable recv size: 256 * 1024
+    let buf = tokio::time::timeout(
+        Duration::from_secs(10),
+        recv_frame(FrameType::ClientInfo, stream),
+    )
+    .await
+    .context("recv_frame timeout")?
+    .context("recv_frame")?;
+
+    if let Frame::ClientInfo {
+        client_public_key,
+        message,
+        signature,
+    } = buf
+    {
+        client_public_key
+            .verify(&message, &signature)
+            .context("invalid signature")?;
+        let info: ClientInfo = postcard::from_bytes(&message).context("deserialization")?;
+        Ok((client_public_key, info))
+    } else {
+        anyhow::bail!("expected FrameType::ClientInfo");
+    }
+}
+
+/// The protocol for the relay server.
+///
+/// This is a framed protocol, using [`tokio_util::codec`] to turn the streams of bytes into
+/// [`Frame`]s.
+#[derive(Debug, Default, Clone)]
+pub(crate) struct DerpCodec;
+
+/// The frames in the [`DerpCodec`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) enum Frame {
+    ClientInfo {
+        client_public_key: PublicKey,
+        message: Bytes,
+        signature: Signature,
+    },
+    SendPacket {
+        dst_key: PublicKey,
+        packet: Bytes,
+    },
+    RecvPacket {
+        src_key: PublicKey,
+        content: Bytes,
+    },
+    KeepAlive,
+    NotePreferred {
+        preferred: bool,
+    },
+    NodeGone {
+        node_id: PublicKey,
+    },
+    Ping {
+        data: [u8; 8],
+    },
+    Pong {
+        data: [u8; 8],
+    },
+    Health {
+        problem: Bytes,
+    },
+    Restarting {
+        reconnect_in: u32,
+        try_for: u32,
+    },
+}
+
+impl Frame {
+    pub(crate) fn typ(&self) -> FrameType {
+        match self {
+            Frame::ClientInfo { .. } => FrameType::ClientInfo,
+            Frame::SendPacket { .. } => FrameType::SendPacket,
+            Frame::RecvPacket { .. } => FrameType::RecvPacket,
+            Frame::KeepAlive => FrameType::KeepAlive,
+            Frame::NotePreferred { .. } => FrameType::NotePreferred,
+            Frame::NodeGone { .. } => FrameType::PeerGone,
+            Frame::Ping { .. } => FrameType::Ping,
+            Frame::Pong { .. } => FrameType::Pong,
+            Frame::Health { .. } => FrameType::Health,
+            Frame::Restarting { .. } => FrameType::Restarting,
+        }
+    }
+
+    /// Serialized length (without the frame header)
+    pub(crate) fn len(&self) -> usize {
+        match self {
+            Frame::ClientInfo {
+                client_public_key: _,
+                message,
+                signature: _,
+            } => MAGIC.as_bytes().len() + PUBLIC_KEY_LENGTH + message.len() + Signature::BYTE_SIZE,
+            Frame::SendPacket { dst_key: _, packet } => PUBLIC_KEY_LENGTH + packet.len(),
+            Frame::RecvPacket {
+                src_key: _,
+                content,
+            } => PUBLIC_KEY_LENGTH + content.len(),
+            Frame::KeepAlive => 0,
+            Frame::NotePreferred { .. } => 1,
+            Frame::NodeGone { .. } => PUBLIC_KEY_LENGTH,
+            Frame::Ping { .. } => 8,
+            Frame::Pong { .. } => 8,
+            Frame::Health { problem } => problem.len(),
+            Frame::Restarting { .. } => 4 + 4,
+        }
+    }
+
+    /// Serialized length with frame header.
+    #[cfg(feature = "server")]
+    pub(crate) fn len_with_header(&self) -> usize {
+        self.len() + HEADER_LEN
+    }
+
+    /// Tries to decode a frame received over websockets.
+    ///
+    /// Specifically, bytes received from a binary websocket message frame.
+    pub(crate) fn decode_from_ws_msg(vec: Vec<u8>) -> anyhow::Result<Self> {
+        if vec.is_empty() {
+            bail!("error parsing relay::codec::Frame: too few bytes (0)");
+        }
+        let bytes = Bytes::from(vec);
+        let typ = FrameType::from(bytes[0]);
+        let frame = Self::from_bytes(typ, bytes.slice(1..))?;
+        Ok(frame)
+    }
+
+    /// Encodes this frame for sending over websockets.
+    ///
+    /// Specifically meant for being put into a binary websocket message frame.
+    pub(crate) fn encode_for_ws_msg(self) -> Vec<u8> {
+        let mut bytes = Vec::new();
+        bytes.put_u8(self.typ().into());
+        self.write_to(&mut bytes);
+        bytes
+    }
+
+    /// Writes it self to the given buffer.
+    fn write_to(&self, dst: &mut impl BufMut) {
+        match self {
+            Frame::ClientInfo {
+                client_public_key,
+                message,
+                signature,
+            } => {
+                dst.put(MAGIC.as_bytes());
+                dst.put(client_public_key.as_ref());
+                dst.put(&signature.to_bytes()[..]);
+                dst.put(&message[..]);
+            }
+            Frame::SendPacket { dst_key, packet } => {
+                dst.put(dst_key.as_ref());
+                dst.put(packet.as_ref());
+            }
+            Frame::RecvPacket { src_key, content } => {
+                dst.put(src_key.as_ref());
+                dst.put(content.as_ref());
+            }
+            Frame::KeepAlive => {}
+            Frame::NotePreferred { preferred } => {
+                if *preferred {
+                    dst.put_u8(PREFERRED);
+                } else {
+                    dst.put_u8(NOT_PREFERRED);
+                }
+            }
+            Frame::NodeGone { node_id: peer } => {
+                dst.put(peer.as_ref());
+            }
+            Frame::Ping { data } => {
+                dst.put(&data[..]);
+            }
+            Frame::Pong { data } => {
+                dst.put(&data[..]);
+            }
+            Frame::Health { problem } => {
+                dst.put(problem.as_ref());
+            }
+            Frame::Restarting {
+                reconnect_in,
+                try_for,
+            } => {
+                dst.put_u32(*reconnect_in);
+                dst.put_u32(*try_for);
+            }
+        }
+    }
+
+    fn from_bytes(frame_type: FrameType, content: Bytes) -> anyhow::Result<Self> {
+        let res = match frame_type {
+            FrameType::ClientInfo => {
+                ensure!(
+                    content.len()
+                        >= PUBLIC_KEY_LENGTH + Signature::BYTE_SIZE + MAGIC.as_bytes().len(),
+                    "invalid client info frame length: {}",
+                    content.len()
+                );
+                ensure!(
+                    &content[..MAGIC.as_bytes().len()] == MAGIC.as_bytes(),
+                    "invalid client info frame magic"
+                );
+
+                let start = MAGIC.as_bytes().len();
+                let client_public_key =
+                    PublicKey::try_from(&content[start..start + PUBLIC_KEY_LENGTH])?;
+                let start = start + PUBLIC_KEY_LENGTH;
+                let signature =
+                    Signature::from_slice(&content[start..start + Signature::BYTE_SIZE])?;
+                let start = start + Signature::BYTE_SIZE;
+                let message = content.slice(start..);
+                Self::ClientInfo {
+                    client_public_key,
+                    message,
+                    signature,
+                }
+            }
+            FrameType::SendPacket => {
+                ensure!(
+                    content.len() >= PUBLIC_KEY_LENGTH,
+                    "invalid send packet frame length: {}",
+                    content.len()
+                );
+                let packet_len = content.len() - PUBLIC_KEY_LENGTH;
+                ensure!(
+                    packet_len <= MAX_PACKET_SIZE,
+                    "data packet longer ({packet_len}) than max of {MAX_PACKET_SIZE}"
+                );
+                let dst_key = PublicKey::try_from(&content[..PUBLIC_KEY_LENGTH])?;
+                let packet = content.slice(PUBLIC_KEY_LENGTH..);
+                Self::SendPacket { dst_key, packet }
+            }
+            FrameType::RecvPacket => {
+                ensure!(
+                    content.len() >= PUBLIC_KEY_LENGTH,
+                    "invalid recv packet frame length: {}",
+                    content.len()
+                );
+                let packet_len = content.len() - PUBLIC_KEY_LENGTH;
+                ensure!(
+                    packet_len <= MAX_PACKET_SIZE,
+                    "data packet longer ({packet_len}) than max of {MAX_PACKET_SIZE}"
+                );
+                let src_key = PublicKey::try_from(&content[..PUBLIC_KEY_LENGTH])?;
+                let content = content.slice(PUBLIC_KEY_LENGTH..);
+                Self::RecvPacket { src_key, content }
+            }
+            FrameType::KeepAlive => {
+                anyhow::ensure!(content.is_empty(), "invalid keep alive frame length");
+                Self::KeepAlive
+            }
+            FrameType::NotePreferred => {
+                anyhow::ensure!(content.len() == 1, "invalid note preferred frame length");
+                let preferred = match content[0] {
+                    PREFERRED => true,
+                    NOT_PREFERRED => false,
+                    _ => anyhow::bail!("invalid note preferred frame content"),
+                };
+                Self::NotePreferred { preferred }
+            }
+            FrameType::PeerGone => {
+                anyhow::ensure!(
+                    content.len() == PUBLIC_KEY_LENGTH,
+                    "invalid peer gone frame length"
+                );
+                let peer = PublicKey::try_from(&content[..32])?;
+                Self::NodeGone { node_id: peer }
+            }
+            FrameType::Ping => {
+                anyhow::ensure!(content.len() == 8, "invalid ping frame length");
+                let mut data = [0u8; 8];
+                data.copy_from_slice(&content[..8]);
+                Self::Ping { data }
+            }
+            FrameType::Pong => {
+                anyhow::ensure!(content.len() == 8, "invalid pong frame length");
+                let mut data = [0u8; 8];
+                data.copy_from_slice(&content[..8]);
+                Self::Pong { data }
+            }
+            FrameType::Health => Self::Health { problem: content },
+            FrameType::Restarting => {
+                ensure!(
+                    content.len() == 4 + 4,
+                    "invalid restarting frame length: {}",
+                    content.len()
+                );
+                let reconnect_in = u32::from_be_bytes(content[..4].try_into()?);
+                let try_for = u32::from_be_bytes(content[4..].try_into()?);
+                Self::Restarting {
+                    reconnect_in,
+                    try_for,
+                }
+            }
+            _ => {
+                anyhow::bail!("invalid frame type: {:?}", frame_type);
+            }
+        };
+        Ok(res)
+    }
+}
+
+const HEADER_LEN: usize = 5;
+
+impl Decoder for DerpCodec {
+    type Item = Frame;
+    type Error = anyhow::Error;
+
+    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
+        // Need at least 5 bytes
+        if src.len() < HEADER_LEN {
+            return Ok(None);
+        }
+
+        // Can't use the `Buf::get_*` APIs, as that advances the buffer.
+        let Some(frame_type) = src.first().map(|b| FrameType::from(*b)) else {
+            return Ok(None); // Not enough bytes
+        };
+        let Some(frame_len) = src
+            .get(1..5)
+            .and_then(|s| TryInto::<[u8; 4]>::try_into(s).ok())
+            .map(u32::from_be_bytes)
+            .map(|l| l as usize)
+        else {
+            return Ok(None); // Not enough bytes
+        };
+
+        if frame_len > MAX_FRAME_SIZE {
+            anyhow::bail!("Frame of length {} is too large.", frame_len);
+        }
+
+        if src.len() < HEADER_LEN + frame_len {
+            // Optimization: prereserve the buffer space
+            src.reserve(HEADER_LEN + frame_len - src.len());
+
+            return Ok(None);
+        }
+
+        // advance the header
+        src.advance(HEADER_LEN);
+
+        let content = src.split_to(frame_len).freeze();
+        let frame = Frame::from_bytes(frame_type, content)?;
+
+        Ok(Some(frame))
+    }
+}
+
+impl Encoder<Frame> for DerpCodec {
+    type Error = std::io::Error;
+
+    fn encode(&mut self, frame: Frame, dst: &mut BytesMut) -> Result<(), Self::Error> {
+        let frame_len: usize = frame.len();
+        if frame_len > MAX_FRAME_SIZE {
+            return Err(std::io::Error::new(
+                std::io::ErrorKind::InvalidData,
+                format!("Frame of length {} is too large.", frame_len),
+            ));
+        }
+
+        let frame_len_u32 = u32::try_from(frame_len).expect("just checked");
+
+        dst.reserve(HEADER_LEN + frame_len);
+        dst.put_u8(frame.typ().into());
+        dst.put_u32(frame_len_u32);
+        frame.write_to(dst);
+
+        Ok(())
+    }
+}
+
+/// Receives the next frame and matches the frame type. If the correct type is found returns the content,
+/// otherwise an error.
+#[cfg(any(test, feature = "server"))]
+#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
+pub(crate) async fn recv_frame<S: Stream<Item = anyhow::Result<Frame>> + Unpin>(
+    frame_type: FrameType,
+    mut stream: S,
+) -> anyhow::Result<Frame> {
+    match stream.next().await {
+        Some(Ok(frame)) => {
+            ensure!(
+                frame_type == frame.typ(),
+                "expected frame {}, found {}",
+                frame_type,
+                frame.typ()
+            );
+            Ok(frame)
+        }
+        Some(Err(err)) => Err(err),
+        None => bail!("EOF: unexpected stream end, expected frame {}", frame_type),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use tokio_util::codec::{FramedRead, FramedWrite};
+
+    use super::*;
+
+    #[tokio::test]
+    async fn test_basic_read_write() -> anyhow::Result<()> {
+        let (reader, writer) = tokio::io::duplex(1024);
+        let mut reader = FramedRead::new(reader, DerpCodec);
+        let mut writer = FramedWrite::new(writer, DerpCodec);
+
+        let expect_buf = b"hello world!";
+        let expected_frame = Frame::Health {
+            problem: expect_buf.to_vec().into(),
+        };
+        write_frame(&mut writer, expected_frame.clone(), None).await?;
+        writer.flush().await?;
+        println!("{:?}", reader);
+        let buf = recv_frame(FrameType::Health, &mut reader).await?;
+        assert_eq!(expect_buf.len(), buf.len());
+        assert_eq!(expected_frame, buf);
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_send_recv_client_key() -> anyhow::Result<()> {
+        let (reader, writer) = tokio::io::duplex(1024);
+        let mut reader = FramedRead::new(reader, DerpCodec);
+        let mut writer = FramedWrite::new(writer, DerpCodec);
+
+        let client_key = SecretKey::generate();
+        let client_info = ClientInfo {
+            version: PROTOCOL_VERSION,
+        };
+        println!("client_key pub {:?}", client_key.public());
+        send_client_key(&mut writer, &client_key, &client_info).await?;
+        let (client_pub_key, got_client_info) = recv_client_key(&mut reader).await?;
+        assert_eq!(client_key.public(), client_pub_key);
+        assert_eq!(client_info, got_client_info);
+        Ok(())
+    }
+
+    #[test]
+    fn test_frame_snapshot() -> anyhow::Result<()> {
+        let client_key = SecretKey::from_bytes(&[42u8; 32]);
+        let client_info = ClientInfo {
+            version: PROTOCOL_VERSION,
+        };
+        let message = postcard::to_stdvec(&client_info)?;
+        let signature = client_key.sign(&message);
+
+        let frames = vec![
+            (
+                Frame::ClientInfo {
+                    client_public_key: client_key.public(),
+                    message: Bytes::from(message),
+                    signature,
+                },
+                "02 52 45 4c 41 59 f0 9f 94 91 19 7f 6b 23 e1 6c
+                85 32 c6 ab c8 38 fa cd 5e a7 89 be 0c 76 b2 92
+                03 34 03 9b fa 8b 3d 36 8d 61 88 e7 7b 22 f2 92
+                ab 37 43 5d a8 de 0b c8 cb 84 e2 88 f4 e7 3b 35
+                82 a5 27 31 e9 ff 98 65 46 5c 87 e0 5e 8d 42 7d
+                f4 22 bb 6e 85 e1 c0 5f 6f 74 98 37 ba a4 a5 c7
+                eb a3 23 0d 77 56 99 10 43 0e 03",
+            ),
+            (
+                Frame::Health {
+                    problem: "Hello? Yes this is dog.".into(),
+                },
+                "0e 48 65 6c 6c 6f 3f 20 59 65 73 20 74 68 69 73
+                20 69 73 20 64 6f 67 2e",
+            ),
+            (Frame::KeepAlive, "06"),
+            (Frame::NotePreferred { preferred: true }, "07 01"),
+            (
+                Frame::NodeGone {
+                    node_id: client_key.public(),
+                },
+                "08 19 7f 6b 23 e1 6c 85 32 c6 ab c8 38 fa cd 5e
+                a7 89 be 0c 76 b2 92 03 34 03 9b fa 8b 3d 36 8d
+                61",
+            ),
+            (
+                Frame::Ping { data: [42u8; 8] },
+                "0c 2a 2a 2a 2a 2a 2a 2a 2a",
+            ),
+            (
+                Frame::Pong { data: [42u8; 8] },
+                "0d 2a 2a 2a 2a 2a 2a 2a 2a",
+            ),
+            (
+                Frame::RecvPacket {
+                    src_key: client_key.public(),
+                    content: "Hello World!".into(),
+                },
+                "05 19 7f 6b 23 e1 6c 85 32 c6 ab c8 38 fa cd 5e
+                a7 89 be 0c 76 b2 92 03 34 03 9b fa 8b 3d 36 8d
+                61 48 65 6c 6c 6f 20 57 6f 72 6c 64 21",
+            ),
+            (
+                Frame::SendPacket {
+                    dst_key: client_key.public(),
+                    packet: "Goodbye!".into(),
+                },
+                "04 19 7f 6b 23 e1 6c 85 32 c6 ab c8 38 fa cd 5e
+                a7 89 be 0c 76 b2 92 03 34 03 9b fa 8b 3d 36 8d
+                61 47 6f 6f 64 62 79 65 21",
+            ),
+            (
+                Frame::Restarting {
+                    reconnect_in: 10,
+                    try_for: 20,
+                },
+                "0f 00 00 00 0a 00 00 00 14",
+            ),
+        ];
+
+        for (frame, expected_hex) in frames {
+            let bytes = frame.encode_for_ws_msg();
+            // To regenerate the hexdumps:
+            // let hexdump = iroh_test::hexdump::print_hexdump(bytes, []);
+            // println!("{hexdump}");
+            let expected_bytes = iroh_test::hexdump::parse_hexdump(expected_hex)?;
+            assert_eq!(bytes, expected_bytes);
+        }
+
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod proptests {
+    use proptest::prelude::*;
+
+    use super::*;
+
+    fn secret_key() -> impl Strategy<Value = SecretKey> {
+        prop::array::uniform32(any::<u8>()).prop_map(SecretKey::from)
+    }
+
+    fn key() -> impl Strategy<Value = PublicKey> {
+        secret_key().prop_map(|key| key.public())
+    }
+
+    /// Generates random data, up to the maximum packet size minus the given number of bytes
+    fn data(consumed: usize) -> impl Strategy<Value = Bytes> {
+        let len = MAX_PACKET_SIZE - consumed;
+        prop::collection::vec(any::<u8>(), 0..len).prop_map(Bytes::from)
+    }
+
+    /// Generates a random valid frame
+    fn frame() -> impl Strategy<Value = Frame> {
+        let client_info = (secret_key()).prop_map(|secret_key| {
+            let info = ClientInfo {
+                version: PROTOCOL_VERSION,
+            };
+            let msg = postcard::to_stdvec(&info).expect("using default ClientInfo");
+            let signature = secret_key.sign(&msg);
+            Frame::ClientInfo {
+                client_public_key: secret_key.public(),
+                message: msg.into(),
+                signature,
+            }
+        });
+        let send_packet =
+            (key(), data(32)).prop_map(|(dst_key, packet)| Frame::SendPacket { dst_key, packet });
+        let recv_packet =
+            (key(), data(32)).prop_map(|(src_key, content)| Frame::RecvPacket { src_key, content });
+        let keep_alive = Just(Frame::KeepAlive);
+        let note_preferred = any::<bool>().prop_map(|preferred| Frame::NotePreferred { preferred });
+        let peer_gone = key().prop_map(|peer| Frame::NodeGone { node_id: peer });
+        let ping = prop::array::uniform8(any::<u8>()).prop_map(|data| Frame::Ping { data });
+        let pong = prop::array::uniform8(any::<u8>()).prop_map(|data| Frame::Pong { data });
+        let health = data(0).prop_map(|problem| Frame::Health { problem });
+        let restarting =
+            (any::<u32>(), any::<u32>()).prop_map(|(reconnect_in, try_for)| Frame::Restarting {
+                reconnect_in,
+                try_for,
+            });
+        prop_oneof![
+            client_info,
+            send_packet,
+            recv_packet,
+            keep_alive,
+            note_preferred,
+            peer_gone,
+            ping,
+            pong,
+            health,
+            restarting,
+        ]
+    }
+
+    fn inject_error(buf: &mut BytesMut) {
+        fn is_fixed_size(tpe: FrameType) -> bool {
+            match tpe {
+                FrameType::KeepAlive
+                | FrameType::NotePreferred
+                | FrameType::Ping
+                | FrameType::Pong
+                | FrameType::Restarting
+                | FrameType::PeerGone => true,
+                FrameType::ClientInfo
+                | FrameType::Health
+                | FrameType::SendPacket
+                | FrameType::RecvPacket
+                | FrameType::Unknown => false,
+            }
+        }
+        let tpe: FrameType = buf[0].into();
+        let mut len = u32::from_be_bytes(buf[1..5].try_into().unwrap()) as usize;
+        if is_fixed_size(tpe) {
+            buf.put_u8(0);
+            len += 1;
+        } else {
+            buf.resize(MAX_FRAME_SIZE + 1, 0);
+            len = MAX_FRAME_SIZE + 1;
+        }
+        buf[1..5].copy_from_slice(&u32::to_be_bytes(len as u32));
+    }
+
+    proptest! {
+
+        // Test that we can roundtrip a frame to bytes
+        #[test]
+        fn frame_roundtrip(frame in frame()) {
+            let mut buf = BytesMut::new();
+            DerpCodec.encode(frame.clone(), &mut buf).unwrap();
+            let decoded = DerpCodec.decode(&mut buf).unwrap().unwrap();
+            prop_assert_eq!(frame, decoded);
+        }
+
+        #[test]
+        fn frame_ws_roundtrip(frame in frame()) {
+            let encoded = frame.clone().encode_for_ws_msg();
+            let decoded = Frame::decode_from_ws_msg(encoded).unwrap();
+            prop_assert_eq!(frame, decoded);
+        }
+
+        // Test that typical invalid frames will result in an error
+        #[test]
+        fn broken_frame_handling(frame in frame()) {
+            let mut buf = BytesMut::new();
+            DerpCodec.encode(frame.clone(), &mut buf).unwrap();
+            inject_error(&mut buf);
+            let decoded = DerpCodec.decode(&mut buf);
+            prop_assert!(decoded.is_err());
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/protos/stun.rs.html b/pr/2992/docs/src/iroh_relay/protos/stun.rs.html new file mode 100644 index 0000000000..0dc7fd9657 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/protos/stun.rs.html @@ -0,0 +1,777 @@ +stun.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+
//! STUN packets sending and receiving.
+
+use std::net::SocketAddr;
+
+use stun_rs::{
+    attributes::stun::{Fingerprint, XorMappedAddress},
+    DecoderContextBuilder, MessageDecoderBuilder, MessageEncoderBuilder, StunMessageBuilder,
+};
+pub use stun_rs::{
+    attributes::StunAttribute, error::StunDecodeError, methods, MessageClass, MessageDecoder,
+    TransactionId,
+};
+
+/// Errors that can occur when handling a STUN packet.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    /// The STUN message could not be parsed or is otherwise invalid.
+    #[error("invalid message")]
+    InvalidMessage,
+    /// STUN request is not a binding request when it should be.
+    #[error("not binding")]
+    NotBinding,
+    /// STUN packet is not a response when it should be.
+    #[error("not success response")]
+    NotSuccessResponse,
+    /// STUN response has malformed attributes.
+    #[error("malformed attributes")]
+    MalformedAttrs,
+    /// STUN request didn't end in fingerprint.
+    #[error("no fingerprint")]
+    NoFingerprint,
+    /// STUN request had bogus fingerprint.
+    #[error("invalid fingerprint")]
+    InvalidFingerprint,
+}
+
+/// Generates a binding request STUN packet.
+pub fn request(tx: TransactionId) -> Vec<u8> {
+    let fp = Fingerprint::default();
+    let msg = StunMessageBuilder::new(methods::BINDING, MessageClass::Request)
+        .with_transaction_id(tx)
+        .with_attribute(fp)
+        .build();
+
+    let encoder = MessageEncoderBuilder::default().build();
+    let mut buffer = vec![0u8; 150];
+    let size = encoder.encode(&mut buffer, &msg).expect("invalid encoding");
+    buffer.truncate(size);
+    buffer
+}
+
+/// Generates a binding response.
+pub fn response(tx: TransactionId, addr: SocketAddr) -> Vec<u8> {
+    let msg = StunMessageBuilder::new(methods::BINDING, MessageClass::SuccessResponse)
+        .with_transaction_id(tx)
+        .with_attribute(XorMappedAddress::from(addr))
+        .build();
+
+    let encoder = MessageEncoderBuilder::default().build();
+    let mut buffer = vec![0u8; 150];
+    let size = encoder.encode(&mut buffer, &msg).expect("invalid encoding");
+    buffer.truncate(size);
+    buffer
+}
+
+// Copied from stun_rs
+// const MAGIC_COOKIE: Cookie = Cookie(0x2112_A442);
+const COOKIE: [u8; 4] = 0x2112_A442u32.to_be_bytes();
+
+/// Reports whether b is a STUN message.
+pub fn is(b: &[u8]) -> bool {
+    b.len() >= stun_rs::MESSAGE_HEADER_SIZE &&
+        b[0]&0b11000000 == 0 && // top two bits must be zero
+        b[4..8] == COOKIE
+}
+
+/// Parses a STUN binding request.
+pub fn parse_binding_request(b: &[u8]) -> Result<TransactionId, Error> {
+    let ctx = DecoderContextBuilder::default()
+        .with_validation() // ensure fingerprint is validated
+        .build();
+    let decoder = MessageDecoderBuilder::default().with_context(ctx).build();
+    let (msg, _) = decoder.decode(b).map_err(|_| Error::InvalidMessage)?;
+
+    let tx = *msg.transaction_id();
+    if msg.method() != methods::BINDING {
+        return Err(Error::NotBinding);
+    }
+
+    // TODO: Tailscale sets the software to tailscale, we should check if we want to do this too.
+
+    if msg
+        .attributes()
+        .last()
+        .map(|attr| !attr.is_fingerprint())
+        .unwrap_or_default()
+    {
+        return Err(Error::NoFingerprint);
+    }
+
+    Ok(tx)
+}
+
+/// Parses a successful binding response STUN packet.
+/// The IP address is extracted from the XOR-MAPPED-ADDRESS attribute.
+pub fn parse_response(b: &[u8]) -> Result<(TransactionId, SocketAddr), Error> {
+    let decoder = MessageDecoder::default();
+    let (msg, _) = decoder.decode(b).map_err(|_| Error::InvalidMessage)?;
+
+    let tx = *msg.transaction_id();
+    if msg.class() != MessageClass::SuccessResponse {
+        return Err(Error::NotSuccessResponse);
+    }
+
+    // Read through the attributes.
+    // The the addr+port reported by XOR-MAPPED-ADDRESS
+    // as the canonical value. If the attribute is not
+    // present but the STUN server responds with
+    // MAPPED-ADDRESS we fall back to it.
+
+    let mut addr = None;
+    let mut fallback_addr = None;
+    for attr in msg.attributes() {
+        match attr {
+            StunAttribute::XorMappedAddress(a) => {
+                let mut a = *a.socket_address();
+                a.set_ip(a.ip().to_canonical());
+                addr = Some(a);
+            }
+            StunAttribute::MappedAddress(a) => {
+                let mut a = *a.socket_address();
+                a.set_ip(a.ip().to_canonical());
+                fallback_addr = Some(a);
+            }
+            _ => {}
+        }
+    }
+
+    if let Some(addr) = addr {
+        return Ok((tx, addr));
+    }
+
+    if let Some(addr) = fallback_addr {
+        return Ok((tx, addr));
+    }
+
+    Err(Error::MalformedAttrs)
+}
+
+#[cfg(test)]
+mod tests {
+
+    use std::net::{IpAddr, Ipv4Addr};
+
+    use super::*;
+
+    struct ResponseTestCase {
+        name: &'static str,
+        data: Vec<u8>,
+        want_tid: Vec<u8>,
+        want_addr: IpAddr,
+        want_port: u16,
+    }
+
+    #[test]
+    fn test_parse_response() {
+        let cases = vec![
+            ResponseTestCase {
+                name: "google-1",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x0c, 0x21, 0x12, 0xa4, 0x42,
+                    0x23, 0x60, 0xb1, 0x1e, 0x3e, 0xc6, 0x8f, 0xfa,
+                    0x93, 0xe0, 0x80, 0x07, 0x00, 0x20, 0x00, 0x08,
+                    0x00, 0x01, 0xc7, 0x86, 0x69, 0x57, 0x85, 0x6f,
+                ],
+                want_tid: vec![
+                    0x23, 0x60, 0xb1, 0x1e, 0x3e, 0xc6, 0x8f, 0xfa,
+                    0x93, 0xe0, 0x80, 0x07,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([72, 69, 33, 45])),
+                want_port: 59028,
+            },
+            ResponseTestCase {
+                name: "google-2",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x0c, 0x21, 0x12, 0xa4, 0x42,
+                    0xf9, 0xf1, 0x21, 0xcb, 0xde, 0x7d, 0x7c, 0x75,
+                    0x92, 0x3c, 0xe2, 0x71, 0x00, 0x20, 0x00, 0x08,
+                    0x00, 0x01, 0xc7, 0x87, 0x69, 0x57, 0x85, 0x6f,
+                ],
+                want_tid: vec![
+                    0xf9, 0xf1, 0x21, 0xcb, 0xde, 0x7d, 0x7c, 0x75,
+                    0x92, 0x3c, 0xe2, 0x71,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([72, 69, 33, 45])),
+                want_port: 59029,
+            },
+            ResponseTestCase{
+                name: "stun.sipgate.net:10000",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x44, 0x21, 0x12, 0xa4, 0x42,
+                    0x48, 0x2e, 0xb6, 0x47, 0x15, 0xe8, 0xb2, 0x8e,
+                    0xae, 0xad, 0x64, 0x44, 0x00, 0x01, 0x00, 0x08,
+                    0x00, 0x01, 0xe4, 0xab, 0x48, 0x45, 0x21, 0x2d,
+                    0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x27, 0x10,
+                    0xd9, 0x0a, 0x44, 0x98, 0x00, 0x05, 0x00, 0x08,
+                    0x00, 0x01, 0x27, 0x11, 0xd9, 0x74, 0x7a, 0x8a,
+                    0x80, 0x20, 0x00, 0x08, 0x00, 0x01, 0xc5, 0xb9,
+                    0x69, 0x57, 0x85, 0x6f, 0x80, 0x22, 0x00, 0x10,
+                    0x56, 0x6f, 0x76, 0x69, 0x64, 0x61, 0x2e, 0x6f,
+                    0x72, 0x67, 0x20, 0x30, 0x2e, 0x39, 0x36, 0x00,
+                ],
+                want_tid: vec![
+                    0x48, 0x2e, 0xb6, 0x47, 0x15, 0xe8, 0xb2, 0x8e,
+                    0xae, 0xad, 0x64, 0x44,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([72, 69, 33, 45])),
+                want_port: 58539,
+            },
+            ResponseTestCase{
+                name: "stun.powervoip.com:3478",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42,
+                    0x7e, 0x57, 0x96, 0x68, 0x29, 0xf4, 0x44, 0x60,
+                    0x9d, 0x1d, 0xea, 0xa6, 0x00, 0x01, 0x00, 0x08,
+                    0x00, 0x01, 0xe9, 0xd3, 0x48, 0x45, 0x21, 0x2d,
+                    0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x0d, 0x96,
+                    0x4d, 0x48, 0xa9, 0xd4, 0x00, 0x05, 0x00, 0x08,
+                    0x00, 0x01, 0x0d, 0x97, 0x4d, 0x48, 0xa9, 0xd5,
+                ],
+                want_tid: vec![
+                    0x7e, 0x57, 0x96, 0x68, 0x29, 0xf4, 0x44, 0x60,
+                    0x9d, 0x1d, 0xea, 0xa6,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([72, 69, 33, 45])),
+                want_port: 59859,
+            },
+            ResponseTestCase{
+                name: "in-process pion server",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42,
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e, 0x80, 0x22, 0x00, 0x0a,
+                    0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
+                    0x65, 0x72, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
+                    0x00, 0x01, 0xce, 0x66, 0x5e, 0x12, 0xa4, 0x43,
+                    0x80, 0x28, 0x00, 0x04, 0xb6, 0x99, 0xbb, 0x02,
+                    0x01, 0x01, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42,
+                ],
+                want_tid: vec![
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([127, 0, 0, 1])),
+                want_port: 61300,
+            },
+            ResponseTestCase{
+                name: "stuntman-server ipv6",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42,
+                    0x06, 0xf5, 0x66, 0x85, 0xd2, 0x8a, 0xf3, 0xe6,
+                    0x9c, 0xe3, 0x41, 0xe2, 0x00, 0x01, 0x00, 0x14,
+                    0x00, 0x02, 0x90, 0xce, 0x26, 0x02, 0x00, 0xd1,
+                    0xb4, 0xcf, 0xc1, 0x00, 0x38, 0xb2, 0x31, 0xff,
+                    0xfe, 0xef, 0x96, 0xf6, 0x80, 0x2b, 0x00, 0x14,
+                    0x00, 0x02, 0x0d, 0x96, 0x26, 0x04, 0xa8, 0x80,
+                    0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0xc5, 0x70, 0x01, 0x00, 0x20, 0x00, 0x14,
+                    0x00, 0x02, 0xb1, 0xdc, 0x07, 0x10, 0xa4, 0x93,
+                    0xb2, 0x3a, 0xa7, 0x85, 0xea, 0x38, 0xc2, 0x19,
+                    0x62, 0x0c, 0xd7, 0x14,
+                ],
+                want_tid: vec![
+                    6, 245, 102, 133, 210, 138, 243, 230, 156, 227,
+                    65, 226,
+                ],
+                want_addr: "2602:d1:b4cf:c100:38b2:31ff:feef:96f6".parse().unwrap(),
+                want_port: 37070,
+            },
+            // Testing STUN attribute padding rules using STUN software attribute
+            // with values of 1 & 3 length respectively before the XorMappedAddress attribute
+            ResponseTestCase {
+                name: "software-a",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x14, 0x21, 0x12, 0xa4, 0x42,
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e, 0x80, 0x22, 0x00, 0x01,
+                    0x61, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
+                    0x00, 0x01, 0xce, 0x66, 0x5e, 0x12, 0xa4, 0x43,
+                ],
+                want_tid: vec![
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([127, 0, 0, 1])),
+                want_port: 61300,
+            },
+            ResponseTestCase {
+                name: "software-abc",
+                data: vec![
+                    0x01, 0x01, 0x00, 0x14, 0x21, 0x12, 0xa4, 0x42,
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e, 0x80, 0x22, 0x00, 0x03,
+                    0x61, 0x62, 0x63, 0x00, 0x00, 0x20, 0x00, 0x08,
+                    0x00, 0x01, 0xce, 0x66, 0x5e, 0x12, 0xa4, 0x43,
+                ],
+                want_tid: vec![
+                    0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c,
+                    0x4f, 0x3e, 0x30, 0x8e,
+                ],
+                want_addr: IpAddr::V4(Ipv4Addr::from([127, 0, 0, 1])),
+                want_port: 61300,
+            },
+            ResponseTestCase {
+                name:     "no-4in6",
+                data:     hex::decode("010100182112a4424fd5d202dcb37d31fc773306002000140002cd3d2112a4424fd5d202dcb382ce2dc3fcc7").unwrap(),
+                want_tid:  vec![79, 213, 210, 2, 220, 179, 125, 49, 252, 119, 51, 6],
+                want_addr: IpAddr::V4(Ipv4Addr::from([209, 180, 207, 193])),
+                want_port: 60463,
+            },
+            ];
+
+        for (i, test) in cases.into_iter().enumerate() {
+            println!("Case {i}: {}", test.name);
+            let (tx, addr_port) = parse_response(&test.data).unwrap();
+            assert!(is(&test.data));
+            assert_eq!(tx.as_bytes(), &test.want_tid[..]);
+            assert_eq!(addr_port.ip(), test.want_addr);
+            assert_eq!(addr_port.port(), test.want_port);
+        }
+    }
+
+    #[test]
+    fn test_parse_binding_request() {
+        let tx = TransactionId::default();
+        let req = request(tx);
+        assert!(is(&req));
+        let got_tx = parse_binding_request(&req).unwrap();
+        assert_eq!(got_tx, tx);
+    }
+
+    #[test]
+    fn test_stun_cookie() {
+        assert_eq!(stun_rs::MAGIC_COOKIE, COOKIE);
+    }
+
+    #[test]
+    fn test_response() {
+        let txn = |n| TransactionId::from([n; 12]);
+
+        struct Case {
+            tx: TransactionId,
+            addr: IpAddr,
+            port: u16,
+        }
+        let tests = vec![
+            Case {
+                tx: txn(1),
+                addr: "1.2.3.4".parse().unwrap(),
+                port: 254,
+            },
+            Case {
+                tx: txn(2),
+                addr: "1.2.3.4".parse().unwrap(),
+                port: 257,
+            },
+            Case {
+                tx: txn(3),
+                addr: "1::4".parse().unwrap(),
+                port: 254,
+            },
+            Case {
+                tx: txn(4),
+                addr: "1::4".parse().unwrap(),
+                port: 257,
+            },
+        ];
+
+        for tt in tests {
+            let res = response(tt.tx, SocketAddr::new(tt.addr, tt.port));
+            assert!(is(&res));
+            let (tx2, addr2) = parse_response(&res).unwrap();
+            assert_eq!(tt.tx, tx2);
+            assert_eq!(tt.addr, addr2.ip());
+            assert_eq!(tt.port, addr2.port());
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/quic.rs.html b/pr/2992/docs/src/iroh_relay/quic.rs.html new file mode 100644 index 0000000000..3737d2ac2a --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/quic.rs.html @@ -0,0 +1,633 @@ +quic.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+
//! Create a QUIC server that accepts connections
+//! for QUIC address discovery.
+use std::{net::SocketAddr, sync::Arc};
+
+use anyhow::Result;
+use quinn::{crypto::rustls::QuicClientConfig, VarInt};
+
+/// ALPN for our quic addr discovery
+pub const ALPN_QUIC_ADDR_DISC: &[u8] = b"/iroh-qad/0";
+/// Endpoint close error code
+pub const QUIC_ADDR_DISC_CLOSE_CODE: VarInt = VarInt::from_u32(1);
+/// Endpoint close reason
+pub const QUIC_ADDR_DISC_CLOSE_REASON: &[u8] = b"finished";
+
+#[cfg(feature = "server")]
+pub(crate) mod server {
+    use quinn::{crypto::rustls::QuicServerConfig, ApplicationClose};
+    use tokio::task::JoinSet;
+    use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
+    use tracing::{debug, info, info_span, Instrument};
+
+    use super::*;
+    pub use crate::server::QuicConfig;
+
+    pub struct QuicServer {
+        bind_addr: SocketAddr,
+        cancel: CancellationToken,
+        handle: AbortOnDropHandle<()>,
+    }
+
+    impl QuicServer {
+        /// Returns a handle for this server.
+        ///
+        /// The server runs in the background as several async tasks.  This allows controlling
+        /// the server, in particular it allows gracefully shutting down the server.
+        pub fn handle(&self) -> ServerHandle {
+            ServerHandle {
+                cancel_token: self.cancel.clone(),
+            }
+        }
+
+        /// Returns the [`AbortOnDropHandle`] for the supervisor task managing the endpoint.
+        ///
+        /// This is the root of all the tasks for the QUIC address discovery service.  Aborting it will abort all the
+        /// other tasks for the service.  Awaiting it will complete when all the service tasks are
+        /// completed.[]
+        pub fn task_handle(&mut self) -> &mut AbortOnDropHandle<()> {
+            &mut self.handle
+        }
+
+        /// Returns the socket address for this QUIC server.
+        pub fn bind_addr(&self) -> SocketAddr {
+            self.bind_addr
+        }
+
+        /// Spawns a QUIC server that creates and QUIC endpoint and listens
+        /// for QUIC connections for address discovery
+        ///
+        /// # Errors
+        /// If the given `quic_config` contains a [`rustls::ServerConfig`] that cannot
+        /// be converted to a [`QuicServerConfig`], usually because it does not support
+        /// TLS 1.3, this method will error.
+        ///
+        /// # Panics
+        /// If there is a panic during a connection, it will be propagated
+        /// up here. Any other errors in a connection will be logged as a
+        ///  warning.
+        pub(crate) fn spawn(mut quic_config: QuicConfig) -> Result<Self> {
+            quic_config.server_config.alpn_protocols =
+                vec![crate::quic::ALPN_QUIC_ADDR_DISC.to_vec()];
+            let server_config = QuicServerConfig::try_from(quic_config.server_config)?;
+            let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(server_config));
+            let transport_config = Arc::get_mut(&mut server_config.transport).unwrap();
+            transport_config
+                .max_concurrent_uni_streams(0_u8.into())
+                .max_concurrent_bidi_streams(0_u8.into())
+                // enable sending quic address discovery frames
+                .send_observed_address_reports(true);
+
+            let endpoint = quinn::Endpoint::server(server_config, quic_config.bind_addr)?;
+            let bind_addr = endpoint.local_addr()?;
+
+            info!(?bind_addr, "QUIC server listening on");
+
+            let cancel = CancellationToken::new();
+            let cancel_accept_loop = cancel.clone();
+
+            let task = tokio::task::spawn(
+                async move {
+                    let mut set = JoinSet::new();
+                    debug!("waiting for connections...");
+                    loop {
+                        tokio::select! {
+                            biased;
+                            _ = cancel_accept_loop.cancelled() => {
+                                break;
+                            }
+                            Some(res) = set.join_next(), if !set.is_empty() => {
+                                if let Err(err) = res {
+                                    if err.is_panic() {
+                                        panic!("task panicked: {err:#?}");
+                                    } else {
+                                        debug!("error accepting incoming connection: {err:#?}");
+                                    }
+                                }
+                            }
+                            res = endpoint.accept() => match res {
+                                Some(conn) => {
+                                     debug!("accepting connection");
+                                     let remote_addr = conn.remote_address();
+                                     set.spawn(
+                                         handle_connection(conn).instrument(info_span!("qad-conn", %remote_addr))
+                                     );                                }
+                                None => {
+                                    debug!("endpoint closed");
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    // close all connections and wait until they have all grace
+                    // fully closed.
+                    endpoint.close(QUIC_ADDR_DISC_CLOSE_CODE, QUIC_ADDR_DISC_CLOSE_REASON);
+                    endpoint.wait_idle().await;
+
+                    // all tasks should be closed, since the endpoint has shutdown
+                    // all connections, but await to ensure they are finished.
+                    set.abort_all();
+                    while !set.is_empty() {
+                        _ = set.join_next().await;
+                    }
+
+                    debug!("quic endpoint has been shutdown.");
+                }
+                .instrument(info_span!("quic-endpoint")),
+            );
+            Ok(Self {
+                bind_addr,
+                cancel,
+                handle: AbortOnDropHandle::new(task),
+            })
+        }
+
+        /// Closes the underlying QUIC endpoint and the tasks running the
+        /// QUIC connections.
+        pub async fn shutdown(mut self) -> Result<()> {
+            self.cancel.cancel();
+            if !self.task_handle().is_finished() {
+                self.task_handle().await?
+            }
+            Ok(())
+        }
+    }
+
+    /// A handle for the Server side of QUIC address discovery.
+    ///
+    /// This does not allow access to the task but can communicate with it.
+    #[derive(Debug, Clone)]
+    pub struct ServerHandle {
+        cancel_token: CancellationToken,
+    }
+
+    impl ServerHandle {
+        /// Gracefully shut down the quic endpoint.
+        pub fn shutdown(&self) {
+            self.cancel_token.cancel()
+        }
+    }
+
+    /// Handle the connection from the client.
+    async fn handle_connection(incoming: quinn::Incoming) -> Result<()> {
+        let connection = match incoming.await {
+            Ok(conn) => conn,
+            Err(e) => {
+                return Err(e.into());
+            }
+        };
+        debug!("established");
+        // wait for the client to close the connection
+        let connection_err = connection.closed().await;
+        match connection_err {
+            quinn::ConnectionError::ApplicationClosed(ApplicationClose { error_code, .. })
+                if error_code == QUIC_ADDR_DISC_CLOSE_CODE =>
+            {
+                Ok(())
+            }
+            _ => Err(connection_err.into()),
+        }
+    }
+}
+
+/// Handles the client side of QUIC address discovery.
+#[derive(Debug)]
+pub struct QuicClient {
+    /// A QUIC Endpoint.
+    ep: quinn::Endpoint,
+    /// A client config.
+    client_config: quinn::ClientConfig,
+}
+
+impl QuicClient {
+    /// Create a new QuicClient to handle the client side of QUIC
+    /// address discovery.
+    pub fn new(ep: quinn::Endpoint, mut client_config: rustls::ClientConfig) -> Result<Self> {
+        // add QAD alpn
+        client_config.alpn_protocols = vec![ALPN_QUIC_ADDR_DISC.into()];
+        // go from rustls client config to rustls QUIC specific client config to
+        // a quinn client config
+        let mut client_config =
+            quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(client_config)?));
+
+        // enable the receive side of address discovery
+        let mut transport = quinn_proto::TransportConfig::default();
+        transport.receive_observed_address_reports(true);
+        client_config.transport_config(Arc::new(transport));
+
+        Ok(Self { ep, client_config })
+    }
+
+    /// Client side of QUIC address discovery.
+    ///
+    /// Creates a connection and returns the observed address
+    /// and estimated latency of the connection.
+    ///
+    /// Consumes and gracefully closes the connection.
+    pub async fn get_addr_and_latency(
+        &self,
+        server_addr: SocketAddr,
+        host: &str,
+    ) -> Result<(SocketAddr, std::time::Duration)> {
+        let connecting = self
+            .ep
+            .connect_with(self.client_config.clone(), server_addr, host);
+        let conn = connecting?.await?;
+        let mut external_addresses = conn.observed_external_addr();
+        // TODO(ramfox): I'd like to be able to cancel this so we can close cleanly
+        // if there the task that runs this function gets aborted.
+        // tokio::select! {
+        //     _ = cancel.cancelled() => {
+        //         conn.close(QUIC_ADDR_DISC_CLOSE_CODE, QUIC_ADDR_DISC_CLOSE_REASON);
+        //         anyhow::bail!("QUIC address discovery canceled early");
+        //     },
+        //     res = external_addresses.wait_for(|addr| addr.is_some()) => {
+        //         let addr = res?.expect("checked");
+        //         let latency = conn.rtt() / 2;
+        //         // gracefully close the connections
+        //         conn.close(QUIC_ADDR_DISC_CLOSE_CODE, QUIC_ADDR_DISC_CLOSE_REASON);
+        //         Ok((addr, latency))
+        //     }
+
+        let res = match external_addresses.wait_for(|addr| addr.is_some()).await {
+            Ok(res) => res,
+            Err(err) => {
+                // attempt to gracefully close the connections
+                conn.close(QUIC_ADDR_DISC_CLOSE_CODE, QUIC_ADDR_DISC_CLOSE_REASON);
+                return Err(err.into());
+            }
+        };
+        let mut observed_addr = res.expect("checked");
+        // if we've sent to an ipv4 address, but received an observed address
+        // that is ivp6 then the address is an [IPv4-Mapped IPv6 Addresses](https://doc.rust-lang.org/beta/std/net/struct.Ipv6Addr.html#ipv4-mapped-ipv6-addresses)
+        if server_addr.is_ipv4() && observed_addr.is_ipv6() {
+            observed_addr =
+                SocketAddr::new(observed_addr.ip().to_canonical(), observed_addr.port());
+        }
+        let latency = conn.rtt() / 2;
+        // gracefully close the connections
+        conn.close(QUIC_ADDR_DISC_CLOSE_CODE, QUIC_ADDR_DISC_CLOSE_REASON);
+        Ok((observed_addr, latency))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::Ipv4Addr;
+
+    use super::{
+        server::{QuicConfig, QuicServer},
+        *,
+    };
+
+    #[tokio::test]
+    async fn quic_endpoint_basic() -> anyhow::Result<()> {
+        let host: Ipv4Addr = "127.0.0.1".parse()?;
+        let _guard = iroh_test::logging::setup();
+
+        // create a server config with self signed certificates
+        let (_, server_config) = super::super::server::testing::self_signed_tls_certs_and_config();
+        let bind_addr = SocketAddr::new(host.into(), 0);
+        let quic_server = QuicServer::spawn(QuicConfig {
+            server_config,
+            bind_addr,
+        })?;
+
+        // create a client-side endpoint
+        let client_endpoint = quinn::Endpoint::client(SocketAddr::new(host.into(), 0))?;
+        let client_addr = client_endpoint.local_addr()?;
+
+        // create the client configuration used for the client endpoint when they
+        // initiate a connection with the server
+        let client_config = crate::client::make_dangerous_client_config();
+        let quic_client = QuicClient::new(client_endpoint.clone(), client_config)?;
+
+        let (addr, _latency) = quic_client
+            .get_addr_and_latency(quic_server.bind_addr(), &host.to_string())
+            .await?;
+
+        // wait until the endpoint delivers the closing message to the server
+        client_endpoint.wait_idle().await;
+        // shut down the quic server
+        quic_server.shutdown().await?;
+
+        assert_eq!(client_addr, addr);
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server.rs.html b/pr/2992/docs/src/iroh_relay/server.rs.html new file mode 100644 index 0000000000..1ce1c7ab90 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server.rs.html @@ -0,0 +1,2207 @@ +server.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+
//! A fully-fledged iroh-relay server over HTTP or HTTPS.
+//!
+//! This module provides an API to run a full fledged iroh-relay server.  It is primarily
+//! used by the `iroh-relay` binary in this crate.  It can be used to run a relay server in
+//! other locations however.
+//!
+//! This code is fully written in a form of structured-concurrency: every spawned task is
+//! always attached to a handle and when the handle is dropped the tasks abort.  So tasks
+//! can not outlive their handle.  It is also always possible to await for completion of a
+//! task.  Some tasks additionally have a method to do graceful shutdown.
+//!
+//! The relay server hosts the following services:
+//!
+//! - HTTPS `/relay`: The main URL endpoint to which clients connect and sends traffic over.
+//! - HTTPS `/ping`: Used for net_report probes.
+//! - HTTPS `/generate_204`: Used for net_report probes.
+//! - STUN: UDP port for STUN requests/responses.
+
+use std::{fmt, future::Future, net::SocketAddr, num::NonZeroU32, pin::Pin, sync::Arc};
+
+use anyhow::{anyhow, bail, Context, Result};
+use derive_more::Debug;
+use futures_lite::StreamExt;
+use http::{
+    response::Builder as ResponseBuilder, HeaderMap, Method, Request, Response, StatusCode,
+};
+use hyper::body::Incoming;
+#[cfg(feature = "test-utils")]
+use iroh_base::node_addr::RelayUrl;
+use iroh_metrics::inc;
+use tokio::{
+    net::{TcpListener, UdpSocket},
+    task::JoinSet,
+};
+use tokio_util::task::AbortOnDropHandle;
+use tracing::{debug, error, info, info_span, instrument, trace, warn, Instrument};
+
+use crate::{
+    http::RELAY_PROBE_PATH,
+    protos,
+    quic::server::{QuicServer, ServerHandle as QuicServerHandle},
+};
+
+pub(crate) mod actor;
+pub(crate) mod client_conn;
+mod clients;
+mod http_server;
+mod metrics;
+pub(crate) mod streams;
+#[cfg(feature = "test-utils")]
+pub mod testing;
+
+pub use self::{
+    metrics::{Metrics, StunMetrics},
+    streams::MaybeTlsStream as MaybeTlsStreamServer,
+};
+
+const NO_CONTENT_CHALLENGE_HEADER: &str = "X-Tailscale-Challenge";
+const NO_CONTENT_RESPONSE_HEADER: &str = "X-Tailscale-Response";
+const NOTFOUND: &[u8] = b"Not Found";
+const ROBOTS_TXT: &[u8] = b"User-agent: *\nDisallow: /\n";
+const INDEX: &[u8] = br#"<html><body>
+<h1>Iroh Relay</h1>
+<p>
+  This is an <a href="https://iroh.computer/">Iroh</a> Relay server.
+</p>
+"#;
+const TLS_HEADERS: [(&str, &str); 2] = [
+    ("Strict-Transport-Security", "max-age=63072000; includeSubDomains"),
+    ("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'; form-action 'none'; base-uri 'self'; block-all-mixed-content; plugin-types 'none'")
+];
+
+type BytesBody = http_body_util::Full<hyper::body::Bytes>;
+type HyperError = Box<dyn std::error::Error + Send + Sync>;
+type HyperResult<T> = std::result::Result<T, HyperError>;
+
+/// Creates a new [`BytesBody`] with no content.
+fn body_empty() -> BytesBody {
+    http_body_util::Full::new(hyper::body::Bytes::new())
+}
+
+/// Configuration for the full Relay & STUN server.
+///
+/// Be aware the generic parameters are for when using the Let's Encrypt TLS configuration.
+/// If not used dummy ones need to be provided, e.g. `ServerConfig::<(), ()>::default()`.
+#[derive(Debug, Default)]
+pub struct ServerConfig<EC: fmt::Debug, EA: fmt::Debug = EC> {
+    /// Configuration for the Relay server, disabled if `None`.
+    pub relay: Option<RelayConfig<EC, EA>>,
+    /// Configuration for the STUN server, disabled if `None`.
+    pub stun: Option<StunConfig>,
+    /// Configuration for the QUIC server, disabled if `None`.
+    pub quic: Option<QuicConfig>,
+    /// Socket to serve metrics on.
+    #[cfg(feature = "metrics")]
+    #[cfg_attr(iroh_docsrs, doc(cfg(feature = "metrics")))]
+    pub metrics_addr: Option<SocketAddr>,
+}
+
+/// Configuration for the Relay HTTP and HTTPS server.
+///
+/// This includes the HTTP services hosted by the Relay server, the Relay `/relay` HTTP
+/// endpoint is only one of the services served.
+#[derive(Debug)]
+pub struct RelayConfig<EC: fmt::Debug, EA: fmt::Debug = EC> {
+    /// The socket address on which the Relay HTTP server should bind.
+    ///
+    /// Normally you'd choose port `80`.  The bind address for the HTTPS server is
+    /// configured in [`RelayConfig::tls`].
+    ///
+    /// If [`RelayConfig::tls`] is `None` then this serves all the HTTP services without
+    /// TLS.
+    pub http_bind_addr: SocketAddr,
+    /// TLS configuration for the HTTPS server.
+    ///
+    /// If *None* all the HTTP services that would be served here are served from
+    /// [`RelayConfig::http_bind_addr`].
+    pub tls: Option<TlsConfig<EC, EA>>,
+    /// Rate limits.
+    pub limits: Limits,
+}
+
+/// Configuration for the STUN server.
+#[derive(Debug)]
+pub struct StunConfig {
+    /// The socket address on which the STUN server should bind.
+    ///
+    /// Normally you'd chose port `3478`, see [`crate::defaults::DEFAULT_STUN_PORT`].
+    pub bind_addr: SocketAddr,
+}
+
+/// Configuration for the QUIC server.
+#[derive(Debug)]
+pub struct QuicConfig {
+    /// The socket address on which the QUIC server should bind.
+    ///
+    /// Normally you'd chose port `7842`, see [`crate::defaults::DEFAULT_RELAY_QUIC_PORT`].
+    pub bind_addr: SocketAddr,
+    /// The TLS server configuration for the QUIC server.
+    ///
+    /// If this [`rustls::ServerConfig`] does not support TLS 1.3, the QUIC server will fail
+    /// to spawn.
+    pub server_config: rustls::ServerConfig,
+}
+
+/// TLS configuration for Relay server.
+///
+/// Normally the Relay server accepts connections on both HTTPS and HTTP.
+#[derive(Debug)]
+pub struct TlsConfig<EC: fmt::Debug, EA: fmt::Debug = EC> {
+    /// The socket address on which to serve the HTTPS server.
+    ///
+    /// Since the captive portal probe has to run over plain text HTTP and TLS is used for
+    /// the main relay server this has to be on a different port.  When TLS is not enabled
+    /// this is served on the [`RelayConfig::http_bind_addr`] socket address.
+    ///
+    /// Normally you'd choose port `80`.
+    pub https_bind_addr: SocketAddr,
+    /// The socket address on which to server the QUIC server is QUIC is enabled.
+    pub quic_bind_addr: SocketAddr,
+    /// Mode for getting a cert.
+    pub cert: CertConfig<EC, EA>,
+    /// The server configuration.
+    pub server_config: rustls::ServerConfig,
+}
+
+/// Rate limits.
+// TODO: accept_conn_limit and accept_conn_burst are not currently implemented.
+#[derive(Debug, Default)]
+pub struct Limits {
+    /// Rate limit for accepting new connection. Unlimited if not set.
+    pub accept_conn_limit: Option<f64>,
+    /// Burst limit for accepting new connection. Unlimited if not set.
+    pub accept_conn_burst: Option<usize>,
+    /// Rate limits for incoming traffic from a client connection.
+    pub client_rx: Option<ClientConnRateLimit>,
+}
+
+/// Per-client rate limit configuration.
+#[derive(Debug, Copy, Clone)]
+pub struct ClientConnRateLimit {
+    /// Max number of bytes per second to read from the client connection.
+    pub bytes_per_second: NonZeroU32,
+    /// Max number of bytes to read in a single burst.
+    pub max_burst_bytes: Option<NonZeroU32>,
+}
+
+/// TLS certificate configuration.
+#[derive(derive_more::Debug)]
+pub enum CertConfig<EC: fmt::Debug, EA: fmt::Debug = EC> {
+    /// Use Let's Encrypt.
+    LetsEncrypt {
+        /// State for Let's Encrypt certificates.
+        #[debug("AcmeConfig")]
+        state: tokio_rustls_acme::AcmeState<EC, EA>,
+    },
+    /// Use a static TLS key and certificate chain.
+    Manual {
+        /// The TLS certificate chain.
+        certs: Vec<rustls::pki_types::CertificateDer<'static>>,
+    },
+}
+
+/// A running Relay + STUN server.
+///
+/// This is a full Relay server, including STUN, Relay and various associated HTTP services.
+///
+/// Dropping this will stop the server.
+#[derive(Debug)]
+pub struct Server {
+    /// The address of the HTTP server, if configured.
+    http_addr: Option<SocketAddr>,
+    /// The address of the STUN server, if configured.
+    stun_addr: Option<SocketAddr>,
+    /// The address of the HTTPS server, if the relay server is using TLS.
+    ///
+    /// If the Relay server is not using TLS then it is served from the
+    /// [`Server::http_addr`].
+    https_addr: Option<SocketAddr>,
+    /// The address of the QUIC server, if configured.
+    quic_addr: Option<SocketAddr>,
+    /// Handle to the relay server.
+    relay_handle: Option<http_server::ServerHandle>,
+    /// Handle to the quic server.
+    quic_handle: Option<QuicServerHandle>,
+    /// The main task running the server.
+    supervisor: AbortOnDropHandle<Result<()>>,
+    /// The certificate for the server.
+    ///
+    /// If the server has manual certificates configured the certificate chain will be
+    /// available here, this can be used by a client to authenticate the server.
+    certificates: Option<Vec<rustls::pki_types::CertificateDer<'static>>>,
+}
+
+impl Server {
+    /// Starts the server.
+    pub async fn spawn<EC, EA>(config: ServerConfig<EC, EA>) -> Result<Self>
+    where
+        EC: fmt::Debug + 'static,
+        EA: fmt::Debug + 'static,
+    {
+        let mut tasks = JoinSet::new();
+
+        #[cfg(feature = "metrics")]
+        if let Some(addr) = config.metrics_addr {
+            debug!("Starting metrics server");
+            use iroh_metrics::core::Metric;
+
+            iroh_metrics::core::Core::init(|reg, metrics| {
+                metrics.insert(metrics::Metrics::new(reg));
+                metrics.insert(StunMetrics::new(reg));
+            });
+            tasks.spawn(
+                iroh_metrics::metrics::start_metrics_server(addr)
+                    .instrument(info_span!("metrics-server")),
+            );
+        }
+
+        // Start the STUN server.
+        let stun_addr = match config.stun {
+            Some(stun) => {
+                debug!("Starting STUN server");
+                match UdpSocket::bind(stun.bind_addr).await {
+                    Ok(sock) => {
+                        let addr = sock.local_addr()?;
+                        info!("STUN server listening on {addr}");
+                        tasks.spawn(
+                            server_stun_listener(sock).instrument(info_span!("stun-server", %addr)),
+                        );
+                        Some(addr)
+                    }
+                    Err(err) => bail!("failed to bind STUN listener: {err:#?}"),
+                }
+            }
+            None => None,
+        };
+
+        // Start the Relay server, but first clone the certs out.
+        let certificates = config.relay.as_ref().and_then(|relay| {
+            relay.tls.as_ref().and_then(|tls| match tls.cert {
+                CertConfig::LetsEncrypt { .. } => None,
+                CertConfig::Manual { ref certs, .. } => Some(certs.clone()),
+            })
+        });
+
+        let quic_server = match config.quic {
+            Some(quic_config) => {
+                debug!("Starting QUIC server {}", quic_config.bind_addr);
+                Some(QuicServer::spawn(quic_config)?)
+            }
+            None => None,
+        };
+        let quic_addr = quic_server.as_ref().map(|srv| srv.bind_addr());
+        let quic_handle = quic_server.as_ref().map(|srv| srv.handle());
+
+        let (relay_server, http_addr) = match config.relay {
+            Some(relay_config) => {
+                debug!("Starting Relay server");
+                let mut headers = HeaderMap::new();
+                for (name, value) in TLS_HEADERS.iter() {
+                    headers.insert(*name, value.parse()?);
+                }
+                let relay_bind_addr = match relay_config.tls {
+                    Some(ref tls) => tls.https_bind_addr,
+                    None => relay_config.http_bind_addr,
+                };
+                let mut builder = http_server::ServerBuilder::new(relay_bind_addr)
+                    .headers(headers)
+                    .request_handler(Method::GET, "/", Box::new(root_handler))
+                    .request_handler(Method::GET, "/index.html", Box::new(root_handler))
+                    .request_handler(Method::GET, RELAY_PROBE_PATH, Box::new(probe_handler))
+                    .request_handler(Method::GET, "/robots.txt", Box::new(robots_handler));
+                if let Some(cfg) = relay_config.limits.client_rx {
+                    builder = builder.client_rx_ratelimit(cfg);
+                }
+                let http_addr = match relay_config.tls {
+                    Some(tls_config) => {
+                        let server_tls_config = match tls_config.cert {
+                            CertConfig::LetsEncrypt { mut state } => {
+                                let acceptor =
+                                    http_server::TlsAcceptor::LetsEncrypt(state.acceptor());
+                                tasks.spawn(
+                                    async move {
+                                        while let Some(event) = state.next().await {
+                                            match event {
+                                                Ok(ok) => debug!("acme event: {ok:?}"),
+                                                Err(err) => error!("error: {err:?}"),
+                                            }
+                                        }
+                                        Err(anyhow!("acme event stream finished"))
+                                    }
+                                    .instrument(info_span!("acme")),
+                                );
+                                Some(http_server::TlsConfig {
+                                    config: Arc::new(tls_config.server_config),
+                                    acceptor,
+                                })
+                            }
+                            CertConfig::Manual { .. } => {
+                                let server_config = Arc::new(tls_config.server_config);
+                                let acceptor =
+                                    tokio_rustls::TlsAcceptor::from(server_config.clone());
+                                let acceptor = http_server::TlsAcceptor::Manual(acceptor);
+                                Some(http_server::TlsConfig {
+                                    config: server_config,
+                                    acceptor,
+                                })
+                            }
+                        };
+                        builder = builder.tls_config(server_tls_config);
+
+                        // Some services always need to be served over HTTP without TLS.  Run
+                        // these standalone.
+                        let http_listener = TcpListener::bind(&relay_config.http_bind_addr)
+                            .await
+                            .context("failed to bind http")?;
+                        let http_addr = http_listener.local_addr()?;
+                        tasks.spawn(
+                            run_captive_portal_service(http_listener)
+                                .instrument(info_span!("http-service", addr = %http_addr)),
+                        );
+                        Some(http_addr)
+                    }
+                    None => {
+                        // If running Relay without TLS add the plain HTTP server directly
+                        // to the Relay server.
+                        builder = builder.request_handler(
+                            Method::GET,
+                            "/generate_204",
+                            Box::new(serve_no_content_handler),
+                        );
+                        None
+                    }
+                };
+                let relay_server = builder.spawn().await?;
+                (Some(relay_server), http_addr)
+            }
+            None => (None, None),
+        };
+        // If http_addr is Some then relay_server is serving HTTPS.  If http_addr is None
+        // relay_server is serving HTTP, including the /generate_204 service.
+        let relay_addr = relay_server.as_ref().map(|srv| srv.addr());
+        let relay_handle = relay_server.as_ref().map(|srv| srv.handle());
+        let task = tokio::spawn(relay_supervisor(tasks, relay_server, quic_server));
+
+        Ok(Self {
+            http_addr: http_addr.or(relay_addr),
+            stun_addr,
+            https_addr: http_addr.and(relay_addr),
+            quic_addr,
+            relay_handle,
+            quic_handle,
+            supervisor: AbortOnDropHandle::new(task),
+            certificates,
+        })
+    }
+
+    /// Requests graceful shutdown.
+    ///
+    /// Returns once all server tasks have stopped.
+    pub async fn shutdown(self) -> Result<()> {
+        // Only the Relay server and QUIC server need shutting down, the supervisor will abort the tasks in
+        // the JoinSet when the server terminates.
+        if let Some(handle) = self.relay_handle {
+            handle.shutdown();
+        }
+        if let Some(handle) = self.quic_handle {
+            handle.shutdown();
+        }
+        self.supervisor.await?
+    }
+
+    /// Returns the handle for the task.
+    ///
+    /// This allows waiting for the server's supervisor task to finish.  Can be useful in
+    /// case there is an error in the server before it is shut down.
+    pub fn task_handle(&mut self) -> &mut AbortOnDropHandle<Result<()>> {
+        &mut self.supervisor
+    }
+
+    /// The socket address the HTTPS server is listening on.
+    pub fn https_addr(&self) -> Option<SocketAddr> {
+        self.https_addr
+    }
+
+    /// The socket address the HTTP server is listening on.
+    pub fn http_addr(&self) -> Option<SocketAddr> {
+        self.http_addr
+    }
+
+    /// The socket address the QUIC server is listening on.
+    pub fn quic_addr(&self) -> Option<SocketAddr> {
+        self.quic_addr
+    }
+
+    /// The socket address the STUN server is listening on.
+    pub fn stun_addr(&self) -> Option<SocketAddr> {
+        self.stun_addr
+    }
+
+    /// The certificates chain if configured with manual TLS certificates.
+    pub fn certificates(&self) -> Option<Vec<rustls::pki_types::CertificateDer<'static>>> {
+        self.certificates.clone()
+    }
+
+    /// Get the server's https [`RelayUrl`].
+    ///
+    /// This uses [`Self::https_addr`] so it's mostly useful for local development.
+    #[cfg(feature = "test-utils")]
+    pub fn https_url(&self) -> Option<RelayUrl> {
+        self.https_addr.map(|addr| {
+            url::Url::parse(&format!("https://{addr}"))
+                .expect("valid url")
+                .into()
+        })
+    }
+
+    /// Get the server's http [`RelayUrl`].
+    ///
+    /// This uses [`Self::http_addr`] so it's mostly useful for local development.
+    #[cfg(feature = "test-utils")]
+    pub fn http_url(&self) -> Option<RelayUrl> {
+        self.http_addr.map(|addr| {
+            url::Url::parse(&format!("http://{addr}"))
+                .expect("valid url")
+                .into()
+        })
+    }
+}
+
+/// Supervisor for the relay server tasks.
+///
+/// As soon as one of the tasks exits, all other tasks are stopped and the server stops.
+/// The supervisor finishes once all tasks are finished.
+#[instrument(skip_all)]
+async fn relay_supervisor(
+    mut tasks: JoinSet<Result<()>>,
+    mut relay_http_server: Option<http_server::Server>,
+    mut quic_server: Option<QuicServer>,
+) -> Result<()> {
+    let quic_enabled = quic_server.is_some();
+    let mut quic_fut = match quic_server {
+        Some(ref mut server) => futures_util::future::Either::Left(server.task_handle()),
+        None => futures_util::future::Either::Right(futures_lite::future::pending()),
+    };
+    let relay_enabled = relay_http_server.is_some();
+    let mut relay_fut = match relay_http_server {
+        Some(ref mut server) => futures_util::future::Either::Left(server.task_handle()),
+        None => futures_util::future::Either::Right(futures_lite::future::pending()),
+    };
+    let res = tokio::select! {
+        biased;
+        ret = tasks.join_next(), if !tasks.is_empty() => ret.expect("checked"),
+        ret = &mut quic_fut, if quic_enabled => ret.map(anyhow::Ok),
+        ret = &mut relay_fut, if relay_enabled => ret.map(anyhow::Ok),
+        else => Ok(Err(anyhow!("No relay services are enabled."))),
+    };
+    let ret = match res {
+        Ok(Ok(())) => {
+            debug!("Task exited");
+            Ok(())
+        }
+        Ok(Err(err)) => {
+            error!(%err, "Task failed");
+            Err(err.context("task failed"))
+        }
+        Err(err) => {
+            if let Ok(panic) = err.try_into_panic() {
+                error!("Task panicked");
+                std::panic::resume_unwind(panic);
+            }
+            debug!("Task cancelled");
+            Err(anyhow!("task cancelled"))
+        }
+    };
+
+    // Ensure the HTTP server terminated, there is no harm in calling this after it is
+    // already shut down.
+    if let Some(server) = relay_http_server {
+        server.shutdown();
+    }
+
+    // Ensure the QUIC server is closed
+    if let Some(server) = quic_server {
+        server.shutdown().await?;
+    }
+
+    // Stop all remaining tasks
+    tasks.shutdown().await;
+
+    ret
+}
+
+/// Runs a STUN server.
+///
+/// When the future is dropped, the server stops.
+async fn server_stun_listener(sock: UdpSocket) -> Result<()> {
+    info!(addr = ?sock.local_addr().ok(), "running STUN server");
+    let sock = Arc::new(sock);
+    let mut buffer = vec![0u8; 64 << 10];
+    let mut tasks = JoinSet::new();
+    loop {
+        tokio::select! {
+            biased;
+
+            Some(res) = tasks.join_next(), if !tasks.is_empty() => {
+                if let Err(err) = res {
+                    if err.is_panic() {
+                        panic!("task panicked: {:#?}", err);
+                    }
+                }
+            }
+            res = sock.recv_from(&mut buffer) => {
+                match res {
+                    Ok((n, src_addr)) => {
+                        inc!(StunMetrics, requests);
+                        let pkt = &buffer[..n];
+                        if !protos::stun::is(pkt) {
+                            debug!(%src_addr, "STUN: ignoring non stun packet");
+                            inc!(StunMetrics, bad_requests);
+                            continue;
+                        }
+                        let pkt = pkt.to_vec();
+                        tasks.spawn(handle_stun_request(src_addr, pkt, sock.clone()));
+                    }
+                    Err(err) => {
+                        inc!(StunMetrics, failures);
+                        warn!("failed to recv: {err:#}");
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Handles a single STUN request, doing all logging required.
+async fn handle_stun_request(src_addr: SocketAddr, pkt: Vec<u8>, sock: Arc<UdpSocket>) {
+    let (txid, response) = match protos::stun::parse_binding_request(&pkt) {
+        Ok(txid) => {
+            debug!(%src_addr, %txid, "STUN: received binding request");
+            (txid, protos::stun::response(txid, src_addr))
+        }
+        Err(err) => {
+            inc!(StunMetrics, bad_requests);
+            warn!(%src_addr, "STUN: invalid binding request: {:?}", err);
+            return;
+        }
+    };
+
+    match sock.send_to(&response, src_addr).await {
+        Ok(len) => {
+            if len != response.len() {
+                warn!(
+                    %src_addr,
+                    %txid,
+                    "failed to write response, {len}/{} bytes sent",
+                    response.len()
+                );
+            } else {
+                match src_addr {
+                    SocketAddr::V4(_) => inc!(StunMetrics, ipv4_success),
+                    SocketAddr::V6(_) => inc!(StunMetrics, ipv6_success),
+                }
+            }
+            trace!(%src_addr, %txid, "sent {len} bytes");
+        }
+        Err(err) => {
+            inc!(StunMetrics, failures);
+            warn!(%src_addr, %txid, "failed to write response: {err:#}");
+        }
+    }
+}
+
+fn root_handler(
+    _r: Request<Incoming>,
+    response: ResponseBuilder,
+) -> HyperResult<Response<BytesBody>> {
+    response
+        .status(StatusCode::OK)
+        .header("Content-Type", "text/html; charset=utf-8")
+        .body(INDEX.into())
+        .map_err(|err| Box::new(err) as HyperError)
+}
+
+/// HTTP latency queries
+fn probe_handler(
+    _r: Request<Incoming>,
+    response: ResponseBuilder,
+) -> HyperResult<Response<BytesBody>> {
+    response
+        .status(StatusCode::OK)
+        .header("Access-Control-Allow-Origin", "*")
+        .body(body_empty())
+        .map_err(|err| Box::new(err) as HyperError)
+}
+
+fn robots_handler(
+    _r: Request<Incoming>,
+    response: ResponseBuilder,
+) -> HyperResult<Response<BytesBody>> {
+    response
+        .status(StatusCode::OK)
+        .body(ROBOTS_TXT.into())
+        .map_err(|err| Box::new(err) as HyperError)
+}
+
+/// For captive portal detection.
+fn serve_no_content_handler<B: hyper::body::Body>(
+    r: Request<B>,
+    mut response: ResponseBuilder,
+) -> HyperResult<Response<BytesBody>> {
+    if let Some(challenge) = r.headers().get(NO_CONTENT_CHALLENGE_HEADER) {
+        if !challenge.is_empty()
+            && challenge.len() < 64
+            && challenge
+                .as_bytes()
+                .iter()
+                .all(|c| is_challenge_char(*c as char))
+        {
+            response = response.header(
+                NO_CONTENT_RESPONSE_HEADER,
+                format!("response {}", challenge.to_str()?),
+            );
+        }
+    }
+
+    response
+        .status(StatusCode::NO_CONTENT)
+        .body(body_empty())
+        .map_err(|err| Box::new(err) as HyperError)
+}
+
+fn is_challenge_char(c: char) -> bool {
+    // Semi-randomly chosen as a limited set of valid characters
+    c.is_ascii_lowercase()
+        || c.is_ascii_uppercase()
+        || c.is_ascii_digit()
+        || c == '.'
+        || c == '-'
+        || c == '_'
+}
+
+/// This is a future that never returns, drop it to cancel/abort.
+async fn run_captive_portal_service(http_listener: TcpListener) -> Result<()> {
+    info!("serving");
+
+    // If this future is cancelled, this is dropped and all tasks are aborted.
+    let mut tasks = JoinSet::new();
+
+    loop {
+        tokio::select! {
+            biased;
+
+            Some(res) = tasks.join_next(), if !tasks.is_empty() => {
+                if let Err(err) = res {
+                    if err.is_panic() {
+                        panic!("task panicked: {:#?}", err);
+                    }
+                }
+            }
+
+            res = http_listener.accept() => {
+                match res {
+                    Ok((stream, peer_addr)) => {
+                        debug!(%peer_addr, "Connection opened",);
+                        let handler = CaptivePortalService;
+
+                        tasks.spawn(async move {
+                            let stream = crate::server::streams::MaybeTlsStream::Plain(stream);
+                            let stream = hyper_util::rt::TokioIo::new(stream);
+                            if let Err(err) = hyper::server::conn::http1::Builder::new()
+                                .serve_connection(stream, handler)
+                                .with_upgrades()
+                                .await
+                            {
+                                error!("Failed to serve connection: {err:?}");
+                            }
+                        });
+                    }
+                    Err(err) => {
+                        error!(
+                            "[CaptivePortalService] failed to accept connection: {:#?}",
+                            err
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[derive(Clone)]
+struct CaptivePortalService;
+
+impl hyper::service::Service<Request<Incoming>> for CaptivePortalService {
+    type Response = Response<BytesBody>;
+    type Error = HyperError;
+    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
+
+    fn call(&self, req: Request<Incoming>) -> Self::Future {
+        match (req.method(), req.uri().path()) {
+            // Captive Portal checker
+            (&Method::GET, "/generate_204") => {
+                Box::pin(async move { serve_no_content_handler(req, Response::builder()) })
+            }
+            _ => {
+                // Return 404 not found response.
+                let r = Response::builder()
+                    .status(StatusCode::NOT_FOUND)
+                    .body(NOTFOUND.into())
+                    .map_err(|err| Box::new(err) as HyperError);
+                Box::pin(async move { r })
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::{net::Ipv4Addr, time::Duration};
+
+    use bytes::Bytes;
+    use http::header::UPGRADE;
+    use iroh_base::{key::SecretKey, node_addr::RelayUrl};
+
+    use super::*;
+    use crate::{
+        client::{conn::ReceivedMessage, ClientBuilder},
+        http::{Protocol, HTTP_UPGRADE_PROTOCOL},
+    };
+
+    async fn spawn_local_relay() -> Result<Server> {
+        Server::spawn(ServerConfig::<(), ()> {
+            relay: Some(RelayConfig::<(), ()> {
+                http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+                tls: None,
+                limits: Default::default(),
+            }),
+            quic: None,
+            stun: None,
+            metrics_addr: None,
+        })
+        .await
+    }
+
+    #[tokio::test]
+    async fn test_no_services() {
+        let _guard = iroh_test::logging::setup();
+        let mut server = Server::spawn(ServerConfig::<(), ()>::default())
+            .await
+            .unwrap();
+        let res = tokio::time::timeout(Duration::from_secs(5), server.task_handle())
+            .await
+            .expect("timeout, server not finished")
+            .expect("server task JoinError");
+        assert!(res.is_err());
+    }
+
+    #[tokio::test]
+    async fn test_conflicting_bind() {
+        let _guard = iroh_test::logging::setup();
+        let mut server = Server::spawn(ServerConfig::<(), ()> {
+            relay: Some(RelayConfig {
+                http_bind_addr: (Ipv4Addr::LOCALHOST, 1234).into(),
+                tls: None,
+                limits: Default::default(),
+            }),
+            stun: None,
+            quic: None,
+            metrics_addr: Some((Ipv4Addr::LOCALHOST, 1234).into()),
+        })
+        .await
+        .unwrap();
+        let res = tokio::time::timeout(Duration::from_secs(5), server.task_handle())
+            .await
+            .expect("timeout, server not finished")
+            .expect("server task JoinError");
+        assert!(res.is_err()); // AddrInUse
+    }
+
+    #[tokio::test]
+    async fn test_root_handler() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+        let url = format!("http://{}", server.http_addr().unwrap());
+
+        let response = reqwest::get(&url).await.unwrap();
+        assert_eq!(response.status(), 200);
+        let body = response.text().await.unwrap();
+        assert!(body.contains("iroh.computer"));
+    }
+
+    #[tokio::test]
+    async fn test_captive_portal_service() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+        let url = format!("http://{}/generate_204", server.http_addr().unwrap());
+        let challenge = "123az__.";
+
+        let client = reqwest::Client::new();
+        let response = client
+            .get(&url)
+            .header(NO_CONTENT_CHALLENGE_HEADER, challenge)
+            .send()
+            .await
+            .unwrap();
+        assert_eq!(response.status(), StatusCode::NO_CONTENT);
+        let header = response.headers().get(NO_CONTENT_RESPONSE_HEADER).unwrap();
+        assert_eq!(header.to_str().unwrap(), format!("response {challenge}"));
+        let body = response.text().await.unwrap();
+        assert!(body.is_empty());
+    }
+
+    #[tokio::test]
+    async fn test_relay_client_legacy_route() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+        // We're testing the legacy endpoint at `/derp`
+        let endpoint_url = format!("http://{}/derp", server.http_addr().unwrap());
+
+        let client = reqwest::Client::new();
+        let result = client
+            .get(endpoint_url)
+            .header(UPGRADE, HTTP_UPGRADE_PROTOCOL)
+            .send()
+            .await
+            .unwrap();
+
+        assert_eq!(result.status(), StatusCode::SWITCHING_PROTOCOLS);
+    }
+
+    #[tokio::test]
+    async fn test_relay_clients_both_derp() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+        let relay_url = format!("http://{}", server.http_addr().unwrap());
+        let relay_url: RelayUrl = relay_url.parse().unwrap();
+
+        // set up client a
+        let a_secret_key = SecretKey::generate();
+        let a_key = a_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_a, mut client_a_receiver) =
+            ClientBuilder::new(relay_url.clone()).build(a_secret_key, resolver);
+        let connect_client = client_a.clone();
+
+        // give the relay server some time to accept connections
+        if let Err(err) = tokio::time::timeout(Duration::from_secs(10), async move {
+            loop {
+                match connect_client.connect().await {
+                    Ok(_) => break,
+                    Err(err) => {
+                        warn!("client unable to connect to relay server: {err:#}");
+                        tokio::time::sleep(Duration::from_millis(100)).await;
+                    }
+                }
+            }
+        })
+        .await
+        {
+            panic!("error connecting to relay server: {err:#}");
+        }
+
+        // set up client b
+        let b_secret_key = SecretKey::generate();
+        let b_key = b_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_b, mut client_b_receiver) =
+            ClientBuilder::new(relay_url.clone()).build(b_secret_key, resolver);
+        client_b.connect().await.unwrap();
+
+        // send message from a to b
+        let msg = Bytes::from("hello, b");
+        client_a.send(b_key, msg.clone()).await.unwrap();
+
+        let res = client_b_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(a_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_b received unexpected message {res:?}");
+        }
+
+        // send message from b to a
+        let msg = Bytes::from("howdy, a");
+        client_b.send(a_key, msg.clone()).await.unwrap();
+
+        let res = client_a_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(b_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_a received unexpected message {res:?}");
+        }
+    }
+
+    #[tokio::test]
+    async fn test_relay_clients_both_websockets() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+
+        let relay_url = format!("http://{}", server.http_addr().unwrap());
+        let relay_url: RelayUrl = relay_url.parse().unwrap();
+
+        // set up client a
+        let a_secret_key = SecretKey::generate();
+        let a_key = a_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_a, mut client_a_receiver) = ClientBuilder::new(relay_url.clone())
+            .protocol(Protocol::Websocket)
+            .build(a_secret_key, resolver);
+        let connect_client = client_a.clone();
+
+        // give the relay server some time to accept connections
+        if let Err(err) = tokio::time::timeout(Duration::from_secs(10), async move {
+            loop {
+                match connect_client.connect().await {
+                    Ok(_) => break,
+                    Err(err) => {
+                        warn!("client unable to connect to relay server: {err:#}");
+                        tokio::time::sleep(Duration::from_millis(100)).await;
+                    }
+                }
+            }
+        })
+        .await
+        {
+            panic!("error connecting to relay server: {err:#}");
+        }
+
+        // set up client b
+        let b_secret_key = SecretKey::generate();
+        let b_key = b_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_b, mut client_b_receiver) = ClientBuilder::new(relay_url.clone())
+            .protocol(Protocol::Websocket) // another websocket client
+            .build(b_secret_key, resolver);
+        client_b.connect().await.unwrap();
+
+        // send message from a to b
+        let msg = Bytes::from("hello, b");
+        client_a.send(b_key, msg.clone()).await.unwrap();
+
+        let res = client_b_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(a_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_b received unexpected message {res:?}");
+        }
+
+        // send message from b to a
+        let msg = Bytes::from("howdy, a");
+        client_b.send(a_key, msg.clone()).await.unwrap();
+
+        let res = client_a_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(b_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_a received unexpected message {res:?}");
+        }
+    }
+
+    #[tokio::test]
+    async fn test_relay_clients_websocket_and_derp() {
+        let _guard = iroh_test::logging::setup();
+        let server = spawn_local_relay().await.unwrap();
+
+        let relay_url = format!("http://{}", server.http_addr().unwrap());
+        let relay_url: RelayUrl = relay_url.parse().unwrap();
+
+        // set up client a
+        let a_secret_key = SecretKey::generate();
+        let a_key = a_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_a, mut client_a_receiver) =
+            ClientBuilder::new(relay_url.clone()).build(a_secret_key, resolver);
+        let connect_client = client_a.clone();
+
+        // give the relay server some time to accept connections
+        if let Err(err) = tokio::time::timeout(Duration::from_secs(10), async move {
+            loop {
+                match connect_client.connect().await {
+                    Ok(_) => break,
+                    Err(err) => {
+                        warn!("client unable to connect to relay server: {err:#}");
+                        tokio::time::sleep(Duration::from_millis(100)).await;
+                    }
+                }
+            }
+        })
+        .await
+        {
+            panic!("error connecting to relay server: {err:#}");
+        }
+
+        // set up client b
+        let b_secret_key = SecretKey::generate();
+        let b_key = b_secret_key.public();
+        let resolver = crate::dns::default_resolver().clone();
+        let (client_b, mut client_b_receiver) = ClientBuilder::new(relay_url.clone())
+            .protocol(Protocol::Websocket) // Use websockets
+            .build(b_secret_key, resolver);
+        client_b.connect().await.unwrap();
+
+        // send message from a to b
+        let msg = Bytes::from("hello, b");
+        client_a.send(b_key, msg.clone()).await.unwrap();
+
+        let res = client_b_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(a_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_b received unexpected message {res:?}");
+        }
+
+        // send message from b to a
+        let msg = Bytes::from("howdy, a");
+        client_b.send(a_key, msg.clone()).await.unwrap();
+
+        let res = client_a_receiver.recv().await.unwrap().unwrap();
+        if let ReceivedMessage::ReceivedPacket { source, data } = res {
+            assert_eq!(b_key, source);
+            assert_eq!(msg, data);
+        } else {
+            panic!("client_a received unexpected message {res:?}");
+        }
+    }
+
+    #[tokio::test]
+    async fn test_stun() {
+        let _guard = iroh_test::logging::setup();
+        let server = Server::spawn(ServerConfig::<(), ()> {
+            relay: None,
+            stun: Some(StunConfig {
+                bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+            }),
+            quic: None,
+            metrics_addr: None,
+        })
+        .await
+        .unwrap();
+
+        let txid = protos::stun::TransactionId::default();
+        let req = protos::stun::request(txid);
+        let socket = UdpSocket::bind("127.0.0.1:0").await.unwrap();
+        socket
+            .send_to(&req, server.stun_addr().unwrap())
+            .await
+            .unwrap();
+
+        // get response
+        let mut buf = vec![0u8; 64000];
+        let (len, addr) = socket.recv_from(&mut buf).await.unwrap();
+        assert_eq!(addr, server.stun_addr().unwrap());
+        buf.truncate(len);
+        let (txid_back, response_addr) = protos::stun::parse_response(&buf).unwrap();
+        assert_eq!(txid, txid_back);
+        assert_eq!(response_addr, socket.local_addr().unwrap());
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/actor.rs.html b/pr/2992/docs/src/iroh_relay/server/actor.rs.html new file mode 100644 index 0000000000..d2fce4a605 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/actor.rs.html @@ -0,0 +1,687 @@ +actor.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
//! The main event loop for the relay server.
+//!
+//! based on tailscale/derp/derp_server.go
+
+use std::{collections::HashMap, time::Duration};
+
+use anyhow::{bail, Result};
+use bytes::Bytes;
+use iroh_base::key::NodeId;
+use iroh_metrics::{inc, inc_by};
+use time::{Date, OffsetDateTime};
+use tokio::sync::mpsc;
+use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
+use tracing::{info, info_span, trace, warn, Instrument};
+
+use crate::{
+    defaults::timeouts::SERVER_WRITE_TIMEOUT as WRITE_TIMEOUT,
+    protos::relay::SERVER_CHANNEL_SIZE,
+    server::{client_conn::ClientConnConfig, clients::Clients, metrics::Metrics},
+};
+
+#[derive(Debug)]
+pub(super) enum Message {
+    SendPacket {
+        dst: NodeId,
+        data: Bytes,
+        src: NodeId,
+    },
+    SendDiscoPacket {
+        dst: NodeId,
+        data: Bytes,
+        src: NodeId,
+    },
+    CreateClient(ClientConnConfig),
+    RemoveClient {
+        node_id: NodeId,
+        conn_num: usize,
+    },
+}
+
+/// A request to write a dataframe to a Client
+#[derive(Debug, Clone)]
+pub(super) struct Packet {
+    /// The sender of the packet
+    pub(super) src: NodeId,
+    /// The data packet bytes.
+    pub(super) data: Bytes,
+}
+
+/// The task for a running server actor.
+///
+/// Will forcefully abort the server actor loop when dropped.
+/// For stopping gracefully, use [`ServerActorTask::close`].
+///
+/// Responsible for managing connections to relay [`Conn`](crate::RelayConn)s, sending packets from one client to another.
+#[derive(Debug)]
+pub(super) struct ServerActorTask {
+    /// Specifies how long to wait before failing when writing to a client.
+    pub(super) write_timeout: Duration,
+    /// Channel on which to communicate to the [`Actor`]
+    pub(super) server_channel: mpsc::Sender<Message>,
+    /// Server loop handler
+    loop_handler: AbortOnDropHandle<Result<()>>,
+    /// Token to shutdown the actor loop.
+    cancel: CancellationToken,
+}
+
+impl ServerActorTask {
+    /// Creates a new `ServerActorTask` and start the actor.
+    pub(super) fn spawn() -> Self {
+        let (server_channel_s, server_channel_r) = mpsc::channel(SERVER_CHANNEL_SIZE);
+        let server_actor = Actor::new(server_channel_r);
+        let cancel_token = CancellationToken::new();
+        let done = cancel_token.clone();
+        let server_task = AbortOnDropHandle::new(tokio::spawn(
+            async move { server_actor.run(done).await }.instrument(info_span!("relay.server")),
+        ));
+
+        Self {
+            write_timeout: WRITE_TIMEOUT,
+            server_channel: server_channel_s,
+            loop_handler: server_task,
+            cancel: cancel_token,
+        }
+    }
+
+    /// Closes the server and waits for the connections to disconnect.
+    pub(super) async fn close(self) {
+        self.cancel.cancel();
+        match self.loop_handler.await {
+            Ok(Ok(())) => {}
+            Ok(Err(e)) => warn!("error shutting down server: {e:#}"),
+            Err(e) => warn!("error waiting for the server process to close: {e:?}"),
+        }
+    }
+}
+
+struct Actor {
+    /// Channel to receive control messages
+    receiver: mpsc::Receiver<Message>,
+    /// All clients connected to this server
+    clients: Clients,
+    /// Statistics about the connected clients
+    client_counter: ClientCounter,
+}
+
+impl Actor {
+    fn new(receiver: mpsc::Receiver<Message>) -> Self {
+        Self {
+            receiver,
+            clients: Clients::default(),
+            client_counter: ClientCounter::default(),
+        }
+    }
+
+    async fn run(mut self, done: CancellationToken) -> Result<()> {
+        loop {
+            tokio::select! {
+                biased;
+
+                _ = done.cancelled() => {
+                    info!("server actor loop cancelled, closing loop");
+                    // TODO: stats: drain channel & count dropped packets etc
+                    // close all client connections and client read/write loops
+                    self.clients.shutdown().await;
+                    return Ok(());
+                }
+                msg = self.receiver.recv() => match msg {
+                    Some(msg) => {
+                        self.handle_message(msg).await;
+                    }
+                    None => {
+                        warn!("unexpected actor error: receiver gone, shutting down actor loop");
+                        self.clients.shutdown().await;
+                        bail!("unexpected actor error, closed client connections, and shutting down actor loop");
+                    }
+                }
+            }
+        }
+    }
+
+    async fn handle_message(&mut self, msg: Message) {
+        match msg {
+            Message::SendPacket { dst, data, src } => {
+                trace!(?src, ?dst, len = data.len(), "send packet");
+                if self.clients.contains_key(&dst) {
+                    match self.clients.send_packet(&dst, Packet { data, src }).await {
+                        Ok(()) => {
+                            self.clients.record_send(&src, dst);
+                            inc!(Metrics, send_packets_sent);
+                        }
+                        Err(err) => {
+                            trace!(?dst, "failed to send packet: {err:#}");
+                            inc!(Metrics, send_packets_dropped);
+                        }
+                    }
+                } else {
+                    warn!(?dst, "no way to reach client, dropped packet");
+                    inc!(Metrics, send_packets_dropped);
+                }
+            }
+            Message::SendDiscoPacket { dst, data, src } => {
+                trace!(?src, ?dst, len = data.len(), "send disco packet");
+                if self.clients.contains_key(&dst) {
+                    match self
+                        .clients
+                        .send_disco_packet(&dst, Packet { data, src })
+                        .await
+                    {
+                        Ok(()) => {
+                            self.clients.record_send(&src, dst);
+                            inc!(Metrics, disco_packets_sent);
+                        }
+                        Err(err) => {
+                            trace!(?dst, "failed to send disco packet: {err:#}");
+                            inc!(Metrics, disco_packets_dropped);
+                        }
+                    }
+                } else {
+                    warn!(?dst, "disco: no way to reach client, dropped packet");
+                    inc!(Metrics, disco_packets_dropped);
+                }
+            }
+            Message::CreateClient(client_builder) => {
+                inc!(Metrics, accepts);
+                let node_id = client_builder.node_id;
+                trace!(node_id = node_id.fmt_short(), "create client");
+
+                // build and register client, starting up read & write loops for the client
+                // connection
+                self.clients.register(client_builder).await;
+                let nc = self.client_counter.update(node_id);
+                inc_by!(Metrics, unique_client_keys, nc);
+            }
+            Message::RemoveClient { node_id, conn_num } => {
+                inc!(Metrics, disconnects);
+                trace!(node_id = %node_id.fmt_short(), "remove client");
+                // ensure we still have the client in question
+                if self.clients.has_client(&node_id, conn_num) {
+                    // remove the client from the map of clients, & notify any nodes that it
+                    // has sent messages that it has left the network
+                    self.clients.unregister(&node_id).await;
+                }
+            }
+        }
+    }
+}
+
+/// Counts how many `NodeId`s seen, how many times.
+/// Gets reset every day.
+struct ClientCounter {
+    clients: HashMap<NodeId, usize>,
+    last_clear_date: Date,
+}
+
+impl Default for ClientCounter {
+    fn default() -> Self {
+        Self {
+            clients: HashMap::new(),
+            last_clear_date: OffsetDateTime::now_utc().date(),
+        }
+    }
+}
+
+impl ClientCounter {
+    fn check_and_clear(&mut self) {
+        let today = OffsetDateTime::now_utc().date();
+        if today != self.last_clear_date {
+            self.clients.clear();
+            self.last_clear_date = today;
+        }
+    }
+
+    /// Updates the client counter.
+    fn update(&mut self, client: NodeId) -> u64 {
+        self.check_and_clear();
+        let new_conn = !self.clients.contains_key(&client);
+        let counter = self.clients.entry(client).or_insert(0);
+        *counter += 1;
+        new_conn as u64
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use bytes::Bytes;
+    use iroh_base::key::SecretKey;
+    use tokio::io::DuplexStream;
+    use tokio_util::codec::Framed;
+
+    use super::*;
+    use crate::{
+        protos::relay::{recv_frame, DerpCodec, Frame, FrameType},
+        server::{
+            client_conn::ClientConnConfig,
+            streams::{MaybeTlsStream, RelayedStream},
+        },
+    };
+
+    fn test_client_builder(
+        node_id: NodeId,
+        server_channel: mpsc::Sender<Message>,
+    ) -> (ClientConnConfig, Framed<DuplexStream, DerpCodec>) {
+        let (test_io, io) = tokio::io::duplex(1024);
+        (
+            ClientConnConfig {
+                node_id,
+                stream: RelayedStream::Derp(Framed::new(MaybeTlsStream::Test(io), DerpCodec)),
+                write_timeout: Duration::from_secs(1),
+                channel_capacity: 10,
+                rate_limit: None,
+                server_channel,
+            },
+            Framed::new(test_io, DerpCodec),
+        )
+    }
+
+    #[tokio::test]
+    async fn test_server_actor() -> Result<()> {
+        // make server actor
+        let (server_channel, server_channel_r) = mpsc::channel(20);
+        let server_actor: Actor = Actor::new(server_channel_r);
+        let done = CancellationToken::new();
+        let server_done = done.clone();
+
+        // run server actor
+        let server_task = tokio::spawn(
+            async move { server_actor.run(server_done).await }
+                .instrument(info_span!("relay.server")),
+        );
+
+        let node_id_a = SecretKey::generate().public();
+        let (client_a, mut a_io) = test_client_builder(node_id_a, server_channel.clone());
+
+        // create client a
+        server_channel
+            .send(Message::CreateClient(client_a))
+            .await
+            .map_err(|_| anyhow::anyhow!("server gone"))?;
+
+        // server message: create client b
+        let node_id_b = SecretKey::generate().public();
+        let (client_b, mut b_io) = test_client_builder(node_id_b, server_channel.clone());
+        server_channel
+            .send(Message::CreateClient(client_b))
+            .await
+            .map_err(|_| anyhow::anyhow!("server gone"))?;
+
+        // write message from b to a
+        let msg = b"hello world!";
+        crate::client::conn::send_packet(&mut b_io, &None, node_id_a, Bytes::from_static(msg))
+            .await?;
+
+        // get message on a's reader
+        let frame = recv_frame(FrameType::RecvPacket, &mut a_io).await?;
+        assert_eq!(
+            frame,
+            Frame::RecvPacket {
+                src_key: node_id_b,
+                content: msg.to_vec().into()
+            }
+        );
+
+        // remove b
+        server_channel
+            .send(Message::RemoveClient {
+                node_id: node_id_b,
+                conn_num: 1,
+            })
+            .await
+            .map_err(|_| anyhow::anyhow!("server gone"))?;
+
+        // get the nodes gone message on a about b leaving the network
+        // (we get this message because b has sent us a packet before)
+        let frame = recv_frame(FrameType::PeerGone, &mut a_io).await?;
+        assert_eq!(Frame::NodeGone { node_id: node_id_b }, frame);
+
+        // close gracefully
+        done.cancel();
+        server_task.await??;
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/client_conn.rs.html b/pr/2992/docs/src/iroh_relay/server/client_conn.rs.html new file mode 100644 index 0000000000..46a858677d --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/client_conn.rs.html @@ -0,0 +1,1601 @@ +client_conn.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+
//! The server-side representation of an ongoing client relaying connection.
+
+use std::{future::Future, num::NonZeroU32, pin::Pin, sync::Arc, task::Poll, time::Duration};
+
+use anyhow::{Context, Result};
+use bytes::Bytes;
+use futures_lite::FutureExt;
+use futures_sink::Sink;
+use futures_util::{SinkExt, Stream, StreamExt};
+use iroh_base::key::NodeId;
+use iroh_metrics::{inc, inc_by};
+use tokio::sync::mpsc;
+use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle};
+use tracing::{error, info, instrument, trace, warn, Instrument};
+
+use crate::{
+    protos::{
+        disco,
+        relay::{write_frame, Frame, KEEP_ALIVE},
+    },
+    server::{
+        actor::{self, Packet},
+        metrics::Metrics,
+        streams::RelayedStream,
+        ClientConnRateLimit,
+    },
+};
+
+/// Configuration for a [`ClientConn`].
+#[derive(Debug)]
+pub(super) struct ClientConnConfig {
+    pub(super) node_id: NodeId,
+    pub(super) stream: RelayedStream,
+    pub(super) write_timeout: Duration,
+    pub(super) channel_capacity: usize,
+    pub(super) rate_limit: Option<ClientConnRateLimit>,
+    pub(super) server_channel: mpsc::Sender<actor::Message>,
+}
+
+/// The [`Server`] side representation of a [`Client`]'s connection.
+///
+/// [`Server`]: crate::server::Server
+/// [`Client`]: crate::client::Client
+#[derive(Debug)]
+pub(super) struct ClientConn {
+    /// Unique counter, incremented each time we accept a new connection.
+    pub(super) conn_num: usize,
+    /// Identity of the connected peer.
+    pub(super) key: NodeId,
+    /// Used to close the connection loop.
+    done: CancellationToken,
+    /// Actor handle.
+    handle: AbortOnDropHandle<()>,
+    /// Queue of packets intended for the client.
+    pub(super) send_queue: mpsc::Sender<Packet>,
+    /// Queue of disco packets intended for the client.
+    pub(super) disco_send_queue: mpsc::Sender<Packet>,
+    /// Channel to notify the client that a previous sender has disconnected.
+    pub(super) peer_gone: mpsc::Sender<NodeId>,
+}
+
+impl ClientConn {
+    /// Creates a client from a connection & starts a read and write loop to handle io to and from
+    /// the client
+    /// Call [`ClientConn::shutdown`] to close the read and write loops before dropping the [`ClientConn`]
+    pub fn new(config: ClientConnConfig, conn_num: usize) -> ClientConn {
+        let ClientConnConfig {
+            node_id: key,
+            stream: io,
+            write_timeout,
+            channel_capacity,
+            rate_limit,
+            server_channel,
+        } = config;
+
+        let stream = match rate_limit {
+            Some(cfg) => {
+                let mut quota = governor::Quota::per_second(cfg.bytes_per_second);
+                if let Some(max_burst) = cfg.max_burst_bytes {
+                    quota = quota.allow_burst(max_burst);
+                }
+                let limiter = governor::RateLimiter::direct(quota);
+                RateLimitedRelayedStream::new(io, limiter)
+            }
+            None => RateLimitedRelayedStream::unlimited(io),
+        };
+
+        let done = CancellationToken::new();
+        let client_id = (key, conn_num);
+        let (send_queue_s, send_queue_r) = mpsc::channel(channel_capacity);
+
+        let (disco_send_queue_s, disco_send_queue_r) = mpsc::channel(channel_capacity);
+        let (peer_gone_s, peer_gone_r) = mpsc::channel(channel_capacity);
+
+        let actor = Actor {
+            stream,
+            timeout: write_timeout,
+            send_queue: send_queue_r,
+            disco_send_queue: disco_send_queue_r,
+            node_gone: peer_gone_r,
+            key,
+            preferred: false,
+            server_channel: server_channel.clone(),
+        };
+
+        // start io loop
+        let io_done = done.clone();
+        let io_client_id = client_id;
+        let handle = tokio::task::spawn(
+            async move {
+                let (key, conn_num) = io_client_id;
+                let res = actor.run(io_done).await;
+
+                // remove the client when the actor terminates, no matter how it exits
+                let _ = server_channel
+                    .send(actor::Message::RemoveClient {
+                        node_id: key,
+                        conn_num,
+                    })
+                    .await;
+                match res {
+                    Err(e) => {
+                        warn!(
+                            "connection manager for {key:?} {conn_num}: writer closed in error {e}"
+                        );
+                    }
+                    Ok(()) => {
+                        info!("connection manager for {key:?} {conn_num}: writer closed");
+                    }
+                }
+            }
+            .instrument(tracing::info_span!("client_conn_actor")),
+        );
+
+        ClientConn {
+            conn_num,
+            key,
+            handle: AbortOnDropHandle::new(handle),
+            done,
+            send_queue: send_queue_s,
+            disco_send_queue: disco_send_queue_s,
+            peer_gone: peer_gone_s,
+        }
+    }
+
+    /// Shutdown the reader and writer loops and closes the connection.
+    ///
+    /// Any shutdown errors will be logged as warnings.
+    pub async fn shutdown(self) {
+        self.done.cancel();
+        if let Err(e) = self.handle.await {
+            warn!(
+                "error closing actor loop for client connection {:?} {}: {e:?}",
+                self.key, self.conn_num
+            );
+        };
+    }
+}
+
+/// Manages all the reads and writes to this client. It periodically sends a `KEEP_ALIVE`
+/// message to the client to keep the connection alive.
+///
+/// Call `run` to manage the input and output to and from the connection and the server.
+/// Once it hits its first write error or error receiving off a channel,
+/// it errors on return.
+/// If writes do not complete in the given `timeout`, it will also error.
+///
+/// On the "write" side, the [`Actor`] can send the client:
+///  - a KEEP_ALIVE frame
+///  - a PEER_GONE frame to inform the client that a peer they have previously sent messages to
+///    is gone from the network
+///  - packets from other peers
+///
+/// On the "read" side, it can:
+///     - receive a ping and write a pong back
+///     - note whether the client is `preferred`, aka this client is the preferred way
+///     to speak to the node ID associated with that client.
+#[derive(Debug)]
+struct Actor {
+    /// IO Stream to talk to the client
+    stream: RateLimitedRelayedStream,
+    /// Maximum time we wait to complete a write to the client
+    timeout: Duration,
+    /// Packets queued to send to the client
+    send_queue: mpsc::Receiver<Packet>,
+    /// Important packets queued to send to the client
+    disco_send_queue: mpsc::Receiver<Packet>,
+    /// Notify the client that a previous sender has disconnected
+    node_gone: mpsc::Receiver<NodeId>,
+    /// [`NodeId`] of this client
+    key: NodeId,
+    /// Channel used to communicate with the server about actions
+    /// it needs to take on behalf of the client
+    server_channel: mpsc::Sender<actor::Message>,
+    /// Notes that the client considers this the preferred connection (important in cases
+    /// where the client moves to a different network, but has the same NodeId)
+    preferred: bool,
+}
+
+impl Actor {
+    async fn run(mut self, done: CancellationToken) -> Result<()> {
+        let jitter = Duration::from_secs(5);
+        let mut keep_alive = tokio::time::interval(KEEP_ALIVE + jitter);
+        // ticks immediately
+        keep_alive.tick().await;
+
+        loop {
+            tokio::select! {
+                biased;
+
+                _ = done.cancelled() => {
+                    trace!("actor loop cancelled, exiting");
+                    // final flush
+                    self.stream.flush().await.context("flush")?;
+                    break;
+                }
+                read_res = self.stream.next() => {
+                    trace!("handle frame");
+                    match read_res {
+                        Some(Ok(frame)) => {
+                            self.handle_frame(frame).await.context("handle_read")?;
+                        }
+                        Some(Err(err)) => {
+                            return Err(err);
+                        }
+                        None => {
+                            // Unexpected EOF
+                            return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "read stream ended").into());
+                        }
+                    }
+                }
+                node_id = self.node_gone.recv() => {
+                    let node_id = node_id.context("Server.node_gone dropped")?;
+                    trace!("node_id gone: {:?}", node_id);
+                    self.write_frame(Frame::NodeGone { node_id }).await?;
+                }
+                packet = self.send_queue.recv() => {
+                    let packet = packet.context("Server.send_queue dropped")?;
+                    trace!("send packet");
+                    self.send_packet(packet).await.context("send packet")?;
+                }
+                packet = self.disco_send_queue.recv() => {
+                    let packet = packet.context("Server.disco_send_queue dropped")?;
+                    trace!("send disco packet");
+                    self.send_packet(packet).await.context("send packet")?;
+                }
+                _ = keep_alive.tick() => {
+                    trace!("keep alive");
+                    self.write_frame(Frame::KeepAlive).await?;
+                }
+            }
+            self.stream.flush().await.context("tick flush")?;
+        }
+        Ok(())
+    }
+
+    /// Writes the given frame to the connection.
+    ///
+    /// Errors if the send does not happen within the `timeout` duration
+    async fn write_frame(&mut self, frame: Frame) -> Result<()> {
+        write_frame(&mut self.stream, frame, Some(self.timeout)).await
+    }
+
+    /// Writes contents to the client in a `RECV_PACKET` frame.
+    ///
+    /// Errors if the send does not happen within the `timeout` duration
+    /// Does not flush.
+    async fn send_packet(&mut self, packet: Packet) -> Result<()> {
+        let src_key = packet.src;
+        let content = packet.data;
+
+        if let Ok(len) = content.len().try_into() {
+            inc_by!(Metrics, bytes_sent, len);
+        }
+        self.write_frame(Frame::RecvPacket { src_key, content })
+            .await
+    }
+
+    /// Handles frame read results.
+    async fn handle_frame(&mut self, frame: Frame) -> Result<()> {
+        // TODO: "note client activity", meaning we update the server that the client with this
+        // public key was the last one to receive data
+        // it will be relevant when we add the ability to hold onto multiple clients
+        // for the same public key
+        match frame {
+            Frame::NotePreferred { preferred } => {
+                self.preferred = preferred;
+                inc!(Metrics, other_packets_recv);
+            }
+            Frame::SendPacket { dst_key, packet } => {
+                let packet_len = packet.len();
+                self.handle_frame_send_packet(dst_key, packet).await?;
+                inc_by!(Metrics, bytes_recv, packet_len as u64);
+            }
+            Frame::Ping { data } => {
+                inc!(Metrics, got_ping);
+                // TODO: add rate limiter
+                self.write_frame(Frame::Pong { data }).await?;
+                inc!(Metrics, sent_pong);
+            }
+            Frame::Health { .. } => {
+                inc!(Metrics, other_packets_recv);
+            }
+            _ => {
+                inc!(Metrics, unknown_frames);
+            }
+        }
+        Ok(())
+    }
+
+    async fn handle_frame_send_packet(&self, dst_key: NodeId, data: Bytes) -> Result<()> {
+        let message = if disco::looks_like_disco_wrapper(&data) {
+            inc!(Metrics, disco_packets_recv);
+            actor::Message::SendDiscoPacket {
+                dst: dst_key,
+                src: self.key,
+                data,
+            }
+        } else {
+            inc!(Metrics, send_packets_recv);
+            actor::Message::SendPacket {
+                dst: dst_key,
+                src: self.key,
+                data,
+            }
+        };
+
+        self.server_channel
+            .send(message)
+            .await
+            .map_err(|_| anyhow::anyhow!("server gone"))?;
+        Ok(())
+    }
+}
+
+/// Rate limiter for reading from a [`RelayedStream`].
+///
+/// The writes to the sink are not rate limited.
+///
+/// This potentially buffers one frame if the rate limiter does not allows this frame.
+/// While the frame is buffered the undernlying stream is no longer polled.
+#[derive(Debug)]
+struct RateLimitedRelayedStream {
+    inner: RelayedStream,
+    limiter: Option<Arc<governor::DefaultDirectRateLimiter>>,
+    state: State,
+    /// Keeps track if this stream was ever rate-limited.
+    limited_once: bool,
+}
+
+#[derive(derive_more::Debug)]
+enum State {
+    #[debug("Blocked")]
+    Blocked {
+        /// Future which will complete when the item can be yielded.
+        delay: Pin<Box<dyn Future<Output = ()> + Send + Sync>>,
+        /// Item to yield when the `delay` future completes.
+        item: anyhow::Result<Frame>,
+    },
+    Ready,
+}
+
+impl RateLimitedRelayedStream {
+    fn new(inner: RelayedStream, limiter: governor::DefaultDirectRateLimiter) -> Self {
+        Self {
+            inner,
+            limiter: Some(Arc::new(limiter)),
+            state: State::Ready,
+            limited_once: false,
+        }
+    }
+
+    fn unlimited(inner: RelayedStream) -> Self {
+        Self {
+            inner,
+            limiter: None,
+            state: State::Ready,
+            limited_once: false,
+        }
+    }
+}
+
+impl RateLimitedRelayedStream {
+    /// Records metrics about being rate-limited.
+    fn record_rate_limited(&mut self) {
+        // TODO: add a label for the frame type.
+        inc!(Metrics, frames_rx_ratelimited_total);
+        if !self.limited_once {
+            inc!(Metrics, conns_rx_ratelimited_total);
+            self.limited_once = true;
+        }
+    }
+}
+
+impl Stream for RateLimitedRelayedStream {
+    type Item = anyhow::Result<Frame>;
+
+    #[instrument(name = "rate_limited_relayed_stream", skip_all)]
+    fn poll_next(
+        mut self: Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> Poll<Option<Self::Item>> {
+        let Some(ref limiter) = self.limiter else {
+            // If there is no rate-limiter directly poll the inner.
+            return Pin::new(&mut self.inner).poll_next(cx);
+        };
+        let limiter = limiter.clone();
+        loop {
+            match &mut self.state {
+                State::Ready => {
+                    // Poll inner for a new item.
+                    match Pin::new(&mut self.inner).poll_next(cx) {
+                        Poll::Ready(Some(item)) => {
+                            match &item {
+                                Ok(frame) => {
+                                    // How many bytes does this frame consume?
+                                    let Ok(frame_len) =
+                                        TryInto::<u32>::try_into(frame.len_with_header())
+                                            .and_then(TryInto::<NonZeroU32>::try_into)
+                                    else {
+                                        error!("frame len not NonZeroU32, is MAX_FRAME_SIZE too large?");
+                                        // Let this frame through so to not completely break.
+                                        return Poll::Ready(Some(item));
+                                    };
+
+                                    match limiter.check_n(frame_len) {
+                                        Ok(Ok(_)) => return Poll::Ready(Some(item)),
+                                        Ok(Err(_)) => {
+                                            // Item is rate-limited.
+                                            self.record_rate_limited();
+                                            let delay = Box::pin({
+                                                let limiter = limiter.clone();
+                                                async move {
+                                                    limiter.until_n_ready(frame_len).await.ok();
+                                                }
+                                            });
+                                            self.state = State::Blocked { delay, item };
+                                            continue;
+                                        }
+                                        Err(_insufficient_capacity) => {
+                                            error!(
+                                                "frame larger than bucket capacity: \
+                                                 configuration error: \
+                                                 max_burst_bytes < MAX_FRAME_SIZE?"
+                                            );
+                                            // Let this frame through so to not completely break.
+                                            return Poll::Ready(Some(item));
+                                        }
+                                    }
+                                }
+                                Err(_) => {
+                                    // Yielding errors is not rate-limited.
+                                    return Poll::Ready(Some(item));
+                                }
+                            }
+                        }
+                        Poll::Ready(None) => return Poll::Ready(None),
+                        Poll::Pending => return Poll::Pending,
+                    }
+                }
+                State::Blocked { delay, .. } => {
+                    match delay.poll(cx) {
+                        Poll::Ready(_) => {
+                            match std::mem::replace(&mut self.state, State::Ready) {
+                                State::Ready => unreachable!(),
+                                State::Blocked { item, .. } => {
+                                    // Yield the item directly, rate-limit has already been
+                                    // accounted for by awaiting the future.
+                                    return Poll::Ready(Some(item));
+                                }
+                            }
+                        }
+                        Poll::Pending => return Poll::Pending,
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl Sink<Frame> for RateLimitedRelayedStream {
+    type Error = std::io::Error;
+
+    fn poll_ready(
+        mut self: Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> Poll<std::result::Result<(), Self::Error>> {
+        Pin::new(&mut self.inner).poll_ready(cx)
+    }
+
+    fn start_send(mut self: Pin<&mut Self>, item: Frame) -> std::result::Result<(), Self::Error> {
+        Pin::new(&mut self.inner).start_send(item)
+    }
+
+    fn poll_flush(
+        mut self: Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> Poll<std::result::Result<(), Self::Error>> {
+        Pin::new(&mut self.inner).poll_flush(cx)
+    }
+
+    fn poll_close(
+        mut self: Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>,
+    ) -> Poll<std::result::Result<(), Self::Error>> {
+        Pin::new(&mut self.inner).poll_close(cx)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use anyhow::bail;
+    use bytes::Bytes;
+    use iroh_base::key::SecretKey;
+    use testresult::TestResult;
+    use tokio_util::codec::Framed;
+
+    use super::*;
+    use crate::{
+        client::conn,
+        protos::relay::{recv_frame, DerpCodec, FrameType},
+        server::streams::MaybeTlsStream,
+    };
+
+    #[tokio::test]
+    async fn test_client_actor_basic() -> Result<()> {
+        let (send_queue_s, send_queue_r) = mpsc::channel(10);
+        let (disco_send_queue_s, disco_send_queue_r) = mpsc::channel(10);
+        let (peer_gone_s, peer_gone_r) = mpsc::channel(10);
+
+        let key = SecretKey::generate().public();
+        let (io, io_rw) = tokio::io::duplex(1024);
+        let mut io_rw = Framed::new(io_rw, DerpCodec);
+        let (server_channel_s, mut server_channel_r) = mpsc::channel(10);
+        let stream = RelayedStream::Derp(Framed::new(MaybeTlsStream::Test(io), DerpCodec));
+
+        let actor = Actor {
+            stream: RateLimitedRelayedStream::unlimited(stream),
+            timeout: Duration::from_secs(1),
+            send_queue: send_queue_r,
+            disco_send_queue: disco_send_queue_r,
+            node_gone: peer_gone_r,
+
+            key,
+            server_channel: server_channel_s,
+            preferred: true,
+        };
+
+        let done = CancellationToken::new();
+        let io_done = done.clone();
+        let handle = tokio::task::spawn(async move { actor.run(io_done).await });
+
+        // Write tests
+        println!("-- write");
+        let data = b"hello world!";
+
+        // send packet
+        println!("  send packet");
+        let packet = Packet {
+            src: key,
+            data: Bytes::from(&data[..]),
+        };
+        send_queue_s.send(packet.clone()).await?;
+        let frame = recv_frame(FrameType::RecvPacket, &mut io_rw).await?;
+        assert_eq!(
+            frame,
+            Frame::RecvPacket {
+                src_key: key,
+                content: data.to_vec().into()
+            }
+        );
+
+        // send disco packet
+        println!("  send disco packet");
+        disco_send_queue_s.send(packet.clone()).await?;
+        let frame = recv_frame(FrameType::RecvPacket, &mut io_rw).await?;
+        assert_eq!(
+            frame,
+            Frame::RecvPacket {
+                src_key: key,
+                content: data.to_vec().into()
+            }
+        );
+
+        // send peer_gone
+        println!("send peer gone");
+        peer_gone_s.send(key).await?;
+        let frame = recv_frame(FrameType::PeerGone, &mut io_rw).await?;
+        assert_eq!(frame, Frame::NodeGone { node_id: key });
+
+        // Read tests
+        println!("--read");
+
+        // send ping, expect pong
+        let data = b"pingpong";
+        write_frame(&mut io_rw, Frame::Ping { data: *data }, None).await?;
+
+        // recv pong
+        println!(" recv pong");
+        let frame = recv_frame(FrameType::Pong, &mut io_rw).await?;
+        assert_eq!(frame, Frame::Pong { data: *data });
+
+        // change preferred to false
+        println!("  preferred: false");
+        write_frame(&mut io_rw, Frame::NotePreferred { preferred: false }, None).await?;
+        // tokio::time::sleep(Duration::from_millis(100)).await;
+        // assert!(!preferred.load(Ordering::Relaxed));
+
+        // change preferred to true
+        println!("  preferred: true");
+        write_frame(&mut io_rw, Frame::NotePreferred { preferred: true }, None).await?;
+        // tokio::time::sleep(Duration::from_millis(100)).await;
+        // assert!(preferred.fetch_and(true, Ordering::Relaxed));
+
+        let target = SecretKey::generate().public();
+
+        // send packet
+        println!("  send packet");
+        let data = b"hello world!";
+        conn::send_packet(&mut io_rw, &None, target, Bytes::from_static(data)).await?;
+        let msg = server_channel_r.recv().await.unwrap();
+        match msg {
+            actor::Message::SendPacket {
+                dst: got_target,
+                data: got_data,
+                src: got_src,
+            } => {
+                assert_eq!(target, got_target);
+                assert_eq!(key, got_src);
+                assert_eq!(&data[..], &got_data);
+            }
+            m => {
+                bail!("expected ServerMessage::SendPacket, got {m:?}");
+            }
+        }
+
+        // send disco packet
+        println!("  send disco packet");
+        // starts with `MAGIC` & key, then data
+        let mut disco_data = disco::MAGIC.as_bytes().to_vec();
+        disco_data.extend_from_slice(target.as_bytes());
+        disco_data.extend_from_slice(data);
+        conn::send_packet(&mut io_rw, &None, target, disco_data.clone().into()).await?;
+        let msg = server_channel_r.recv().await.unwrap();
+        match msg {
+            actor::Message::SendDiscoPacket {
+                dst: got_target,
+                src: got_src,
+                data: got_data,
+            } => {
+                assert_eq!(target, got_target);
+                assert_eq!(key, got_src);
+                assert_eq!(&disco_data[..], &got_data);
+            }
+            m => {
+                bail!("expected ServerMessage::SendDiscoPacket, got {m:?}");
+            }
+        }
+
+        done.cancel();
+        handle.await??;
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_client_conn_read_err() -> Result<()> {
+        let (_send_queue_s, send_queue_r) = mpsc::channel(10);
+        let (_disco_send_queue_s, disco_send_queue_r) = mpsc::channel(10);
+        let (_peer_gone_s, peer_gone_r) = mpsc::channel(10);
+
+        let key = SecretKey::generate().public();
+        let (io, io_rw) = tokio::io::duplex(1024);
+        let mut io_rw = Framed::new(io_rw, DerpCodec);
+        let (server_channel_s, mut server_channel_r) = mpsc::channel(10);
+        let stream = RelayedStream::Derp(Framed::new(MaybeTlsStream::Test(io), DerpCodec));
+
+        println!("-- create client conn");
+        let actor = Actor {
+            stream: RateLimitedRelayedStream::unlimited(stream),
+            timeout: Duration::from_secs(1),
+            send_queue: send_queue_r,
+            disco_send_queue: disco_send_queue_r,
+            node_gone: peer_gone_r,
+
+            key,
+            server_channel: server_channel_s,
+            preferred: true,
+        };
+
+        let done = CancellationToken::new();
+        let io_done = done.clone();
+
+        println!("-- run client conn");
+        let handle = tokio::task::spawn(async move { actor.run(io_done).await });
+
+        // send packet
+        println!("   send packet");
+        let data = b"hello world!";
+        let target = SecretKey::generate().public();
+
+        conn::send_packet(&mut io_rw, &None, target, Bytes::from_static(data)).await?;
+        let msg = server_channel_r.recv().await.unwrap();
+        match msg {
+            actor::Message::SendPacket {
+                dst: got_target,
+                src: got_src,
+                data: got_data,
+            } => {
+                assert_eq!(target, got_target);
+                assert_eq!(key, got_src);
+                assert_eq!(&data[..], &got_data);
+                println!("    send packet success");
+            }
+            m => {
+                bail!("expected ServerMessage::SendPacket, got {m:?}");
+            }
+        }
+
+        println!("-- drop io");
+        drop(io_rw);
+
+        // expect task to complete after encountering an error
+        if let Err(err) = tokio::time::timeout(Duration::from_secs(1), handle).await?? {
+            if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
+                if io_err.kind() == std::io::ErrorKind::UnexpectedEof {
+                    println!("   task closed successfully with `UnexpectedEof` error");
+                } else {
+                    bail!("expected `UnexpectedEof` error, got unknown error: {io_err:?}");
+                }
+            } else {
+                bail!("expected `std::io::Error`, got `None`");
+            }
+        } else {
+            bail!("expected task to finish in `UnexpectedEof` error, got `Ok(())`");
+        }
+
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_rate_limit() -> TestResult {
+        let _logging = iroh_test::logging::setup();
+
+        const LIMIT: u32 = 50;
+        const MAX_FRAMES: u32 = 100;
+
+        // Rate limiter allowing LIMIT bytes/s
+        let quota = governor::Quota::per_second(NonZeroU32::try_from(LIMIT)?);
+        let limiter = governor::RateLimiter::direct(quota);
+
+        // Build the rate limited stream.
+        let (io_read, io_write) = tokio::io::duplex((LIMIT * MAX_FRAMES) as _);
+        let mut frame_writer = Framed::new(io_write, DerpCodec);
+        let stream = RelayedStream::Derp(Framed::new(MaybeTlsStream::Test(io_read), DerpCodec));
+        let mut stream = RateLimitedRelayedStream::new(stream, limiter);
+
+        // Prepare a frame to send, assert its size.
+        let data = Bytes::from_static(b"hello world!!");
+        let target = SecretKey::generate().public();
+        let frame = Frame::SendPacket {
+            dst_key: target,
+            packet: data.clone(),
+        };
+        let frame_len = frame.len_with_header();
+        assert_eq!(frame_len, LIMIT as usize);
+
+        // Send a frame, it should arrive.
+        info!("-- send packet");
+        frame_writer.send(frame.clone()).await?;
+        frame_writer.flush().await?;
+        let recv_frame = tokio::time::timeout(Duration::from_millis(500), stream.next())
+            .await
+            .expect("timeout")
+            .expect("option")
+            .expect("ok");
+        assert_eq!(recv_frame, frame);
+
+        // Next frame does not arrive.
+        info!("-- send packet");
+        frame_writer.send(frame.clone()).await?;
+        frame_writer.flush().await?;
+        let res = tokio::time::timeout(Duration::from_millis(100), stream.next()).await;
+        assert!(res.is_err(), "expecting a timeout");
+        info!("-- timeout happened");
+
+        // Wait long enough.
+        info!("-- sleep");
+        tokio::time::sleep(Duration::from_secs(1)).await;
+
+        // Frame arrives.
+        let recv_frame = tokio::time::timeout(Duration::from_millis(500), stream.next())
+            .await
+            .expect("timeout")
+            .expect("option")
+            .expect("ok");
+        assert_eq!(recv_frame, frame);
+
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/clients.rs.html b/pr/2992/docs/src/iroh_relay/server/clients.rs.html new file mode 100644 index 0000000000..43e98ba2f6 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/clients.rs.html @@ -0,0 +1,621 @@ +clients.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+
//! The "Server" side of the client. Uses the `ClientConnManager`.
+// Based on tailscale/derp/derp_server.go
+
+use std::collections::{HashMap, HashSet};
+
+use anyhow::{bail, Result};
+use iroh_base::key::NodeId;
+use iroh_metrics::inc;
+use tokio::sync::mpsc;
+use tracing::{trace, warn};
+
+use super::{
+    actor::Packet,
+    client_conn::{ClientConn, ClientConnConfig},
+    metrics::Metrics,
+};
+
+/// Number of times we try to send to a client connection before dropping the data;
+const RETRIES: usize = 3;
+
+/// Manages the connections to all currently connected clients.
+#[derive(Debug, Default)]
+pub(super) struct Clients {
+    /// The list of all currently connected clients.
+    inner: HashMap<NodeId, Client>,
+    /// The next connection number to use.
+    conn_num: usize,
+}
+
+impl Clients {
+    pub async fn shutdown(&mut self) {
+        trace!("shutting down {} clients", self.inner.len());
+
+        futures_buffered::join_all(
+            self.inner
+                .drain()
+                .map(|(_, client)| async move { client.shutdown().await }),
+        )
+        .await;
+    }
+
+    /// Record that `src` sent or forwarded a packet to `dst`
+    pub fn record_send(&mut self, src: &NodeId, dst: NodeId) {
+        if let Some(client) = self.inner.get_mut(src) {
+            client.record_send(dst);
+        }
+    }
+
+    pub fn contains_key(&self, key: &NodeId) -> bool {
+        self.inner.contains_key(key)
+    }
+
+    pub fn has_client(&self, key: &NodeId, conn_num: usize) -> bool {
+        if let Some(client) = self.inner.get(key) {
+            return client.conn.conn_num == conn_num;
+        }
+        false
+    }
+
+    fn next_conn_num(&mut self) -> usize {
+        let conn_num = self.conn_num;
+        self.conn_num = self.conn_num.wrapping_add(1);
+        conn_num
+    }
+
+    /// Builds the client handler and starts the read & write loops for the connection.
+    pub async fn register(&mut self, client_config: ClientConnConfig) {
+        let key = client_config.node_id;
+        trace!("registering client: {:?}", key);
+        let conn_num = self.next_conn_num();
+        let client = ClientConn::new(client_config, conn_num);
+        // TODO: in future, do not remove clients that share a NodeId, instead,
+        // expand the `Client` struct to handle multiple connections & a policy for
+        // how to handle who we write to when multiple connections exist.
+        let client = Client::new(client);
+        if let Some(old_client) = self.inner.insert(key, client) {
+            warn!("multiple connections found for {key:?}, pruning old connection",);
+            old_client.shutdown().await;
+        }
+    }
+
+    /// Removes the client from the map of clients, & sends a notification
+    /// to each client that peers has sent data to, to let them know that
+    /// peer is gone from the network.
+    pub async fn unregister(&mut self, peer: &NodeId) {
+        trace!("unregistering client: {:?}", peer);
+        if let Some(client) = self.inner.remove(peer) {
+            for key in client.sent_to.iter() {
+                self.send_peer_gone(key, *peer);
+            }
+            warn!("pruning connection {peer:?}");
+            client.shutdown().await;
+        }
+    }
+
+    /// Attempt to send a packet to client with [`NodeId`] `key`
+    pub async fn send_packet(&mut self, key: &NodeId, packet: Packet) -> Result<()> {
+        if let Some(client) = self.inner.get(key) {
+            let res = client.send_packet(packet);
+            return self.process_result(key, res).await;
+        }
+        bail!("Could not find client for {key:?}, dropped packet");
+    }
+
+    pub async fn send_disco_packet(&mut self, key: &NodeId, packet: Packet) -> Result<()> {
+        if let Some(client) = self.inner.get(key) {
+            let res = client.send_disco_packet(packet);
+            return self.process_result(key, res).await;
+        }
+        bail!("Could not find client for {key:?}, dropped packet");
+    }
+
+    fn send_peer_gone(&mut self, key: &NodeId, peer: NodeId) {
+        if let Some(client) = self.inner.get(key) {
+            let res = client.send_peer_gone(peer);
+            let _ = self.process_result_no_fallback(key, res);
+            return;
+        }
+        warn!("Could not find client for {key:?}, dropping peer gone packet");
+    }
+
+    async fn process_result(&mut self, key: &NodeId, res: Result<(), SendError>) -> Result<()> {
+        match res {
+            Ok(_) => return Ok(()),
+            Err(SendError::PacketDropped) => {
+                warn!("client {key:?} too busy to receive packet, dropping packet");
+            }
+            Err(SendError::SenderClosed) => {
+                warn!("Can no longer write to client {key:?}, dropping message and pruning connection");
+                self.unregister(key).await;
+            }
+        }
+        bail!("unable to send msg");
+    }
+
+    fn process_result_no_fallback(
+        &mut self,
+        key: &NodeId,
+        res: Result<(), SendError>,
+    ) -> Result<()> {
+        match res {
+            Ok(_) => return Ok(()),
+            Err(SendError::PacketDropped) => {
+                warn!("client {key:?} too busy to receive packet, dropping packet");
+            }
+            Err(SendError::SenderClosed) => {
+                warn!("Can no longer write to client {key:?}");
+            }
+        }
+        bail!("unable to send msg");
+    }
+}
+
+/// Represents a connection to a client.
+// TODO: expand to allow for _multiple connections_ associated with a single NodeId. This
+// introduces some questions around which connection should be prioritized when forwarding packets
+#[derive(Debug)]
+pub(super) struct Client {
+    /// The client connection associated with the [`NodeId`]
+    conn: ClientConn,
+    /// list of peers we have sent messages to
+    sent_to: HashSet<NodeId>,
+}
+
+impl Client {
+    fn new(conn: ClientConn) -> Self {
+        Self {
+            conn,
+            sent_to: HashSet::default(),
+        }
+    }
+
+    /// Record that this client sent a packet to the `dst` client
+    fn record_send(&mut self, dst: NodeId) {
+        self.sent_to.insert(dst);
+    }
+
+    async fn shutdown(self) {
+        self.conn.shutdown().await;
+    }
+
+    fn send_packet(&self, packet: Packet) -> Result<(), SendError> {
+        try_send(&self.conn.send_queue, packet)
+    }
+
+    fn send_disco_packet(&self, packet: Packet) -> Result<(), SendError> {
+        try_send(&self.conn.disco_send_queue, packet)
+    }
+
+    fn send_peer_gone(&self, key: NodeId) -> Result<(), SendError> {
+        let res = try_send(&self.conn.peer_gone, key);
+        match res {
+            Ok(_) => {
+                inc!(Metrics, other_packets_sent);
+            }
+            Err(_) => {
+                inc!(Metrics, other_packets_dropped);
+            }
+        }
+        res
+    }
+}
+
+/// Tries up to `3` times to send a message into the given channel, retrying iff it is full.
+fn try_send<T>(sender: &mpsc::Sender<T>, msg: T) -> Result<(), SendError> {
+    let mut msg = msg;
+    for _ in 0..RETRIES {
+        match sender.try_send(msg) {
+            Ok(_) => return Ok(()),
+            // if the queue is full, try again (max 3 times)
+            Err(mpsc::error::TrySendError::Full(m)) => msg = m,
+            // only other option is `TrySendError::Closed`, report the
+            // closed error
+            Err(_) => return Err(SendError::SenderClosed),
+        }
+    }
+    Err(SendError::PacketDropped)
+}
+
+#[derive(Debug)]
+enum SendError {
+    PacketDropped,
+    SenderClosed,
+}
+
+#[cfg(test)]
+mod tests {
+    use std::time::Duration;
+
+    use bytes::Bytes;
+    use iroh_base::key::SecretKey;
+    use tokio::io::DuplexStream;
+    use tokio_util::codec::{Framed, FramedRead};
+
+    use super::*;
+    use crate::{
+        protos::relay::{recv_frame, DerpCodec, Frame, FrameType},
+        server::streams::{MaybeTlsStream, RelayedStream},
+    };
+
+    fn test_client_builder(key: NodeId) -> (ClientConnConfig, FramedRead<DuplexStream, DerpCodec>) {
+        let (test_io, io) = tokio::io::duplex(1024);
+        let (server_channel, _) = mpsc::channel(10);
+        (
+            ClientConnConfig {
+                node_id: key,
+                stream: RelayedStream::Derp(Framed::new(MaybeTlsStream::Test(io), DerpCodec)),
+                write_timeout: Duration::from_secs(1),
+                channel_capacity: 10,
+                rate_limit: None,
+                server_channel,
+            },
+            FramedRead::new(test_io, DerpCodec),
+        )
+    }
+
+    #[tokio::test]
+    async fn test_clients() -> Result<()> {
+        let a_key = SecretKey::generate().public();
+        let b_key = SecretKey::generate().public();
+
+        let (builder_a, mut a_rw) = test_client_builder(a_key);
+
+        let mut clients = Clients::default();
+        clients.register(builder_a).await;
+
+        // send packet
+        let data = b"hello world!";
+        let expect_packet = Packet {
+            src: b_key,
+            data: Bytes::from(&data[..]),
+        };
+        clients
+            .send_packet(&a_key.clone(), expect_packet.clone())
+            .await?;
+        let frame = recv_frame(FrameType::RecvPacket, &mut a_rw).await?;
+        assert_eq!(
+            frame,
+            Frame::RecvPacket {
+                src_key: b_key,
+                content: data.to_vec().into(),
+            }
+        );
+
+        // send disco packet
+        clients
+            .send_disco_packet(&a_key.clone(), expect_packet)
+            .await?;
+        let frame = recv_frame(FrameType::RecvPacket, &mut a_rw).await?;
+        assert_eq!(
+            frame,
+            Frame::RecvPacket {
+                src_key: b_key,
+                content: data.to_vec().into(),
+            }
+        );
+
+        // send peer_gone
+        clients.send_peer_gone(&a_key, b_key);
+        let frame = recv_frame(FrameType::PeerGone, &mut a_rw).await?;
+        assert_eq!(frame, Frame::NodeGone { node_id: b_key });
+
+        clients.unregister(&a_key.clone()).await;
+
+        assert!(!clients.inner.contains_key(&a_key));
+
+        clients.shutdown().await;
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/http_server.rs.html b/pr/2992/docs/src/iroh_relay/server/http_server.rs.html new file mode 100644 index 0000000000..a62cd3177c --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/http_server.rs.html @@ -0,0 +1,2203 @@ +http_server.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+
use std::{
+    collections::HashMap, future::Future, net::SocketAddr, pin::Pin, sync::Arc, time::Duration,
+};
+
+use anyhow::{bail, ensure, Context as _, Result};
+use bytes::Bytes;
+use derive_more::Debug;
+use futures_lite::FutureExt;
+use http::{header::CONNECTION, response::Builder as ResponseBuilder};
+use hyper::{
+    body::Incoming,
+    header::{HeaderValue, UPGRADE},
+    service::Service,
+    upgrade::Upgraded,
+    HeaderMap, Method, Request, Response, StatusCode,
+};
+use iroh_metrics::inc;
+use tokio::{
+    net::{TcpListener, TcpStream},
+    sync::mpsc,
+};
+use tokio_rustls_acme::AcmeAcceptor;
+use tokio_tungstenite::{
+    tungstenite::{handshake::derive_accept_key, protocol::Role},
+    WebSocketStream,
+};
+use tokio_util::{codec::Framed, sync::CancellationToken, task::AbortOnDropHandle};
+use tracing::{debug, debug_span, error, info, info_span, trace, warn, Instrument};
+
+use crate::{
+    http::{Protocol, LEGACY_RELAY_PATH, RELAY_PATH, SUPPORTED_WEBSOCKET_VERSION},
+    protos::relay::{recv_client_key, DerpCodec, PER_CLIENT_SEND_QUEUE_DEPTH, PROTOCOL_VERSION},
+    server::{
+        actor::{Message, ServerActorTask},
+        client_conn::ClientConnConfig,
+        metrics::Metrics,
+        streams::{MaybeTlsStream, RelayedStream},
+        ClientConnRateLimit,
+    },
+};
+
+type BytesBody = http_body_util::Full<hyper::body::Bytes>;
+type HyperError = Box<dyn std::error::Error + Send + Sync>;
+type HyperResult<T> = std::result::Result<T, HyperError>;
+type HyperHandler = Box<
+    dyn Fn(Request<Incoming>, ResponseBuilder) -> HyperResult<Response<BytesBody>>
+        + Send
+        + Sync
+        + 'static,
+>;
+
+/// Creates a new [`BytesBody`] with no content.
+fn body_empty() -> BytesBody {
+    http_body_util::Full::new(hyper::body::Bytes::new())
+}
+
+/// Creates a new [`BytesBody`] with given content.
+fn body_full(content: impl Into<hyper::body::Bytes>) -> BytesBody {
+    http_body_util::Full::new(content.into())
+}
+
+fn downcast_upgrade(upgraded: Upgraded) -> Result<(MaybeTlsStream, Bytes)> {
+    match upgraded.downcast::<hyper_util::rt::TokioIo<MaybeTlsStream>>() {
+        Ok(parts) => Ok((parts.io.into_inner(), parts.read_buf)),
+        Err(_) => {
+            bail!("could not downcast the upgraded connection to MaybeTlsStream")
+        }
+    }
+}
+
+/// The Relay HTTP server.
+///
+/// A running HTTP server serving the relay endpoint and optionally a number of additional
+/// HTTP services added with [`ServerBuilder::request_handler`].  If configured using
+/// [`ServerBuilder::tls_config`] the server will handle TLS as well.
+///
+/// Created using [`ServerBuilder::spawn`].
+#[derive(Debug)]
+pub(super) struct Server {
+    addr: SocketAddr,
+    http_server_task: AbortOnDropHandle<()>,
+    cancel_server_loop: CancellationToken,
+}
+
+impl Server {
+    /// Returns a handle for this server.
+    ///
+    /// The server runs in the background as several async tasks.  This allows controlling
+    /// the server, in particular it allows gracefully shutting down the server.
+    pub(super) fn handle(&self) -> ServerHandle {
+        ServerHandle {
+            cancel_token: self.cancel_server_loop.clone(),
+        }
+    }
+
+    /// Closes the underlying relay server and the HTTP(S) server tasks.
+    pub(super) fn shutdown(&self) {
+        self.cancel_server_loop.cancel();
+    }
+
+    /// Returns the [`AbortOnDropHandle`] for the supervisor task managing the server.
+    ///
+    /// This is the root of all the tasks for the server.  Aborting it will abort all the
+    /// other tasks for the server.  Awaiting it will complete when all the server tasks are
+    /// completed.
+    pub(super) fn task_handle(&mut self) -> &mut AbortOnDropHandle<()> {
+        &mut self.http_server_task
+    }
+
+    /// Returns the local address of this server.
+    pub(super) fn addr(&self) -> SocketAddr {
+        self.addr
+    }
+}
+
+/// A handle for the [`Server`].
+///
+/// This does not allow access to the task but can communicate with it.
+#[derive(Debug, Clone)]
+pub(super) struct ServerHandle {
+    cancel_token: CancellationToken,
+}
+
+impl ServerHandle {
+    /// Gracefully shut down the server.
+    pub(super) fn shutdown(&self) {
+        self.cancel_token.cancel()
+    }
+}
+
+/// Configuration to use for the TLS connection
+#[derive(Debug, Clone)]
+pub(super) struct TlsConfig {
+    /// The server config
+    pub(super) config: Arc<rustls::ServerConfig>,
+    /// The kind
+    pub(super) acceptor: TlsAcceptor,
+}
+
+/// Builder for the Relay HTTP Server.
+///
+/// Defaults to handling relay requests on the "/relay" (and "/derp" for backwards compatibility) endpoint.
+/// Other HTTP endpoints can be added using [`ServerBuilder::request_handler`].
+#[derive(derive_more::Debug)]
+pub(super) struct ServerBuilder {
+    /// The ip + port combination for this server.
+    addr: SocketAddr,
+    /// Optional tls configuration/TlsAcceptor combination.
+    ///
+    /// When `None`, the server will serve HTTP, otherwise it will serve HTTPS.
+    tls_config: Option<TlsConfig>,
+    /// A map of request handlers to routes.
+    ///
+    /// Used when certain routes in your server should be made available at the same port as
+    /// the relay server, and so must be handled along side requests to the relay endpoint.
+    handlers: Handlers,
+    /// Headers to use for HTTP responses.
+    headers: HeaderMap,
+    /// Rate-limiting configuration for an individual client connection.
+    ///
+    /// Rate-limiting is enforced on received traffic from individual clients.  This
+    /// configuration applies to a single client connection.
+    client_rx_ratelimit: Option<ClientConnRateLimit>,
+}
+
+impl ServerBuilder {
+    /// Creates a new [ServerBuilder].
+    pub(super) fn new(addr: SocketAddr) -> Self {
+        Self {
+            addr,
+            tls_config: None,
+            handlers: Default::default(),
+            headers: HeaderMap::new(),
+            client_rx_ratelimit: None,
+        }
+    }
+
+    /// Serves all requests content using TLS.
+    pub(super) fn tls_config(mut self, config: Option<TlsConfig>) -> Self {
+        self.tls_config = config;
+        self
+    }
+
+    /// Sets the per-client rate-limit configuration for incoming data.
+    ///
+    /// On each client connection the incoming data is rate-limited.  By default
+    /// no rate limit is enforced.
+    pub(super) fn client_rx_ratelimit(mut self, config: ClientConnRateLimit) -> Self {
+        self.client_rx_ratelimit = Some(config);
+        self
+    }
+
+    /// Adds a custom handler for a specific Method & URI.
+    pub(super) fn request_handler(
+        mut self,
+        method: Method,
+        uri_path: &'static str,
+        handler: HyperHandler,
+    ) -> Self {
+        self.handlers.insert((method, uri_path), handler);
+        self
+    }
+
+    /// Adds HTTP headers to responses.
+    pub(super) fn headers(mut self, headers: HeaderMap) -> Self {
+        for (k, v) in headers.iter() {
+            self.headers.insert(k.clone(), v.clone());
+        }
+        self
+    }
+
+    /// Builds and spawns an HTTP(S) Relay Server.
+    pub(super) async fn spawn(self) -> Result<Server> {
+        let server_task = ServerActorTask::spawn();
+        let service = RelayService::new(
+            self.handlers,
+            self.headers,
+            server_task.server_channel.clone(),
+            server_task.write_timeout,
+            self.client_rx_ratelimit,
+        );
+
+        let addr = self.addr;
+        let tls_config = self.tls_config;
+
+        // Bind a TCP listener on `addr` and handles content using HTTPS.
+
+        let listener = TcpListener::bind(&addr)
+            .await
+            .with_context(|| format!("failed to bind server socket to {addr}"))?;
+
+        // we will use this cancel token to stop the infinite loop in the `listener.accept() task`
+        let cancel_server_loop = CancellationToken::new();
+
+        let addr = listener.local_addr()?;
+        let http_str = tls_config.as_ref().map_or("HTTP/WS", |_| "HTTPS/WSS");
+        info!("[{http_str}] relay: serving on {addr}");
+
+        let cancel = cancel_server_loop.clone();
+        let task = tokio::task::spawn(
+            async move {
+                // create a join set to track all our connection tasks
+                let mut set = tokio::task::JoinSet::new();
+                loop {
+                    tokio::select! {
+                        biased;
+                        _ = cancel.cancelled() => {
+                            break;
+                        }
+                        Some(res) = set.join_next(), if !set.is_empty() => {
+                            if let Err(err) = res {
+                                if err.is_panic() {
+                                    panic!("task panicked: {:#?}", err);
+                                }
+                            }
+                        }
+                        res = listener.accept() => match res {
+                            Ok((stream, peer_addr)) => {
+                                debug!("connection opened from {peer_addr}");
+                                let tls_config = tls_config.clone();
+                                let service = service.clone();
+                                // spawn a task to handle the connection
+                                set.spawn(async move {
+                                    service
+                                        .handle_connection(stream, tls_config)
+                                        .await
+                                }.instrument(info_span!("conn", peer = %peer_addr)));
+                            }
+                            Err(err) => {
+                                error!("failed to accept connection: {err}");
+                            }
+                        }
+                    }
+                }
+                // TODO: if the task this is running in is aborted this server is not shut
+                // down.
+                server_task.close().await;
+                set.shutdown().await;
+                debug!("server has been shutdown.");
+            }
+            .instrument(info_span!("relay-http-serve")),
+        );
+
+        Ok(Server {
+            addr,
+            http_server_task: AbortOnDropHandle::new(task),
+            cancel_server_loop,
+        })
+    }
+}
+
+/// The hyper Service that serves the actual relay endpoints.
+#[derive(Clone, Debug)]
+struct RelayService(Arc<Inner>);
+
+#[derive(Debug)]
+struct Inner {
+    handlers: Handlers,
+    headers: HeaderMap,
+    server_channel: mpsc::Sender<Message>,
+    write_timeout: Duration,
+    rate_limit: Option<ClientConnRateLimit>,
+}
+
+impl RelayService {
+    /// Upgrades the HTTP connection to the relay protocol, runs relay client.
+    fn call_client_conn(
+        &self,
+        mut req: Request<Incoming>,
+    ) -> Pin<Box<dyn Future<Output = Result<Response<BytesBody>, hyper::Error>> + Send>> {
+        // TODO: soooo much cloning. See if there is an alternative
+        let this = self.clone();
+        let mut builder = Response::builder();
+        for (key, value) in self.0.headers.iter() {
+            builder = builder.header(key, value);
+        }
+
+        async move {
+            {
+                // Send a 400 to any request that doesn't have an `Upgrade` header.
+                let Some(protocol) = req.headers().get(UPGRADE).and_then(Protocol::parse_header)
+                else {
+                    return Ok(builder
+                        .status(StatusCode::BAD_REQUEST)
+                        .body(body_empty())
+                        .expect("valid body"));
+                };
+
+                let websocket_headers = if protocol == Protocol::Websocket {
+                    let Some(key) = req.headers().get("Sec-WebSocket-Key").cloned() else {
+                        warn!("missing header Sec-WebSocket-Key for websocket relay protocol");
+                        return Ok(builder
+                            .status(StatusCode::BAD_REQUEST)
+                            .body(body_empty())
+                            .expect("valid body"));
+                    };
+
+                    let Some(version) = req.headers().get("Sec-WebSocket-Version").cloned() else {
+                        warn!("missing header Sec-WebSocket-Version for websocket relay protocol");
+                        return Ok(builder
+                            .status(StatusCode::BAD_REQUEST)
+                            .body(body_empty())
+                            .expect("valid body"));
+                    };
+
+                    if version.as_bytes() != SUPPORTED_WEBSOCKET_VERSION.as_bytes() {
+                        warn!("invalid header Sec-WebSocket-Version: {:?}", version);
+                        return Ok(builder
+                            .status(StatusCode::BAD_REQUEST)
+                            // It's convention to send back the version(s) we *do* support
+                            .header("Sec-WebSocket-Version", SUPPORTED_WEBSOCKET_VERSION)
+                            .body(body_empty())
+                            .expect("valid body"));
+                    }
+
+                    Some((key, version))
+                } else {
+                    None
+                };
+
+                debug!(?protocol, "upgrading connection");
+
+                // Setup a future that will eventually receive the upgraded
+                // connection and talk a new protocol, and spawn the future
+                // into the runtime.
+                //
+                // Note: This can't possibly be fulfilled until the 101 response
+                // is returned below, so it's better to spawn this future instead
+                // waiting for it to complete to then return a response.
+                tokio::task::spawn(
+                    async move {
+                        match hyper::upgrade::on(&mut req).await {
+                            Ok(upgraded) => {
+                                if let Err(err) =
+                                    this.0.relay_connection_handler(protocol, upgraded).await
+                                {
+                                    warn!(
+                                        ?protocol,
+                                        "error accepting upgraded connection: {err:#}",
+                                    );
+                                } else {
+                                    debug!(?protocol, "upgraded connection completed");
+                                };
+                            }
+                            Err(err) => warn!("upgrade error: {err:#}"),
+                        }
+                    }
+                    .instrument(debug_span!("handler")),
+                );
+
+                // Now return a 101 Response saying we agree to the upgrade to the
+                // HTTP_UPGRADE_PROTOCOL
+                builder = builder
+                    .status(StatusCode::SWITCHING_PROTOCOLS)
+                    .header(UPGRADE, HeaderValue::from_static(protocol.upgrade_header()));
+
+                if let Some((key, _version)) = websocket_headers {
+                    Ok(builder
+                        .header("Sec-WebSocket-Accept", &derive_accept_key(key.as_bytes()))
+                        .header(CONNECTION, "upgrade")
+                        .body(body_full("switching to websocket protocol"))
+                        .expect("valid body"))
+                } else {
+                    Ok(builder.body(body_empty()).expect("valid body"))
+                }
+            }
+        }
+        .boxed()
+    }
+}
+
+impl Service<Request<Incoming>> for RelayService {
+    type Response = Response<BytesBody>;
+    type Error = HyperError;
+    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
+
+    fn call(&self, req: Request<Incoming>) -> Self::Future {
+        // Create a client if the request hits the relay endpoint.
+        if matches!(
+            (req.method(), req.uri().path()),
+            (&hyper::Method::GET, LEGACY_RELAY_PATH | RELAY_PATH)
+        ) {
+            let this = self.clone();
+            return Box::pin(async move { this.call_client_conn(req).await.map_err(Into::into) });
+        }
+        // Otherwise handle the relay connection as normal.
+
+        // Check all other possible endpoints.
+        let uri = req.uri().clone();
+        if let Some(res) = self.0.handlers.get(&(req.method().clone(), uri.path())) {
+            let f = res(req, self.0.default_response());
+            return Box::pin(async move { f });
+        }
+        // Otherwise return 404
+        let res = self.0.not_found_fn(req, self.0.default_response());
+        Box::pin(async move { res })
+    }
+}
+
+impl Inner {
+    fn default_response(&self) -> ResponseBuilder {
+        let mut response = Response::builder();
+        for (key, value) in self.headers.iter() {
+            response = response.header(key.clone(), value.clone());
+        }
+        response
+    }
+
+    fn not_found_fn(
+        &self,
+        _req: Request<Incoming>,
+        mut res: ResponseBuilder,
+    ) -> HyperResult<Response<BytesBody>> {
+        for (k, v) in self.headers.iter() {
+            res = res.header(k.clone(), v.clone());
+        }
+        let body = body_full("Not Found");
+        let r = res.status(StatusCode::NOT_FOUND).body(body)?;
+        HyperResult::Ok(r)
+    }
+
+    /// The server HTTP handler to do HTTP upgrades.
+    ///
+    /// This handler runs while doing the connection upgrade handshake.  Once the connection
+    /// is upgraded it sends the stream to the relay server which takes it over.  After
+    /// having sent off the connection this handler returns.
+    async fn relay_connection_handler(&self, protocol: Protocol, upgraded: Upgraded) -> Result<()> {
+        debug!(?protocol, "relay_connection upgraded");
+        let (io, read_buf) = downcast_upgrade(upgraded)?;
+        ensure!(
+            read_buf.is_empty(),
+            "can not deal with buffered data yet: {:?}",
+            read_buf
+        );
+
+        self.accept(protocol, io).await
+    }
+
+    /// Adds a new connection to the server and serves it.
+    ///
+    /// Will error if it takes too long (10 sec) to write or read to the connection, if there is
+    /// some read or write error to the connection,  if the server is meant to verify clients,
+    /// and is unable to verify this one, or if there is some issue communicating with the server.
+    ///
+    /// The provided [`AsyncRead`] and [`AsyncWrite`] must be already connected to the connection.
+    ///
+    /// [`AsyncRead`]: tokio::io::AsyncRead
+    /// [`AsyncWrite`]: tokio::io::AsyncWrite
+    async fn accept(&self, protocol: Protocol, io: MaybeTlsStream) -> Result<()> {
+        trace!(?protocol, "accept: start");
+        let mut io = match protocol {
+            Protocol::Relay => {
+                inc!(Metrics, derp_accepts);
+                RelayedStream::Derp(Framed::new(io, DerpCodec))
+            }
+            Protocol::Websocket => {
+                inc!(Metrics, websocket_accepts);
+                RelayedStream::Ws(WebSocketStream::from_raw_socket(io, Role::Server, None).await)
+            }
+        };
+        trace!("accept: recv client key");
+        let (client_key, info) = recv_client_key(&mut io)
+            .await
+            .context("unable to receive client information")?;
+
+        if info.version != PROTOCOL_VERSION {
+            bail!(
+                "unexpected client version {}, expected {}",
+                info.version,
+                PROTOCOL_VERSION
+            );
+        }
+
+        trace!("accept: build client conn");
+        let client_conn_builder = ClientConnConfig {
+            node_id: client_key,
+            stream: io,
+            write_timeout: self.write_timeout,
+            channel_capacity: PER_CLIENT_SEND_QUEUE_DEPTH,
+            rate_limit: self.rate_limit,
+            server_channel: self.server_channel.clone(),
+        };
+        trace!("accept: create client");
+        self.server_channel
+            .send(Message::CreateClient(client_conn_builder))
+            .await
+            .map_err(|_| {
+                anyhow::anyhow!("server channel closed, the server is probably shutdown")
+            })?;
+        Ok(())
+    }
+}
+
+/// TLS Certificate Authority acceptor.
+#[derive(Clone, derive_more::Debug)]
+pub(super) enum TlsAcceptor {
+    /// Uses Let's Encrypt as the Certificate Authority. This is used in production.
+    LetsEncrypt(#[debug("tokio_rustls_acme::AcmeAcceptor")] AcmeAcceptor),
+    /// Manually added tls acceptor. Generally used for tests or for when we've passed in
+    /// a certificate via a file.
+    Manual(#[debug("tokio_rustls::TlsAcceptor")] tokio_rustls::TlsAcceptor),
+}
+
+impl RelayService {
+    fn new(
+        handlers: Handlers,
+        headers: HeaderMap,
+        server_channel: mpsc::Sender<Message>,
+        write_timeout: Duration,
+        rate_limit: Option<ClientConnRateLimit>,
+    ) -> Self {
+        Self(Arc::new(Inner {
+            handlers,
+            headers,
+            server_channel,
+            write_timeout,
+            rate_limit,
+        }))
+    }
+
+    /// Handle the incoming connection.
+    ///
+    /// If a `tls_config` is given, will serve the connection using HTTPS.
+    async fn handle_connection(self, stream: TcpStream, tls_config: Option<TlsConfig>) {
+        let res = match tls_config {
+            Some(tls_config) => {
+                debug!("HTTPS: serve connection");
+                self.tls_serve_connection(stream, tls_config).await
+            }
+            None => {
+                debug!("HTTP: serve connection");
+                self.serve_connection(MaybeTlsStream::Plain(stream)).await
+            }
+        };
+        match res {
+            Ok(()) => {}
+            Err(error) => match error.downcast_ref::<std::io::Error>() {
+                Some(io_error) if io_error.kind() == std::io::ErrorKind::UnexpectedEof => {
+                    debug!(reason=?error, "peer disconnected");
+                }
+                _ => {
+                    error!(?error, "failed to handle connection");
+                }
+            },
+        }
+    }
+
+    /// Serve the tls connection
+    async fn tls_serve_connection(self, stream: TcpStream, tls_config: TlsConfig) -> Result<()> {
+        let TlsConfig { acceptor, config } = tls_config;
+        match acceptor {
+            TlsAcceptor::LetsEncrypt(a) => match a.accept(stream).await? {
+                None => {
+                    info!("TLS[acme]: received TLS-ALPN-01 validation request");
+                }
+                Some(start_handshake) => {
+                    debug!("TLS[acme]: start handshake");
+                    let tls_stream = start_handshake
+                        .into_stream(config)
+                        .await
+                        .context("TLS[acme] handshake")?;
+                    self.serve_connection(MaybeTlsStream::Tls(tls_stream))
+                        .await
+                        .context("TLS[acme] serve connection")?;
+                }
+            },
+            TlsAcceptor::Manual(a) => {
+                debug!("TLS[manual]: accept");
+                let tls_stream = a.accept(stream).await.context("TLS[manual] accept")?;
+                self.serve_connection(MaybeTlsStream::Tls(tls_stream))
+                    .await
+                    .context("TLS[manual] serve connection")?;
+            }
+        }
+        Ok(())
+    }
+
+    /// Wrapper for the actual http connection (with upgrades)
+    async fn serve_connection<I>(self, io: I) -> Result<()>
+    where
+        I: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + Sync + 'static,
+    {
+        hyper::server::conn::http1::Builder::new()
+            .serve_connection(hyper_util::rt::TokioIo::new(io), self)
+            .with_upgrades()
+            .await?;
+        Ok(())
+    }
+}
+
+#[derive(Default)]
+struct Handlers(HashMap<(Method, &'static str), HyperHandler>);
+
+impl std::fmt::Debug for Handlers {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let s = self.0.keys().fold(String::new(), |curr, next| {
+            let (method, uri) = next;
+            format!("{curr}\n({method},{uri}): Box<Fn(ResponseBuilder) -> Result<Response<Body>> + Send + Sync + 'static>")
+        });
+        write!(f, "HashMap<{s}>")
+    }
+}
+
+impl std::ops::Deref for Handlers {
+    type Target = HashMap<(Method, &'static str), HyperHandler>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl std::ops::DerefMut for Handlers {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::sync::Arc;
+
+    use anyhow::Result;
+    use bytes::Bytes;
+    use iroh_base::key::{PublicKey, SecretKey};
+    use reqwest::Url;
+    use tokio::{sync::mpsc, task::JoinHandle};
+    use tokio_util::codec::{FramedRead, FramedWrite};
+    use tracing::{info, info_span, Instrument};
+    use tracing_subscriber::{prelude::*, EnvFilter};
+
+    use super::*;
+    use crate::client::{
+        conn::{ConnBuilder, ConnReader, ConnWriter, ReceivedMessage},
+        streams::{MaybeTlsStreamReader, MaybeTlsStreamWriter},
+        Client, ClientBuilder,
+    };
+
+    pub(crate) fn make_tls_config() -> TlsConfig {
+        let subject_alt_names = vec!["localhost".to_string()];
+
+        let cert = rcgen::generate_simple_self_signed(subject_alt_names).unwrap();
+        let rustls_certificate = cert.cert.der().clone();
+        let rustls_key = rustls::pki_types::PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der());
+        let config = rustls::ServerConfig::builder_with_provider(Arc::new(
+            rustls::crypto::ring::default_provider(),
+        ))
+        .with_safe_default_protocol_versions()
+        .expect("protocols supported by ring")
+        .with_no_client_auth()
+        .with_single_cert(vec![(rustls_certificate)], rustls_key.into())
+        .expect("cert is right");
+
+        let config = Arc::new(config);
+        let acceptor = tokio_rustls::TlsAcceptor::from(config.clone());
+
+        TlsConfig {
+            config,
+            acceptor: TlsAcceptor::Manual(acceptor),
+        }
+    }
+
+    #[tokio::test]
+    async fn test_http_clients_and_server() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        let a_key = SecretKey::generate();
+        let b_key = SecretKey::generate();
+
+        // start server
+        let server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
+            .spawn()
+            .await?;
+
+        let addr = server.addr();
+
+        // get dial info
+        let port = addr.port();
+        let addr = {
+            if let std::net::IpAddr::V4(ipv4_addr) = addr.ip() {
+                ipv4_addr
+            } else {
+                anyhow::bail!("cannot get ipv4 addr from socket addr {addr:?}");
+            }
+        };
+        info!("addr: {addr}:{port}");
+        let relay_addr: Url = format!("http://{addr}:{port}").parse().unwrap();
+
+        // create clients
+        let (a_key, mut a_recv, client_a_task, client_a) = {
+            let span = info_span!("client-a");
+            let _guard = span.enter();
+            create_test_client(a_key, relay_addr.clone())
+        };
+        info!("created client {a_key:?}");
+        let (b_key, mut b_recv, client_b_task, client_b) = {
+            let span = info_span!("client-b");
+            let _guard = span.enter();
+            create_test_client(b_key, relay_addr)
+        };
+        info!("created client {b_key:?}");
+
+        info!("ping a");
+        client_a.ping().await?;
+
+        info!("ping b");
+        client_b.ping().await?;
+
+        info!("sending message from a to b");
+        let msg = Bytes::from_static(b"hi there, client b!");
+        client_a.send(b_key, msg.clone()).await?;
+        info!("waiting for message from a on b");
+        let (got_key, got_msg) = b_recv.recv().await.expect("expected message from client_a");
+        assert_eq!(a_key, got_key);
+        assert_eq!(msg, got_msg);
+
+        info!("sending message from b to a");
+        let msg = Bytes::from_static(b"right back at ya, client b!");
+        client_b.send(a_key, msg.clone()).await?;
+        info!("waiting for message b on a");
+        let (got_key, got_msg) = a_recv.recv().await.expect("expected message from client_b");
+        assert_eq!(b_key, got_key);
+        assert_eq!(msg, got_msg);
+
+        client_a.close().await?;
+        client_a_task.abort();
+        client_b.close().await?;
+        client_b_task.abort();
+        server.shutdown();
+
+        Ok(())
+    }
+
+    fn create_test_client(
+        key: SecretKey,
+        server_url: Url,
+    ) -> (
+        PublicKey,
+        mpsc::Receiver<(PublicKey, Bytes)>,
+        JoinHandle<()>,
+        Client,
+    ) {
+        let client = ClientBuilder::new(server_url).insecure_skip_cert_verify(true);
+        let dns_resolver = crate::dns::default_resolver();
+        let (client, mut client_reader) = client.build(key.clone(), dns_resolver.clone());
+        let public_key = key.public();
+        let (received_msg_s, received_msg_r) = tokio::sync::mpsc::channel(10);
+        let client_reader_task = tokio::spawn(
+            async move {
+                loop {
+                    info!("waiting for message on {:?}", key.public());
+                    match client_reader.recv().await {
+                        None => {
+                            info!("client received nothing");
+                            return;
+                        }
+                        Some(Err(e)) => {
+                            info!("client {:?} `recv` error {e}", key.public());
+                            return;
+                        }
+                        Some(Ok(msg)) => {
+                            info!("got message on {:?}: {msg:?}", key.public());
+                            if let ReceivedMessage::ReceivedPacket { source, data } = msg {
+                                received_msg_s
+                                    .send((source, data))
+                                    .await
+                                    .unwrap_or_else(|err| {
+                                        panic!(
+                                            "client {:?}, error sending message over channel: {:?}",
+                                            key.public(),
+                                            err
+                                        )
+                                    });
+                            }
+                        }
+                    }
+                }
+            }
+            .instrument(info_span!("test-client-reader")),
+        );
+        (public_key, received_msg_r, client_reader_task, client)
+    }
+
+    #[tokio::test]
+    async fn test_https_clients_and_server() -> Result<()> {
+        tracing_subscriber::registry()
+            .with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
+            .with(EnvFilter::from_default_env())
+            .try_init()
+            .ok();
+
+        let a_key = SecretKey::generate();
+        let b_key = SecretKey::generate();
+
+        // create tls_config
+        let tls_config = make_tls_config();
+
+        // start server
+        let mut server = ServerBuilder::new("127.0.0.1:0".parse().unwrap())
+            .tls_config(Some(tls_config))
+            .spawn()
+            .await?;
+
+        let addr = server.addr();
+
+        // get dial info
+        let port = addr.port();
+        let addr = {
+            if let std::net::IpAddr::V4(ipv4_addr) = addr.ip() {
+                ipv4_addr
+            } else {
+                anyhow::bail!("cannot get ipv4 addr from socket addr {addr:?}");
+            }
+        };
+        info!("Relay listening on: {addr}:{port}");
+
+        let url: Url = format!("https://localhost:{port}").parse().unwrap();
+
+        // create clients
+        let (a_key, mut a_recv, client_a_task, client_a) = create_test_client(a_key, url.clone());
+        info!("created client {a_key:?}");
+        let (b_key, mut b_recv, client_b_task, client_b) = create_test_client(b_key, url);
+        info!("created client {b_key:?}");
+
+        client_a.ping().await?;
+        client_b.ping().await?;
+
+        info!("sending message from a to b");
+        let msg = Bytes::from_static(b"hi there, client b!");
+        client_a.send(b_key, msg.clone()).await?;
+        info!("waiting for message from a on b");
+        let (got_key, got_msg) = b_recv.recv().await.expect("expected message from client_a");
+        assert_eq!(a_key, got_key);
+        assert_eq!(msg, got_msg);
+
+        info!("sending message from b to a");
+        let msg = Bytes::from_static(b"right back at ya, client b!");
+        client_b.send(a_key, msg.clone()).await?;
+        info!("waiting for message b on a");
+        let (got_key, got_msg) = a_recv.recv().await.expect("expected message from client_b");
+        assert_eq!(b_key, got_key);
+        assert_eq!(msg, got_msg);
+
+        server.shutdown();
+        server.task_handle().await?;
+        client_a.close().await?;
+        client_a_task.abort();
+        client_b.close().await?;
+        client_b_task.abort();
+        Ok(())
+    }
+
+    fn make_test_client(secret_key: SecretKey) -> (tokio::io::DuplexStream, ConnBuilder) {
+        let (client, server) = tokio::io::duplex(10);
+        let (client_reader, client_writer) = tokio::io::split(client);
+
+        let client_reader = MaybeTlsStreamReader::Mem(client_reader);
+        let client_writer = MaybeTlsStreamWriter::Mem(client_writer);
+
+        let client_reader = ConnReader::Derp(FramedRead::new(client_reader, DerpCodec));
+        let client_writer = ConnWriter::Derp(FramedWrite::new(client_writer, DerpCodec));
+
+        (
+            server,
+            ConnBuilder::new(secret_key, None, client_reader, client_writer),
+        )
+    }
+
+    #[tokio::test]
+    async fn test_server_basic() -> Result<()> {
+        let _guard = iroh_test::logging::setup();
+
+        // create the server!
+        let server_task: ServerActorTask = ServerActorTask::spawn();
+        let service = RelayService::new(
+            Default::default(),
+            Default::default(),
+            server_task.server_channel.clone(),
+            server_task.write_timeout,
+            None,
+        );
+
+        // create client a and connect it to the server
+        let key_a = SecretKey::generate();
+        let public_key_a = key_a.public();
+        let (rw_a, client_a_builder) = make_test_client(key_a);
+        let s = service.clone();
+        let handler_task = tokio::spawn(async move {
+            s.0.accept(Protocol::Relay, MaybeTlsStream::Test(rw_a))
+                .await
+        });
+        let (client_a, mut client_receiver_a) = client_a_builder.build().await?;
+        handler_task.await??;
+
+        // create client b and connect it to the server
+        let key_b = SecretKey::generate();
+        let public_key_b = key_b.public();
+        let (rw_b, client_b_builder) = make_test_client(key_b);
+        let s = service.clone();
+        let handler_task = tokio::spawn(async move {
+            s.0.accept(Protocol::Relay, MaybeTlsStream::Test(rw_b))
+                .await
+        });
+        let (client_b, mut client_receiver_b) = client_b_builder.build().await?;
+        handler_task.await??;
+
+        // send message from a to b!
+        let msg = Bytes::from_static(b"hello client b!!");
+        client_a.send(public_key_b, msg.clone()).await?;
+        match client_receiver_b.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_a, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // send message from b to a!
+        let msg = Bytes::from_static(b"nice to meet you client a!!");
+        client_b.send(public_key_a, msg.clone()).await?;
+        match client_receiver_a.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_b, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // close the server and clients
+        server_task.close().await;
+
+        // client connections have been shutdown
+        let res = client_a
+            .send(public_key_b, Bytes::from_static(b"try to send"))
+            .await;
+        assert!(res.is_err());
+        assert!(client_receiver_b.recv().await.is_err());
+        Ok(())
+    }
+
+    #[tokio::test]
+    async fn test_server_replace_client() -> Result<()> {
+        tracing_subscriber::registry()
+            .with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
+            .with(EnvFilter::from_default_env())
+            .try_init()
+            .ok();
+
+        // create the server!
+        let server_task: ServerActorTask = ServerActorTask::spawn();
+        let service = RelayService::new(
+            Default::default(),
+            Default::default(),
+            server_task.server_channel.clone(),
+            server_task.write_timeout,
+            None,
+        );
+
+        // create client a and connect it to the server
+        let key_a = SecretKey::generate();
+        let public_key_a = key_a.public();
+        let (rw_a, client_a_builder) = make_test_client(key_a);
+        let s = service.clone();
+        let handler_task = tokio::spawn(async move {
+            s.0.accept(Protocol::Relay, MaybeTlsStream::Test(rw_a))
+                .await
+        });
+        let (client_a, mut client_receiver_a) = client_a_builder.build().await?;
+        handler_task.await??;
+
+        // create client b and connect it to the server
+        let key_b = SecretKey::generate();
+        let public_key_b = key_b.public();
+        let (rw_b, client_b_builder) = make_test_client(key_b.clone());
+        let s = service.clone();
+        let handler_task = tokio::spawn(async move {
+            s.0.accept(Protocol::Relay, MaybeTlsStream::Test(rw_b))
+                .await
+        });
+        let (client_b, mut client_receiver_b) = client_b_builder.build().await?;
+        handler_task.await??;
+
+        // send message from a to b!
+        let msg = Bytes::from_static(b"hello client b!!");
+        client_a.send(public_key_b, msg.clone()).await?;
+        match client_receiver_b.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_a, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // send message from b to a!
+        let msg = Bytes::from_static(b"nice to meet you client a!!");
+        client_b.send(public_key_a, msg.clone()).await?;
+        match client_receiver_a.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_b, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // create client b and connect it to the server
+        let (new_rw_b, new_client_b_builder) = make_test_client(key_b);
+        let s = service.clone();
+        let handler_task = tokio::spawn(async move {
+            s.0.accept(Protocol::Relay, MaybeTlsStream::Test(new_rw_b))
+                .await
+        });
+        let (new_client_b, mut new_client_receiver_b) = new_client_b_builder.build().await?;
+        handler_task.await??;
+
+        // assert!(client_b.recv().await.is_err());
+
+        // send message from a to b!
+        let msg = Bytes::from_static(b"are you still there, b?!");
+        client_a.send(public_key_b, msg.clone()).await?;
+        match new_client_receiver_b.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_a, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // send message from b to a!
+        let msg = Bytes::from_static(b"just had a spot of trouble but I'm back now,a!!");
+        new_client_b.send(public_key_a, msg.clone()).await?;
+        match client_receiver_a.recv().await? {
+            ReceivedMessage::ReceivedPacket { source, data } => {
+                assert_eq!(public_key_b, source);
+                assert_eq!(&msg[..], data);
+            }
+            msg => {
+                anyhow::bail!("expected ReceivedPacket msg, got {msg:?}");
+            }
+        }
+
+        // close the server and clients
+        server_task.close().await;
+
+        // client connections have been shutdown
+        let res = client_a
+            .send(public_key_b, Bytes::from_static(b"try to send"))
+            .await;
+        assert!(res.is_err());
+        assert!(new_client_receiver_b.recv().await.is_err());
+        Ok(())
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/metrics.rs.html b/pr/2992/docs/src/iroh_relay/server/metrics.rs.html new file mode 100644 index 0000000000..284a5c89c0 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/metrics.rs.html @@ -0,0 +1,339 @@ +metrics.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+
use iroh_metrics::{
+    core::{Counter, Metric},
+    struct_iterable::Iterable,
+};
+
+/// Metrics tracked for the relay server
+#[derive(Debug, Clone, Iterable)]
+pub struct Metrics {
+    /*
+     * Metrics about packets
+     */
+    /// Bytes sent from a `FrameType::SendPacket`
+    pub bytes_sent: Counter,
+    /// Bytes received from a `FrameType::SendPacket`
+    pub bytes_recv: Counter,
+
+    /// `FrameType::SendPacket` sent, that are not disco messages
+    pub send_packets_sent: Counter,
+    /// `FrameType::SendPacket` received, that are not disco messages
+    pub send_packets_recv: Counter,
+    /// `FrameType::SendPacket` dropped, that are not disco messages
+    pub send_packets_dropped: Counter,
+
+    /// `FrameType::SendPacket` sent that are disco messages
+    pub disco_packets_sent: Counter,
+    /// `FrameType::SendPacket` received that are disco messages
+    pub disco_packets_recv: Counter,
+    /// `FrameType::SendPacket` dropped that are disco messages
+    pub disco_packets_dropped: Counter,
+
+    /// Packets of other `FrameType`s sent
+    pub other_packets_sent: Counter,
+    /// Packets of other `FrameType`s received
+    pub other_packets_recv: Counter,
+    /// Packets of other `FrameType`s dropped
+    pub other_packets_dropped: Counter,
+
+    /// Number of `FrameType::Ping`s received
+    pub got_ping: Counter,
+    /// Number of `FrameType::Pong`s sent
+    pub sent_pong: Counter,
+    /// Number of `FrameType::Unknown` received
+    pub unknown_frames: Counter,
+
+    /// Number of frames received from client connection which have been rate-limited.
+    pub frames_rx_ratelimited_total: Counter,
+    /// Number of client connections which have had any frames rate-limited.
+    pub conns_rx_ratelimited_total: Counter,
+
+    /*
+     * Metrics about peers
+     */
+    /// Number of connections we have accepted
+    pub accepts: Counter,
+    /// Number of connections we have removed because of an error
+    pub disconnects: Counter,
+
+    /// Number of unique client keys per day
+    pub unique_client_keys: Counter,
+
+    /// Number of accepted websocket connections
+    pub websocket_accepts: Counter,
+    /// Number of accepted 'iroh derp http' connection upgrades
+    pub derp_accepts: Counter,
+    // TODO: enable when we can have multiple connections for one node id
+    // pub duplicate_client_keys: Counter,
+    // pub duplicate_client_conns: Counter,
+    // TODO: only important stat that we cannot track right now
+    // pub average_queue_duration:
+}
+
+impl Default for Metrics {
+    fn default() -> Self {
+        Self {
+            /*
+             * Metrics about packets
+             */
+            send_packets_sent: Counter::new("Number of 'send' packets relayed."),
+            bytes_sent: Counter::new("Number of bytes sent."),
+            send_packets_recv: Counter::new("Number of 'send' packets received."),
+            bytes_recv: Counter::new("Number of bytes received."),
+            send_packets_dropped: Counter::new("Number of 'send' packets dropped."),
+            disco_packets_sent: Counter::new("Number of disco packets sent."),
+            disco_packets_recv: Counter::new("Number of disco packets received."),
+            disco_packets_dropped: Counter::new("Number of disco packets dropped."),
+
+            other_packets_sent: Counter::new(
+                "Number of packets sent that were not disco packets or 'send' packets",
+            ),
+            other_packets_recv: Counter::new(
+                "Number of packets received that were not disco packets or 'send' packets",
+            ),
+            other_packets_dropped: Counter::new(
+                "Number of times a non-disco, non-'send; packet was dropped.",
+            ),
+            got_ping: Counter::new("Number of times the server has received a Ping from a client."),
+            sent_pong: Counter::new("Number of times the server has sent a Pong to a client."),
+            unknown_frames: Counter::new("Number of unknown frames sent to this server."),
+            frames_rx_ratelimited_total: Counter::new(
+                "Number of frames received from client connection which have been rate-limited.",
+            ),
+            conns_rx_ratelimited_total: Counter::new(
+                "Number of client connections which have had any frames rate-limited.",
+            ),
+
+            /*
+             * Metrics about peers
+             */
+            accepts: Counter::new("Number of times this server has accepted a connection."),
+            disconnects: Counter::new("Number of clients that have then disconnected."),
+
+            unique_client_keys: Counter::new("Number of unique client keys per day."),
+
+            websocket_accepts: Counter::new("Number of accepted websocket connections"),
+            derp_accepts: Counter::new("Number of accepted 'iroh derp http' connection upgrades"),
+            // TODO: enable when we can have multiple connections for one node id
+            // pub duplicate_client_keys: Counter::new("Number of duplicate client keys."),
+            // pub duplicate_client_conns: Counter::new("Number of duplicate client connections."),
+            // TODO: only important stat that we cannot track right now
+            // pub average_queue_duration:
+        }
+    }
+}
+
+impl Metric for Metrics {
+    fn name() -> &'static str {
+        "relayserver"
+    }
+}
+
+/// StunMetrics tracked for the DERPER
+#[derive(Debug, Clone, Iterable)]
+pub struct StunMetrics {
+    /*
+     * Metrics about STUN requests
+     */
+    /// Number of stun requests made
+    pub requests: Counter,
+    /// Number of successful requests over ipv4
+    pub ipv4_success: Counter,
+    /// Number of successful requests over ipv6
+    pub ipv6_success: Counter,
+
+    /// Number of bad requests, either non-stun packets or incorrect binding request
+    pub bad_requests: Counter,
+    /// Number of failures
+    pub failures: Counter,
+}
+
+impl Default for StunMetrics {
+    fn default() -> Self {
+        Self {
+            /*
+             * Metrics about STUN requests
+             */
+            requests: Counter::new("Number of STUN requests made to the server."),
+            ipv4_success: Counter::new("Number of successful ipv4 STUN requests served."),
+            ipv6_success: Counter::new("Number of successful ipv6 STUN requests served."),
+            bad_requests: Counter::new("Number of bad requests made to the STUN endpoint."),
+            failures: Counter::new("Number of STUN requests that end in failure."),
+        }
+    }
+}
+
+impl Metric for StunMetrics {
+    fn name() -> &'static str {
+        "stun"
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/streams.rs.html b/pr/2992/docs/src/iroh_relay/server/streams.rs.html new file mode 100644 index 0000000000..b3e0ae0b31 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/streams.rs.html @@ -0,0 +1,337 @@ +streams.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+
//! Streams used in the server-side implementation of iroh relays.
+
+use std::{
+    pin::Pin,
+    task::{Context, Poll},
+};
+
+use anyhow::Result;
+use futures_lite::Stream;
+use futures_sink::Sink;
+use tokio::io::{AsyncRead, AsyncWrite};
+use tokio_tungstenite::{tungstenite, WebSocketStream};
+use tokio_util::codec::Framed;
+
+use crate::protos::relay::{DerpCodec, Frame};
+
+/// A Stream and Sink for [`Frame`]s connected to a single relay client.
+///
+/// The stream receives message from the client while the sink sends them to the client.
+#[derive(Debug)]
+pub(crate) enum RelayedStream {
+    Derp(Framed<MaybeTlsStream, DerpCodec>),
+    Ws(WebSocketStream<MaybeTlsStream>),
+}
+
+fn tung_to_io_err(e: tungstenite::Error) -> std::io::Error {
+    match e {
+        tungstenite::Error::Io(io_err) => io_err,
+        _ => std::io::Error::new(std::io::ErrorKind::Other, e.to_string()),
+    }
+}
+
+impl Sink<Frame> for RelayedStream {
+    type Error = std::io::Error;
+
+    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut framed) => Pin::new(framed).poll_ready(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_ready(cx).map_err(tung_to_io_err),
+        }
+    }
+
+    fn start_send(mut self: Pin<&mut Self>, item: Frame) -> Result<(), Self::Error> {
+        match *self {
+            Self::Derp(ref mut framed) => Pin::new(framed).start_send(item),
+            Self::Ws(ref mut ws) => Pin::new(ws)
+                .start_send(tungstenite::Message::Binary(item.encode_for_ws_msg()))
+                .map_err(tung_to_io_err),
+        }
+    }
+
+    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut framed) => Pin::new(framed).poll_flush(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_flush(cx).map_err(tung_to_io_err),
+        }
+    }
+
+    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match *self {
+            Self::Derp(ref mut framed) => Pin::new(framed).poll_close(cx),
+            Self::Ws(ref mut ws) => Pin::new(ws).poll_close(cx).map_err(tung_to_io_err),
+        }
+    }
+}
+
+impl Stream for RelayedStream {
+    type Item = anyhow::Result<Frame>;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        match *self {
+            Self::Derp(ref mut framed) => Pin::new(framed).poll_next(cx),
+            Self::Ws(ref mut ws) => match Pin::new(ws).poll_next(cx) {
+                Poll::Ready(Some(Ok(tungstenite::Message::Binary(vec)))) => {
+                    Poll::Ready(Some(Frame::decode_from_ws_msg(vec)))
+                }
+                Poll::Ready(Some(Ok(msg))) => {
+                    tracing::warn!(?msg, "Got websocket message of unsupported type, skipping.");
+                    Poll::Pending
+                }
+                Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e.into()))),
+                Poll::Ready(None) => Poll::Ready(None),
+                Poll::Pending => Poll::Pending,
+            },
+        }
+    }
+}
+
+/// The main underlying IO stream type used for the relay server.
+///
+/// Allows choosing whether or not the underlying [`tokio::net::TcpStream`] is served over Tls
+#[derive(Debug)]
+pub enum MaybeTlsStream {
+    /// A plain non-Tls [`tokio::net::TcpStream`]
+    Plain(tokio::net::TcpStream),
+    /// A Tls wrapped [`tokio::net::TcpStream`]
+    Tls(tokio_rustls::server::TlsStream<tokio::net::TcpStream>),
+    /// An in-memory bidirectional pipe.
+    #[cfg(test)]
+    Test(tokio::io::DuplexStream),
+}
+
+impl AsyncRead for MaybeTlsStream {
+    fn poll_read(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &mut tokio::io::ReadBuf<'_>,
+    ) -> Poll<std::io::Result<()>> {
+        match &mut *self {
+            MaybeTlsStream::Plain(ref mut s) => Pin::new(s).poll_read(cx, buf),
+            MaybeTlsStream::Tls(ref mut s) => Pin::new(s).poll_read(cx, buf),
+            #[cfg(test)]
+            MaybeTlsStream::Test(ref mut s) => Pin::new(s).poll_read(cx, buf),
+        }
+    }
+}
+
+impl AsyncWrite for MaybeTlsStream {
+    fn poll_flush(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<std::result::Result<(), std::io::Error>> {
+        match &mut *self {
+            MaybeTlsStream::Plain(ref mut s) => Pin::new(s).poll_flush(cx),
+            MaybeTlsStream::Tls(ref mut s) => Pin::new(s).poll_flush(cx),
+            #[cfg(test)]
+            MaybeTlsStream::Test(ref mut s) => Pin::new(s).poll_flush(cx),
+        }
+    }
+
+    fn poll_shutdown(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<std::result::Result<(), std::io::Error>> {
+        match &mut *self {
+            MaybeTlsStream::Plain(ref mut s) => Pin::new(s).poll_shutdown(cx),
+            MaybeTlsStream::Tls(ref mut s) => Pin::new(s).poll_shutdown(cx),
+            #[cfg(test)]
+            MaybeTlsStream::Test(ref mut s) => Pin::new(s).poll_shutdown(cx),
+        }
+    }
+
+    fn poll_write(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        buf: &[u8],
+    ) -> Poll<std::result::Result<usize, std::io::Error>> {
+        match &mut *self {
+            MaybeTlsStream::Plain(ref mut s) => Pin::new(s).poll_write(cx, buf),
+            MaybeTlsStream::Tls(ref mut s) => Pin::new(s).poll_write(cx, buf),
+            #[cfg(test)]
+            MaybeTlsStream::Test(ref mut s) => Pin::new(s).poll_write(cx, buf),
+        }
+    }
+
+    fn poll_write_vectored(
+        mut self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        bufs: &[std::io::IoSlice<'_>],
+    ) -> Poll<std::result::Result<usize, std::io::Error>> {
+        match &mut *self {
+            MaybeTlsStream::Plain(ref mut s) => Pin::new(s).poll_write_vectored(cx, bufs),
+            MaybeTlsStream::Tls(ref mut s) => Pin::new(s).poll_write_vectored(cx, bufs),
+            #[cfg(test)]
+            MaybeTlsStream::Test(ref mut s) => Pin::new(s).poll_write_vectored(cx, bufs),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_relay/server/testing.rs.html b/pr/2992/docs/src/iroh_relay/server/testing.rs.html new file mode 100644 index 0000000000..8203577361 --- /dev/null +++ b/pr/2992/docs/src/iroh_relay/server/testing.rs.html @@ -0,0 +1,197 @@ +testing.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+
//! Exposes functions to quickly configure a server suitable for testing.
+use std::net::{Ipv4Addr, Ipv6Addr};
+
+use super::{CertConfig, QuicConfig, RelayConfig, ServerConfig, StunConfig, TlsConfig};
+
+/// Creates a [`StunConfig`] suitable for testing.
+///
+/// To ensure port availability for testing, the port is configured to be assigned by the OS.
+pub fn stun_config() -> StunConfig {
+    StunConfig {
+        bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+    }
+}
+
+/// Creates a [`rustls::ServerConfig`] and certificates suitable for testing.
+///
+/// - Uses a self signed certificate valid for the `"localhost"` and `"127.0.0.1"` domains.
+pub fn self_signed_tls_certs_and_config() -> (
+    Vec<rustls::pki_types::CertificateDer<'static>>,
+    rustls::ServerConfig,
+) {
+    let cert = rcgen::generate_simple_self_signed(vec![
+        "localhost".to_string(),
+        "127.0.0.1".to_string(),
+        "::1".to_string(),
+    ])
+    .expect("valid");
+    let rustls_cert = cert.cert.der();
+    let private_key = rustls::pki_types::PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der());
+    let private_key = rustls::pki_types::PrivateKeyDer::from(private_key);
+    let certs = vec![rustls_cert.clone()];
+    let server_config = rustls::ServerConfig::builder_with_provider(std::sync::Arc::new(
+        rustls::crypto::ring::default_provider(),
+    ))
+    .with_safe_default_protocol_versions()
+    .expect("protocols supported by ring")
+    .with_no_client_auth();
+
+    let server_config = server_config
+        .with_single_cert(certs.clone(), private_key)
+        .expect("valid");
+    (certs, server_config)
+}
+
+/// Creates a [`TlsConfig`] suitable for testing.
+///
+/// - Uses a self signed certificate valid for the `"localhost"` and `"127.0.0.1"` domains.
+/// - Configures https to be served on an OS assigned port on ipv4.
+pub fn tls_config() -> TlsConfig<()> {
+    let (certs, server_config) = self_signed_tls_certs_and_config();
+    TlsConfig {
+        server_config,
+        cert: CertConfig::<(), ()>::Manual { certs },
+        https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        quic_bind_addr: (Ipv4Addr::UNSPECIFIED, 0).into(),
+    }
+}
+
+/// Creates a [`RelayConfig`] suitable for testing.
+///
+/// - Binds http to an OS assigned port on ipv4.
+/// - Uses [`tls_config`] to enable TLS.
+/// - Uses default limits.
+pub fn relay_config() -> RelayConfig<()> {
+    RelayConfig {
+        http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
+        tls: Some(tls_config()),
+        limits: Default::default(),
+    }
+}
+
+/// Creates a [`QuicConfig`] suitable for testing.
+///
+/// - Binds to an OS assigned port on ipv6 and ipv4, if dual stack is enabled.
+/// - Uses [`self_signed_tls_certs_and_config`] to create tls certificates
+pub fn quic_config() -> QuicConfig {
+    let (_, server_config) = self_signed_tls_certs_and_config();
+    QuicConfig {
+        bind_addr: (Ipv6Addr::UNSPECIFIED, 0).into(),
+        server_config,
+    }
+}
+
+/// Creates a [`ServerConfig`] suitable for testing.
+///
+/// - Relaying is enabled using [`relay_config`]
+/// - Stun is enabled using [`stun_config`]
+/// - QUIC addr discovery is disabled.
+/// - Metrics are not enabled.
+pub fn server_config() -> ServerConfig<()> {
+    ServerConfig {
+        relay: Some(relay_config()),
+        stun: Some(stun_config()),
+        quic: Some(quic_config()),
+        #[cfg(feature = "metrics")]
+        metrics_addr: None,
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_test/hexdump.rs.html b/pr/2992/docs/src/iroh_test/hexdump.rs.html new file mode 100644 index 0000000000..16c6c74e0c --- /dev/null +++ b/pr/2992/docs/src/iroh_test/hexdump.rs.html @@ -0,0 +1,361 @@ +hexdump.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+
use anyhow::{ensure, Context, Result};
+
+/// Parses a commented multi line hexdump into a vector of bytes.
+///
+/// This is useful to write wire level protocol tests.
+pub fn parse_hexdump(s: &str) -> Result<Vec<u8>> {
+    let mut result = Vec::new();
+
+    for (line_number, line) in s.lines().enumerate() {
+        let data_part = line.split('#').next().unwrap_or("");
+        let cleaned: String = data_part.chars().filter(|c| !c.is_whitespace()).collect();
+
+        ensure!(
+            cleaned.len() % 2 == 0,
+            "Non-even number of hex chars detected on line {}.",
+            line_number + 1
+        );
+
+        for i in (0..cleaned.len()).step_by(2) {
+            let byte_str = &cleaned[i..i + 2];
+            let byte = u8::from_str_radix(byte_str, 16)
+                .with_context(|| format!("Invalid hex data on line {}.", line_number + 1))?;
+
+            result.push(byte);
+        }
+    }
+
+    Ok(result)
+}
+
+/// Returns a hexdump of the given bytes in multiple lines as a String.
+pub fn print_hexdump(bytes: impl AsRef<[u8]>, line_lengths: impl AsRef<[usize]>) -> String {
+    let line_lengths = line_lengths.as_ref();
+    let mut bytes_iter = bytes.as_ref().iter();
+    let default_line_length = line_lengths
+        .last()
+        .filter(|x| **x != 0)
+        .copied()
+        .unwrap_or(16);
+    let mut line_lengths_iter = line_lengths.iter();
+    let mut output = String::new();
+
+    loop {
+        let line_length = line_lengths_iter
+            .next()
+            .copied()
+            .unwrap_or(default_line_length);
+        if line_length == 0 {
+            output.push('\n');
+        } else {
+            let line: Vec<_> = bytes_iter.by_ref().take(line_length).collect();
+
+            if line.is_empty() {
+                break;
+            }
+
+            for byte in &line {
+                output.push_str(&format!("{:02x} ", byte));
+            }
+            output.pop(); // Remove the trailing space
+            output.push('\n');
+        }
+    }
+
+    output
+}
+
+/// This is a macro to assert that two byte slices are equal.
+///
+/// It is like assert_eq!, but it will print a nicely formatted hexdump of the
+/// two slices if they are not equal. This makes it much easier to track down
+/// a difference in a large byte slice.
+#[macro_export]
+macro_rules! assert_eq_hex {
+    ($a:expr, $b:expr) => {
+        assert_eq_hex!($a, $b, [])
+    };
+    ($a:expr, $b:expr, $hint:expr) => {
+        let a = $a;
+        let b = $b;
+        let hint = $hint;
+        let ar: &[u8] = a.as_ref();
+        let br: &[u8] = b.as_ref();
+        let hintr: &[usize] = hint.as_ref();
+        if ar != br {
+            panic!(
+                "assertion failed: `(left == right)`\nleft:\n{}\nright:\n{}\n",
+                ::iroh_test::hexdump::print_hexdump(ar, hintr),
+                ::iroh_test::hexdump::print_hexdump(br, hintr),
+            )
+        }
+    };
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{parse_hexdump, print_hexdump};
+
+    #[test]
+    fn test_basic() {
+        let input = r"
+            a1b2 # comment
+            3c4d
+        ";
+        let result = parse_hexdump(input).unwrap();
+        assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]);
+    }
+
+    #[test]
+    fn test_upper_case() {
+        let input = r"
+            A1B2 # comment
+            3C4D
+        ";
+        let result = parse_hexdump(input).unwrap();
+        assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]);
+    }
+
+    #[test]
+    fn test_mixed_case() {
+        let input = r"
+            a1B2 # comment
+            3C4d
+        ";
+        let result = parse_hexdump(input).unwrap();
+        assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]);
+    }
+
+    #[test]
+    fn test_odd_characters() {
+        let input = r"
+            a1b
+        ";
+        let result = parse_hexdump(input);
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_invalid_characters() {
+        let input = r"
+            a1g2 # 'g' is not valid in hex
+        ";
+        let result = parse_hexdump(input);
+        assert!(result.is_err());
+    }
+    #[test]
+    fn test_basic_hexdump() {
+        let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5];
+        let output = print_hexdump(data, [1, 2]);
+        assert_eq!(output, "01\n02 03\n04 05\n");
+    }
+
+    #[test]
+    fn test_newline_insertion() {
+        let data: &[u8] = &[0x1, 0x2, 0x3, 0x4];
+        let output = print_hexdump(data, [1, 0, 2]);
+        assert_eq!(output, "01\n\n02 03\n04\n");
+    }
+
+    #[test]
+    fn test_indefinite_line_length() {
+        let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];
+        let output = print_hexdump(data, [2, 4]);
+        assert_eq!(output, "01 02\n03 04 05 06\n07 08\n");
+    }
+
+    #[test]
+    fn test_empty_data() {
+        let data: &[u8] = &[];
+        let output = print_hexdump(data, [1, 2]);
+        assert_eq!(output, "");
+    }
+
+    #[test]
+    fn test_zeros_then_default() {
+        let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];
+        let output = print_hexdump(data, [1, 0, 0, 2]);
+        assert_eq!(output, "01\n\n\n02 03\n04 05\n06 07\n08\n");
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_test/lib.rs.html b/pr/2992/docs/src/iroh_test/lib.rs.html new file mode 100644 index 0000000000..fe6b6d6bc4 --- /dev/null +++ b/pr/2992/docs/src/iroh_test/lib.rs.html @@ -0,0 +1,45 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+
//! Internal utilities to support testing.
+
+pub mod hexdump;
+pub mod logging;
+
+// #[derive(derive_more::Debug)]
+#[allow(missing_debug_implementations)]
+pub struct CallOnDrop(Option<Box<dyn FnOnce()>>);
+
+impl CallOnDrop {
+    pub fn new(f: impl FnOnce() + 'static) -> Self {
+        Self(Some(Box::new(f)))
+    }
+}
+
+impl Drop for CallOnDrop {
+    fn drop(&mut self) {
+        if let Some(f) = self.0.take() {
+            f();
+        }
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/src/iroh_test/logging.rs.html b/pr/2992/docs/src/iroh_test/logging.rs.html new file mode 100644 index 0000000000..275ced8c2d --- /dev/null +++ b/pr/2992/docs/src/iroh_test/logging.rs.html @@ -0,0 +1,267 @@ +logging.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+
//! Logging during tests.
+
+use tokio::runtime::RuntimeFlavor;
+use tracing::level_filters::LevelFilter;
+use tracing_subscriber::{
+    layer::{Layer, SubscriberExt},
+    util::SubscriberInitExt,
+    EnvFilter,
+};
+
+/// Configures logging for the current test, **single-threaded runtime only**.
+///
+/// This setup can be used for any sync test or async test using a single-threaded tokio
+/// runtime (the default).
+///
+/// This configures logging that will interact well with tests: logs will be captured by the
+/// test framework and only printed on failure.
+///
+/// The logging is unfiltered, it logs all crates and modules on TRACE level.  If that's too
+/// much consider if your test is too large (or write a version that allows filtering...).
+///
+/// # Example
+///
+/// ```
+/// #[tokio::test]
+/// async fn test_something() {
+///     let _guard = iroh_test::logging::setup();
+///     assert!(true);
+/// }
+/// ```
+#[must_use = "The tracing guard must only be dropped at the end of the test"]
+pub fn setup() -> tracing::subscriber::DefaultGuard {
+    if let Ok(handle) = tokio::runtime::Handle::try_current() {
+        match handle.runtime_flavor() {
+            RuntimeFlavor::CurrentThread => (),
+            RuntimeFlavor::MultiThread => {
+                panic!("setup_logging() does not work in a multi-threaded tokio runtime");
+            }
+            _ => panic!("unknown runtime flavour"),
+        }
+    }
+    testing_subscriber().set_default()
+}
+
+/// The first call to this function will install a global logger.
+///
+/// The logger uses the `RUST_LOG` environment variable to decide on what level to log
+/// anything, which is set by our CI.  When running the tests with nextest the log
+/// output will be captured for just the executing test.
+///
+/// Logs to stdout since the assertion messages are logged on stderr by default.
+pub fn setup_multithreaded() {
+    tracing_subscriber::registry()
+        .with(
+            tracing_subscriber::fmt::layer()
+                .event_format(tracing_subscriber::fmt::format().with_line_number(true))
+                .with_writer(std::io::stdout),
+        )
+        .with(EnvFilter::from_default_env())
+        .try_init()
+        .ok();
+}
+
+// /// Invoke the future with test logging configured.
+// ///
+// /// This can be used to execute any future which uses tracing for logging, it sets up the
+// /// logging as [`setup_logging`] does but in a way which will work for both single and
+// /// multi-threaded tokio runtimes.
+// pub(crate) async fn with_logging<F: Future>(f: F) -> F::Output {
+//     f.with_subscriber(testing_subscriber()).await
+// }
+
+/// Returns the a [`tracing::Subscriber`] configured for our tests.
+///
+/// This subscriber will ensure that log output is captured by the test's default output
+/// capturing and thus is only shown with the test on failure.  By default it uses
+/// `RUST_LOG=trace` as configuration but you can specify the `RUST_LOG` environment
+/// variable explicitly to override this.
+///
+/// To use this in a tokio multi-threaded runtime use:
+///
+/// ```ignore
+/// use tracing_future::WithSubscriber;
+/// use iroh_test::logging::testing_subscriber;
+///
+/// #[tokio::test(flavor = "multi_thread")]
+/// async fn test_something() -> Result<()> {
+///    async move {
+///        Ok(())
+///    }.with_subscriber(testing_subscriber()).await
+/// }
+/// ```
+pub fn testing_subscriber() -> impl tracing::Subscriber {
+    let var = std::env::var_os("RUST_LOG");
+    let trace_log_layer = match var {
+        Some(_) => None,
+        None => Some(
+            tracing_subscriber::fmt::layer()
+                .event_format(tracing_subscriber::fmt::format().with_line_number(true))
+                .with_writer(|| TestWriter)
+                .with_filter(LevelFilter::TRACE),
+        ),
+    };
+    let env_log_layer = var.map(|_| {
+        tracing_subscriber::fmt::layer()
+            .event_format(tracing_subscriber::fmt::format().with_line_number(true))
+            .with_writer(|| TestWriter)
+            .with_filter(EnvFilter::from_default_env())
+    });
+    tracing_subscriber::registry()
+        .with(trace_log_layer)
+        .with(env_log_layer)
+}
+
+/// A tracing writer that interacts well with test output capture.
+///
+/// Using this writer will make sure that the output is captured normally and only printed
+/// when the test fails.  See [`setup`] to actually use this.
+#[derive(Debug)]
+struct TestWriter;
+
+impl std::io::Write for TestWriter {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        print!(
+            "{}",
+            std::str::from_utf8(buf).expect("tried to log invalid UTF-8")
+        );
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> std::io::Result<()> {
+        std::io::stdout().flush()
+    }
+}
+
\ No newline at end of file diff --git a/pr/2992/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt b/pr/2992/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt new file mode 100644 index 0000000000..1447df792f --- /dev/null +++ b/pr/2992/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt @@ -0,0 +1,50 @@ +# REUSE-IgnoreStart + +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. + +# REUSE-IgnoreEnd diff --git a/pr/2992/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt b/pr/2992/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt new file mode 100644 index 0000000000..d7e9c149b7 --- /dev/null +++ b/pr/2992/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt @@ -0,0 +1,98 @@ +// REUSE-IgnoreStart + +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/pr/2992/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 b/pr/2992/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 new file mode 100644 index 0000000000..7a1e5fc548 Binary files /dev/null and b/pr/2992/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 differ diff --git a/pr/2992/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 b/pr/2992/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 new file mode 100644 index 0000000000..e766e06ccb Binary files /dev/null and b/pr/2992/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 differ diff --git a/pr/2992/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt b/pr/2992/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/pr/2992/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/pr/2992/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt b/pr/2992/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/pr/2992/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/pr/2992/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 b/pr/2992/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 new file mode 100644 index 0000000000..1866ad4bce Binary files /dev/null and b/pr/2992/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt b/pr/2992/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt new file mode 100644 index 0000000000..4b3edc29eb --- /dev/null +++ b/pr/2992/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt @@ -0,0 +1,103 @@ +// REUSE-IgnoreStart + +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/pr/2992/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 b/pr/2992/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 new file mode 100644 index 0000000000..462c34efcd Binary files /dev/null and b/pr/2992/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt b/pr/2992/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt new file mode 100644 index 0000000000..0d2941e148 --- /dev/null +++ b/pr/2992/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt @@ -0,0 +1,97 @@ +// REUSE-IgnoreStart + +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/pr/2992/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 b/pr/2992/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 new file mode 100644 index 0000000000..10b558e0b6 Binary files /dev/null and b/pr/2992/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 b/pr/2992/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 new file mode 100644 index 0000000000..5ec64eef0e Binary files /dev/null and b/pr/2992/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 b/pr/2992/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 new file mode 100644 index 0000000000..181a07f63b Binary files /dev/null and b/pr/2992/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 b/pr/2992/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 new file mode 100644 index 0000000000..2ae08a7bed Binary files /dev/null and b/pr/2992/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md b/pr/2992/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md new file mode 100644 index 0000000000..175fa4f47a --- /dev/null +++ b/pr/2992/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md @@ -0,0 +1,98 @@ + + +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + diff --git a/pr/2992/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 b/pr/2992/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 new file mode 100644 index 0000000000..0263fc3042 Binary files /dev/null and b/pr/2992/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 differ diff --git a/pr/2992/docs/static.files/favicon-2c020d218678b618.svg b/pr/2992/docs/static.files/favicon-2c020d218678b618.svg new file mode 100644 index 0000000000..8b34b51198 --- /dev/null +++ b/pr/2992/docs/static.files/favicon-2c020d218678b618.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/pr/2992/docs/static.files/favicon-32x32-422f7d1d52889060.png b/pr/2992/docs/static.files/favicon-32x32-422f7d1d52889060.png new file mode 100644 index 0000000000..69b8613ce1 Binary files /dev/null and b/pr/2992/docs/static.files/favicon-32x32-422f7d1d52889060.png differ diff --git a/pr/2992/docs/static.files/main-20a3ad099b048cf2.js b/pr/2992/docs/static.files/main-20a3ad099b048cf2.js new file mode 100644 index 0000000000..133116e4d8 --- /dev/null +++ b/pr/2992/docs/static.files/main-20a3ad099b048cf2.js @@ -0,0 +1,11 @@ +"use strict";window.RUSTDOC_TOOLTIP_HOVER_MS=300;window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS=450;function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden")}function showMain(){removeClass(document.getElementById(MAIN_ID),"hidden")}function blurHandler(event,parentElem,hideCallback){if(!parentElem.contains(document.activeElement)&&!parentElem.contains(event.relatedTarget)){hideCallback()}}window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate");function setMobileTopbar(){const mobileTopbar=document.querySelector(".mobile-topbar");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileTopbar){const mobileTitle=document.createElement("h2");mobileTitle.className="location";if(hasClass(document.querySelector(".rustdoc"),"crate")){mobileTitle.innerHTML=`Crate ${window.currentCrate}`}else if(locationTitle){mobileTitle.innerHTML=locationTitle.innerHTML}mobileTopbar.appendChild(mobileTitle)}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden")}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function preLoadCss(cssUrl){const link=document.createElement("link");link.href=cssUrl;link.rel="preload";link.as="style";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url,errorCallback){const script=document.createElement("script");script.src=url;if(errorCallback!==undefined){script.onerror=errorCallback}document.head.append(script)}getSettingsButton().onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}window.hideAllModals(false);addClass(getSettingsButton(),"rotate");event.preventDefault();loadScript(getVar("static-root-path")+getVar("settings-js"));setTimeout(()=>{const themes=getVar("themes").split(",");for(const theme of themes){if(theme!==""){preLoadCss(getVar("root-path")+theme+".css")}}},0)};window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},isDisplayed:()=>searchState.outputElement().parentElement.id===ALTERNATIVE_DISPLAY_ID,focus:()=>{searchState.input.focus()},defocus:()=>{searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=searchState.outputElement()}switchDisplayedElement(search);searchState.mouseMovedAfterSearch=false;document.title=searchState.title},removeQueryParameters:()=>{document.title=searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.hash)}},hideResults:()=>{switchDisplayedElement(null);searchState.removeQueryParameters()},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=").map(x=>x.replace(/\+/g," "));params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=searchState.input;if(!searchState.input){return}let searchLoaded=false;function sendSearchForm(){document.getElementsByClassName("search-form")[0].submit()}function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(getVar("static-root-path")+getVar("search-js"),sendSearchForm);loadScript(resourcePath("search-index",".js"),sendSearchForm)}}search_input.addEventListener("focus",()=>{search_input.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=searchState.getQueryStringParams();if(params.search!==undefined){searchState.setLoadingSearch();loadSearch()}},setLoadingSearch:()=>{const search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search)},descShards:new Map(),loadDesc:async function({descShard,descIndex}){if(descShard.promise===null){descShard.promise=new Promise((resolve,reject)=>{descShard.resolve=resolve;const ds=descShard;const fname=`${ds.crate}-desc-${ds.shard}-`;const url=resourcePath(`search.desc/${descShard.crate}/${fname}`,".js",);loadScript(url,reject)})}const list=await descShard.promise;return list[descIndex]},loadedDescShard:function(crate,shard,data){this.descShards.get(crate)[shard].resolve(data.split("\n"))},};const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}const pageId=window.location.hash.replace(/^#/,"");if(savedHash!==pageId){savedHash=pageId;if(pageId!==""){expandSection(pageId)}}if(savedHash.startsWith("impl-")){const splitAt=savedHash.indexOf("/");if(splitAt!==-1){const implId=savedHash.slice(0,splitAt);const assocId=savedHash.slice(splitAt+1);const implElem=document.getElementById(implId);if(implElem&&implElem.parentElement.tagName==="SUMMARY"&&implElem.parentElement.parentElement.tagName==="DETAILS"){onEachLazy(implElem.parentElement.parentElement.querySelectorAll(`[id^="${assocId}"]`),item=>{const numbered=/([^-]+)-([0-9]+)/.exec(item.id);if(item.id===assocId||(numbered&&numbered[1]===assocId)){openParentDetails(item);item.scrollIntoView();setTimeout(()=>{window.location.replace("#"+item.id)},0)}},)}}}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){searchState.clearInputTimeout();searchState.hideResults();ev.preventDefault();searchState.defocus();window.hideAllModals(true)}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"&&document.activeElement.type!=="radio"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":case"/":ev.preventDefault();searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementsByClassName("sidebar-elems")[0];function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const modpath=hasClass(document.querySelector(".rustdoc"),"mod")?"../":"";const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const name of filtered){let path;if(shortty==="mod"){path=`${modpath}${name}/index.html`}else{path=`${modpath}${shortty}.${name}.html`}let current_page=document.location.href.toString();if(current_page.endsWith("/")){current_page+="index.html"}const link=document.createElement("a");link.href=path;if(path===current_page){link.className="current"}link.textContent=name;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Aliases");block("union","unions","Unions");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("opaque","opaque-types","Opaque Types");block("attr","attributes","Attribute Macros");block("derive","derives","Derive Macros");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector(".main-heading h1 > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=new Set((script?script.getAttribute("data-ignore-extern-crates"):"").split(","),);for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.has(lib)){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}window.register_type_impls=imp=>{if(!imp||!imp[window.currentCrate]){return}window.pending_type_impls=null;const idMap=new Map();let implementations=document.getElementById("implementations-list");let trait_implementations=document.getElementById("trait-implementations-list");let trait_implementations_header=document.getElementById("trait-implementations");const script=document.querySelector("script[data-self-path]");const selfPath=script?script.getAttribute("data-self-path"):null;const mainContent=document.querySelector("#main-content");const sidebarSection=document.querySelector(".sidebar section");let methods=document.querySelector(".sidebar .block.method");let associatedTypes=document.querySelector(".sidebar .block.associatedtype");let associatedConstants=document.querySelector(".sidebar .block.associatedconstant");let sidebarTraitList=document.querySelector(".sidebar .block.trait-implementation");for(const impList of imp[window.currentCrate]){const types=impList.slice(2);const text=impList[0];const isTrait=impList[1]!==0;const traitName=impList[1];if(types.indexOf(selfPath)===-1){continue}let outputList=isTrait?trait_implementations:implementations;if(outputList===null){const outputListName=isTrait?"Trait Implementations":"Implementations";const outputListId=isTrait?"trait-implementations-list":"implementations-list";const outputListHeaderId=isTrait?"trait-implementations":"implementations";const outputListHeader=document.createElement("h2");outputListHeader.id=outputListHeaderId;outputListHeader.innerText=outputListName;outputList=document.createElement("div");outputList.id=outputListId;if(isTrait){const link=document.createElement("a");link.href=`#${outputListHeaderId}`;link.innerText="Trait Implementations";const h=document.createElement("h3");h.appendChild(link);trait_implementations=outputList;trait_implementations_header=outputListHeader;sidebarSection.appendChild(h);sidebarTraitList=document.createElement("ul");sidebarTraitList.className="block trait-implementation";sidebarSection.appendChild(sidebarTraitList);mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}else{implementations=outputList;if(trait_implementations){mainContent.insertBefore(outputListHeader,trait_implementations_header);mainContent.insertBefore(outputList,trait_implementations_header)}else{const mainContent=document.querySelector("#main-content");mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}}}const template=document.createElement("template");template.innerHTML=text;onEachLazy(template.content.querySelectorAll("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});onEachLazy(template.content.querySelectorAll("[id]"),el=>{let i=0;if(idMap.has(el.id)){i=idMap.get(el.id)}else if(document.getElementById(el.id)){i=1;while(document.getElementById(`${el.id}-${2 * i}`)){i=2*i}while(document.getElementById(`${el.id}-${i}`)){i+=1}}if(i!==0){const oldHref=`#${el.id}`;const newHref=`#${el.id}-${i}`;el.id=`${el.id}-${i}`;onEachLazy(template.content.querySelectorAll("a[href]"),link=>{if(link.getAttribute("href")===oldHref){link.href=newHref}})}idMap.set(el.id,i+1)});const templateAssocItems=template.content.querySelectorAll("section.tymethod, "+"section.method, section.associatedtype, section.associatedconstant");if(isTrait){const li=document.createElement("li");const a=document.createElement("a");a.href=`#${template.content.querySelector(".impl").id}`;a.textContent=traitName;li.appendChild(a);sidebarTraitList.append(li)}else{onEachLazy(templateAssocItems,item=>{let block=hasClass(item,"associatedtype")?associatedTypes:(hasClass(item,"associatedconstant")?associatedConstants:(methods));if(!block){const blockTitle=hasClass(item,"associatedtype")?"Associated Types":(hasClass(item,"associatedconstant")?"Associated Constants":("Methods"));const blockClass=hasClass(item,"associatedtype")?"associatedtype":(hasClass(item,"associatedconstant")?"associatedconstant":("method"));const blockHeader=document.createElement("h3");const blockLink=document.createElement("a");blockLink.href="#implementations";blockLink.innerText=blockTitle;blockHeader.appendChild(blockLink);block=document.createElement("ul");block.className=`block ${blockClass}`;const insertionReference=methods||sidebarTraitList;if(insertionReference){const insertionReferenceH=insertionReference.previousElementSibling;sidebarSection.insertBefore(blockHeader,insertionReferenceH);sidebarSection.insertBefore(block,insertionReferenceH)}else{sidebarSection.appendChild(blockHeader);sidebarSection.appendChild(block)}if(hasClass(item,"associatedtype")){associatedTypes=block}else if(hasClass(item,"associatedconstant")){associatedConstants=block}else{methods=block}}const li=document.createElement("li");const a=document.createElement("a");a.innerText=item.id.split("-")[0].split(".")[1];a.href=`#${item.id}`;li.appendChild(a);block.appendChild(li)})}outputList.appendChild(template.content)}for(const list of[methods,associatedTypes,associatedConstants,sidebarTraitList]){if(!list){continue}const newChildren=Array.prototype.slice.call(list.children);newChildren.sort((a,b)=>{const aI=a.innerText;const bI=b.innerText;return aIbI?1:0});list.replaceChildren(...newChildren)}};if(window.pending_type_impls){window.register_type_impls(window.pending_type_impls)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementsByClassName("sidebar-elems")[0];if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";link.textContent=crate;const li=document.createElement("li");if(window.rootPath!=="./"&&crate===window.currentCrate){li.className="current"}li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hasClass(e,"type-contents-toggle")&&!hasClass(e,"more-examples-toggle")){e.open=true}});innerToggle.title="collapse all docs";innerToggle.children[0].innerText="\u2212"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.title="expand all docs";innerToggle.children[0].innerText="+"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}})}());window.rustdoc_add_line_numbers_to_examples=()=>{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");if(line_numbers.length>0){return}const count=x.textContent.split("\n").length;const elems=[];for(let i=0;i{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");for(const node of line_numbers){parent.removeChild(node)}})};if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}function showSidebar(){window.hideAllModals(false);const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.CURRENT_TOOLTIP_ELEMENT){const base=window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;const force_visible=base.TOOLTIP_FORCE_VISIBLE;hideTooltip(false);if(force_visible){showTooltip(base);base.TOOLTIP_FORCE_VISIBLE=true}}});const mainElem=document.getElementById(MAIN_ID);if(mainElem){mainElem.addEventListener("click",hideSidebar)}onEachLazy(document.querySelectorAll("a[href^='#']"),el=>{el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})});onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});function showTooltip(e){const notable_ty=e.getAttribute("data-notable-ty");if(!window.NOTABLE_TRAITS&¬able_ty){const data=document.getElementById("notable-traits-data");if(data){window.NOTABLE_TRAITS=JSON.parse(data.innerText)}else{throw new Error("showTooltip() called with notable without any notable traits!")}}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE===e){clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);return}window.hideAllModals(false);const wrapper=document.createElement("div");if(notable_ty){wrapper.innerHTML="
"+window.NOTABLE_TRAITS[notable_ty]+"
"}else{if(e.getAttribute("title")!==null){e.setAttribute("data-title",e.getAttribute("title"));e.removeAttribute("title")}if(e.getAttribute("data-title")!==null){const titleContent=document.createElement("div");titleContent.className="content";titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));wrapper.appendChild(titleContent)}}wrapper.className="tooltip popover";const focusCatcher=document.createElement("div");focusCatcher.setAttribute("tabindex","0");focusCatcher.onfocus=hideTooltip;wrapper.appendChild(focusCatcher);const pos=e.getBoundingClientRect();wrapper.style.top=(pos.top+window.scrollY+pos.height)+"px";wrapper.style.left=0;wrapper.style.right="auto";wrapper.style.visibility="hidden";const body=document.getElementsByTagName("body")[0];body.appendChild(wrapper);const wrapperPos=wrapper.getBoundingClientRect();const finalPos=pos.left+window.scrollX-wrapperPos.width+24;if(finalPos>0){wrapper.style.left=finalPos+"px"}else{wrapper.style.setProperty("--popover-arrow-offset",(wrapperPos.right-pos.right+4)+"px",)}wrapper.style.visibility="";window.CURRENT_TOOLTIP_ELEMENT=wrapper;window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE=e;clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);wrapper.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}clearTooltipHoverTimeout(e)};wrapper.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!e.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(wrapper,"fade-out")}}}function setTooltipHoverTimeout(element,show){clearTooltipHoverTimeout(element);if(!show&&!window.CURRENT_TOOLTIP_ELEMENT){return}if(show&&window.CURRENT_TOOLTIP_ELEMENT){return}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE!==element){return}element.TOOLTIP_HOVER_TIMEOUT=setTimeout(()=>{if(show){showTooltip(element)}else if(!element.TOOLTIP_FORCE_VISIBLE){hideTooltip(false)}},show?window.RUSTDOC_TOOLTIP_HOVER_MS:window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS)}function clearTooltipHoverTimeout(element){if(element.TOOLTIP_HOVER_TIMEOUT!==undefined){removeClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out");clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);delete element.TOOLTIP_HOVER_TIMEOUT}}function tooltipBlurHandler(event){if(window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)){setTimeout(()=>hideTooltip(false),0)}}function hideTooltip(focus){if(window.CURRENT_TOOLTIP_ELEMENT){if(window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE){if(focus){window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus()}window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE=false}const body=document.getElementsByTagName("body")[0];body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);window.CURRENT_TOOLTIP_ELEMENT=null}}onEachLazy(document.getElementsByClassName("tooltip"),e=>{e.onclick=()=>{e.TOOLTIP_FORCE_VISIBLE=e.TOOLTIP_FORCE_VISIBLE?false:true;if(window.CURRENT_TOOLTIP_ELEMENT&&!e.TOOLTIP_FORCE_VISIBLE){hideTooltip(true)}else{showTooltip(e);window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex","0");window.CURRENT_TOOLTIP_ELEMENT.focus();window.CURRENT_TOOLTIP_ELEMENT.onblur=tooltipBlurHandler}return false};e.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointermove=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out")}}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){blurHandler(event,getHelpButton(),window.hidePopoverMenus)}function buildHelpMenu(){const book_info=document.createElement("span");const channel=getVar("channel");book_info.className="top";book_info.innerHTML=`You can find more information in \ +the rustdoc book.`;const shortcuts=[["?","Show this help dialog"],["S / /","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=[`For a full list of all search features, take a look here.`,"Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec or String, enum:Cow -> bool)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for functions that accept or return \ + slices and \ + arrays by writing \ + square brackets (e.g., -> [u8] or [] -> Option)","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hideAllModals=switchFocus=>{hideSidebar();window.hidePopoverMenus();hideTooltip(switchFocus)};window.hidePopoverMenus=()=>{onEachLazy(document.querySelectorAll(".search-form .popover"),elem=>{elem.style.display="none"})};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){getHelpButton().querySelector("a").focus();const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hideAllModals();menu.style.display=""}}if(isHelpPage){showHelp();document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault()})}else{document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){const SIDEBAR_MIN=100;const SIDEBAR_MAX=500;const RUSTDOC_MOBILE_BREAKPOINT=700;const BODY_MIN=400;const SIDEBAR_VANISH_THRESHOLD=SIDEBAR_MIN/2;const sidebarButton=document.getElementById("sidebar-button");if(sidebarButton){sidebarButton.addEventListener("click",e=>{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false");if(document.querySelector(".rustdoc.src")){window.rustdocToggleSrcSidebar()}e.preventDefault()})}let currentPointerId=null;let desiredSidebarSize=null;let pendingSidebarResizingFrame=false;const resizer=document.querySelector(".sidebar-resizer");const sidebar=document.querySelector(".sidebar");if(!resizer||!sidebar){return}const isSrcPage=hasClass(document.body,"src");function hideSidebar(){if(isSrcPage){window.rustdocCloseSourceSidebar();updateLocalStorage("src-sidebar-width",null);document.documentElement.style.removeProperty("--src-sidebar-width");sidebar.style.removeProperty("--src-sidebar-width");resizer.style.removeProperty("--src-sidebar-width")}else{addClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","true");updateLocalStorage("desktop-sidebar-width",null);document.documentElement.style.removeProperty("--desktop-sidebar-width");sidebar.style.removeProperty("--desktop-sidebar-width");resizer.style.removeProperty("--desktop-sidebar-width")}}function showSidebar(){if(isSrcPage){window.rustdocShowSourceSidebar()}else{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false")}}function changeSidebarSize(size){if(isSrcPage){updateLocalStorage("src-sidebar-width",size);sidebar.style.setProperty("--src-sidebar-width",size+"px");resizer.style.setProperty("--src-sidebar-width",size+"px")}else{updateLocalStorage("desktop-sidebar-width",size);sidebar.style.setProperty("--desktop-sidebar-width",size+"px");resizer.style.setProperty("--desktop-sidebar-width",size+"px")}}function isSidebarHidden(){return isSrcPage?!hasClass(document.documentElement,"src-sidebar-expanded"):hasClass(document.documentElement,"hide-sidebar")}function resize(e){if(currentPointerId===null||currentPointerId!==e.pointerId){return}e.preventDefault();const pos=e.clientX-3;if(pos=SIDEBAR_MIN){if(isSidebarHidden()){showSidebar()}const constrainedPos=Math.min(pos,window.innerWidth-BODY_MIN,SIDEBAR_MAX);changeSidebarSize(constrainedPos);desiredSidebarSize=constrainedPos;if(pendingSidebarResizingFrame!==false){clearTimeout(pendingSidebarResizingFrame)}pendingSidebarResizingFrame=setTimeout(()=>{if(currentPointerId===null||pendingSidebarResizingFrame===false){return}pendingSidebarResizingFrame=false;document.documentElement.style.setProperty("--resizing-sidebar-width",desiredSidebarSize+"px",)},100)}}window.addEventListener("resize",()=>{if(window.innerWidth=(window.innerWidth-BODY_MIN)){changeSidebarSize(window.innerWidth-BODY_MIN)}else if(desiredSidebarSize!==null&&desiredSidebarSize>SIDEBAR_MIN){changeSidebarSize(desiredSidebarSize)}});function stopResize(e){if(currentPointerId===null){return}if(e){e.preventDefault()}desiredSidebarSize=sidebar.getBoundingClientRect().width;removeClass(resizer,"active");window.removeEventListener("pointermove",resize,false);window.removeEventListener("pointerup",stopResize,false);removeClass(document.documentElement,"sidebar-resizing");document.documentElement.style.removeProperty("--resizing-sidebar-width");if(resizer.releasePointerCapture){resizer.releasePointerCapture(currentPointerId);currentPointerId=null}}function initResize(e){if(currentPointerId!==null||e.altKey||e.ctrlKey||e.metaKey||e.button!==0){return}if(resizer.setPointerCapture){resizer.setPointerCapture(e.pointerId);if(!resizer.hasPointerCapture(e.pointerId)){resizer.releasePointerCapture(e.pointerId);return}currentPointerId=e.pointerId}window.hideAllModals(false);e.preventDefault();window.addEventListener("pointermove",resize,false);window.addEventListener("pointercancel",stopResize,false);window.addEventListener("pointerup",stopResize,false);addClass(resizer,"active");addClass(document.documentElement,"sidebar-resizing");const pos=e.clientX-sidebar.offsetLeft-3;document.documentElement.style.setProperty("--resizing-sidebar-width",pos+"px");desiredSidebarSize=null}resizer.addEventListener("pointerdown",initResize,false)}());(function(){let reset_button_timeout=null;const but=document.getElementById("copy-path");if(!but){return}but.onclick=()=>{const parent=but.parentElement;const path=[];onEach(parent.childNodes,child=>{if(child.tagName==="A"){path.push(child.textContent)}});const el=document.createElement("textarea");el.value=path.join("::");el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el);but.classList.add("clicked");if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){reset_button_timeout=null;but.classList.remove("clicked")}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/pr/2992/docs/static.files/normalize-76eba96aa4d2e634.css b/pr/2992/docs/static.files/normalize-76eba96aa4d2e634.css new file mode 100644 index 0000000000..469959f137 --- /dev/null +++ b/pr/2992/docs/static.files/normalize-76eba96aa4d2e634.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/pr/2992/docs/static.files/noscript-09095024cf37855e.css b/pr/2992/docs/static.files/noscript-09095024cf37855e.css new file mode 100644 index 0000000000..59786941f9 --- /dev/null +++ b/pr/2992/docs/static.files/noscript-09095024cf37855e.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path,#sidebar-button,.sidebar-resizer{display:none !important;}nav.sub{display:none;}.src .sidebar{display:none;}.notable-traits{display:none;}:root,:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}@media (prefers-color-scheme:dark){:root,:root:not([data-theme]){--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}} \ No newline at end of file diff --git a/pr/2992/docs/static.files/rust-logo-151179464ae7ed46.svg b/pr/2992/docs/static.files/rust-logo-151179464ae7ed46.svg new file mode 100644 index 0000000000..62424d8ffd --- /dev/null +++ b/pr/2992/docs/static.files/rust-logo-151179464ae7ed46.svg @@ -0,0 +1,61 @@ + + + diff --git a/pr/2992/docs/static.files/rustdoc-b21aa549bf6d91ff.css b/pr/2992/docs/static.files/rustdoc-b21aa549bf6d91ff.css new file mode 100644 index 0000000000..b0c4e1b6b8 --- /dev/null +++ b/pr/2992/docs/static.files/rustdoc-b21aa549bf6d91ff.css @@ -0,0 +1,46 @@ + :root{--nav-sub-mobile-padding:8px;--search-typename-width:6.75rem;--desktop-sidebar-width:200px;--src-sidebar-width:300px;--desktop-sidebar-z-index:100;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular-46f98efaafac5295.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{box-sizing:border-box;}body{font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}.main-heading h1{margin:0;padding:0;flex-grow:1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{display:flex;flex-wrap:wrap;padding-bottom:6px;margin-bottom:15px;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h1,h2{line-height:1.25;padding-top:3px;padding-bottom:9px;}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;white-space:pre-wrap;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-name>a,.out-of-band,span.since,a.src,#help-button>a,summary.hideme,.scraped-example-list,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}#toggle-all-docs,a.anchor,.section-header a,#src-sidebar a,.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.stab,.result-name i{color:var(--main-color);}span.enum,a.enum,span.struct,a.struct,span.union,a.union,span.primitive,a.primitive,span.type,a.type,span.foreigntype,a.foreigntype{color:var(--type-link-color);}span.trait,a.trait,span.traitalias,a.traitalias{color:var(--trait-link-color);}span.associatedtype,a.associatedtype,span.constant,a.constant,span.static,a.static{color:var(--assoc-item-link-color);}span.fn,a.fn,span.method,a.method,span.tymethod,a.tymethod{color:var(--function-link-color);}span.attr,a.attr,span.derive,a.derive,span.macro,a.macro{color:var(--macro-link-color);}span.mod,a.mod{color:var(--mod-link-color);}span.keyword,a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);text-decoration:none;}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p,.docblock>.warning{margin:0 0 .75em 0;}p:last-child,.docblock>.warning:last-child{margin:0;}button{padding:1px 6px;cursor:pointer;}button#toggle-all-docs{padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.src main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}details:not(.toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.docblock-short pre code{padding:0;}pre{padding:14px;line-height:1.5;}pre.item-decl{overflow-x:auto;}.item-decl .type-contents-toggle{contain:initial;}.src .content pre{padding:20px;}.rustdoc.src .example-wrap pre.src-line-numbers{padding:20px 0 20px 4px;}img{max-width:100%;}.logo-container{line-height:0;display:block;}.rust-logo{filter:var(--rust-logo-filter);}.sidebar{font-size:0.875rem;flex:0 0 var(--desktop-sidebar-width);width:var(--desktop-sidebar-width);overflow-y:scroll;overscroll-behavior:contain;position:sticky;height:100vh;top:0;left:0;z-index:var(--desktop-sidebar-z-index);}.rustdoc.src .sidebar{flex-basis:50px;width:50px;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;}.hide-sidebar .sidebar,.hide-sidebar .sidebar-resizer{display:none;}.sidebar-resizer{touch-action:none;width:9px;cursor:col-resize;z-index:calc(var(--desktop-sidebar-z-index) + 1);position:fixed;height:100%;left:calc(var(--desktop-sidebar-width) + 1px);}.rustdoc.src .sidebar-resizer{left:49px;}.src-sidebar-expanded .src .sidebar-resizer{left:var(--src-sidebar-width);}.sidebar-resizing{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;}.sidebar-resizing*{cursor:col-resize !important;}.sidebar-resizing .sidebar{position:fixed;}.sidebar-resizing>body{padding-left:var(--resizing-sidebar-width);}.sidebar-resizer:hover,.sidebar-resizer:active,.sidebar-resizer:focus,.sidebar-resizer.active{width:10px;margin:0;left:var(--desktop-sidebar-width);border-left:solid 1px var(--sidebar-resizer-hover);}.src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:active,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active{left:calc(var(--src-sidebar-width) - 1px);}@media (pointer:coarse){.sidebar-resizer{display:none !important;}}.sidebar-resizer.active{padding:0 140px;width:2px;margin-left:-140px;border-left:none;}.sidebar-resizer.active:before{border-left:solid 2px var(--sidebar-resizer-active);display:block;height:100%;content:"";}.sidebar,.mobile-topbar,.sidebar-menu-toggle,#src-sidebar{background-color:var(--sidebar-background-color);}.src .sidebar>*{visibility:hidden;}.src-sidebar-expanded .src .sidebar{overflow-y:auto;flex-basis:var(--src-sidebar-width);width:var(--src-sidebar-width);}.src-sidebar-expanded .src .sidebar>*{visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.logo-container>img{height:48px;width:48px;}ul.block,.block li{padding:0;margin:0;list-style:none;}.sidebar-elems a,.sidebar>h2 a{display:block;padding:0.25rem;margin-left:-0.25rem;margin-right:0.25rem;}.sidebar h2{overflow-wrap:anywhere;padding:0;margin:0.7rem 0;}.sidebar h3{font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>.version,.sidebar>h2{padding-left:24px;}.sidebar a{color:var(--sidebar-link-color);}.sidebar .current,.sidebar .current a,.sidebar-crate a.logo-container:hover+h2 a,.sidebar a:hover:not(.logo-container){background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}.sidebar-crate{display:flex;align-items:center;justify-content:center;margin:14px 32px 1rem;row-gap:10px;column-gap:32px;flex-wrap:wrap;}.sidebar-crate h2{flex-grow:1;margin:0 -8px;align-self:start;}.sidebar-crate .logo-container{margin:0 -16px 0 -16px;text-align:center;}.sidebar-crate h2 a{display:block;margin:0 calc(-24px + 0.25rem) 0 -0.2rem;padding:calc((16px - 0.57rem ) / 2 ) 0.25rem;padding-left:0.2rem;}.sidebar-crate h2 .version{display:block;font-weight:normal;font-size:1rem;overflow-wrap:break-word;}.sidebar-crate+.version{margin-top:-1rem;margin-bottom:1rem;}.mobile-topbar{display:none;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap pre{margin:0;flex-grow:1;}.rustdoc:not(.src) .example-wrap pre{overflow:auto hidden;}.rustdoc .example-wrap pre.example-line-numbers,.rustdoc .example-wrap pre.src-line-numbers{flex-grow:0;min-width:fit-content;overflow:initial;text-align:right;-webkit-user-select:none;user-select:none;padding:14px 8px;color:var(--src-line-numbers-span-color);}.rustdoc .example-wrap pre.src-line-numbers{padding:14px 0;}.src-line-numbers a,.src-line-numbers span{color:var(--src-line-numbers-span-color);padding:0 8px;}.src-line-numbers :target{background-color:transparent;border-right:none;padding:0 8px;}.src-line-numbers .line-highlighted{background-color:var(--src-line-number-highlighted-background-color);}.search-loading{text-align:center;}.docblock-short{overflow-wrap:break-word;overflow-wrap:anywhere;}.docblock :not(pre)>code,.docblock-short code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:24px;position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.out-of-band{flex-grow:0;font-size:1.125rem;}.docblock code,.docblock-short code,pre,.rustdoc.src .example-wrap{background-color:var(--code-block-background-color);}#main-content{position:relative;}.docblock table{margin:.5em 0;border-collapse:collapse;}.docblock table td,.docblock table th{padding:.5em;border:1px solid var(--border-color);}.docblock table tbody tr:nth-child(2n){background:var(--table-alt-row-background-color);}div.where{white-space:pre-wrap;font-size:0.875rem;}.item-info{display:block;margin-left:24px;}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 25px 0;display:flex;align-items:center;}.search-form{position:relative;display:flex;height:34px;flex-grow:1;}.src nav.sub{margin:0 0 15px 0;}.section-header{display:block;position:relative;}.section-header:hover>.anchor,.impl:hover>.anchor,.trait-impl:hover>.anchor,.variant:hover>.anchor{display:initial;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.section-header>.anchor{left:-15px;padding-right:8px;}h2.section-header>.anchor{padding-right:6px;}a.doc-anchor{color:var(--main-color);display:none;position:absolute;left:-17px;padding-right:5px;padding-left:3px;}*:hover>.doc-anchor{display:block;}.top-doc>.docblock>*:first-child>.doc-anchor{display:none !important;}.main-heading a:hover,.example-wrap .rust a:hover,.all-items a:hover,.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,.item-info a{text-decoration:underline;}.crate.block li.current a{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{display:table;padding:0;margin:0;}.item-table>li{display:table-row;}.item-table>li>div{display:table-cell;}.item-table>li>.item-name{padding-right:1.25rem;}.search-results-title{margin-top:0;white-space:nowrap;display:flex;align-items:baseline;}#crate-search-div{position:relative;min-width:5em;}#crate-search{min-width:115px;padding:0 23px 0 4px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}#crate-search:hover,#crate-search:focus{border-color:var(--crate-search-hover-border);}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url('data:image/svg+xml, \ + ');filter:var(--crate-search-div-filter);}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:var(--crate-search-div-hover-filter);}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;flex-grow:1;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;}.search-results.active{display:block;}.search-results>a{display:flex;margin-left:2px;margin-right:2px;border-bottom:1px solid var(--search-result-border-color);gap:1em;}.search-results>a>div.desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:2;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.search-results .result-name{display:flex;align-items:center;justify-content:start;flex:3;}.search-results .result-name .alias{color:var(--search-results-alias-color);}.search-results .result-name .grey{color:var(--search-results-grey-color);}.search-results .result-name .typename{color:var(--search-results-grey-color);font-size:0.875rem;width:var(--search-typename-width);}.search-results .result-name .path{word-break:break-all;max-width:calc(100% - var(--search-typename-width));display:inline-block;}.search-results .result-name .path>*{display:inline;}.popover{position:absolute;top:100%;right:0;z-index:calc(var(--desktop-sidebar-z-index) + 1);margin-top:7px;border-radius:3px;border:1px solid var(--border-color);background-color:var(--main-background-color);color:var(--main-color);--popover-arrow-offset:11px;}.popover::before{content:'';position:absolute;right:var(--popover-arrow-offset);border:solid var(--border-color);border-width:1px 1px 0 0;background-color:var(--main-background-color);padding:4px;transform:rotate(-45deg);top:-5px;}.setting-line{margin:1.2em 0.6em;}.setting-radio input,.setting-check input{margin-right:0.3em;height:1.2rem;width:1.2rem;border:2px solid var(--settings-input-border-color);outline:none;-webkit-appearance:none;cursor:pointer;}.setting-radio input{border-radius:50%;}.setting-radio span,.setting-check span{padding-bottom:1px;}.setting-radio{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:inline-flex;align-items:center;cursor:pointer;}.setting-radio+.setting-radio{margin-left:0.5em;}.setting-check{margin-right:20px;display:flex;align-items:center;cursor:pointer;}.setting-radio input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-check input:checked{background-color:var(--settings-input-color);border-width:1px;content:url('data:image/svg+xml,\ + \ + ');}.setting-radio input:focus,.setting-check input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-radio input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-radio input:hover,.setting-check input:hover{border-color:var(--settings-input-color) !important;}#help.popover{max-width:600px;--popover-arrow-offset:48px;}#help dt{float:left;clear:left;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side>div{width:50%;float:left;padding:0 20px 20px 17px;}.item-info .stab{display:block;padding:3px;margin-bottom:5px;}.item-name .stab{margin-left:0.3125em;}.stab{padding:0 2px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);width:fit-content;white-space:pre-wrap;border-radius:3px;display:inline;vertical-align:baseline;}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji,.item-info .stab::before{font-size:1.25rem;}.stab .emoji{margin-right:0.3rem;}.item-info .stab::before{content:"\0";width:0;display:inline-block;color:transparent;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;float:right;}.rightside:not(a),.out-of-band{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attr{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.rustdoc.src .example-wrap pre.rust a{background:var(--codeblock-link-background);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;left:-25px;top:5px;margin:0;line-height:1;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}.content .docblock .warning{border-left:2px solid var(--warning-border-color);padding:14px;position:relative;overflow-x:visible !important;}.content .docblock .warning::before{color:var(--warning-border-color);content:"ⓘ";position:absolute;left:-25px;top:5px;font-weight:bold;font-size:1.25rem;}.top-doc>.docblock>.warning:first-child::before{top:20px;}a.test-arrow{visibility:hidden;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:1.375rem;top:5px;right:5px;z-index:1;color:var(--test-arrow-color);background-color:var(--test-arrow-background-color);}a.test-arrow:hover{color:var(--test-arrow-hover-color);background-color:var(--test-arrow-hover-background-color);}.example-wrap:hover .test-arrow{visibility:visible;}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;display:block;}.out-of-band>span.since{font-size:1.25rem;}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}:target{padding-right:3px;background-color:var(--target-background-color);border-right:3px solid var(--target-border-color);}.code-header a.tooltip{color:inherit;margin-right:15px;position:relative;}.code-header a.tooltip:hover{color:var(--link-color);}a.tooltip:hover::after{position:absolute;top:calc(100% - 10px);left:-15px;right:-15px;height:20px;content:"\00a0";}.fade-out{opacity:0;transition:opacity 0.45s cubic-bezier(0,0,0.1,1.0);}.popover.tooltip .content{margin:0.25em 0.5em;}.popover.tooltip .content pre,.popover.tooltip .content code{background:transparent;margin:0;padding:0;font-size:1.25rem;white-space:pre-wrap;}.popover.tooltip .content>h3:first-child{margin:0 0 5px 0;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#search-tabs{display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#search-tabs button{text-align:center;font-size:1.125rem;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#search-tabs button:not(.selected){background-color:var(--search-tab-button-not-selected-background);border-top-color:var(--search-tab-button-not-selected-border-top-color);}#search-tabs button:hover,#search-tabs button.selected{background-color:var(--search-tab-button-selected-background);border-top-color:var(--search-tab-button-selected-border-top-color);}#search-tabs .count{font-size:1rem;font-variant-numeric:tabular-nums;color:var(--search-tab-title-count-color);}#search .error code{border-radius:3px;background-color:var(--search-error-code-background-color);}.search-corrections{font-weight:normal;}#src-sidebar{width:100%;overflow:auto;}#src-sidebar div.files>a:hover,details.dir-entry summary:hover,#src-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:var(--src-sidebar-background-hover);}#src-sidebar div.files>a.selected{background-color:var(--src-sidebar-background-selected);}.src-sidebar-title{position:sticky;top:0;display:flex;padding:8px 8px 0 48px;margin-bottom:7px;background:var(--sidebar-background-color);border-bottom:1px solid var(--border-color);}#settings-menu,#help-button{margin-left:4px;display:flex;}#sidebar-button{display:none;line-height:0;}.hide-sidebar #sidebar-button,.src #sidebar-button{display:flex;margin-right:4px;position:fixed;left:6px;height:34px;width:34px;background-color:var(--main-background-color);z-index:1;}.src #sidebar-button{left:8px;z-index:calc(var(--desktop-sidebar-z-index) + 1);}.hide-sidebar .src #sidebar-button{position:static;}#settings-menu>a,#help-button>a,#sidebar-button>a{display:flex;align-items:center;justify-content:center;background-color:var(--button-background-color);border:1px solid var(--border-color);border-radius:2px;color:var(--settings-button-color);font-size:20px;width:33px;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus,#sidebar-button>a:hover,#sidebar-button>a:focus{border-color:var(--settings-button-border-focus);}#settings-menu>a{line-height:0;font-size:0;}#settings-menu>a:before{content:url('data:image/svg+xml,\ + ');width:22px;height:22px;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:34px;width:33px;margin-left:10px;padding:0;padding-left:2px;border:0;font-size:0;}#copy-path::before{filter:var(--copy-path-img-filter);content:url('data:image/svg+xml,\ +\ +\ +');width:19px;height:18px;}#copy-path:hover::before{filter:var(--copy-path-img-hover-filter);}#copy-path.clicked::before{content:url('data:image/svg+xml,\ + \ + ');}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;color:var(--kbd-color);background-color:var(--kbd-background);box-shadow:inset 0 -1px 0 var(--kbd-box-shadow-color);}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary{margin:0 0 0 -4px;padding:0 0 0 4px;cursor:pointer;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.toggle{contain:layout;position:relative;}details.toggle>summary.hideme{cursor:pointer;font-size:1rem;}details.toggle>summary{list-style:none;outline:none;}details.toggle>summary::-webkit-details-marker,details.toggle>summary::marker{display:none;}details.toggle>summary.hideme>span{margin-left:9px;}details.toggle>summary::before{background:url('data:image/svg+xml,') no-repeat top left;content:"";cursor:pointer;width:16px;height:16px;display:inline-block;vertical-align:middle;opacity:.5;filter:var(--toggle-filter);}details.toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.toggle>summary.hideme::after{content:"";}details.toggle>summary:focus::before,details.toggle>summary:hover::before{opacity:1;}details.toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.non-exhaustive{margin-bottom:8px;}details.toggle>summary.hideme::before{position:relative;}details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}details.toggle[open] >summary.hideme{position:absolute;}details.toggle[open] >summary.hideme>span{display:none;}details.toggle[open] >summary::before{background:url('data:image/svg+xml,') no-repeat top left;}details.toggle[open] >summary::after{content:"Collapse";}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}.src #sidebar-button>a:before,.sidebar-menu-toggle:before{content:url('data:image/svg+xml,\ + ');opacity:0.75;}.sidebar-menu-toggle:hover:before,.sidebar-menu-toggle:active:before,.sidebar-menu-toggle:focus:before{opacity:1;}.src #sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');opacity:0.75;}@media (max-width:850px){#search-tabs .count{display:block;}}@media (max-width:700px){*[id]{scroll-margin-top:45px;}.rustdoc{display:block;}main{padding-left:15px;padding-top:0px;}.main-heading{flex-direction:column;}.out-of-band{text-align:left;margin-left:initial;padding:initial;}.out-of-band .since::before{content:"Since ";}.sidebar .logo-container,.sidebar .location,.sidebar-resizer{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;z-index:11;height:calc(100vh - 45px);width:200px;}.src main,.rustdoc.src .sidebar{top:0;padding:0;height:100vh;border:0;}.src .search-form{margin-left:40px;}.hide-sidebar .search-form{margin-left:32px;}.hide-sidebar .src .search-form{margin-left:0;}.sidebar.shown,.src-sidebar-expanded .src .sidebar,.rustdoc:not(.src) .sidebar:focus-within{left:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;white-space:nowrap;text-overflow:ellipsis;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin:5px 0 5px 20px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.hide-sidebar .mobile-topbar{display:none;}.sidebar-menu-toggle{width:45px;border:none;line-height:0;}.hide-sidebar .sidebar-menu-toggle{display:none;}.sidebar-elems{margin-top:1em;}.anchor{display:none !important;}#main-content>details.toggle>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}#copy-path,#help-button{display:none;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}.sidebar-menu-toggle:before{filter:var(--mobile-sidebar-menu-filter);}.sidebar-menu-toggle:hover{background:var(--main-background-color);}.item-table,.item-row,.item-table>li,.item-table>li>div,.search-results>a,.search-results>a>div{display:block;}.search-results>a{padding:5px 0px;}.search-results>a>div.desc,.item-table>li>div.desc{padding-left:2em;}.search-results .result-name{display:block;}.search-results .result-name .typename{width:initial;margin-right:0;}.search-results .result-name .typename,.search-results .result-name .path{display:inline;}.src-sidebar-expanded .src .sidebar{position:fixed;max-width:100vw;width:100vw;}.src .src-sidebar-title{padding-top:0;}details.toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>details.toggle:not(.top-doc)>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}.impl-items>.item-info{margin-left:34px;}.src nav.sub{margin:0;padding:var(--nav-sub-mobile-padding);}}@media (min-width:701px){.scraped-example-title{position:absolute;z-index:10;background:var(--main-background-color);bottom:8px;right:5px;padding:2px 4px;box-shadow:0 0 4px var(--main-background-color);}}@media print{nav.sidebar,nav.sub,.out-of-band,a.src,#copy-path,details.toggle[open] >summary::before,details.toggle>summary::before,details.toggle.top-doc>summary{display:none;}.docblock{margin-left:0;}main{padding:10px;}}@media (max-width:464px){.docblock{margin-left:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}.search-form{align-self:stretch;}}.variant,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.impl-items>.toggle>summary,.methods>section,.methods>.toggle>summary{margin-bottom:0.75em;}.variants>.docblock,.implementors-toggle>.docblock,.impl-items>.toggle[open]:not(:last-child),.methods>.toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .impl-items>.toggle:not(:last-child),#synthetic-implementations-list .impl-items>.toggle:not(:last-child),#blanket-implementations-list .impl-items>.toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;border:1px solid var(--scrape-example-help-border-color);border-radius:50px;color:var(--scrape-example-help-color);}.scraped-example-list .scrape-help:hover{border-color:var(--scrape-example-help-hover-border-color);color:var(--scrape-example-help-hover-color);}.scraped-example{position:relative;}.scraped-example .code-wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;width:100%;}.scraped-example:not(.expanded) .code-wrapper{max-height:calc(1.5em * 5 + 10px);}.scraped-example:not(.expanded) .code-wrapper pre{overflow-y:hidden;padding-bottom:0;max-height:calc(1.5em * 5 + 10px);}.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper,.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper pre{max-height:calc(1.5em * 10 + 10px);}.scraped-example .code-wrapper .next,.scraped-example .code-wrapper .prev,.scraped-example .code-wrapper .expand{color:var(--main-color);position:absolute;top:0.25em;z-index:1;padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.scraped-example .code-wrapper .prev{right:2.25em;}.scraped-example .code-wrapper .next{right:1.25em;}.scraped-example .code-wrapper .expand{right:0.25em;}.scraped-example:not(.expanded) .code-wrapper::before,.scraped-example:not(.expanded) .code-wrapper::after{content:" ";width:100%;height:5px;position:absolute;z-index:1;}.scraped-example:not(.expanded) .code-wrapper::before{top:0;background:linear-gradient(to bottom,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded) .code-wrapper::after{bottom:0;background:linear-gradient(to top,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example .code-wrapper .example-wrap{width:100%;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded) .code-wrapper .example-wrap{overflow-x:hidden;}.scraped-example .example-wrap .rust span.highlight{background:var(--scrape-example-code-line-highlight);}.scraped-example .example-wrap .rust span.highlight.focus{background:var(--scrape-example-code-line-highlight-focus);}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;cursor:pointer;}.more-scraped-examples{margin-left:25px;position:relative;}.toggle-line{position:absolute;top:5px;bottom:0;right:calc(100% + 10px);padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;background:var(--scrape-example-toggle-line-background);}.toggle-line:hover .toggle-line-inner{background:var(--scrape-example-toggle-line-hover-background);}.more-scraped-examples .scraped-example,.example-links{margin-top:20px;}.more-scraped-examples .scraped-example:first-child{margin-top:5px;}.example-links ul{margin-bottom:0;}:root[data-theme="light"],:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="dark"]{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="ayu"]{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--settings-input-border-color:#999;--settings-button-color:#fff;--settings-button-border-focus:#e0e0e0;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--search-result-border-color:#aaa3;--search-color:#fff;--search-error-code-background-color:#4f4c4c;--search-results-alias-color:#c5c5c5;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:none;--search-tab-button-not-selected-background:transparent !important;--search-tab-button-selected-border-top-color:none;--search-tab-button-selected-background:#141920 !important;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;--src-line-numbers-span-color:#5c6773;--src-line-number-highlighted-background-color:rgba(255,236,164,0.06);--test-arrow-color:#788797;--test-arrow-background-color:rgba(57,175,215,0.09);--test-arrow-hover-color:#c5c5c5;--test-arrow-hover-background-color:rgba(57,175,215,0.368);--target-background-color:rgba(255,236,164,0.06);--target-border-color:rgba(255,180,76,0.85);--kbd-color:#c5c5c5;--kbd-background:#314559;--kbd-box-shadow-color:#5c6773;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);--crate-search-div-hover-filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);--crate-search-hover-border:#e0e0e0;--src-sidebar-background-selected:#14191f;--src-sidebar-background-hover:#14191f;--table-alt-row-background-color:#191f26;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(15,20,25,1);--scrape-example-code-wrapper-background-end:rgba(15,20,25,0);--sidebar-resizer-hover:hsl(34,50%,33%);--sidebar-resizer-active:hsl(34,100%,66%);}:root[data-theme="ayu"] h1,:root[data-theme="ayu"] h2,:root[data-theme="ayu"] h3,:root[data-theme="ayu"] h4,:where(:root[data-theme="ayu"]) h1 a,:root[data-theme="ayu"] .sidebar h2 a,:root[data-theme="ayu"] .sidebar h3 a{color:#fff;}:root[data-theme="ayu"] .docblock code{color:#ffb454;}:root[data-theme="ayu"] .docblock a>code{color:#39AFD7 !important;}:root[data-theme="ayu"] .code-header,:root[data-theme="ayu"] .docblock pre>code,:root[data-theme="ayu"] pre,:root[data-theme="ayu"] pre>code,:root[data-theme="ayu"] .item-info code,:root[data-theme="ayu"] .rustdoc.source .example-wrap{color:#e6e1cf;}:root[data-theme="ayu"] .sidebar .current,:root[data-theme="ayu"] .sidebar .current a,:root[data-theme="ayu"] .sidebar a:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:hover,:root[data-theme="ayu"] details.dir-entry summary:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:focus,:root[data-theme="ayu"] details.dir-entry summary:focus,:root[data-theme="ayu"] #src-sidebar div.files>a.selected{color:#ffb44c;}:root[data-theme="ayu"] .sidebar-elems .location{color:#ff7733;}:root[data-theme="ayu"] .src-line-numbers .line-highlighted{color:#708090;padding-right:7px;border-right:1px solid #ffb44c;}:root[data-theme="ayu"] .search-results a:hover,:root[data-theme="ayu"] .search-results a:focus{color:#fff !important;background-color:#3c3c3c;}:root[data-theme="ayu"] .search-results a{color:#0096cf;}:root[data-theme="ayu"] .search-results a div.desc{color:#c5c5c5;}:root[data-theme="ayu"] .result-name .primitive>i,:root[data-theme="ayu"] .result-name .keyword>i{color:#788797;}:root[data-theme="ayu"] #search-tabs>button.selected{border-bottom:1px solid #ffb44c !important;border-top:none;}:root[data-theme="ayu"] #search-tabs>button:not(.selected){border:none;background-color:transparent !important;}:root[data-theme="ayu"] #search-tabs>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}:root[data-theme="ayu"] #settings-menu>a img,:root[data-theme="ayu"] #sidebar-button>a:before{filter:invert(100);} \ No newline at end of file diff --git a/pr/2992/docs/static.files/scrape-examples-ef1e698c1d417c0c.js b/pr/2992/docs/static.files/scrape-examples-ef1e698c1d417c0c.js new file mode 100644 index 0000000000..ba830e3744 --- /dev/null +++ b/pr/2992/docs/static.files/scrape-examples-ef1e698c1d417c0c.js @@ -0,0 +1 @@ +"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelector(".src-line-numbers");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines.children[line].offsetTop}else{const wrapper=elt.querySelector(".code-wrapper");const halfHeight=wrapper.offsetHeight/2;const offsetTop=lines.children[loc[0]].offsetTop;const lastLine=lines.children[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function updateScrapedExample(example,isHidden){const locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");if(locs.length>1){const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};example.querySelector(".prev").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});example.querySelector(".next").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}const expandButton=example.querySelector(".expand");if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded")}})}scrollToLoc(example,locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>updateScrapedExample(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>updateScrapedExample(el,true))})},{once:true})})})() \ No newline at end of file diff --git a/pr/2992/docs/static.files/search-bf21c90c8c1d92b1.js b/pr/2992/docs/static.files/search-bf21c90c8c1d92b1.js new file mode 100644 index 0000000000..81d04e0eb3 --- /dev/null +++ b/pr/2992/docs/static.files/search-bf21c90c8c1d92b1.js @@ -0,0 +1,5 @@ +"use strict";if(!Array.prototype.toSpliced){Array.prototype.toSpliced=function(){const me=this.slice();Array.prototype.splice.apply(me,arguments);return me}}(function(){const itemTypes=["keyword","primitive","mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","associatedtype","constant","associatedconstant","union","foreigntype","existential","attr","derive","traitalias","generic",];const longItemTypes=["keyword","primitive type","module","extern crate","re-export","struct","enum","function","type alias","static","trait","","trait method","method","struct field","enum variant","macro","assoc type","constant","assoc const","union","foreign type","existential type","attribute macro","derive macro","trait alias",];const TY_GENERIC=itemTypes.indexOf("generic");const TY_IMPORT=itemTypes.indexOf("import");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";const UNBOXING_LIMIT=5;function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("search-tabs").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});const isTypeSearch=(nb>0||iter===1);iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb;const correctionsElem=document.getElementsByClassName("search-corrections");if(isTypeSearch){removeClass(correctionsElem[0],"hidden")}else{addClass(correctionsElem[0],"hidden")}}else if(nb!==0){printTab(0)}}const editDistanceState={current:[],prev:[],prevPrev:[],calculate:function calculate(a,b,limit){if(a.lengthlimit){return limit+1}while(b.length>0&&b[0]===a[0]){a=a.substring(1);b=b.substring(1)}while(b.length>0&&b[b.length-1]===a[a.length-1]){a=a.substring(0,a.length-1);b=b.substring(0,b.length-1)}if(b.length===0){return minDist}const aLength=a.length;const bLength=b.length;for(let i=0;i<=bLength;++i){this.current[i]=0;this.prev[i]=i;this.prevPrev[i]=Number.MAX_VALUE}for(let i=1;i<=aLength;++i){this.current[0]=i;const aIdx=i-1;for(let j=1;j<=bLength;++j){const bIdx=j-1;const substitutionCost=a[aIdx]===b[bIdx]?0:1;this.current[j]=Math.min(this.prev[j]+1,this.current[j-1]+1,this.prev[j-1]+substitutionCost,);if((i>1)&&(j>1)&&(a[aIdx]===b[bIdx-1])&&(a[aIdx-1]===b[bIdx])){this.current[j]=Math.min(this.current[j],this.prevPrev[j-2]+1,)}}const prevPrevTmp=this.prevPrev;this.prevPrev=this.prev;this.prev=this.current;this.current=prevPrevTmp}const distance=this.prev[bLength];return distance<=limit?distance:(limit+1)},};function editDistance(a,b,limit){return editDistanceState.calculate(a,b,limit)}function initSearch(rawSearchIndex){const MAX_RESULTS=200;const NO_TYPE_FILTER=-1;let searchIndex;let searchIndexDeprecated;let searchIndexEmptyDesc;let functionTypeFingerprint;let currentResults;const typeNameIdMap=new Map();const ALIASES=new Map();const typeNameIdOfArray=buildTypeMapIndex("array");const typeNameIdOfSlice=buildTypeMapIndex("slice");const typeNameIdOfArrayOrSlice=buildTypeMapIndex("[]");const typeNameIdOfTuple=buildTypeMapIndex("tuple");const typeNameIdOfUnit=buildTypeMapIndex("unit");const typeNameIdOfTupleOrUnit=buildTypeMapIndex("()");const typeNameIdOfFn=buildTypeMapIndex("fn");const typeNameIdOfFnMut=buildTypeMapIndex("fnmut");const typeNameIdOfFnOnce=buildTypeMapIndex("fnonce");const typeNameIdOfHof=buildTypeMapIndex("->");function buildTypeMapIndex(name,isAssocType){if(name===""||name===null){return null}if(typeNameIdMap.has(name)){const obj=typeNameIdMap.get(name);obj.assocOnly=isAssocType&&obj.assocOnly;return obj.id}else{const id=typeNameIdMap.size;typeNameIdMap.set(name,{id,assocOnly:isAssocType});return id}}function isSpecialStartCharacter(c){return"<\"".indexOf(c)!==-1}function isEndCharacter(c){return"=,>-])".indexOf(c)!==-1}function itemTypeFromName(typename){const index=itemTypes.findIndex(i=>i===typename);if(index<0){throw["Unknown type filter ",typename]}return index}function getStringElem(query,parserState,isInGenerics){if(isInGenerics){throw["Unexpected ","\""," in generics"]}else if(query.literalSearch){throw["Cannot have more than one literal search element"]}else if(parserState.totalElems-parserState.genericsElems>0){throw["Cannot use literal search when there is more than one element"]}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw["Unclosed ","\""]}else if(parserState.userQuery[end]!=="\""){throw["Unexpected ",parserState.userQuery[end]," in a string element"]}else if(start===end){throw["Cannot have empty string element"]}parserState.pos+=1;query.literalSearch=true}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function isIdentCharacter(c){return(c==="_"||(c>="0"&&c<="9")||(c>="a"&&c<="z")||(c>="A"&&c<="Z"))}function isSeparatorCharacter(c){return c===","||c==="="}function isPathSeparator(c){return c===":"||c===" "}function prevIs(parserState,lookingFor){let pos=parserState.pos;while(pos>0){const c=parserState.userQuery[pos-1];if(c===lookingFor){return true}else if(c!==" "){break}pos-=1}return false}function isLastElemGeneric(elems,parserState){return(elems.length>0&&elems[elems.length-1].generics.length>0)||prevIs(parserState,">")}function skipWhitespace(parserState){while(parserState.pos0){throw["Cannot have more than one element if you use quotes"]}const typeFilter=parserState.typeFilter;parserState.typeFilter=null;if(name==="!"){if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive never type ","!"," and ",typeFilter," both specified",]}if(generics.length!==0){throw["Never type ","!"," does not accept generic parameters",]}const bindingName=parserState.isInBinding;parserState.isInBinding=null;return makePrimitiveElement("never",{bindingName})}const quadcolon=/::\s*::/.exec(path);if(path.startsWith("::")){throw["Paths cannot start with ","::"]}else if(path.endsWith("::")){throw["Paths cannot end with ","::"]}else if(quadcolon!==null){throw["Unexpected ",quadcolon[0]]}const pathSegments=path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/);if(pathSegments.length===0||(pathSegments.length===1&&pathSegments[0]==="")){if(generics.length>0||prevIs(parserState,">")){throw["Found generics without a path"]}else{throw["Unexpected ",parserState.userQuery[parserState.pos]]}}for(const[i,pathSegment]of pathSegments.entries()){if(pathSegment==="!"){if(i!==0){throw["Never type ","!"," is not associated item"]}pathSegments[i]="never"}}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}const bindingName=parserState.isInBinding;parserState.isInBinding=null;const bindings=new Map();const pathLast=pathSegments[pathSegments.length-1];return{name:name.trim(),id:null,fullPath:pathSegments,pathWithoutLast:pathSegments.slice(0,pathSegments.length-1),pathLast,normalizedPathLast:pathLast.replace(/_/g,""),generics:generics.filter(gen=>{if(gen.bindingName!==null){if(gen.name!==null){gen.bindingName.generics.unshift(gen)}bindings.set(gen.bindingName.name,gen.bindingName.generics);return false}return true}),bindings,typeFilter,bindingName,}}function getIdentEndPosition(parserState){const start=parserState.pos;let end=parserState.pos;let foundExclamation=-1;while(parserState.pos0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}else{throw["Unexpected ",c]}}parserState.pos+=1;end=parserState.pos}if(foundExclamation!==-1&&foundExclamation!==start&&isIdentCharacter(parserState.userQuery[foundExclamation-1])){if(parserState.typeFilter===null){parserState.typeFilter="macro"}else if(parserState.typeFilter!=="macro"){throw["Invalid search type: macro ","!"," and ",parserState.typeFilter," both specified",]}end=foundExclamation}return end}function getFilteredNextElem(query,parserState,elems,isInGenerics){const start=parserState.pos;if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){throw["Expected type filter before ",":"]}getNextElem(query,parserState,elems,isInGenerics);if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}if(elems.length===0){throw["Expected type filter before ",":"]}else if(query.literalSearch){throw["Cannot use quotes on type filter"]}const typeFilterElem=elems.pop();checkExtraTypeFilterCharacters(start,parserState);parserState.typeFilter=typeFilterElem.name;parserState.pos+=1;parserState.totalElems-=1;query.literalSearch=false;getNextElem(query,parserState,elems,isInGenerics)}}function getNextElem(query,parserState,elems,isInGenerics){const generics=[];skipWhitespace(parserState);let start=parserState.pos;let end;if("[(".indexOf(parserState.userQuery[parserState.pos])!==-1){let endChar=")";let name="()";let friendlyName="tuple";if(parserState.userQuery[parserState.pos]==="["){endChar="]";name="[]";friendlyName="slice"}parserState.pos+=1;const{foundSeparator}=getItemsBefore(query,parserState,generics,endChar);const typeFilter=parserState.typeFilter;const bindingName=parserState.isInBinding;parserState.typeFilter=null;parserState.isInBinding=null;for(const gen of generics){if(gen.bindingName!==null){throw["Type parameter ","=",` cannot be within ${friendlyName} `,name]}}if(name==="()"&&!foundSeparator&&generics.length===1&&typeFilter===null){elems.push(generics[0])}else if(name==="()"&&generics.length===1&&generics[0].name==="->"){generics[0].typeFilter=typeFilter;elems.push(generics[0])}else{if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive ",name," and ",typeFilter," both specified",]}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}elems.push(makePrimitiveElement(name,{bindingName,generics}))}}else{const isStringElem=parserState.userQuery[start]==="\"";if(isStringElem){start+=1;getStringElem(query,parserState,isInGenerics);end=parserState.pos-1}else{end=getIdentEndPosition(parserState)}if(parserState.pos=end){throw["Found generics without a path"]}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}else if(parserState.pos=end){throw["Found generics without a path"]}if(parserState.isInBinding){throw["Unexpected ","("," after ","="]}parserState.pos+=1;const typeFilter=parserState.typeFilter;parserState.typeFilter=null;getItemsBefore(query,parserState,generics,")");skipWhitespace(parserState);if(isReturnArrow(parserState)){parserState.pos+=2;skipWhitespace(parserState);getFilteredNextElem(query,parserState,generics,isInGenerics);generics[generics.length-1].bindingName=makePrimitiveElement("output")}else{generics.push(makePrimitiveElement(null,{bindingName:makePrimitiveElement("output"),typeFilter:null,}))}parserState.typeFilter=typeFilter}if(isStringElem){skipWhitespace(parserState)}if(start>=end&&generics.length===0){return}if(parserState.userQuery[parserState.pos]==="="){if(parserState.isInBinding){throw["Cannot write ","="," twice in a binding"]}if(!isInGenerics){throw["Type parameter ","="," must be within generics list"]}const name=parserState.userQuery.slice(start,end).trim();if(name==="!"){throw["Type parameter ","="," key cannot be ","!"," never type"]}if(name.includes("!")){throw["Type parameter ","="," key cannot be ","!"," macro"]}if(name.includes("::")){throw["Type parameter ","="," key cannot contain ","::"," path"]}if(name.includes(":")){throw["Type parameter ","="," key cannot contain ",":"," type"]}parserState.isInBinding={name,generics}}else{elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics,),)}}}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;let foundSeparator=false;const oldTypeFilter=parserState.typeFilter;parserState.typeFilter=null;const oldIsInBinding=parserState.isInBinding;parserState.isInBinding=null;let hofParameters=null;let extra="";if(endChar===">"){extra="<"}else if(endChar==="]"){extra="["}else if(endChar===")"){extra="("}else if(endChar===""){extra="->"}else{extra=endChar}while(parserState.pos"," after ","="]}hofParameters=[...elems];elems.length=0;parserState.pos+=2;foundStopChar=true;foundSeparator=false;continue}else if(c===" "){parserState.pos+=1;continue}else if(isSeparatorCharacter(c)){parserState.pos+=1;foundStopChar=true;foundSeparator=true;continue}else if(c===":"&&isPathStart(parserState)){throw["Unexpected ","::",": paths cannot start with ","::"]}else if(isEndCharacter(c)){throw["Unexpected ",c," after ",extra]}if(!foundStopChar){let extra=[];if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(endChar!==""){throw["Expected ",",",", ","=",", or ",endChar,...extra,", found ",c,]}throw["Expected ",","," or ","=",...extra,", found ",c,]}const posBefore=parserState.pos;getFilteredNextElem(query,parserState,elems,endChar!=="");if(endChar!==""&&parserState.pos>=parserState.length){throw["Unclosed ",extra]}if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}if(parserState.pos>=parserState.length&&endChar!==""){throw["Unclosed ",extra]}parserState.pos+=1;if(hofParameters){foundSeparator=false;if([...elems,...hofParameters].some(x=>x.bindingName)||parserState.isInBinding){throw["Unexpected ","="," within ","->"]}const hofElem=makePrimitiveElement("->",{generics:hofParameters,bindings:new Map([["output",[...elems]]]),typeFilter:null,});elems.length=0;elems[0]=hofElem}parserState.typeFilter=oldTypeFilter;parserState.isInBinding=oldIsInBinding;return{foundSeparator}}function checkExtraTypeFilterCharacters(start,parserState){const query=parserState.userQuery.slice(start,parserState.pos).trim();for(const c in query){if(!isIdentCharacter(query[c])){throw["Unexpected ",query[c]," in type filter (before ",":",")",]}}}function parseInput(query,parserState){let foundStopChar=true;while(parserState.pos"){if(isReturnArrow(parserState)){break}throw["Unexpected ",c," (did you mean ","->","?)"]}else if(parserState.pos>0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}throw["Unexpected ",c]}else if(c===" "){skipWhitespace(parserState);continue}if(!foundStopChar){let extra="";if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(parserState.typeFilter!==null){throw["Expected ",","," or ","->",...extra,", found ",c,]}throw["Expected ",",",", ",":"," or ","->",...extra,", found ",c,]}const before=query.elems.length;getFilteredNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}while(parserState.pos"]}break}else{parserState.pos+=1}}}function newParsedQuery(userQuery){return{original:userQuery,userQuery:userQuery.toLowerCase(),elems:[],returned:[],foundElems:0,totalElems:0,literalSearch:false,error:null,correction:null,proposeCorrectionFrom:null,proposeCorrectionTo:null,typeFingerprint:new Uint32Array(4),}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&rawSearchIndex.has(elem.value)){return elem.value}return null}function parseQuery(userQuery){function convertTypeFilterOnElem(elem){if(elem.typeFilter!==null){let typeFilter=elem.typeFilter;if(typeFilter==="const"){typeFilter="constant"}elem.typeFilter=itemTypeFromName(typeFilter)}else{elem.typeFilter=NO_TYPE_FILTER}for(const elem2 of elem.generics){convertTypeFilterOnElem(elem2)}for(const constraints of elem.bindings.values()){for(const constraint of constraints){convertTypeFilterOnElem(constraint)}}}userQuery=userQuery.trim().replace(/\r|\n|\t/g," ");const parserState={length:userQuery.length,pos:0,totalElems:0,genericsElems:0,typeFilter:null,isInBinding:null,userQuery:userQuery.toLowerCase(),};let query=newParsedQuery(userQuery);try{parseInput(query,parserState);for(const elem of query.elems){convertTypeFilterOnElem(elem)}for(const elem of query.returned){convertTypeFilterOnElem(elem)}}catch(err){query=newParsedQuery(userQuery);query.error=err;return query}if(!query.literalSearch){query.literalSearch=parserState.totalElems>1}query.foundElems=query.elems.length+query.returned.length;query.totalElems=parserState.totalElems;return query}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}async function execQuery(parsedQuery,filterCrates,currentCrate){const results_others=new Map(),results_in_args=new Map(),results_returned=new Map();function transformResults(results){const duplicates=new Set();const out=[];for(const result of results){if(result.id!==-1){const obj=searchIndex[result.id];obj.dist=result.dist;const res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=res[2]+"|"+obj.ty;if(duplicates.has(obj.fullPath)){continue}if(obj.ty===TY_IMPORT&&duplicates.has(res[2])){continue}if(duplicates.has(res[2]+"|"+TY_IMPORT)){continue}duplicates.add(obj.fullPath);duplicates.add(res[2]);obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}async function sortResults(results,isType,preferredCrate){const userQuery=parsedQuery.userQuery;const result_list=[];for(const result of results.values()){result.item=searchIndex[result.id];result.word=searchIndex[result.id].word;result_list.push(result)}result_list.sort((aaa,bbb)=>{let a,b;a=(aaa.word!==userQuery);b=(bbb.word!==userQuery);if(a!==b){return a-b}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.path_dist;b=bbb.path_dist;if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}a=(aaa.dist);b=(bbb.dist);if(a!==b){return a-b}a=searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);b=searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);if(a!==b){return a-b}a=(aaa.item.crate!==preferredCrate);b=(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=aaa.word.length;b=bbb.word.length;if(a!==b){return a-b}a=aaa.word;b=bbb.word;if(a!==b){return(a>b?+1:-1)}a=searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);b=searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});return transformResults(result_list)}function unifyFunctionTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return false}const mgens=mgensIn===null?null:new Map(mgensIn);if(queryElems.length===0){return!solutionCb||solutionCb(mgens)}if(!fnTypesIn||fnTypesIn.length===0){return false}const ql=queryElems.length;const fl=fnTypesIn.length;if(ql===1&&queryElems[0].generics.length===0&&queryElems[0].bindings.size===0){const queryElem=queryElems[0];for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}if(fnType.id<0&&queryElem.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==queryElem.id){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,queryElem.id);if(!solutionCb||solutionCb(mgensScratch)){return true}}else if(!solutionCb||solutionCb(mgens?new Map(mgens):null)){return true}}for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}if(fnType.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,0);if(unifyFunctionTypes(whereClause[(-fnType.id)-1],queryElems,whereClause,mgensScratch,solutionCb,unboxingDepth+1,)){return true}}else if(unifyFunctionTypes([...fnType.generics,...Array.from(fnType.bindings.values()).flat()],queryElems,whereClause,mgens?new Map(mgens):null,solutionCb,unboxingDepth+1,)){return true}}return false}const fnTypes=fnTypesIn.slice();const flast=fl-1;const qlast=ql-1;const queryElem=queryElems[qlast];let queryElemsTmp=null;for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==queryElem.id){continue}mgensScratch.set(fnType.id,queryElem.id)}else{mgensScratch=mgens}fnTypes[i]=fnTypes[flast];fnTypes.length=flast;if(!queryElemsTmp){queryElemsTmp=queryElems.slice(0,qlast)}const passesUnification=unifyFunctionTypes(fnTypes,queryElemsTmp,whereClause,mgensScratch,mgensScratch=>{if(fnType.generics.length===0&&queryElem.generics.length===0&&fnType.bindings.size===0&&queryElem.bindings.size===0){return!solutionCb||solutionCb(mgensScratch)}const solution=unifyFunctionTypeCheckBindings(fnType,queryElem,whereClause,mgensScratch,unboxingDepth,);if(!solution){return false}const simplifiedGenerics=solution.simplifiedGenerics;for(const simplifiedMgens of solution.mgens){const passesUnification=unifyFunctionTypes(simplifiedGenerics,queryElem.generics,whereClause,simplifiedMgens,solutionCb,unboxingDepth,);if(passesUnification){return true}}return false},unboxingDepth,);if(passesUnification){return true}fnTypes[flast]=fnTypes[i];fnTypes[i]=fnType;fnTypes.length=fl}for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==0){continue}mgensScratch.set(fnType.id,0)}else{mgensScratch=mgens}const generics=fnType.id<0?whereClause[(-fnType.id)-1]:fnType.generics;const bindings=fnType.bindings?Array.from(fnType.bindings.values()).flat():[];const passesUnification=unifyFunctionTypes(fnTypes.toSpliced(i,1,...generics,...bindings),queryElems,whereClause,mgensScratch,solutionCb,unboxingDepth+1,);if(passesUnification){return true}}return false}function unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgensIn){if(!typePassesFilter(queryElem.typeFilter,fnType.ty)){return false}if(fnType.id<0&&queryElem.id<0){if(mgensIn){if(mgensIn.has(fnType.id)&&mgensIn.get(fnType.id)!==queryElem.id){return false}for(const[fid,qid]of mgensIn.entries()){if(fnType.id!==fid&&queryElem.id===qid){return false}if(fnType.id===fid&&queryElem.id!==qid){return false}}}return true}else{if(queryElem.id===typeNameIdOfArrayOrSlice&&(fnType.id===typeNameIdOfSlice||fnType.id===typeNameIdOfArray)){}else if(queryElem.id===typeNameIdOfTupleOrUnit&&(fnType.id===typeNameIdOfTuple||fnType.id===typeNameIdOfUnit)){}else if(queryElem.id===typeNameIdOfHof&&(fnType.id===typeNameIdOfFn||fnType.id===typeNameIdOfFnMut||fnType.id===typeNameIdOfFnOnce)){}else if(fnType.id!==queryElem.id||queryElem.id===null){return false}if((fnType.generics.length+fnType.bindings.size)===0&&queryElem.generics.length!==0){return false}if(fnType.bindings.size0){const fnTypePath=fnType.path!==undefined&&fnType.path!==null?fnType.path.split("::"):[];if(queryElemPathLength>fnTypePath.length){return false}let i=0;for(const path of fnTypePath){if(path===queryElem.pathWithoutLast[i]){i+=1;if(i>=queryElemPathLength){break}}}if(i0){let mgensSolutionSet=[mgensIn];for(const[name,constraints]of queryElem.bindings.entries()){if(mgensSolutionSet.length===0){return false}if(!fnType.bindings.has(name)){return false}const fnTypeBindings=fnType.bindings.get(name);mgensSolutionSet=mgensSolutionSet.flatMap(mgens=>{const newSolutions=[];unifyFunctionTypes(fnTypeBindings,constraints,whereClause,mgens,newMgens=>{newSolutions.push(newMgens);return false},unboxingDepth,);return newSolutions})}if(mgensSolutionSet.length===0){return false}const binds=Array.from(fnType.bindings.entries()).flatMap(entry=>{const[name,constraints]=entry;if(queryElem.bindings.has(name)){return[]}else{return constraints}});if(simplifiedGenerics.length>0){simplifiedGenerics=[...simplifiedGenerics,...binds]}else{simplifiedGenerics=binds}return{simplifiedGenerics,mgens:mgensSolutionSet}}return{simplifiedGenerics,mgens:[mgensIn]}}function unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return false}if(fnType.id<0&&queryElem.id>=0){if(!whereClause){return false}if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){return false}const mgensTmp=new Map(mgens);mgensTmp.set(fnType.id,null);return checkIfInList(whereClause[(-fnType.id)-1],queryElem,whereClause,mgensTmp,unboxingDepth,)}else if(fnType.generics.length>0||fnType.bindings.size>0){const simplifiedGenerics=[...fnType.generics,...Array.from(fnType.bindings.values()).flat(),];return checkIfInList(simplifiedGenerics,queryElem,whereClause,mgens,unboxingDepth,)}return false}function checkIfInList(list,elem,whereClause,mgens,unboxingDepth){for(const entry of list){if(checkType(entry,elem,whereClause,mgens,unboxingDepth)){return true}}return false}function checkType(row,elem,whereClause,mgens,unboxingDepth){if(unboxingDepth>=UNBOXING_LIMIT){return false}if(row.bindings.size===0&&elem.bindings.size===0){if(elem.id<0&&mgens===null){return row.id<0||checkIfInList(row.generics,elem,whereClause,mgens,unboxingDepth+1,)}if(row.id>0&&elem.id>0&&elem.pathWithoutLast.length===0&&typePassesFilter(elem.typeFilter,row.ty)&&elem.generics.length===0&&elem.id!==typeNameIdOfArrayOrSlice&&elem.id!==typeNameIdOfTupleOrUnit&&elem.id!==typeNameIdOfHof){return row.id===elem.id||checkIfInList(row.generics,elem,whereClause,mgens,unboxingDepth,)}}return unifyFunctionTypes([row],[elem],whereClause,mgens,null,unboxingDepth)}function checkPath(contains,ty){if(contains.length===0){return 0}const maxPathEditDistance=Math.floor(contains.reduce((acc,next)=>acc+next.length,0)/3,);let ret_dist=maxPathEditDistance+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;pathiter:for(let i=length-clength;i>=0;i-=1){let dist_total=0;for(let x=0;xmaxPathEditDistance){continue pathiter}dist_total+=dist}}ret_dist=Math.min(ret_dist,Math.round(dist_total/clength))}return ret_dist>maxPathEditDistance?null:ret_dist}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,descShard:item.descShard,descIndex:item.descIndex,exactPath:item.exactPath,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,bitIndex:item.bitIndex,implDisambiguator:item.implDisambiguator,}}function handleAliases(ret,query,filterCrates,currentCrate){const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(ALIASES.has(filterCrates)&&ALIASES.get(filterCrates).has(lowerQuery)){const query_aliases=ALIASES.get(filterCrates).get(lowerQuery);for(const alias of query_aliases){aliases.push(createAliasFromItem(searchIndex[alias]))}}}else{for(const[crate,crateAliasesIndex]of ALIASES){if(crateAliasesIndex.has(lowerQuery)){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=crateAliasesIndex.get(lowerQuery);for(const alias of query_aliases){pushTo.push(createAliasFromItem(searchIndex[alias]))}}}}const sortFunc=(aaa,bbb)=>{if(aaa.path{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach(pushFunc);crateAliases.forEach(pushFunc)}function addIntoResults(results,fullId,id,index,dist,path_dist,maxEditDistance){if(dist<=maxEditDistance||index!==-1){if(results.has(fullId)){const result=results.get(fullId);if(result.dontValidate||result.dist<=dist){return}}results.set(fullId,{id:id,index:index,dontValidate:parsedQuery.literalSearch,dist:dist,path_dist:path_dist,})}}function handleSingleArg(row,pos,elem,results_others,results_in_args,results_returned,maxEditDistance,){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let path_dist=0;const fullId=row.id;const tfpDist=compareTypeFingerprints(fullId,parsedQuery.typeFingerprint,);if(tfpDist!==null){const in_args=row.type&&row.type.inputs&&checkIfInList(row.type.inputs,elem,row.type.where_clause,null,0);const returned=row.type&&row.type.output&&checkIfInList(row.type.output,elem,row.type.where_clause,null,0);if(in_args){results_in_args.max_dist=Math.max(results_in_args.max_dist||0,tfpDist);const maxDist=results_in_args.sizenormalizedIndex&&normalizedIndex!==-1)){index=normalizedIndex}if(elem.fullPath.length>1){path_dist=checkPath(elem.pathWithoutLast,row);if(path_dist===null){return}}if(parsedQuery.literalSearch){if(row.word===elem.pathLast){addIntoResults(results_others,fullId,pos,index,0,path_dist)}return}const dist=editDistance(row.normalizedName,elem.normalizedPathLast,maxEditDistance);if(index===-1&&dist>maxEditDistance){return}addIntoResults(results_others,fullId,pos,index,dist,path_dist,maxEditDistance)}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)||!row.type){return}const tfpDist=compareTypeFingerprints(row.id,parsedQuery.typeFingerprint,);if(tfpDist===null){return}if(results.size>=MAX_RESULTS&&tfpDist>results.max_dist){return}if(!unifyFunctionTypes(row.type.inputs,parsedQuery.elems,row.type.where_clause,null,mgens=>{return unifyFunctionTypes(row.type.output,parsedQuery.returned,row.type.where_clause,mgens,null,0,)},0,)){return}results.max_dist=Math.max(results.max_dist||0,tfpDist);addIntoResults(results,row.id,pos,0,tfpDist,0,Number.MAX_VALUE)}function innerRunQuery(){const queryLen=parsedQuery.elems.reduce((acc,next)=>acc+next.pathLast.length,0)+parsedQuery.returned.reduce((acc,next)=>acc+next.pathLast.length,0);const maxEditDistance=Math.floor(queryLen/3);const genericSymbols=new Map();function convertNameToId(elem,isAssocType){if(typeNameIdMap.has(elem.normalizedPathLast)&&(isAssocType||!typeNameIdMap.get(elem.normalizedPathLast).assocOnly)){elem.id=typeNameIdMap.get(elem.normalizedPathLast).id}else if(!parsedQuery.literalSearch){let match=null;let matchDist=maxEditDistance+1;let matchName="";for(const[name,{id,assocOnly}]of typeNameIdMap){const dist=editDistance(name,elem.normalizedPathLast,maxEditDistance);if(dist<=matchDist&&dist<=maxEditDistance&&(isAssocType||!assocOnly)){if(dist===matchDist&&matchName>name){continue}match=id;matchDist=dist;matchName=name}}if(match!==null){parsedQuery.correction=matchName}elem.id=match}if((elem.id===null&&parsedQuery.totalElems>1&&elem.typeFilter===-1&&elem.generics.length===0&&elem.bindings.size===0)||elem.typeFilter===TY_GENERIC){if(genericSymbols.has(elem.name)){elem.id=genericSymbols.get(elem.name)}else{elem.id=-(genericSymbols.size+1);genericSymbols.set(elem.name,elem.id)}if(elem.typeFilter===-1&&elem.name.length>=3){const maxPartDistance=Math.floor(elem.name.length/3);let matchDist=maxPartDistance+1;let matchName="";for(const name of typeNameIdMap.keys()){const dist=editDistance(name,elem.name,maxPartDistance);if(dist<=matchDist&&dist<=maxPartDistance){if(dist===matchDist&&matchName>name){continue}matchDist=dist;matchName=name}}if(matchName!==""){parsedQuery.proposeCorrectionFrom=elem.name;parsedQuery.proposeCorrectionTo=matchName}}elem.typeFilter=TY_GENERIC}if(elem.generics.length>0&&elem.typeFilter===TY_GENERIC){parsedQuery.error=["Generic type parameter ",elem.name," does not accept generic parameters",]}for(const elem2 of elem.generics){convertNameToId(elem2)}elem.bindings=new Map(Array.from(elem.bindings.entries()).map(entry=>{const[name,constraints]=entry;if(!typeNameIdMap.has(name)){parsedQuery.error=["Type parameter ",name," does not exist",];return[null,[]]}for(const elem2 of constraints){convertNameToId(elem2)}return[typeNameIdMap.get(name).id,constraints]}),)}const fps=new Set();for(const elem of parsedQuery.elems){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}for(const elem of parsedQuery.returned){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}if(parsedQuery.foundElems===1&&parsedQuery.returned.length===0){if(parsedQuery.elems.length===1){const elem=parsedQuery.elems[0];for(let i=0,nSearchIndex=searchIndex.length;i0){const sortQ=(a,b)=>{const ag=a.generics.length===0&&a.bindings.size===0;const bg=b.generics.length===0&&b.bindings.size===0;if(ag!==bg){return ag-bg}const ai=a.id>0;const bi=b.id>0;return ai-bi};parsedQuery.elems.sort(sortQ);parsedQuery.returned.sort(sortQ);for(let i=0,nSearchIndex=searchIndex.length;i{const descs=await Promise.all(list.map(result=>{return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex)?"":searchState.loadDesc(result)}));for(const[i,result]of list.entries()){result.desc=descs[i]}}));if(parsedQuery.error!==null&&ret.others.length!==0){ret.query.error=null}return ret}function nextTab(direction){const next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){const target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#search-tabs button").item(searchState.currentTab);searchState.focusedByTab[searchState.currentTab]=null;if(target){target.focus()}}function buildHrefAndPath(item){let displayPath;let href;const type=itemTypes[item.ty];const name=item.name;let path=item.path;let exactPath=item.exactPath;if(type==="mod"){displayPath=path+"::";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="import"){displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/index.html#reexport."+name}else if(type==="primitive"||type==="keyword"){displayPath="";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=ROOT_PATH+name+"/index.html"}else if(item.parent!==undefined){const myparent=item.parent;let anchor=type+"."+name;const parentType=itemTypes[myparent.ty];let pageType=parentType;let pageName=myparent.name;exactPath=`${myparent.exactPath}::${myparent.name}`;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){const enumNameIdx=item.path.lastIndexOf("::");const enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}if(item.implDisambiguator!==null){anchor=item.implDisambiguator+"/"+anchor}href=ROOT_PATH+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html#"+anchor}else{displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href,`${exactPath}::${name}`]}function pathSplitter(path){const tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}async function addTab(array,query,display){const extraClass=display?" active":"";const output=document.createElement("div");if(array.length>0){output.className="search-results "+extraClass;for(const item of array){const name=item.name;const type=itemTypes[item.ty];const longType=longItemTypes[item.ty];const typeName=longType.length!==0?`${longType}`:"?";const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const resultName=document.createElement("div");resultName.className="result-name";resultName.insertAdjacentHTML("beforeend",`${typeName}`);link.appendChild(resultName);let alias=" ";if(item.is_alias){alias=`
\ +${item.alias} - see \ +
`}resultName.insertAdjacentHTML("beforeend",`
${alias}\ +${item.displayPath}${name}\ +
`);const description=document.createElement("div");description.className="desc";description.insertAdjacentHTML("beforeend",item.desc);link.appendChild(description);output.appendChild(link)}}else if(query.error===null){output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,array.length]}function makeTabHeader(tabNb,text,nbElems){const fmtNbElems=nbElems<10?`\u{2007}(${nbElems})\u{2007}\u{2007}`:nbElems<100?`\u{2007}(${nbElems})\u{2007}`:`\u{2007}(${nbElems})`;if(searchState.currentTab===tabNb){return""}return""}async function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true")){window.onunload=()=>{};searchState.removeQueryParameters();const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=parseQuery(searchState.input.value)}currentResults=results.query.userQuery;const[ret_others,ret_in_args,ret_returned]=await Promise.all([addTab(results.others,results.query,true),addTab(results.in_args,results.query,false),addTab(results.returned,results.query,false),]);let currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}let crates="";if(rawSearchIndex.size>1){crates=" in 
"}let output=`

Results${crates}

`;if(results.query.error!==null){const error=results.query.error;error.forEach((value,index)=>{value=value.split("<").join("<").split(">").join(">");if(index%2!==0){error[index]=`${value.replaceAll(" ", " ")}`}else{error[index]=value}});output+=`

Query parser error: "${error.join("")}".

`;output+="
"+makeTabHeader(0,"In Names",ret_others[1])+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,ret_others[1])+"
";currentTab=0}if(results.query.correction!==null){const orig=results.query.returned.length>0?results.query.returned[0].name:results.query.elems[0].name;output+="

"+`Type "${orig}" not found. `+"Showing results for closest type name "+`"${results.query.correction}" instead.

`}if(results.query.proposeCorrectionFrom!==null){const orig=results.query.proposeCorrectionFrom;const targ=results.query.proposeCorrectionTo;output+="

"+`Type "${orig}" not found and used as generic parameter. `+`Consider searching for "${targ}" instead.

`}const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("search-tabs").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function updateSearchHistory(url){if(!browserSupportsHistoryApi()){return}const params=searchState.getQueryStringParams();if(!history.state&&!params.search){history.pushState(null,"",url)}else{history.replaceState(null,"",url)}}async function search(forced){const query=parseQuery(searchState.input.value.trim());let filterCrates=getFilterCrates();if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}searchState.setLoadingSearch();const params=searchState.getQueryStringParams();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="Results for "+query.original+" - Rust";updateSearchHistory(buildUrl(query.original,filterCrates));await showResults(await execQuery(query,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function buildItemSearchTypeAll(types,lowercasePaths){return types.length>0?types.map(type=>buildItemSearchType(type,lowercasePaths)):EMPTY_GENERICS_ARRAY}const EMPTY_BINDINGS_MAP=new Map();const EMPTY_GENERICS_ARRAY=[];let TYPES_POOL=new Map();function buildItemSearchType(type,lowercasePaths,isAssocType){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;const BINDINGS_DATA=2;let pathIndex,generics,bindings;if(typeof type==="number"){pathIndex=type;generics=EMPTY_GENERICS_ARRAY;bindings=EMPTY_BINDINGS_MAP}else{pathIndex=type[PATH_INDEX_DATA];generics=buildItemSearchTypeAll(type[GENERICS_DATA],lowercasePaths,);if(type.length>BINDINGS_DATA&&type[BINDINGS_DATA].length>0){bindings=new Map(type[BINDINGS_DATA].map(binding=>{const[assocType,constraints]=binding;return[buildItemSearchType(assocType,lowercasePaths,true).id,buildItemSearchTypeAll(constraints,lowercasePaths),]}))}else{bindings=EMPTY_BINDINGS_MAP}}let result;if(pathIndex<0){result={id:pathIndex,ty:TY_GENERIC,path:null,exactPath:null,generics,bindings,}}else if(pathIndex===0){result={id:null,ty:null,path:null,exactPath:null,generics,bindings,}}else{const item=lowercasePaths[pathIndex-1];result={id:buildTypeMapIndex(item.name,isAssocType),ty:item.ty,path:item.path,exactPath:item.exactPath,generics,bindings,}}const cr=TYPES_POOL.get(result.id);if(cr){if(cr.generics.length===result.generics.length&&cr.generics!==result.generics&&cr.generics.every((x,i)=>result.generics[i]===x)){result.generics=cr.generics}if(cr.bindings.size===result.bindings.size&&cr.bindings!==result.bindings){let ok=true;for(const[k,v]of cr.bindings.entries()){const v2=result.bindings.get(v);if(!v2){ok=false;break}if(v!==v2&&v.length===v2.length&&v.every((x,i)=>v2[i]===x)){result.bindings.set(k,v)}else if(v!==v2){ok=false;break}}if(ok){result.bindings=cr.bindings}}if(cr.ty===result.ty&&cr.path===result.path&&cr.bindings===result.bindings&&cr.generics===result.generics&&cr.ty===result.ty){return cr}}TYPES_POOL.set(result.id,result);return result}function buildFunctionSearchTypeCallback(lowercasePaths){return functionSearchType=>{if(functionSearchType===0){return null}const INPUTS_DATA=0;const OUTPUT_DATA=1;let inputs,output;if(typeof functionSearchType[INPUTS_DATA]==="number"){inputs=[buildItemSearchType(functionSearchType[INPUTS_DATA],lowercasePaths)]}else{inputs=buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],lowercasePaths,)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){output=[buildItemSearchType(functionSearchType[OUTPUT_DATA],lowercasePaths)]}else{output=buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],lowercasePaths,)}}else{output=[]}const where_clause=[];const l=functionSearchType.length;for(let i=2;i{k=(~~k+0x7ed55d16)+(k<<12);k=(k ^ 0xc761c23c)^(k>>>19);k=(~~k+0x165667b1)+(k<<5);k=(~~k+0xd3a2646c)^(k<<9);k=(~~k+0xfd7046c5)+(k<<3);return(k ^ 0xb55a4f09)^(k>>>16)};const hashint2=k=>{k=~k+(k<<15);k ^=k>>>12;k+=k<<2;k ^=k>>>4;k=Math.imul(k,2057);return k ^(k>>16)};if(input!==null){const h0a=hashint1(input);const h0b=hashint2(input);const h1a=~~(h0a+Math.imul(h0b,2));const h1b=~~(h0a+Math.imul(h0b,3));const h2a=~~(h0a+Math.imul(h0b,4));const h2b=~~(h0a+Math.imul(h0b,5));output[0]|=(1<<(h0a%32))|(1<<(h1b%32));output[1]|=(1<<(h1a%32))|(1<<(h2b%32));output[2]|=(1<<(h2a%32))|(1<<(h0b%32));fps.add(input)}for(const g of type.generics){buildFunctionTypeFingerprint(g,output,fps)}const fb={id:null,ty:0,generics:EMPTY_GENERICS_ARRAY,bindings:EMPTY_BINDINGS_MAP,};for(const[k,v]of type.bindings.entries()){fb.id=k;fb.generics=v;buildFunctionTypeFingerprint(fb,output,fps)}output[3]=fps.size}function compareTypeFingerprints(fullId,queryFingerprint){const fh0=functionTypeFingerprint[fullId*4];const fh1=functionTypeFingerprint[(fullId*4)+1];const fh2=functionTypeFingerprint[(fullId*4)+2];const[qh0,qh1,qh2]=queryFingerprint;const[in0,in1,in2]=[fh0&qh0,fh1&qh1,fh2&qh2];if((in0 ^ qh0)||(in1 ^ qh1)||(in2 ^ qh2)){return null}return functionTypeFingerprint[(fullId*4)+3]}class VlqHexDecoder{constructor(string,cons){this.string=string;this.cons=cons;this.offset=0;this.backrefQueue=[]}decodeList(){const cb="}".charCodeAt(0);let c=this.string.charCodeAt(this.offset);const ret=[];while(c!==cb){ret.push(this.decode());c=this.string.charCodeAt(this.offset)}this.offset+=1;return ret}decode(){const[ob,la]=["{","`"].map(c=>c.charCodeAt(0));let n=0;let c=this.string.charCodeAt(this.offset);if(c===ob){this.offset+=1;return this.decodeList()}while(c>1];this.offset+=1;return sign?-value:value}next(){const c=this.string.charCodeAt(this.offset);const[zero,ua,la]=["0","@","`"].map(c=>c.charCodeAt(0));if(c>=zero&&c16){this.backrefQueue.pop()}return result}}class RoaringBitmap{constructor(str){const strdecoded=atob(str);const u8array=new Uint8Array(strdecoded.length);for(let j=0;j=4){offsets=[];for(let j=0;j>3]&(1<<(j&0x7))){const runcount=(u8array[i]|(u8array[i+1]<<8));i+=2;this.containers.push(new RoaringBitmapRun(runcount,u8array.slice(i,i+(runcount*4)),));i+=runcount*4}else if(this.cardinalities[j]>=4096){this.containers.push(new RoaringBitmapBits(u8array.slice(i,i+8192)));i+=8192}else{const end=this.cardinalities[j]*2;this.containers.push(new RoaringBitmapArray(this.cardinalities[j],u8array.slice(i,i+end),));i+=end}}}contains(keyvalue){const key=keyvalue>>16;const value=keyvalue&0xFFFF;for(let i=0;i=start&&value<=(start+lenm1)){return true}}return false}}class RoaringBitmapArray{constructor(cardinality,array){this.cardinality=cardinality;this.array=array}contains(value){const l=this.cardinality*2;for(let i=0;i>3]&(1<<(value&7)))}}function buildIndex(rawSearchIndex){searchIndex=[];searchIndexDeprecated=new Map();searchIndexEmptyDesc=new Map();const charA="A".charCodeAt(0);let currentIndex=0;let id=0;for(const crate of rawSearchIndex.values()){id+=crate.t.length+1}functionTypeFingerprint=new Uint32Array((id+1)*4);id=0;for(const[crate,crateCorpus]of rawSearchIndex){const itemDescShardDecoder=new VlqHexDecoder(crateCorpus.D,noop=>noop);let descShard={crate,shard:0,start:0,len:itemDescShardDecoder.next(),promise:null,resolve:null,};const descShardList=[descShard];searchIndexDeprecated.set(crate,new RoaringBitmap(crateCorpus.c));searchIndexEmptyDesc.set(crate,new RoaringBitmap(crateCorpus.e));let descIndex=0;const crateRow={crate,ty:3,name:crate,path:"",descShard,descIndex,exactPath:"",desc:crateCorpus.doc,parent:undefined,type:null,id,word:crate,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),bitIndex:0,implDisambiguator:null,};id+=1;searchIndex.push(crateRow);currentIndex+=1;if(!searchIndexEmptyDesc.get(crate).contains(0)){descIndex+=1}const itemTypes=crateCorpus.t;const itemNames=crateCorpus.n;const itemPaths=new Map(crateCorpus.q);const itemReexports=new Map(crateCorpus.r);const itemParentIdxs=crateCorpus.i;const implDisambiguator=new Map(crateCorpus.b);const paths=crateCorpus.p;const aliases=crateCorpus.a;const lowercasePaths=[];const itemFunctionDecoder=new VlqHexDecoder(crateCorpus.f,buildFunctionSearchTypeCallback(lowercasePaths),);let len=paths.length;let lastPath=itemPaths.get(0);for(let i=0;i2){path=itemPaths.has(elem[2])?itemPaths.get(elem[2]):lastPath;lastPath=path}const exactPath=elem.length>3?itemPaths.get(elem[3]):path;lowercasePaths.push({ty,name:name.toLowerCase(),path,exactPath});paths[i]={ty,name,path,exactPath}}lastPath="";len=itemTypes.length;for(let i=0;i=descShard.len&&!searchIndexEmptyDesc.get(crate).contains(bitIndex)){descShard={crate,shard:descShard.shard+1,start:descShard.start+descShard.len,len:itemDescShardDecoder.next(),promise:null,resolve:null,};descIndex=0;descShardList.push(descShard)}let word="";if(typeof itemNames[i]==="string"){word=itemNames[i].toLowerCase()}const path=itemPaths.has(i)?itemPaths.get(i):lastPath;const type=itemFunctionDecoder.next();if(type!==null){if(type){const fp=functionTypeFingerprint.subarray(id*4,(id+1)*4);const fps=new Set();for(const t of type.inputs){buildFunctionTypeFingerprint(t,fp,fps)}for(const t of type.output){buildFunctionTypeFingerprint(t,fp,fps)}for(const w of type.where_clause){for(const t of w){buildFunctionTypeFingerprint(t,fp,fps)}}}}const row={crate,ty:itemTypes.charCodeAt(i)-charA,name:itemNames[i],path,descShard,descIndex,exactPath:itemReexports.has(i)?itemPaths.get(itemReexports.get(i)):path,parent:itemParentIdxs[i]>0?paths[itemParentIdxs[i]-1]:undefined,type,id,word,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),bitIndex,implDisambiguator:implDisambiguator.has(i)?implDisambiguator.get(i):null,};id+=1;searchIndex.push(row);lastPath=row.path;if(!searchIndexEmptyDesc.get(crate).contains(bitIndex)){descIndex+=1}}if(aliases){const currentCrateAliases=new Map();ALIASES.set(crate,currentCrateAliases);for(const alias_name in aliases){if(!Object.prototype.hasOwnProperty.call(aliases,alias_name)){continue}let currentNameAliases;if(currentCrateAliases.has(alias_name)){currentNameAliases=currentCrateAliases.get(alias_name)}else{currentNameAliases=[];currentCrateAliases.set(alias_name,currentNameAliases)}for(const local_alias of aliases[alias_name]){currentNameAliases.push(local_alias+currentIndex)}}}currentIndex+=itemTypes.length;searchState.descShards.set(crate,descShardList)}TYPES_POOL=new Map()}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{searchState.input.placeholder=searchState.input.origPlaceholder});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;e.preventDefault();search()}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const query=searchState.input.value.trim();updateSearchHistory(buildUrl(query,null))}currentResults=null;search(true)}buildIndex(rawSearchIndex);if(typeof window!=="undefined"){registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}if(typeof exports!=="undefined"){exports.initSearch=initSearch;exports.execQuery=execQuery;exports.parseQuery=parseQuery}}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch(new Map())}})() \ No newline at end of file diff --git a/pr/2992/docs/static.files/settings-4313503d2e1961c2.js b/pr/2992/docs/static.files/settings-4313503d2e1961c2.js new file mode 100644 index 0000000000..ab425fe49d --- /dev/null +++ b/pr/2992/docs/static.files/settings-4313503d2e1961c2.js @@ -0,0 +1,17 @@ +"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){if(settingName==="theme"){const useSystem=value==="system preference"?"true":"false";updateLocalStorage("use-system-theme",useSystem)}updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":updateTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break;case"hide-sidebar":if(value===true){addClass(document.documentElement,"hide-sidebar")}else{removeClass(document.documentElement,"hide-sidebar")}break}}function showLightAndDark(){removeClass(document.getElementById("preferred-light-theme"),"hidden");removeClass(document.getElementById("preferred-dark-theme"),"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme"),"hidden");addClass(document.getElementById("preferred-dark-theme"),"hidden")}function updateLightAndDark(){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||(useSystem===null&&getSettingValue("theme")===null)){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"),toggle=>{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\ +
+
${setting_name}
+
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\ + `});output+=`\ +
+
`}else{const checked=setting["default"]===true?" checked":"";output+=`\ +
\ + \ +
`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Hide persistent navigation bar","js_name":"hide-sidebar","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display="";onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"),el=>{const val=getSettingValue(el.id);const checked=val==="true";if(checked!==el.checked&&val!==null){el.checked=checked}})}function settingsBlurHandler(event){blurHandler(event,getSettingsButton(),window.hidePopoverMenus)}if(isSettingsPage){getSettingsButton().onclick=event=>{event.preventDefault()}}else{const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(settingsMenu.contains(event.target)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/pr/2992/docs/static.files/src-script-e66d777a5a92e9b2.js b/pr/2992/docs/static.files/src-script-e66d777a5a92e9b2.js new file mode 100644 index 0000000000..d0aebb8510 --- /dev/null +++ b/pr/2992/docs/static.files/src-script-e66d777a5a92e9b2.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth{removeClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","false")};window.rustdocShowSourceSidebar=()=>{addClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","true")};window.rustdocToggleSrcSidebar=()=>{if(document.documentElement.classList.contains("src-sidebar-expanded")){window.rustdocCloseSourceSidebar()}else{window.rustdocShowSourceSidebar()}};function createSrcSidebar(){const container=document.querySelector("nav.sidebar");const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;for(const[key,source]of srcIndex){source[NAME_OFFSET]=key;hasFoundFile=createDirEntry(source,sidebar,"",hasFoundFile)}container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}function highlightSrcLines(){const match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{onEachLazy(e.getElementsByTagName("a"),i_e=>{removeClass(i_e,"line-highlighted")})});for(let i=from;i<=to;++i){elem=document.getElementById(i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",highlightSrcLines);onEachLazy(document.getElementsByClassName("src-line-numbers"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})() \ No newline at end of file diff --git a/pr/2992/docs/static.files/storage-e32f0c247825364d.js b/pr/2992/docs/static.files/storage-e32f0c247825364d.js new file mode 100644 index 0000000000..61ddce2397 --- /dev/null +++ b/pr/2992/docs/static.files/storage-e32f0c247825364d.js @@ -0,0 +1 @@ +"use strict";const builtinThemes=["light","dark","ayu"];const darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");return settingsElement&&settingsElement.dataset?settingsElement.dataset:null})();function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current===null&&settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return current}const localStoredTheme=getSettingValue("theme");function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(elem&&elem.classList){elem.classList.add(className)}}function removeClass(elem,className){if(elem&&elem.classList){elem.classList.remove(className)}}function onEach(arr,func){for(const elem of arr){if(func(elem)){return true}}return false}function onEachLazy(lazyArray,func){return onEach(Array.prototype.slice.call(lazyArray),func)}function updateLocalStorage(name,value){try{window.localStorage.setItem("rustdoc-"+name,value)}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}const getVar=(function getVar(name){const el=document.querySelector("head > meta[name='rustdoc-vars']");return el?el.attributes["data-"+name].value:null});function switchTheme(newThemeName,saveTheme){const themeNames=getVar("themes").split(",").filter(t=>t);themeNames.push(...builtinThemes);if(themeNames.indexOf(newThemeName)===-1){return}if(saveTheme){updateLocalStorage("theme",newThemeName)}document.documentElement.setAttribute("data-theme",newThemeName);if(builtinThemes.indexOf(newThemeName)!==-1){if(window.currentTheme){window.currentTheme.parentNode.removeChild(window.currentTheme);window.currentTheme=null}}else{const newHref=getVar("root-path")+encodeURIComponent(newThemeName)+getVar("resource-suffix")+".css";if(!window.currentTheme){if(document.readyState==="loading"){document.write(``);window.currentTheme=document.getElementById("themeStyle")}else{window.currentTheme=document.createElement("link");window.currentTheme.rel="stylesheet";window.currentTheme.id="themeStyle";window.currentTheme.href=newHref;document.documentElement.appendChild(window.currentTheme)}}else if(newHref!==window.currentTheme.href){window.currentTheme.href=newHref}}}const updateTheme=(function(){const mql=window.matchMedia("(prefers-color-scheme: dark)");function updateTheme(){if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";updateLocalStorage("use-system-theme","true");switchTheme(mql.matches?darkTheme:lightTheme,true)}else{switchTheme(getSettingValue("theme"),false)}}mql.addEventListener("change",updateTheme);return updateTheme})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}}updateTheme();if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"src-sidebar-expanded")}if(getSettingValue("hide-sidebar")==="true"){addClass(document.documentElement,"hide-sidebar")}function updateSidebarWidth(){const desktopSidebarWidth=getSettingValue("desktop-sidebar-width");if(desktopSidebarWidth&&desktopSidebarWidth!=="null"){document.documentElement.style.setProperty("--desktop-sidebar-width",desktopSidebarWidth+"px",)}const srcSidebarWidth=getSettingValue("src-sidebar-width");if(srcSidebarWidth&&srcSidebarWidth!=="null"){document.documentElement.style.setProperty("--src-sidebar-width",srcSidebarWidth+"px",)}}updateSidebarWidth();window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(updateTheme,0);setTimeout(updateSidebarWidth,0)}}) \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/clap_builder/derive/trait.Args.js b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Args.js new file mode 100644 index 0000000000..72a1701f30 --- /dev/null +++ b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Args.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_net_bench":[["impl Args for Opt"],["impl Args for Opt"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/clap_builder/derive/trait.CommandFactory.js b/pr/2992/docs/trait.impl/clap_builder/derive/trait.CommandFactory.js new file mode 100644 index 0000000000..b7a087239b --- /dev/null +++ b/pr/2992/docs/trait.impl/clap_builder/derive/trait.CommandFactory.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_net_bench":[["impl CommandFactory for Commands"],["impl CommandFactory for Opt"],["impl CommandFactory for Opt"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/clap_builder/derive/trait.FromArgMatches.js b/pr/2992/docs/trait.impl/clap_builder/derive/trait.FromArgMatches.js new file mode 100644 index 0000000000..c74aff72c6 --- /dev/null +++ b/pr/2992/docs/trait.impl/clap_builder/derive/trait.FromArgMatches.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh_net_bench":[["impl FromArgMatches for Commands"],["impl FromArgMatches for Opt"],["impl FromArgMatches for Opt"]], +"iroh_node_util":[["impl FromArgMatches for NetCommands"],["impl FromArgMatches for NodeCommands"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/clap_builder/derive/trait.Parser.js b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Parser.js new file mode 100644 index 0000000000..2b7f916047 --- /dev/null +++ b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Parser.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_net_bench":[["impl Parser for Commands"],["impl Parser for Opt"],["impl Parser for Opt"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/clap_builder/derive/trait.Subcommand.js b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Subcommand.js new file mode 100644 index 0000000000..1ae8992c38 --- /dev/null +++ b/pr/2992/docs/trait.impl/clap_builder/derive/trait.Subcommand.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh_net_bench":[["impl Subcommand for Commands"]], +"iroh_node_util":[["impl Subcommand for NetCommands"],["impl Subcommand for NodeCommands"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/borrow/trait.Borrow.js b/pr/2992/docs/trait.impl/core/borrow/trait.Borrow.js new file mode 100644 index 0000000000..cc34de1a7e --- /dev/null +++ b/pr/2992/docs/trait.impl/core/borrow/trait.Borrow.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_base":[["impl Borrow<[u8; 32]> for Hash"],["impl Borrow<[u8]> for Hash"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/clone/trait.Clone.js b/pr/2992/docs/trait.impl/core/clone/trait.Clone.js new file mode 100644 index 0000000000..2edc8c5d75 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/clone/trait.Clone.js @@ -0,0 +1,9 @@ +(function() {var implementors = { +"iroh":[["impl Clone for ConnectionType"],["impl Clone for ControlMsg"],["impl Clone for DirectAddrType"],["impl Clone for RelayMode"],["impl Clone for Source"],["impl Clone for DhtDiscovery"],["impl Clone for PkarrPublisher"],["impl Clone for PkarrRelayClient"],["impl Clone for PkarrResolver"],["impl Clone for DiscoveryItem"],["impl Clone for NodeInfo"],["impl Clone for DirectAddr"],["impl Clone for DirectAddrInfo"],["impl Clone for Endpoint"],["impl Clone for RemoteInfo"],["impl Clone for Metrics"],["impl Clone for ProtocolMap"],["impl Clone for Router"]], +"iroh_base":[["impl Clone for BlobFormat"],["impl Clone for AddrInfoOptions"],["impl Clone for Hash"],["impl Clone for HashAndFormat"],["impl Clone for PublicKey"],["impl Clone for SecretKey"],["impl Clone for AddrInfo"],["impl Clone for NodeAddr"],["impl Clone for RelayUrl"],["impl Clone for QuicConfig"],["impl Clone for RelayMap"],["impl Clone for RelayNode"],["impl Clone for BlobTicket"],["impl Clone for NodeTicket"]], +"iroh_dns_server":[["impl Clone for CertMode"],["impl Clone for RateLimitConfig"],["impl Clone for DnsConfig"],["impl Clone for DnsHandler"],["impl Clone for Handle"],["impl Clone for HttpConfig"],["impl Clone for HttpsConfig"],["impl Clone for Metrics"],["impl Clone for AppState"]], +"iroh_net_bench":[["impl Clone for Commands"],["impl Clone for Opt"],["impl Clone for Opt"]], +"iroh_net_report":[["impl Clone for Addr"],["impl Clone for Metrics"],["impl Clone for RelayLatencies"],["impl Clone for Report"]], +"iroh_node_util":[["impl Clone for NetCommands"],["impl Clone for NodeCommands"],["impl Clone for Rotation"],["impl Clone for EnvFilter"],["impl Clone for FileLogging"],["impl Clone for Client"],["impl Clone for Client"],["impl Clone for RemoteInfoRequest"],["impl Clone for RpcService"]], +"iroh_relay":[["impl Clone for ReceivedMessage"],["impl Clone for Protocol"],["impl Clone for Client"],["impl Clone for ClientConnRateLimit"],["impl Clone for Metrics"],["impl Clone for StunMetrics"],["impl Clone for Conn"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/cmp/trait.Eq.js b/pr/2992/docs/trait.impl/core/cmp/trait.Eq.js new file mode 100644 index 0000000000..b2afb72128 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/cmp/trait.Eq.js @@ -0,0 +1,8 @@ +(function() {var implementors = { +"iroh":[["impl Eq for IrohAttr"],["impl Eq for ConnectionType"],["impl Eq for ControlMsg"],["impl Eq for DirectAddrType"],["impl Eq for RelayMode"],["impl Eq for Source"],["impl Eq for NodeInfo"],["impl Eq for DirectAddr"],["impl Eq for DirectAddrInfo"],["impl Eq for RemoteInfo"]], +"iroh_base":[["impl Eq for BlobFormat"],["impl Eq for AddrInfoOptions"],["impl Eq for Hash"],["impl Eq for HashAndFormat"],["impl Eq for PublicKey"],["impl Eq for AddrInfo"],["impl Eq for NodeAddr"],["impl Eq for RelayUrl"],["impl Eq for QuicConfig"],["impl Eq for RelayMap"],["impl Eq for RelayNode"],["impl Eq for BlobTicket"],["impl Eq for NodeTicket"]], +"iroh_dns_server":[["impl Eq for CertMode"]], +"iroh_net_report":[["impl Eq for RelayLatencies"],["impl Eq for Report"]], +"iroh_node_util":[["impl Eq for Rotation"],["impl Eq for EnvFilter"],["impl Eq for FileLogging"]], +"iroh_relay":[["impl Eq for Protocol"],["impl Eq for Conn"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/cmp/trait.Ord.js b/pr/2992/docs/trait.impl/core/cmp/trait.Ord.js new file mode 100644 index 0000000000..030e39e8ef --- /dev/null +++ b/pr/2992/docs/trait.impl/core/cmp/trait.Ord.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[["impl Ord for IrohAttr"],["impl Ord for DirectAddrType"],["impl Ord for DirectAddr"]], +"iroh_base":[["impl Ord for BlobFormat"],["impl Ord for Hash"],["impl Ord for HashAndFormat"],["impl Ord for PublicKey"],["impl Ord for AddrInfo"],["impl Ord for NodeAddr"],["impl Ord for RelayUrl"],["impl Ord for QuicConfig"],["impl Ord for RelayNode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/cmp/trait.PartialEq.js b/pr/2992/docs/trait.impl/core/cmp/trait.PartialEq.js new file mode 100644 index 0000000000..1aad094db9 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/cmp/trait.PartialEq.js @@ -0,0 +1,8 @@ +(function() {var implementors = { +"iroh":[["impl PartialEq for IrohAttr"],["impl PartialEq for ConnectionType"],["impl PartialEq for ControlMsg"],["impl PartialEq for DirectAddrType"],["impl PartialEq for RelayMode"],["impl PartialEq for Source"],["impl PartialEq for NodeInfo"],["impl PartialEq for DirectAddr"],["impl PartialEq for DirectAddrInfo"],["impl PartialEq for RemoteInfo"]], +"iroh_base":[["impl PartialEq for BlobFormat"],["impl PartialEq for AddrInfoOptions"],["impl PartialEq for Hash"],["impl PartialEq for HashAndFormat"],["impl PartialEq for PublicKey"],["impl PartialEq for AddrInfo"],["impl PartialEq for NodeAddr"],["impl PartialEq for RelayUrl"],["impl PartialEq for QuicConfig"],["impl PartialEq for RelayMap"],["impl PartialEq for RelayNode"],["impl PartialEq for BlobTicket"],["impl PartialEq for NodeTicket"]], +"iroh_dns_server":[["impl PartialEq for CertMode"]], +"iroh_net_report":[["impl PartialEq for RelayLatencies"],["impl PartialEq for Report"]], +"iroh_node_util":[["impl PartialEq for Rotation"],["impl PartialEq for EnvFilter"],["impl PartialEq for FileLogging"]], +"iroh_relay":[["impl PartialEq for Protocol"],["impl PartialEq for Conn"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/cmp/trait.PartialOrd.js b/pr/2992/docs/trait.impl/core/cmp/trait.PartialOrd.js new file mode 100644 index 0000000000..be10d8ce2b --- /dev/null +++ b/pr/2992/docs/trait.impl/core/cmp/trait.PartialOrd.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[["impl PartialOrd for IrohAttr"],["impl PartialOrd for DirectAddrType"],["impl PartialOrd for DirectAddr"]], +"iroh_base":[["impl PartialOrd for BlobFormat"],["impl PartialOrd for Hash"],["impl PartialOrd for HashAndFormat"],["impl PartialOrd for PublicKey"],["impl PartialOrd for AddrInfo"],["impl PartialOrd for NodeAddr"],["impl PartialOrd for RelayUrl"],["impl PartialOrd for QuicConfig"],["impl PartialOrd for RelayNode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/convert/trait.AsRef.js b/pr/2992/docs/trait.impl/core/convert/trait.AsRef.js new file mode 100644 index 0000000000..9fb2188a4c --- /dev/null +++ b/pr/2992/docs/trait.impl/core/convert/trait.AsRef.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[["impl AsRef<str> for IrohAttr"]], +"iroh_base":[["impl AsRef<[u8]> for Hash"],["impl AsRef<[u8]> for PublicKey"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/convert/trait.From.js b/pr/2992/docs/trait.impl/core/convert/trait.From.js new file mode 100644 index 0000000000..faebfb21e3 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/convert/trait.From.js @@ -0,0 +1,6 @@ +(function() {var implementors = { +"iroh":[["impl From<&NodeInfo> for TxtAttrs<IrohAttr>"],["impl From<&TxtAttrs<IrohAttr>> for NodeInfo"],["impl From<NodeInfo> for AddrInfo"],["impl From<NodeInfo> for NodeAddr"],["impl From<TxtAttrs<IrohAttr>> for NodeInfo"],["impl From<RemoteInfo> for NodeAddr"],["impl From<GenError> for CreateConfigError"],["impl From<ParseError> for Error"],["impl From<VerificationError> for Error"],["impl From<Error> for GenError"],["impl From<Error> for ParseError"],["impl From<Error> for VerificationError"],["impl From<NoInitialCipherSuite> for CreateConfigError"],["impl<T> From<T> for ConcurrentDiscovery
where\n T: IntoIterator<Item = Box<dyn Discovery>>,
"]], +"iroh_base":[["impl From<&[u8; 32]> for Hash"],["impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for NodeAddr"],["impl From<FromHexError> for HexOrBase32ParseError"],["impl From<HexOrBase32ParseError> for KeyParsingError"],["impl From<BlobFormat> for u64"],["impl From<Url> for RelayUrl"],["impl From<DecodeError> for HexOrBase32ParseError"],["impl From<DecodeError> for Error"],["impl From<Hash> for Hash"],["impl From<Hash> for [u8; 32]"],["impl From<PublicKey> for NodeAddr"],["impl From<NodeAddr> for NodeTicket"],["impl From<RelayUrl> for Url"],["impl From<NodeTicket> for NodeAddr"],["impl From<Error> for KeyParsingError"],["impl From<Error> for Error"],["impl From<Hash> for Hash"],["impl From<SigningKey> for SecretKey"],["impl From<VerifyingKey> for PublicKey"],["impl From<[u8; 32]> for Hash"],["impl From<[u8; 32]> for SecretKey"]], +"iroh_node_util":[["impl From<Result<Option<RelayUrl>, Error>> for Response"],["impl From<Result<Option<RelayUrl>, Error>> for Response"],["impl From<Result<(), Error>> for Response"],["impl From<Result<(), Error>> for Response"],["impl From<Result<NodeStatus, Error>> for Response"],["impl From<Result<NodeStatus, Error>> for Response"],["impl From<Result<RemoteInfoResponse, Error>> for Response"],["impl From<Result<RemoteInfoResponse, Error>> for Response"],["impl From<Result<RemoteInfosIterResponse, Error>> for Response"],["impl From<Result<RemoteInfosIterResponse, Error>> for Response"],["impl From<Result<StatsResponse, Error>> for Response"],["impl From<Result<StatsResponse, Error>> for Response"],["impl From<Result<NodeAddr, Error>> for Response"],["impl From<Result<NodeAddr, Error>> for Response"],["impl From<Result<PublicKey, Error>> for Response"],["impl From<Result<PublicKey, Error>> for Response"],["impl From<Request> for Request"],["impl From<Response> for Response"],["impl From<Request> for Request"],["impl From<Response> for Response"],["impl From<()> for Response"],["impl From<()> for Response"],["impl From<AddAddrRequest> for Request"],["impl From<AddAddrRequest> for Request"],["impl From<AddrRequest> for Request"],["impl From<AddrRequest> for Request"],["impl From<IdRequest> for Request"],["impl From<IdRequest> for Request"],["impl From<NodeWatchRequest> for Request"],["impl From<NodeWatchRequest> for Request"],["impl From<RelayRequest> for Request"],["impl From<RelayRequest> for Request"],["impl From<RemoteInfoRequest> for Request"],["impl From<RemoteInfoRequest> for Request"],["impl From<RemoteInfosIterRequest> for Request"],["impl From<RemoteInfosIterRequest> for Request"],["impl From<WatchResponse> for Response"],["impl From<WatchResponse> for Response"],["impl From<ShutdownRequest> for Request"],["impl From<ShutdownRequest> for Request"],["impl From<StatsRequest> for Request"],["impl From<StatsRequest> for Request"],["impl From<StatusRequest> for Request"],["impl From<StatusRequest> for Request"]], +"iroh_relay":[["impl From<Error> for ClientError"],["impl From<Error> for ClientError"],["impl From<Error> for ClientError"],["impl From<Error> for ClientError"],["impl From<JoinError> for ClientError"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/convert/trait.TryFrom.js b/pr/2992/docs/trait.impl/core/convert/trait.TryFrom.js new file mode 100644 index 0000000000..4af97f0679 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/convert/trait.TryFrom.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"iroh":[["impl TryFrom<&str> for IrohAttr"]], +"iroh_base":[["impl TryFrom<&[u8; 32]> for PublicKey"],["impl TryFrom<&[u8]> for PublicKey"],["impl TryFrom<&[u8]> for SecretKey"]], +"iroh_node_util":[["impl TryFrom<Request> for Request"],["impl TryFrom<Request> for Request"],["impl TryFrom<Request> for AddAddrRequest"],["impl TryFrom<Request> for AddrRequest"],["impl TryFrom<Request> for IdRequest"],["impl TryFrom<Request> for NodeWatchRequest"],["impl TryFrom<Request> for RelayRequest"],["impl TryFrom<Request> for RemoteInfoRequest"],["impl TryFrom<Request> for RemoteInfosIterRequest"],["impl TryFrom<Request> for ShutdownRequest"],["impl TryFrom<Request> for StatsRequest"],["impl TryFrom<Request> for StatusRequest"],["impl TryFrom<Response> for Result<Option<RelayUrl>, Error>"],["impl TryFrom<Response> for Result<(), Error>"],["impl TryFrom<Response> for Result<NodeStatus, Error>"],["impl TryFrom<Response> for Result<RemoteInfoResponse, Error>"],["impl TryFrom<Response> for Result<RemoteInfosIterResponse, Error>"],["impl TryFrom<Response> for Result<StatsResponse, Error>"],["impl TryFrom<Response> for Result<NodeAddr, Error>"],["impl TryFrom<Response> for Result<NodeId, Error>"],["impl TryFrom<Response> for Response"],["impl TryFrom<Response> for Response"],["impl TryFrom<Response> for ()"],["impl TryFrom<Response> for WatchResponse"],["impl TryFrom<Request> for AddAddrRequest"],["impl TryFrom<Request> for AddrRequest"],["impl TryFrom<Request> for IdRequest"],["impl TryFrom<Request> for NodeWatchRequest"],["impl TryFrom<Request> for RelayRequest"],["impl TryFrom<Request> for RemoteInfoRequest"],["impl TryFrom<Request> for RemoteInfosIterRequest"],["impl TryFrom<Response> for Result<Option<RelayUrl>, Error>"],["impl TryFrom<Response> for Result<(), Error>"],["impl TryFrom<Response> for Result<RemoteInfoResponse, Error>"],["impl TryFrom<Response> for Result<RemoteInfosIterResponse, Error>"],["impl TryFrom<Response> for Result<NodeAddr, Error>"],["impl TryFrom<Response> for Result<NodeId, Error>"],["impl TryFrom<Response> for WatchResponse"],["impl TryFrom<Request> for ShutdownRequest"],["impl TryFrom<Request> for StatsRequest"],["impl TryFrom<Request> for StatusRequest"],["impl TryFrom<Response> for Result<NodeStatus, Error>"],["impl TryFrom<Response> for Result<StatsResponse, Error>"],["impl TryFrom<Response> for ()"],["impl<'a> TryFrom<&'a Request> for &'a Request"],["impl<'a> TryFrom<&'a Request> for &'a Request"],["impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest"],["impl<'a> TryFrom<&'a Request> for &'a AddrRequest"],["impl<'a> TryFrom<&'a Request> for &'a IdRequest"],["impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest"],["impl<'a> TryFrom<&'a Request> for &'a RelayRequest"],["impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest"],["impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest"],["impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest"],["impl<'a> TryFrom<&'a Request> for &'a StatsRequest"],["impl<'a> TryFrom<&'a Request> for &'a StatusRequest"],["impl<'a> TryFrom<&'a Response> for &'a Result<Option<RelayUrl>, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<(), Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeStatus, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfoResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfosIterResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<StatsResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeAddr, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeId, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Response"],["impl<'a> TryFrom<&'a Response> for &'a Response"],["impl<'a> TryFrom<&'a Response> for &'a ()"],["impl<'a> TryFrom<&'a Response> for &'a WatchResponse"],["impl<'a> TryFrom<&'a Request> for &'a AddAddrRequest"],["impl<'a> TryFrom<&'a Request> for &'a AddrRequest"],["impl<'a> TryFrom<&'a Request> for &'a IdRequest"],["impl<'a> TryFrom<&'a Request> for &'a NodeWatchRequest"],["impl<'a> TryFrom<&'a Request> for &'a RelayRequest"],["impl<'a> TryFrom<&'a Request> for &'a RemoteInfoRequest"],["impl<'a> TryFrom<&'a Request> for &'a RemoteInfosIterRequest"],["impl<'a> TryFrom<&'a Response> for &'a Result<Option<RelayUrl>, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<(), Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfoResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<RemoteInfosIterResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeAddr, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeId, Error>"],["impl<'a> TryFrom<&'a Response> for &'a WatchResponse"],["impl<'a> TryFrom<&'a Request> for &'a ShutdownRequest"],["impl<'a> TryFrom<&'a Request> for &'a StatsRequest"],["impl<'a> TryFrom<&'a Request> for &'a StatusRequest"],["impl<'a> TryFrom<&'a Response> for &'a Result<NodeStatus, Error>"],["impl<'a> TryFrom<&'a Response> for &'a Result<StatsResponse, Error>"],["impl<'a> TryFrom<&'a Response> for &'a ()"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/default/trait.Default.js b/pr/2992/docs/trait.impl/core/default/trait.Default.js new file mode 100644 index 0000000000..d9d088e2b2 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/default/trait.Default.js @@ -0,0 +1,9 @@ +(function() {var implementors = { +"iroh":[["impl Default for Builder"],["impl Default for DhtDiscovery"],["impl Default for StaticProvider"],["impl Default for ConcurrentDiscovery"],["impl Default for Builder"],["impl Default for Metrics"],["impl Default for ProtocolMap"]], +"iroh_base":[["impl Default for BlobFormat"],["impl Default for AddrInfoOptions"],["impl Default for AddrInfo"],["impl Default for QuicConfig"]], +"iroh_dns_server":[["impl Default for &RateLimitConfig"],["impl Default for BootstrapOption"],["impl Default for RateLimitConfig"],["impl Default for Config"],["impl Default for MainlineConfig"],["impl Default for Metrics"]], +"iroh_net_bench":[["impl Default for Stats"],["impl Default for StreamStats"],["impl Default for ClientStats"]], +"iroh_net_report":[["impl Default for Metrics"],["impl Default for RelayLatencies"],["impl Default for Report"]], +"iroh_node_util":[["impl Default for Rotation"],["impl Default for EnvFilter"],["impl Default for FileLogging"]], +"iroh_relay":[["impl Default for Limits"],["impl Default for Metrics"],["impl Default for StunMetrics"],["impl<EC: Default + Debug, EA: Default + Debug> Default for ServerConfig<EC, EA>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/error/trait.Error.js b/pr/2992/docs/trait.impl/core/error/trait.Error.js new file mode 100644 index 0000000000..5ead85e69c --- /dev/null +++ b/pr/2992/docs/trait.impl/core/error/trait.Error.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"iroh":[["impl Error for CreateConfigError"],["impl Error for GenError"],["impl Error for ParseError"],["impl Error for VerificationError"]], +"iroh_base":[["impl Error for HexOrBase32ParseError"],["impl Error for KeyParsingError"],["impl Error for Error"]], +"iroh_relay":[["impl Error for ClientError"],["impl Error for Error"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/fmt/trait.Debug.js b/pr/2992/docs/trait.impl/core/fmt/trait.Debug.js new file mode 100644 index 0000000000..1c742431e5 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/fmt/trait.Debug.js @@ -0,0 +1,9 @@ +(function() {var implementors = { +"iroh":[["impl Debug for IrohAttr"],["impl Debug for ConnectionType"],["impl Debug for ControlMsg"],["impl Debug for DirectAddrType"],["impl Debug for RelayMode"],["impl Debug for Source"],["impl Debug for CreateConfigError"],["impl Debug for Dialer"],["impl Debug for DnsDiscovery"],["impl Debug for LocalSwarmDiscovery"],["impl Debug for Builder"],["impl Debug for DhtDiscovery"],["impl Debug for PkarrPublisher"],["impl Debug for PkarrRelayClient"],["impl Debug for PkarrResolver"],["impl Debug for StaticProvider"],["impl Debug for ConcurrentDiscovery"],["impl Debug for DiscoveryItem"],["impl Debug for NodeInfo"],["impl Debug for Builder"],["impl Debug for Connecting"],["impl Debug for ConnectionTypeStream"],["impl Debug for DirectAddr"],["impl Debug for DirectAddrInfo"],["impl Debug for DirectAddrsStream"],["impl Debug for Endpoint"],["impl Debug for Incoming"],["impl Debug for IncomingFuture"],["impl Debug for RemoteInfo"],["impl Debug for Metrics"],["impl Debug for ProtocolMap"],["impl Debug for Router"],["impl Debug for RouterBuilder"],["impl Debug for CleanupDropGuard"],["impl Debug for DnsPkarrServer"],["impl Debug for GenError"],["impl Debug for P2pExtension"],["impl Debug for ParseError"],["impl Debug for VerificationError"],["impl<'a> Debug for Accept<'a>"],["impl<'a> Debug for P2pCertificate<'a>"],["impl<T: Debug> Debug for TxtAttrs<T>"]], +"iroh_base":[["impl Debug for HexOrBase32ParseError"],["impl Debug for BlobFormat"],["impl Debug for KeyParsingError"],["impl Debug for AddrInfoOptions"],["impl Debug for Error"],["impl Debug for Hash"],["impl Debug for HashAndFormat"],["impl Debug for PublicKey"],["impl Debug for SecretKey"],["impl Debug for SharedSecret"],["impl Debug for AddrInfo"],["impl Debug for NodeAddr"],["impl Debug for RelayUrl"],["impl Debug for QuicConfig"],["impl Debug for RelayMap"],["impl Debug for RelayNode"],["impl Debug for BlobTicket"],["impl Debug for NodeTicket"]], +"iroh_dns_server":[["impl Debug for BootstrapOption"],["impl Debug for CertMode"],["impl Debug for RateLimitConfig"],["impl Debug for Config"],["impl Debug for MainlineConfig"],["impl Debug for MetricsConfig"],["impl Debug for DnsConfig"],["impl Debug for DnsHandler"],["impl Debug for Handle"],["impl Debug for HttpConfig"],["impl Debug for HttpsConfig"],["impl Debug for Metrics"]], +"iroh_net_bench":[["impl Debug for Commands"],["impl Debug for Opt"],["impl Debug for Stats"],["impl Debug for StreamStats"],["impl Debug for TransferResult"],["impl Debug for Opt"]], +"iroh_net_report":[["impl Debug for Addr"],["impl Debug for Client"],["impl Debug for Metrics"],["impl Debug for RelayLatencies"],["impl Debug for Report"]], +"iroh_node_util":[["impl Debug for NetCommands"],["impl Debug for NodeCommands"],["impl Debug for Rotation"],["impl Debug for Request"],["impl Debug for Response"],["impl Debug for Request"],["impl Debug for Response"],["impl Debug for Request"],["impl Debug for Response"],["impl Debug for EnvFilter"],["impl Debug for FileLogging"],["impl Debug for Client"],["impl Debug for NodeStatus"],["impl Debug for Client"],["impl Debug for AddAddrRequest"],["impl Debug for AddrRequest"],["impl Debug for IdRequest"],["impl Debug for NodeWatchRequest"],["impl Debug for RelayRequest"],["impl Debug for RemoteInfoRequest"],["impl Debug for RemoteInfoResponse"],["impl Debug for RemoteInfosIterRequest"],["impl Debug for RemoteInfosIterResponse"],["impl Debug for WatchResponse"],["impl Debug for CounterStats"],["impl Debug for ShutdownRequest"],["impl Debug for StatsRequest"],["impl Debug for StatsResponse"],["impl Debug for StatusRequest"],["impl Debug for RpcService"]], +"iroh_relay":[["impl Debug for ClientError"],["impl Debug for ReceivedMessage"],["impl Debug for Protocol"],["impl Debug for Error"],["impl Debug for MaybeTlsStream"],["impl Debug for Client"],["impl Debug for ClientBuilder"],["impl Debug for ClientReceiver"],["impl Debug for QuicClient"],["impl Debug for ClientConnRateLimit"],["impl Debug for Limits"],["impl Debug for Metrics"],["impl Debug for QuicConfig"],["impl Debug for Server"],["impl Debug for StunConfig"],["impl Debug for StunMetrics"],["impl Debug for Conn"],["impl<EC: Debug, EA: Debug> Debug for CertConfig<EC, EA>"],["impl<EC: Debug, EA: Debug> Debug for RelayConfig<EC, EA>
where\n Option<TlsConfig<EC, EA>>: Debug,
"],["impl<EC: Debug, EA: Debug> Debug for ServerConfig<EC, EA>
where\n Option<RelayConfig<EC, EA>>: Debug,
"],["impl<EC: Debug, EA: Debug> Debug for TlsConfig<EC, EA>
where\n CertConfig<EC, EA>: Debug,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/fmt/trait.Display.js b/pr/2992/docs/trait.impl/core/fmt/trait.Display.js new file mode 100644 index 0000000000..5e44690377 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/fmt/trait.Display.js @@ -0,0 +1,8 @@ +(function() {var implementors = { +"iroh":[["impl Display for IrohAttr"],["impl Display for ConnectionType"],["impl Display for ControlMsg"],["impl Display for DirectAddrType"],["impl Display for Source"],["impl Display for CreateConfigError"],["impl Display for GenError"],["impl Display for ParseError"],["impl Display for VerificationError"]], +"iroh_base":[["impl Display for HexOrBase32ParseError"],["impl Display for BlobFormat"],["impl Display for KeyParsingError"],["impl Display for AddrInfoOptions"],["impl Display for Error"],["impl Display for Hash"],["impl Display for HashAndFormat"],["impl Display for PublicKey"],["impl Display for SecretKey"],["impl Display for RelayUrl"],["impl Display for RelayMap"],["impl Display for RelayNode"],["impl Display for BlobTicket"],["impl Display for NodeTicket"]], +"iroh_dns_server":[["impl Display for CertMode"]], +"iroh_net_report":[["impl Display for Report"]], +"iroh_node_util":[["impl Display for Request"],["impl Display for Response"],["impl Display for Request"],["impl Display for Response"],["impl Display for EnvFilter"]], +"iroh_relay":[["impl Display for ClientError"],["impl Display for Error"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/future/future/trait.Future.js b/pr/2992/docs/trait.impl/core/future/future/trait.Future.js new file mode 100644 index 0000000000..58fcefb94f --- /dev/null +++ b/pr/2992/docs/trait.impl/core/future/future/trait.Future.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[["impl Future for Accept<'_>"],["impl Future for Connecting"],["impl Future for IncomingFuture"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/future/into_future/trait.IntoFuture.js b/pr/2992/docs/trait.impl/core/future/into_future/trait.IntoFuture.js new file mode 100644 index 0000000000..40110555f6 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/future/into_future/trait.IntoFuture.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[["impl IntoFuture for Incoming"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/hash/trait.Hash.js b/pr/2992/docs/trait.impl/core/hash/trait.Hash.js new file mode 100644 index 0000000000..d0ba595510 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/hash/trait.Hash.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[["impl Hash for IrohAttr"],["impl Hash for DirectAddrType"],["impl Hash for Source"],["impl Hash for DirectAddr"]], +"iroh_base":[["impl Hash for BlobFormat"],["impl Hash for Hash"],["impl Hash for HashAndFormat"],["impl Hash for PublicKey"],["impl Hash for RelayUrl"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.Copy.js b/pr/2992/docs/trait.impl/core/marker/trait.Copy.js new file mode 100644 index 0000000000..47ffeb3f35 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.Copy.js @@ -0,0 +1,7 @@ +(function() {var implementors = { +"iroh":[["impl Copy for ControlMsg"],["impl Copy for DirectAddrType"]], +"iroh_base":[["impl Copy for BlobFormat"],["impl Copy for AddrInfoOptions"],["impl Copy for Hash"],["impl Copy for HashAndFormat"],["impl Copy for PublicKey"]], +"iroh_net_bench":[["impl Copy for Commands"],["impl Copy for Opt"],["impl Copy for Opt"]], +"iroh_node_util":[["impl Copy for RpcService"]], +"iroh_relay":[["impl Copy for Protocol"],["impl Copy for ClientConnRateLimit"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.Freeze.js b/pr/2992/docs/trait.impl/core/marker/trait.Freeze.js new file mode 100644 index 0000000000..84b475d472 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.Freeze.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl !Freeze for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl !Freeze for Builder",1,["iroh::endpoint::Builder"]],["impl !Freeze for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl !Freeze for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl !Freeze for Incoming",1,["iroh::endpoint::Incoming"]],["impl !Freeze for IncomingFuture",1,["iroh::endpoint::IncomingFuture"]],["impl Freeze for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl Freeze for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl Freeze for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl Freeze for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl Freeze for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl Freeze for Source",1,["iroh::magicsock::node_map::Source"]],["impl Freeze for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl Freeze for Dialer",1,["iroh::dialer::Dialer"]],["impl Freeze for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl Freeze for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl Freeze for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl Freeze for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl Freeze for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl Freeze for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl Freeze for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl Freeze for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl Freeze for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl Freeze for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl Freeze for Connecting",1,["iroh::endpoint::Connecting"]],["impl Freeze for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl Freeze for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl Freeze for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl Freeze for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl Freeze for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl Freeze for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl Freeze for Router",1,["iroh::protocol::Router"]],["impl Freeze for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl Freeze for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl Freeze for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl Freeze for GenError",1,["iroh::tls::certificate::GenError"]],["impl Freeze for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl Freeze for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl Freeze for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> !Freeze for Accept<'a>",1,["iroh::endpoint::Accept"]],["impl<'a> Freeze for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<T> Freeze for TxtAttrs<T>",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl !Freeze for SecretKey",1,["iroh_base::key::SecretKey"]],["impl Freeze for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl Freeze for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl Freeze for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl Freeze for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl Freeze for Error",1,["iroh_base::ticket::Error"]],["impl Freeze for Hash",1,["iroh_base::hash::Hash"]],["impl Freeze for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl Freeze for PublicKey",1,["iroh_base::key::PublicKey"]],["impl Freeze for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl Freeze for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl Freeze for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl Freeze for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl Freeze for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl Freeze for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl Freeze for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl Freeze for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl Freeze for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl Freeze for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl Freeze for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl Freeze for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl Freeze for Config",1,["iroh_dns_server::config::Config"]],["impl Freeze for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl Freeze for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl Freeze for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl Freeze for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl Freeze for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl Freeze for Handle",1,["iroh_dns_server::dns::Handle"]],["impl Freeze for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl Freeze for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl Freeze for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl Freeze for Metrics",1,["iroh_dns_server::metrics::Metrics"]],["impl Freeze for Server",1,["iroh_dns_server::server::Server"]],["impl Freeze for AppState",1,["iroh_dns_server::state::AppState"]]], +"iroh_net_bench":[["impl Freeze for Commands",1,["iroh_net_bench::Commands"]],["impl Freeze for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl Freeze for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl Freeze for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl Freeze for Stats",1,["iroh_net_bench::stats::Stats"]],["impl Freeze for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl Freeze for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl Freeze for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl Freeze for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl Freeze for Addr",1,["iroh_net_report::Addr"]],["impl Freeze for Client",1,["iroh_net_report::Client"]],["impl Freeze for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl Freeze for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl Freeze for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl Freeze for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl Freeze for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl Freeze for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl Freeze for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl Freeze for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl Freeze for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl Freeze for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl Freeze for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl Freeze for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl Freeze for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl Freeze for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl Freeze for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl Freeze for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl Freeze for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl Freeze for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl Freeze for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl Freeze for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl Freeze for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl Freeze for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl Freeze for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl Freeze for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl Freeze for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl Freeze for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl Freeze for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl Freeze for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl Freeze for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl Freeze for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl Freeze for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl Freeze for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl Freeze for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl !Freeze for ClientError",1,["iroh_relay::client::ClientError"]],["impl !Freeze for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl !Freeze for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl Freeze for Protocol",1,["iroh_relay::http::Protocol"]],["impl Freeze for Error",1,["iroh_relay::protos::stun::Error"]],["impl Freeze for Client",1,["iroh_relay::client::Client"]],["impl Freeze for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl Freeze for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl Freeze for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl Freeze for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl Freeze for Limits",1,["iroh_relay::server::Limits"]],["impl Freeze for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl Freeze for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl Freeze for Server",1,["iroh_relay::server::Server"]],["impl Freeze for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl Freeze for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl Freeze for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA> Freeze for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA> Freeze for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA> Freeze for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA> Freeze for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl Freeze for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.Send.js b/pr/2992/docs/trait.impl/core/marker/trait.Send.js new file mode 100644 index 0000000000..1f685d4707 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.Send.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl Send for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl Send for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl Send for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl Send for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl Send for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl Send for Source",1,["iroh::magicsock::node_map::Source"]],["impl Send for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl Send for Dialer",1,["iroh::dialer::Dialer"]],["impl Send for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl Send for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl Send for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl Send for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl Send for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl Send for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl Send for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl Send for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl Send for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl Send for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl Send for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl Send for Builder",1,["iroh::endpoint::Builder"]],["impl Send for Connecting",1,["iroh::endpoint::Connecting"]],["impl Send for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl Send for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl Send for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl Send for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl Send for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl Send for Incoming",1,["iroh::endpoint::Incoming"]],["impl Send for IncomingFuture",1,["iroh::endpoint::IncomingFuture"]],["impl Send for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl Send for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl Send for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl Send for Router",1,["iroh::protocol::Router"]],["impl Send for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl Send for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl Send for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl Send for GenError",1,["iroh::tls::certificate::GenError"]],["impl Send for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl Send for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl Send for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> Send for Accept<'a>",1,["iroh::endpoint::Accept"]],["impl<'a> Send for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<T> Send for TxtAttrs<T>
where\n T: Send,
",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl Send for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl Send for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl Send for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl Send for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl Send for Error",1,["iroh_base::ticket::Error"]],["impl Send for Hash",1,["iroh_base::hash::Hash"]],["impl Send for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl Send for PublicKey",1,["iroh_base::key::PublicKey"]],["impl Send for SecretKey",1,["iroh_base::key::SecretKey"]],["impl Send for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl Send for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl Send for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl Send for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl Send for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl Send for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl Send for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl Send for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl Send for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl Send for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl Send for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl Send for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl Send for Config",1,["iroh_dns_server::config::Config"]],["impl Send for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl Send for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl Send for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl Send for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl Send for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl Send for Handle",1,["iroh_dns_server::dns::Handle"]],["impl Send for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl Send for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl Send for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl Send for Metrics",1,["iroh_dns_server::metrics::Metrics"]],["impl Send for Server",1,["iroh_dns_server::server::Server"]],["impl Send for AppState",1,["iroh_dns_server::state::AppState"]]], +"iroh_net_bench":[["impl Send for Commands",1,["iroh_net_bench::Commands"]],["impl Send for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl Send for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl Send for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl Send for Stats",1,["iroh_net_bench::stats::Stats"]],["impl Send for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl Send for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl Send for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl Send for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl Send for Addr",1,["iroh_net_report::Addr"]],["impl Send for Client",1,["iroh_net_report::Client"]],["impl Send for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl Send for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl Send for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl Send for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl Send for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl Send for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl Send for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl Send for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl Send for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl Send for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl Send for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl Send for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl Send for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl Send for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl Send for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl Send for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl Send for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl Send for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl Send for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl Send for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl Send for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl Send for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl Send for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl Send for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl Send for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl Send for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl Send for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl Send for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl Send for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl Send for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl Send for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl Send for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl Send for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl Send for ClientError",1,["iroh_relay::client::ClientError"]],["impl Send for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl Send for Protocol",1,["iroh_relay::http::Protocol"]],["impl Send for Error",1,["iroh_relay::protos::stun::Error"]],["impl Send for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl Send for Client",1,["iroh_relay::client::Client"]],["impl Send for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl Send for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl Send for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl Send for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl Send for Limits",1,["iroh_relay::server::Limits"]],["impl Send for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl Send for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl Send for Server",1,["iroh_relay::server::Server"]],["impl Send for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl Send for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl Send for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA> Send for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA> Send for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA> Send for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA> Send for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl !Send for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.StructuralPartialEq.js b/pr/2992/docs/trait.impl/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 0000000000..806cff55e3 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,8 @@ +(function() {var implementors = { +"iroh":[["impl StructuralPartialEq for IrohAttr"],["impl StructuralPartialEq for ConnectionType"],["impl StructuralPartialEq for ControlMsg"],["impl StructuralPartialEq for DirectAddrType"],["impl StructuralPartialEq for RelayMode"],["impl StructuralPartialEq for Source"],["impl StructuralPartialEq for NodeInfo"],["impl StructuralPartialEq for DirectAddr"],["impl StructuralPartialEq for DirectAddrInfo"],["impl StructuralPartialEq for RemoteInfo"]], +"iroh_base":[["impl StructuralPartialEq for BlobFormat"],["impl StructuralPartialEq for AddrInfoOptions"],["impl StructuralPartialEq for Hash"],["impl StructuralPartialEq for HashAndFormat"],["impl StructuralPartialEq for PublicKey"],["impl StructuralPartialEq for AddrInfo"],["impl StructuralPartialEq for NodeAddr"],["impl StructuralPartialEq for RelayUrl"],["impl StructuralPartialEq for QuicConfig"],["impl StructuralPartialEq for RelayMap"],["impl StructuralPartialEq for RelayNode"],["impl StructuralPartialEq for BlobTicket"],["impl StructuralPartialEq for NodeTicket"]], +"iroh_dns_server":[["impl StructuralPartialEq for CertMode"]], +"iroh_net_report":[["impl StructuralPartialEq for RelayLatencies"],["impl StructuralPartialEq for Report"]], +"iroh_node_util":[["impl StructuralPartialEq for Rotation"],["impl StructuralPartialEq for EnvFilter"],["impl StructuralPartialEq for FileLogging"]], +"iroh_relay":[["impl StructuralPartialEq for Protocol"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.Sync.js b/pr/2992/docs/trait.impl/core/marker/trait.Sync.js new file mode 100644 index 0000000000..b5d8d748e9 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.Sync.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl Sync for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl Sync for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl Sync for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl Sync for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl Sync for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl Sync for Source",1,["iroh::magicsock::node_map::Source"]],["impl Sync for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl Sync for Dialer",1,["iroh::dialer::Dialer"]],["impl Sync for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl Sync for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl Sync for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl Sync for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl Sync for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl Sync for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl Sync for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl Sync for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl Sync for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl Sync for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl Sync for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl Sync for Builder",1,["iroh::endpoint::Builder"]],["impl Sync for Connecting",1,["iroh::endpoint::Connecting"]],["impl Sync for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl Sync for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl Sync for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl Sync for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl Sync for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl Sync for Incoming",1,["iroh::endpoint::Incoming"]],["impl Sync for IncomingFuture",1,["iroh::endpoint::IncomingFuture"]],["impl Sync for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl Sync for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl Sync for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl Sync for Router",1,["iroh::protocol::Router"]],["impl Sync for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl Sync for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl Sync for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl Sync for GenError",1,["iroh::tls::certificate::GenError"]],["impl Sync for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl Sync for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl Sync for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> Sync for Accept<'a>",1,["iroh::endpoint::Accept"]],["impl<'a> Sync for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<T> Sync for TxtAttrs<T>
where\n T: Sync,
",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl Sync for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl Sync for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl Sync for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl Sync for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl Sync for Error",1,["iroh_base::ticket::Error"]],["impl Sync for Hash",1,["iroh_base::hash::Hash"]],["impl Sync for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl Sync for PublicKey",1,["iroh_base::key::PublicKey"]],["impl Sync for SecretKey",1,["iroh_base::key::SecretKey"]],["impl Sync for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl Sync for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl Sync for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl Sync for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl Sync for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl Sync for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl Sync for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl Sync for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl Sync for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl Sync for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl Sync for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl Sync for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl Sync for Config",1,["iroh_dns_server::config::Config"]],["impl Sync for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl Sync for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl Sync for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl Sync for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl Sync for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl Sync for Handle",1,["iroh_dns_server::dns::Handle"]],["impl Sync for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl Sync for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl Sync for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl Sync for Metrics",1,["iroh_dns_server::metrics::Metrics"]],["impl Sync for Server",1,["iroh_dns_server::server::Server"]],["impl Sync for AppState",1,["iroh_dns_server::state::AppState"]]], +"iroh_net_bench":[["impl Sync for Commands",1,["iroh_net_bench::Commands"]],["impl Sync for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl Sync for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl Sync for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl Sync for Stats",1,["iroh_net_bench::stats::Stats"]],["impl Sync for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl Sync for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl Sync for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl Sync for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl Sync for Addr",1,["iroh_net_report::Addr"]],["impl Sync for Client",1,["iroh_net_report::Client"]],["impl Sync for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl Sync for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl Sync for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl Sync for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl Sync for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl Sync for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl Sync for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl Sync for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl Sync for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl Sync for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl Sync for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl Sync for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl Sync for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl Sync for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl Sync for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl Sync for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl Sync for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl Sync for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl Sync for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl Sync for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl Sync for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl Sync for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl Sync for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl Sync for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl Sync for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl Sync for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl Sync for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl Sync for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl Sync for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl Sync for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl Sync for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl Sync for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl Sync for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl Sync for ClientError",1,["iroh_relay::client::ClientError"]],["impl Sync for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl Sync for Protocol",1,["iroh_relay::http::Protocol"]],["impl Sync for Error",1,["iroh_relay::protos::stun::Error"]],["impl Sync for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl Sync for Client",1,["iroh_relay::client::Client"]],["impl Sync for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl Sync for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl Sync for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl Sync for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl Sync for Limits",1,["iroh_relay::server::Limits"]],["impl Sync for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl Sync for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl Sync for Server",1,["iroh_relay::server::Server"]],["impl Sync for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl Sync for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl Sync for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA = EC> !Sync for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA = EC> !Sync for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA = EC> !Sync for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA = EC> !Sync for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl !Sync for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/marker/trait.Unpin.js b/pr/2992/docs/trait.impl/core/marker/trait.Unpin.js new file mode 100644 index 0000000000..3758a55480 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/marker/trait.Unpin.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl Unpin for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl Unpin for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl Unpin for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl Unpin for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl Unpin for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl Unpin for Source",1,["iroh::magicsock::node_map::Source"]],["impl Unpin for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl Unpin for Dialer",1,["iroh::dialer::Dialer"]],["impl Unpin for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl Unpin for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl Unpin for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl Unpin for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl Unpin for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl Unpin for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl Unpin for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl Unpin for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl Unpin for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl Unpin for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl Unpin for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl Unpin for Builder",1,["iroh::endpoint::Builder"]],["impl Unpin for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl Unpin for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl Unpin for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl Unpin for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl Unpin for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl Unpin for Incoming",1,["iroh::endpoint::Incoming"]],["impl Unpin for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl Unpin for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl Unpin for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl Unpin for Router",1,["iroh::protocol::Router"]],["impl Unpin for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl Unpin for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl Unpin for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl Unpin for GenError",1,["iroh::tls::certificate::GenError"]],["impl Unpin for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl Unpin for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl Unpin for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> Unpin for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<'pin> Unpin for Connecting
where\n PinnedFieldsOf<__Connecting<'pin>>: Unpin,
"],["impl<'pin> Unpin for IncomingFuture
where\n PinnedFieldsOf<__IncomingFuture<'pin>>: Unpin,
"],["impl<'pin, 'a> Unpin for Accept<'a>
where\n PinnedFieldsOf<__Accept<'pin, 'a>>: Unpin,
"],["impl<T> Unpin for TxtAttrs<T>",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl Unpin for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl Unpin for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl Unpin for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl Unpin for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl Unpin for Error",1,["iroh_base::ticket::Error"]],["impl Unpin for Hash",1,["iroh_base::hash::Hash"]],["impl Unpin for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl Unpin for PublicKey",1,["iroh_base::key::PublicKey"]],["impl Unpin for SecretKey",1,["iroh_base::key::SecretKey"]],["impl Unpin for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl Unpin for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl Unpin for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl Unpin for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl Unpin for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl Unpin for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl Unpin for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl Unpin for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl Unpin for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl Unpin for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl Unpin for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl Unpin for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl Unpin for Config",1,["iroh_dns_server::config::Config"]],["impl Unpin for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl Unpin for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl Unpin for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl Unpin for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl Unpin for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl Unpin for Handle",1,["iroh_dns_server::dns::Handle"]],["impl Unpin for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl Unpin for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl Unpin for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl Unpin for Metrics",1,["iroh_dns_server::metrics::Metrics"]],["impl Unpin for Server",1,["iroh_dns_server::server::Server"]],["impl Unpin for AppState",1,["iroh_dns_server::state::AppState"]]], +"iroh_net_bench":[["impl Unpin for Commands",1,["iroh_net_bench::Commands"]],["impl Unpin for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl Unpin for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl Unpin for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl Unpin for Stats",1,["iroh_net_bench::stats::Stats"]],["impl Unpin for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl Unpin for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl Unpin for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl Unpin for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl Unpin for Addr",1,["iroh_net_report::Addr"]],["impl Unpin for Client",1,["iroh_net_report::Client"]],["impl Unpin for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl Unpin for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl Unpin for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl Unpin for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl Unpin for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl Unpin for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl Unpin for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl Unpin for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl Unpin for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl Unpin for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl Unpin for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl Unpin for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl Unpin for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl Unpin for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl Unpin for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl Unpin for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl Unpin for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl Unpin for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl Unpin for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl Unpin for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl Unpin for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl Unpin for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl Unpin for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl Unpin for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl Unpin for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl Unpin for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl Unpin for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl Unpin for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl Unpin for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl Unpin for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl Unpin for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl Unpin for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl Unpin for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl Unpin for ClientError",1,["iroh_relay::client::ClientError"]],["impl Unpin for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl Unpin for Protocol",1,["iroh_relay::http::Protocol"]],["impl Unpin for Error",1,["iroh_relay::protos::stun::Error"]],["impl Unpin for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl Unpin for Client",1,["iroh_relay::client::Client"]],["impl Unpin for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl Unpin for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl Unpin for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl Unpin for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl Unpin for Limits",1,["iroh_relay::server::Limits"]],["impl Unpin for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl Unpin for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl Unpin for Server",1,["iroh_relay::server::Server"]],["impl Unpin for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl Unpin for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl Unpin for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA> Unpin for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA> Unpin for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA> Unpin for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA> Unpin for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl Unpin for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/ops/deref/trait.Deref.js b/pr/2992/docs/trait.impl/core/ops/deref/trait.Deref.js new file mode 100644 index 0000000000..664655b466 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/ops/deref/trait.Deref.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_base":[["impl Deref for RelayUrl"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/ops/drop/trait.Drop.js b/pr/2992/docs/trait.impl/core/ops/drop/trait.Drop.js new file mode 100644 index 0000000000..634f4d4747 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/ops/drop/trait.Drop.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[["impl Drop for PkarrPublisher"]], +"iroh_test":[["impl Drop for CallOnDrop"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js b/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 0000000000..511656f1e1 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl !RefUnwindSafe for Dialer",1,["iroh::dialer::Dialer"]],["impl !RefUnwindSafe for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl !RefUnwindSafe for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl !RefUnwindSafe for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl !RefUnwindSafe for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl !RefUnwindSafe for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl !RefUnwindSafe for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl !RefUnwindSafe for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl !RefUnwindSafe for Builder",1,["iroh::endpoint::Builder"]],["impl !RefUnwindSafe for Connecting",1,["iroh::endpoint::Connecting"]],["impl !RefUnwindSafe for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl !RefUnwindSafe for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl !RefUnwindSafe for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl !RefUnwindSafe for Incoming",1,["iroh::endpoint::Incoming"]],["impl !RefUnwindSafe for IncomingFuture",1,["iroh::endpoint::IncomingFuture"]],["impl !RefUnwindSafe for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl !RefUnwindSafe for Router",1,["iroh::protocol::Router"]],["impl !RefUnwindSafe for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl !RefUnwindSafe for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl !RefUnwindSafe for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl RefUnwindSafe for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl RefUnwindSafe for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl RefUnwindSafe for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl RefUnwindSafe for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl RefUnwindSafe for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl RefUnwindSafe for Source",1,["iroh::magicsock::node_map::Source"]],["impl RefUnwindSafe for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl RefUnwindSafe for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl RefUnwindSafe for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl RefUnwindSafe for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl RefUnwindSafe for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl RefUnwindSafe for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl RefUnwindSafe for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl RefUnwindSafe for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl RefUnwindSafe for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl RefUnwindSafe for GenError",1,["iroh::tls::certificate::GenError"]],["impl RefUnwindSafe for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl RefUnwindSafe for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl RefUnwindSafe for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> !RefUnwindSafe for Accept<'a>",1,["iroh::endpoint::Accept"]],["impl<'a> RefUnwindSafe for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<T> RefUnwindSafe for TxtAttrs<T>
where\n T: RefUnwindSafe,
",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl !RefUnwindSafe for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl RefUnwindSafe for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl RefUnwindSafe for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl RefUnwindSafe for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl RefUnwindSafe for Error",1,["iroh_base::ticket::Error"]],["impl RefUnwindSafe for Hash",1,["iroh_base::hash::Hash"]],["impl RefUnwindSafe for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl RefUnwindSafe for PublicKey",1,["iroh_base::key::PublicKey"]],["impl RefUnwindSafe for SecretKey",1,["iroh_base::key::SecretKey"]],["impl RefUnwindSafe for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl RefUnwindSafe for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl RefUnwindSafe for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl RefUnwindSafe for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl RefUnwindSafe for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl RefUnwindSafe for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl RefUnwindSafe for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl RefUnwindSafe for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl RefUnwindSafe for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl !RefUnwindSafe for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl !RefUnwindSafe for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl !RefUnwindSafe for Handle",1,["iroh_dns_server::dns::Handle"]],["impl !RefUnwindSafe for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl !RefUnwindSafe for Server",1,["iroh_dns_server::server::Server"]],["impl !RefUnwindSafe for AppState",1,["iroh_dns_server::state::AppState"]],["impl RefUnwindSafe for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl RefUnwindSafe for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl RefUnwindSafe for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl RefUnwindSafe for Config",1,["iroh_dns_server::config::Config"]],["impl RefUnwindSafe for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl RefUnwindSafe for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl RefUnwindSafe for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl RefUnwindSafe for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl RefUnwindSafe for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl RefUnwindSafe for Metrics",1,["iroh_dns_server::metrics::Metrics"]]], +"iroh_net_bench":[["impl !RefUnwindSafe for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl RefUnwindSafe for Commands",1,["iroh_net_bench::Commands"]],["impl RefUnwindSafe for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl RefUnwindSafe for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl RefUnwindSafe for Stats",1,["iroh_net_bench::stats::Stats"]],["impl RefUnwindSafe for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl RefUnwindSafe for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl RefUnwindSafe for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl RefUnwindSafe for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl RefUnwindSafe for Addr",1,["iroh_net_report::Addr"]],["impl RefUnwindSafe for Client",1,["iroh_net_report::Client"]],["impl RefUnwindSafe for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl RefUnwindSafe for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl RefUnwindSafe for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl !RefUnwindSafe for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl !RefUnwindSafe for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl RefUnwindSafe for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl RefUnwindSafe for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl RefUnwindSafe for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl RefUnwindSafe for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl RefUnwindSafe for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl RefUnwindSafe for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl RefUnwindSafe for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl RefUnwindSafe for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl RefUnwindSafe for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl RefUnwindSafe for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl RefUnwindSafe for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl RefUnwindSafe for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl RefUnwindSafe for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl RefUnwindSafe for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl RefUnwindSafe for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl RefUnwindSafe for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl RefUnwindSafe for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl RefUnwindSafe for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl RefUnwindSafe for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl RefUnwindSafe for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl RefUnwindSafe for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl RefUnwindSafe for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl RefUnwindSafe for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl RefUnwindSafe for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl RefUnwindSafe for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl RefUnwindSafe for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl RefUnwindSafe for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl RefUnwindSafe for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl !RefUnwindSafe for ClientError",1,["iroh_relay::client::ClientError"]],["impl !RefUnwindSafe for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl !RefUnwindSafe for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl !RefUnwindSafe for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl !RefUnwindSafe for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl RefUnwindSafe for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl RefUnwindSafe for Protocol",1,["iroh_relay::http::Protocol"]],["impl RefUnwindSafe for Error",1,["iroh_relay::protos::stun::Error"]],["impl RefUnwindSafe for Client",1,["iroh_relay::client::Client"]],["impl RefUnwindSafe for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl RefUnwindSafe for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl RefUnwindSafe for Limits",1,["iroh_relay::server::Limits"]],["impl RefUnwindSafe for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl RefUnwindSafe for Server",1,["iroh_relay::server::Server"]],["impl RefUnwindSafe for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl RefUnwindSafe for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl RefUnwindSafe for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA = EC> !RefUnwindSafe for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA = EC> !RefUnwindSafe for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA = EC> !RefUnwindSafe for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA = EC> !RefUnwindSafe for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl !RefUnwindSafe for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js b/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 0000000000..3d2c87e954 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,10 @@ +(function() {var implementors = { +"iroh":[["impl !UnwindSafe for Dialer",1,["iroh::dialer::Dialer"]],["impl !UnwindSafe for LocalSwarmDiscovery",1,["iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery"]],["impl !UnwindSafe for Builder",1,["iroh::discovery::pkarr::dht::Builder"]],["impl !UnwindSafe for DhtDiscovery",1,["iroh::discovery::pkarr::dht::DhtDiscovery"]],["impl !UnwindSafe for PkarrPublisher",1,["iroh::discovery::pkarr::PkarrPublisher"]],["impl !UnwindSafe for PkarrRelayClient",1,["iroh::discovery::pkarr::PkarrRelayClient"]],["impl !UnwindSafe for PkarrResolver",1,["iroh::discovery::pkarr::PkarrResolver"]],["impl !UnwindSafe for ConcurrentDiscovery",1,["iroh::discovery::ConcurrentDiscovery"]],["impl !UnwindSafe for Builder",1,["iroh::endpoint::Builder"]],["impl !UnwindSafe for Connecting",1,["iroh::endpoint::Connecting"]],["impl !UnwindSafe for ConnectionTypeStream",1,["iroh::magicsock::node_map::ConnectionTypeStream"]],["impl !UnwindSafe for DirectAddrsStream",1,["iroh::magicsock::DirectAddrsStream"]],["impl !UnwindSafe for Endpoint",1,["iroh::endpoint::Endpoint"]],["impl !UnwindSafe for Incoming",1,["iroh::endpoint::Incoming"]],["impl !UnwindSafe for IncomingFuture",1,["iroh::endpoint::IncomingFuture"]],["impl !UnwindSafe for ProtocolMap",1,["iroh::protocol::ProtocolMap"]],["impl !UnwindSafe for Router",1,["iroh::protocol::Router"]],["impl !UnwindSafe for RouterBuilder",1,["iroh::protocol::RouterBuilder"]],["impl !UnwindSafe for CleanupDropGuard",1,["iroh::test_utils::CleanupDropGuard"]],["impl !UnwindSafe for DnsPkarrServer",1,["iroh::test_utils::dns_and_pkarr_servers::DnsPkarrServer"]],["impl UnwindSafe for IrohAttr",1,["iroh::dns::node_info::IrohAttr"]],["impl UnwindSafe for ConnectionType",1,["iroh::magicsock::node_map::node_state::ConnectionType"]],["impl UnwindSafe for ControlMsg",1,["iroh::magicsock::node_map::node_state::ControlMsg"]],["impl UnwindSafe for DirectAddrType",1,["iroh::magicsock::DirectAddrType"]],["impl UnwindSafe for RelayMode",1,["iroh::endpoint::RelayMode"]],["impl UnwindSafe for Source",1,["iroh::magicsock::node_map::Source"]],["impl UnwindSafe for CreateConfigError",1,["iroh::tls::CreateConfigError"]],["impl UnwindSafe for DnsDiscovery",1,["iroh::discovery::dns::DnsDiscovery"]],["impl UnwindSafe for StaticProvider",1,["iroh::discovery::static_provider::StaticProvider"]],["impl UnwindSafe for DiscoveryItem",1,["iroh::discovery::DiscoveryItem"]],["impl UnwindSafe for NodeInfo",1,["iroh::dns::node_info::NodeInfo"]],["impl UnwindSafe for DirectAddr",1,["iroh::magicsock::DirectAddr"]],["impl UnwindSafe for DirectAddrInfo",1,["iroh::magicsock::node_map::node_state::DirectAddrInfo"]],["impl UnwindSafe for RemoteInfo",1,["iroh::magicsock::node_map::node_state::RemoteInfo"]],["impl UnwindSafe for Metrics",1,["iroh::magicsock::metrics::Metrics"]],["impl UnwindSafe for GenError",1,["iroh::tls::certificate::GenError"]],["impl UnwindSafe for P2pExtension",1,["iroh::tls::certificate::P2pExtension"]],["impl UnwindSafe for ParseError",1,["iroh::tls::certificate::ParseError"]],["impl UnwindSafe for VerificationError",1,["iroh::tls::certificate::VerificationError"]],["impl<'a> !UnwindSafe for Accept<'a>",1,["iroh::endpoint::Accept"]],["impl<'a> UnwindSafe for P2pCertificate<'a>",1,["iroh::tls::certificate::P2pCertificate"]],["impl<T> UnwindSafe for TxtAttrs<T>
where\n T: RefUnwindSafe,
",1,["iroh::dns::node_info::TxtAttrs"]]], +"iroh_base":[["impl !UnwindSafe for KeyParsingError",1,["iroh_base::key::KeyParsingError"]],["impl UnwindSafe for HexOrBase32ParseError",1,["iroh_base::base32::HexOrBase32ParseError"]],["impl UnwindSafe for BlobFormat",1,["iroh_base::hash::BlobFormat"]],["impl UnwindSafe for AddrInfoOptions",1,["iroh_base::node_addr::AddrInfoOptions"]],["impl UnwindSafe for Error",1,["iroh_base::ticket::Error"]],["impl UnwindSafe for Hash",1,["iroh_base::hash::Hash"]],["impl UnwindSafe for HashAndFormat",1,["iroh_base::hash::HashAndFormat"]],["impl UnwindSafe for PublicKey",1,["iroh_base::key::PublicKey"]],["impl UnwindSafe for SecretKey",1,["iroh_base::key::SecretKey"]],["impl UnwindSafe for SharedSecret",1,["iroh_base::key::encryption::SharedSecret"]],["impl UnwindSafe for AddrInfo",1,["iroh_base::node_addr::AddrInfo"]],["impl UnwindSafe for NodeAddr",1,["iroh_base::node_addr::NodeAddr"]],["impl UnwindSafe for RelayUrl",1,["iroh_base::relay_url::RelayUrl"]],["impl UnwindSafe for QuicConfig",1,["iroh_base::relay_map::QuicConfig"]],["impl UnwindSafe for RelayMap",1,["iroh_base::relay_map::RelayMap"]],["impl UnwindSafe for RelayNode",1,["iroh_base::relay_map::RelayNode"]],["impl UnwindSafe for BlobTicket",1,["iroh_base::ticket::blob::BlobTicket"]],["impl UnwindSafe for NodeTicket",1,["iroh_base::ticket::node::NodeTicket"]]], +"iroh_dns_server":[["impl !UnwindSafe for DnsHandler",1,["iroh_dns_server::dns::DnsHandler"]],["impl !UnwindSafe for DnsServer",1,["iroh_dns_server::dns::DnsServer"]],["impl !UnwindSafe for Handle",1,["iroh_dns_server::dns::Handle"]],["impl !UnwindSafe for HttpServer",1,["iroh_dns_server::http::HttpServer"]],["impl !UnwindSafe for Server",1,["iroh_dns_server::server::Server"]],["impl !UnwindSafe for AppState",1,["iroh_dns_server::state::AppState"]],["impl UnwindSafe for BootstrapOption",1,["iroh_dns_server::config::BootstrapOption"]],["impl UnwindSafe for CertMode",1,["iroh_dns_server::http::tls::CertMode"]],["impl UnwindSafe for RateLimitConfig",1,["iroh_dns_server::http::rate_limiting::RateLimitConfig"]],["impl UnwindSafe for Config",1,["iroh_dns_server::config::Config"]],["impl UnwindSafe for MainlineConfig",1,["iroh_dns_server::config::MainlineConfig"]],["impl UnwindSafe for MetricsConfig",1,["iroh_dns_server::config::MetricsConfig"]],["impl UnwindSafe for DnsConfig",1,["iroh_dns_server::dns::DnsConfig"]],["impl UnwindSafe for HttpConfig",1,["iroh_dns_server::http::HttpConfig"]],["impl UnwindSafe for HttpsConfig",1,["iroh_dns_server::http::HttpsConfig"]],["impl UnwindSafe for Metrics",1,["iroh_dns_server::metrics::Metrics"]]], +"iroh_net_bench":[["impl !UnwindSafe for EndpointSelector",1,["iroh_net_bench::EndpointSelector"]],["impl UnwindSafe for Commands",1,["iroh_net_bench::Commands"]],["impl UnwindSafe for ConnectionSelector",1,["iroh_net_bench::ConnectionSelector"]],["impl UnwindSafe for Opt",1,["iroh_net_bench::s2n::Opt"]],["impl UnwindSafe for Stats",1,["iroh_net_bench::stats::Stats"]],["impl UnwindSafe for StreamStats",1,["iroh_net_bench::stats::StreamStats"]],["impl UnwindSafe for TransferResult",1,["iroh_net_bench::stats::TransferResult"]],["impl UnwindSafe for ClientStats",1,["iroh_net_bench::ClientStats"]],["impl UnwindSafe for Opt",1,["iroh_net_bench::Opt"]]], +"iroh_net_report":[["impl UnwindSafe for Addr",1,["iroh_net_report::Addr"]],["impl UnwindSafe for Client",1,["iroh_net_report::Client"]],["impl UnwindSafe for Metrics",1,["iroh_net_report::metrics::Metrics"]],["impl UnwindSafe for RelayLatencies",1,["iroh_net_report::RelayLatencies"]],["impl UnwindSafe for Report",1,["iroh_net_report::Report"]]], +"iroh_node_util":[["impl !UnwindSafe for Client",1,["iroh_node_util::rpc::client::net::Client"]],["impl !UnwindSafe for Client",1,["iroh_node_util::rpc::client::node::Client"]],["impl UnwindSafe for NetCommands",1,["iroh_node_util::cli::net::NetCommands"]],["impl UnwindSafe for NodeCommands",1,["iroh_node_util::cli::node::NodeCommands"]],["impl UnwindSafe for Rotation",1,["iroh_node_util::logging::Rotation"]],["impl UnwindSafe for Request",1,["iroh_node_util::rpc::proto::Request"]],["impl UnwindSafe for Response",1,["iroh_node_util::rpc::proto::Response"]],["impl UnwindSafe for Request",1,["iroh_node_util::rpc::proto::net::Request"]],["impl UnwindSafe for Response",1,["iroh_node_util::rpc::proto::net::Response"]],["impl UnwindSafe for Request",1,["iroh_node_util::rpc::proto::node::Request"]],["impl UnwindSafe for Response",1,["iroh_node_util::rpc::proto::node::Response"]],["impl UnwindSafe for EnvFilter",1,["iroh_node_util::logging::EnvFilter"]],["impl UnwindSafe for FileLogging",1,["iroh_node_util::logging::FileLogging"]],["impl UnwindSafe for NodeStatus",1,["iroh_node_util::rpc::client::net::NodeStatus"]],["impl UnwindSafe for AddAddrRequest",1,["iroh_node_util::rpc::proto::net::AddAddrRequest"]],["impl UnwindSafe for AddrRequest",1,["iroh_node_util::rpc::proto::net::AddrRequest"]],["impl UnwindSafe for IdRequest",1,["iroh_node_util::rpc::proto::net::IdRequest"]],["impl UnwindSafe for NodeWatchRequest",1,["iroh_node_util::rpc::proto::net::NodeWatchRequest"]],["impl UnwindSafe for RelayRequest",1,["iroh_node_util::rpc::proto::net::RelayRequest"]],["impl UnwindSafe for RemoteInfoRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfoRequest"]],["impl UnwindSafe for RemoteInfoResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfoResponse"]],["impl UnwindSafe for RemoteInfosIterRequest",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterRequest"]],["impl UnwindSafe for RemoteInfosIterResponse",1,["iroh_node_util::rpc::proto::net::RemoteInfosIterResponse"]],["impl UnwindSafe for WatchResponse",1,["iroh_node_util::rpc::proto::net::WatchResponse"]],["impl UnwindSafe for CounterStats",1,["iroh_node_util::rpc::proto::node::CounterStats"]],["impl UnwindSafe for ShutdownRequest",1,["iroh_node_util::rpc::proto::node::ShutdownRequest"]],["impl UnwindSafe for StatsRequest",1,["iroh_node_util::rpc::proto::node::StatsRequest"]],["impl UnwindSafe for StatsResponse",1,["iroh_node_util::rpc::proto::node::StatsResponse"]],["impl UnwindSafe for StatusRequest",1,["iroh_node_util::rpc::proto::node::StatusRequest"]],["impl UnwindSafe for RpcService",1,["iroh_node_util::rpc::proto::RpcService"]]], +"iroh_relay":[["impl !UnwindSafe for ClientError",1,["iroh_relay::client::ClientError"]],["impl !UnwindSafe for MaybeTlsStream",1,["iroh_relay::server::streams::MaybeTlsStream"]],["impl !UnwindSafe for ClientBuilder",1,["iroh_relay::client::ClientBuilder"]],["impl !UnwindSafe for QuicClient",1,["iroh_relay::quic::QuicClient"]],["impl !UnwindSafe for QuicConfig",1,["iroh_relay::server::QuicConfig"]],["impl UnwindSafe for ReceivedMessage",1,["iroh_relay::client::conn::ReceivedMessage"]],["impl UnwindSafe for Protocol",1,["iroh_relay::http::Protocol"]],["impl UnwindSafe for Error",1,["iroh_relay::protos::stun::Error"]],["impl UnwindSafe for Client",1,["iroh_relay::client::Client"]],["impl UnwindSafe for ClientReceiver",1,["iroh_relay::client::ClientReceiver"]],["impl UnwindSafe for ClientConnRateLimit",1,["iroh_relay::server::ClientConnRateLimit"]],["impl UnwindSafe for Limits",1,["iroh_relay::server::Limits"]],["impl UnwindSafe for Metrics",1,["iroh_relay::server::metrics::Metrics"]],["impl UnwindSafe for Server",1,["iroh_relay::server::Server"]],["impl UnwindSafe for StunConfig",1,["iroh_relay::server::StunConfig"]],["impl UnwindSafe for StunMetrics",1,["iroh_relay::server::metrics::StunMetrics"]],["impl UnwindSafe for Conn",1,["iroh_relay::client::conn::Conn"]],["impl<EC, EA = EC> !UnwindSafe for CertConfig<EC, EA>",1,["iroh_relay::server::CertConfig"]],["impl<EC, EA = EC> !UnwindSafe for RelayConfig<EC, EA>",1,["iroh_relay::server::RelayConfig"]],["impl<EC, EA = EC> !UnwindSafe for ServerConfig<EC, EA>",1,["iroh_relay::server::ServerConfig"]],["impl<EC, EA = EC> !UnwindSafe for TlsConfig<EC, EA>",1,["iroh_relay::server::TlsConfig"]]], +"iroh_test":[["impl !UnwindSafe for CallOnDrop",1,["iroh_test::CallOnDrop"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/core/str/traits/trait.FromStr.js b/pr/2992/docs/trait.impl/core/str/traits/trait.FromStr.js new file mode 100644 index 0000000000..f372df0991 --- /dev/null +++ b/pr/2992/docs/trait.impl/core/str/traits/trait.FromStr.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"iroh":[["impl FromStr for IrohAttr"]], +"iroh_base":[["impl FromStr for AddrInfoOptions"],["impl FromStr for Hash"],["impl FromStr for HashAndFormat"],["impl FromStr for PublicKey"],["impl FromStr for SecretKey"],["impl FromStr for RelayUrl"],["impl FromStr for BlobTicket"],["impl FromStr for NodeTicket"]], +"iroh_node_util":[["impl FromStr for EnvFilter"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/futures_core/stream/trait.Stream.js b/pr/2992/docs/trait.impl/futures_core/stream/trait.Stream.js new file mode 100644 index 0000000000..563b264694 --- /dev/null +++ b/pr/2992/docs/trait.impl/futures_core/stream/trait.Stream.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[["impl Stream for Dialer"],["impl Stream for ConnectionTypeStream"],["impl Stream for DirectAddrsStream"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/hickory_server/server/request_handler/trait.RequestHandler.js b/pr/2992/docs/trait.impl/hickory_server/server/request_handler/trait.RequestHandler.js new file mode 100644 index 0000000000..681bf932d9 --- /dev/null +++ b/pr/2992/docs/trait.impl/hickory_server/server/request_handler/trait.RequestHandler.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_dns_server":[["impl RequestHandler for DnsHandler"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/hickory_server/server/response_handler/trait.ResponseHandler.js b/pr/2992/docs/trait.impl/hickory_server/server/response_handler/trait.ResponseHandler.js new file mode 100644 index 0000000000..85f3fea227 --- /dev/null +++ b/pr/2992/docs/trait.impl/hickory_server/server/response_handler/trait.ResponseHandler.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_dns_server":[["impl ResponseHandler for Handle"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh/discovery/trait.Discovery.js b/pr/2992/docs/trait.impl/iroh/discovery/trait.Discovery.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh/discovery/trait.Discovery.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh/dns/trait.ResolverExt.js b/pr/2992/docs/trait.impl/iroh/dns/trait.ResolverExt.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh/dns/trait.ResolverExt.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh/protocol/trait.IntoArcAny.js b/pr/2992/docs/trait.impl/iroh/protocol/trait.IntoArcAny.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh/protocol/trait.IntoArcAny.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_base/ticket/trait.Ticket.js b/pr/2992/docs/trait.impl/iroh_base/ticket/trait.Ticket.js new file mode 100644 index 0000000000..8b7e5491a0 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_base/ticket/trait.Ticket.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"iroh":[], +"iroh_base":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_metrics/core/trait.Metric.js b/pr/2992/docs/trait.impl/iroh_metrics/core/trait.Metric.js new file mode 100644 index 0000000000..b6c43a9dbd --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_metrics/core/trait.Metric.js @@ -0,0 +1,6 @@ +(function() {var implementors = { +"iroh":[["impl Metric for Metrics"]], +"iroh_dns_server":[["impl Metric for Metrics"]], +"iroh_net_report":[["impl Metric for Metrics"]], +"iroh_relay":[["impl Metric for Metrics"],["impl Metric for StunMetrics"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.Controller.js b/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.Controller.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.Controller.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.ControllerFactory.js b/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.ControllerFactory.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_quinn_proto/congestion/trait.ControllerFactory.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.AeadKey.js b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.AeadKey.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.AeadKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.HandshakeTokenKey.js b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.HandshakeTokenKey.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.HandshakeTokenKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.ServerConfig.js b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.ServerConfig.js new file mode 100644 index 0000000000..270d4e1d95 --- /dev/null +++ b/pr/2992/docs/trait.impl/iroh_quinn_proto/crypto/trait.ServerConfig.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/postcard/max_size/trait.MaxSize.js b/pr/2992/docs/trait.impl/postcard/max_size/trait.MaxSize.js new file mode 100644 index 0000000000..a5080663d4 --- /dev/null +++ b/pr/2992/docs/trait.impl/postcard/max_size/trait.MaxSize.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_base":[["impl MaxSize for BlobFormat"],["impl MaxSize for Hash"],["impl MaxSize for HashAndFormat"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/quic_rpc/message/trait.Msg.js b/pr/2992/docs/trait.impl/quic_rpc/message/trait.Msg.js new file mode 100644 index 0000000000..3947391147 --- /dev/null +++ b/pr/2992/docs/trait.impl/quic_rpc/message/trait.Msg.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_node_util":[["impl Msg<RpcService> for NodeWatchRequest"],["impl Msg<RpcService> for RemoteInfosIterRequest"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/quic_rpc/pattern/rpc/trait.RpcMsg.js b/pr/2992/docs/trait.impl/quic_rpc/pattern/rpc/trait.RpcMsg.js new file mode 100644 index 0000000000..fb643afe1e --- /dev/null +++ b/pr/2992/docs/trait.impl/quic_rpc/pattern/rpc/trait.RpcMsg.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_node_util":[["impl RpcMsg<RpcService> for AddAddrRequest"],["impl RpcMsg<RpcService> for AddrRequest"],["impl RpcMsg<RpcService> for IdRequest"],["impl RpcMsg<RpcService> for RelayRequest"],["impl RpcMsg<RpcService> for RemoteInfoRequest"],["impl RpcMsg<RpcService> for ShutdownRequest"],["impl RpcMsg<RpcService> for StatsRequest"],["impl RpcMsg<RpcService> for StatusRequest"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/quic_rpc/pattern/server_streaming/trait.ServerStreamingMsg.js b/pr/2992/docs/trait.impl/quic_rpc/pattern/server_streaming/trait.ServerStreamingMsg.js new file mode 100644 index 0000000000..6938732114 --- /dev/null +++ b/pr/2992/docs/trait.impl/quic_rpc/pattern/server_streaming/trait.ServerStreamingMsg.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_node_util":[["impl ServerStreamingMsg<RpcService> for NodeWatchRequest"],["impl ServerStreamingMsg<RpcService> for RemoteInfosIterRequest"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/quic_rpc/trait.Service.js b/pr/2992/docs/trait.impl/quic_rpc/trait.Service.js new file mode 100644 index 0000000000..54f2f631a0 --- /dev/null +++ b/pr/2992/docs/trait.impl/quic_rpc/trait.Service.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_node_util":[["impl Service for RpcService"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/redb/types/trait.Key.js b/pr/2992/docs/trait.impl/redb/types/trait.Key.js new file mode 100644 index 0000000000..8970ce493a --- /dev/null +++ b/pr/2992/docs/trait.impl/redb/types/trait.Key.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_base":[["impl Key for Hash"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/redb/types/trait.Value.js b/pr/2992/docs/trait.impl/redb/types/trait.Value.js new file mode 100644 index 0000000000..62f5851b3b --- /dev/null +++ b/pr/2992/docs/trait.impl/redb/types/trait.Value.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_base":[["impl Value for Hash"],["impl Value for HashAndFormat"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/serde/de/trait.Deserialize.js b/pr/2992/docs/trait.impl/serde/de/trait.Deserialize.js new file mode 100644 index 0000000000..4d1b9cb30a --- /dev/null +++ b/pr/2992/docs/trait.impl/serde/de/trait.Deserialize.js @@ -0,0 +1,6 @@ +(function() {var implementors = { +"iroh":[["impl<'de> Deserialize<'de> for ConnectionType"],["impl<'de> Deserialize<'de> for ControlMsg"],["impl<'de> Deserialize<'de> for Source"],["impl<'de> Deserialize<'de> for DirectAddrInfo"],["impl<'de> Deserialize<'de> for RemoteInfo"]], +"iroh_base":[["impl<'de> Deserialize<'de> for BlobFormat"],["impl<'de> Deserialize<'de> for AddrInfoOptions"],["impl<'de> Deserialize<'de> for Hash"],["impl<'de> Deserialize<'de> for HashAndFormat"],["impl<'de> Deserialize<'de> for PublicKey"],["impl<'de> Deserialize<'de> for SecretKey"],["impl<'de> Deserialize<'de> for AddrInfo"],["impl<'de> Deserialize<'de> for NodeAddr"],["impl<'de> Deserialize<'de> for RelayUrl"],["impl<'de> Deserialize<'de> for QuicConfig"],["impl<'de> Deserialize<'de> for RelayNode"],["impl<'de> Deserialize<'de> for BlobTicket"],["impl<'de> Deserialize<'de> for NodeTicket"]], +"iroh_dns_server":[["impl<'de> Deserialize<'de> for BootstrapOption"],["impl<'de> Deserialize<'de> for CertMode"],["impl<'de> Deserialize<'de> for RateLimitConfig"],["impl<'de> Deserialize<'de> for Config"],["impl<'de> Deserialize<'de> for MainlineConfig"],["impl<'de> Deserialize<'de> for MetricsConfig"],["impl<'de> Deserialize<'de> for DnsConfig"],["impl<'de> Deserialize<'de> for HttpConfig"],["impl<'de> Deserialize<'de> for HttpsConfig"]], +"iroh_node_util":[["impl<'de> Deserialize<'de> for Rotation"],["impl<'de> Deserialize<'de> for Request"],["impl<'de> Deserialize<'de> for Response"],["impl<'de> Deserialize<'de> for Request"],["impl<'de> Deserialize<'de> for Response"],["impl<'de> Deserialize<'de> for Request"],["impl<'de> Deserialize<'de> for Response"],["impl<'de> Deserialize<'de> for EnvFilter
where\n Self: FromStr,\n <Self as FromStr>::Err: Display,
"],["impl<'de> Deserialize<'de> for FileLogging"],["impl<'de> Deserialize<'de> for NodeStatus"],["impl<'de> Deserialize<'de> for AddAddrRequest"],["impl<'de> Deserialize<'de> for AddrRequest"],["impl<'de> Deserialize<'de> for IdRequest"],["impl<'de> Deserialize<'de> for NodeWatchRequest"],["impl<'de> Deserialize<'de> for RelayRequest"],["impl<'de> Deserialize<'de> for RemoteInfoRequest"],["impl<'de> Deserialize<'de> for RemoteInfoResponse"],["impl<'de> Deserialize<'de> for RemoteInfosIterRequest"],["impl<'de> Deserialize<'de> for RemoteInfosIterResponse"],["impl<'de> Deserialize<'de> for WatchResponse"],["impl<'de> Deserialize<'de> for CounterStats"],["impl<'de> Deserialize<'de> for ShutdownRequest"],["impl<'de> Deserialize<'de> for StatsRequest"],["impl<'de> Deserialize<'de> for StatsResponse"],["impl<'de> Deserialize<'de> for StatusRequest"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/serde/ser/trait.Serialize.js b/pr/2992/docs/trait.impl/serde/ser/trait.Serialize.js new file mode 100644 index 0000000000..2180c78d0d --- /dev/null +++ b/pr/2992/docs/trait.impl/serde/ser/trait.Serialize.js @@ -0,0 +1,6 @@ +(function() {var implementors = { +"iroh":[["impl Serialize for ConnectionType"],["impl Serialize for ControlMsg"],["impl Serialize for Source"],["impl Serialize for DirectAddrInfo"],["impl Serialize for RemoteInfo"]], +"iroh_base":[["impl Serialize for BlobFormat"],["impl Serialize for AddrInfoOptions"],["impl Serialize for Hash"],["impl Serialize for HashAndFormat"],["impl Serialize for PublicKey"],["impl Serialize for SecretKey"],["impl Serialize for AddrInfo"],["impl Serialize for NodeAddr"],["impl Serialize for RelayUrl"],["impl Serialize for QuicConfig"],["impl Serialize for RelayNode"],["impl Serialize for BlobTicket"],["impl Serialize for NodeTicket"]], +"iroh_dns_server":[["impl Serialize for BootstrapOption"],["impl Serialize for CertMode"],["impl Serialize for RateLimitConfig"],["impl Serialize for Config"],["impl Serialize for MainlineConfig"],["impl Serialize for MetricsConfig"],["impl Serialize for DnsConfig"],["impl Serialize for HttpConfig"],["impl Serialize for HttpsConfig"]], +"iroh_node_util":[["impl Serialize for Rotation"],["impl Serialize for Request"],["impl Serialize for Response"],["impl Serialize for Request"],["impl Serialize for Response"],["impl Serialize for Request"],["impl Serialize for Response"],["impl Serialize for EnvFilter
where\n Self: Display,
"],["impl Serialize for FileLogging"],["impl Serialize for NodeStatus"],["impl Serialize for AddAddrRequest"],["impl Serialize for AddrRequest"],["impl Serialize for IdRequest"],["impl Serialize for NodeWatchRequest"],["impl Serialize for RelayRequest"],["impl Serialize for RemoteInfoRequest"],["impl Serialize for RemoteInfoResponse"],["impl Serialize for RemoteInfosIterRequest"],["impl Serialize for RemoteInfosIterResponse"],["impl Serialize for WatchResponse"],["impl Serialize for CounterStats"],["impl Serialize for ShutdownRequest"],["impl Serialize for StatsRequest"],["impl Serialize for StatsResponse"],["impl Serialize for StatusRequest"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/struct_iterable_internal/trait.Iterable.js b/pr/2992/docs/trait.impl/struct_iterable_internal/trait.Iterable.js new file mode 100644 index 0000000000..1d93bb5c6a --- /dev/null +++ b/pr/2992/docs/trait.impl/struct_iterable_internal/trait.Iterable.js @@ -0,0 +1,6 @@ +(function() {var implementors = { +"iroh":[["impl Iterable for Metrics"]], +"iroh_dns_server":[["impl Iterable for Metrics"]], +"iroh_net_report":[["impl Iterable for Metrics"]], +"iroh_relay":[["impl Iterable for Metrics"],["impl Iterable for StunMetrics"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/tokio/io/async_read/trait.AsyncRead.js b/pr/2992/docs/trait.impl/tokio/io/async_read/trait.AsyncRead.js new file mode 100644 index 0000000000..8ca6a2273b --- /dev/null +++ b/pr/2992/docs/trait.impl/tokio/io/async_read/trait.AsyncRead.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_relay":[["impl AsyncRead for MaybeTlsStream"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/trait.impl/tokio/io/async_write/trait.AsyncWrite.js b/pr/2992/docs/trait.impl/tokio/io/async_write/trait.AsyncWrite.js new file mode 100644 index 0000000000..f9d9495401 --- /dev/null +++ b/pr/2992/docs/trait.impl/tokio/io/async_write/trait.AsyncWrite.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"iroh_relay":[["impl AsyncWrite for MaybeTlsStream"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/pr/2992/docs/type.impl/hickory_resolver/async_resolver/type.TokioAsyncResolver.js b/pr/2992/docs/type.impl/hickory_resolver/async_resolver/type.TokioAsyncResolver.js new file mode 100644 index 0000000000..b7d6fe3811 --- /dev/null +++ b/pr/2992/docs/type.impl/hickory_resolver/async_resolver/type.TokioAsyncResolver.js @@ -0,0 +1,3 @@ +(function() {var type_impls = { +"iroh":[] +};if (window.register_type_impls) {window.register_type_impls(type_impls);} else {window.pending_type_impls = type_impls;}})() \ No newline at end of file diff --git a/pr/2992/docs/type.impl/iroh/key/struct.PublicKey.js b/pr/2992/docs/type.impl/iroh/key/struct.PublicKey.js new file mode 100644 index 0000000000..8a75a65cbf --- /dev/null +++ b/pr/2992/docs/type.impl/iroh/key/struct.PublicKey.js @@ -0,0 +1,3 @@ +(function() {var type_impls = { +"iroh":[["
source§

impl AsRef<[u8]> for PublicKey

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
","AsRef<[u8]>","iroh::NodeId"],["
source§

impl Clone for PublicKey

source§

fn clone(&self) -> PublicKey

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
","Clone","iroh::NodeId"],["
source§

impl Debug for PublicKey

source§

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

Formats the value using the given formatter. Read more
","Debug","iroh::NodeId"],["
source§

impl<'de> Deserialize<'de> for PublicKey

source§

fn deserialize<D>(\n deserializer: D\n) -> Result<PublicKey, <D as Deserializer<'de>>::Error>
where\n D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
","Deserialize<'de>","iroh::NodeId"],["
source§

impl Display for PublicKey

source§

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

Formats the value using the given formatter. Read more
","Display","iroh::NodeId"],["
source§

impl From<VerifyingKey> for PublicKey

source§

fn from(verifying_key: VerifyingKey) -> PublicKey

Converts to this type from the input type.
","From","iroh::NodeId"],["
source§

impl FromStr for PublicKey

Deserialises the PublicKey from it’s base32 encoding.

\n

Display is capable of serialising this format.

\n
§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<PublicKey, <PublicKey as FromStr>::Err>

Parses a string s to return a value of this type. Read more
","FromStr","iroh::NodeId"],["
source§

impl Hash for PublicKey

source§

fn hash<H>(&self, state: &mut H)
where\n H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where\n H: Hasher,\n Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
","Hash","iroh::NodeId"],["
source§

impl Ord for PublicKey

source§

fn cmp(&self, other: &PublicKey) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where\n Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where\n Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where\n Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
","Ord","iroh::NodeId"],["
source§

impl PartialEq for PublicKey

source§

fn eq(&self, other: &PublicKey) -> bool

This method tests for self and other values to be equal, and is used\nby ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always\nsufficient, and should not be overridden without very good reason.
","PartialEq","iroh::NodeId"],["
source§

impl PartialOrd for PublicKey

source§

fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <=\noperator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >=\noperator. Read more
","PartialOrd","iroh::NodeId"],["
source§

impl PublicKey

source

pub fn as_bytes(&self) -> &[u8; 32]

Get this public key as a byte array.

\n
source

pub fn from_bytes(bytes: &[u8; 32]) -> Result<PublicKey, Error>

Construct a PublicKey from a slice of bytes.

\n
§Warning
\n

This will return a [SignatureError] if the bytes passed into this method do not represent\na valid ed25519_dalek curve point. Will never fail for bytes return from Self::as_bytes.\nSee [VerifyingKey::from_bytes] for details.

\n
source

pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), Error>

Verify a signature on a message with this secret key’s public key.

\n
§Return
\n

Returns Ok(()) if the signature is valid, and Err otherwise.

\n
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string\nrepresentation of the key.

\n
",0,"iroh::NodeId"],["
source§

impl Serialize for PublicKey

source§

fn serialize<S>(\n &self,\n serializer: S\n) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where\n S: Serializer,

Serialize this value into the given Serde serializer. Read more
","Serialize","iroh::NodeId"],["
source§

impl TryFrom<&[u8]> for PublicKey

§

type Error = Error

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

fn try_from(\n bytes: &[u8]\n) -> Result<PublicKey, <PublicKey as TryFrom<&[u8]>>::Error>

Performs the conversion.
","TryFrom<&[u8]>","iroh::NodeId"],["
source§

impl TryFrom<&[u8; 32]> for PublicKey

§

type Error = Error

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

fn try_from(\n bytes: &[u8; 32]\n) -> Result<PublicKey, <PublicKey as TryFrom<&[u8; 32]>>::Error>

Performs the conversion.
","TryFrom<&[u8; 32]>","iroh::NodeId"],["
source§

impl Copy for PublicKey

","Copy","iroh::NodeId"],["
source§

impl Eq for PublicKey

","Eq","iroh::NodeId"],["
source§

impl StructuralPartialEq for PublicKey

","StructuralPartialEq","iroh::NodeId"]] +};if (window.register_type_impls) {window.register_type_impls(type_impls);} else {window.pending_type_impls = type_impls;}})() \ No newline at end of file diff --git a/pr/2992/docs/type.impl/iroh_base/key/struct.PublicKey.js b/pr/2992/docs/type.impl/iroh_base/key/struct.PublicKey.js new file mode 100644 index 0000000000..9a571ba573 --- /dev/null +++ b/pr/2992/docs/type.impl/iroh_base/key/struct.PublicKey.js @@ -0,0 +1,3 @@ +(function() {var type_impls = { +"iroh_base":[["
source§

impl AsRef<[u8]> for PublicKey

source§

fn as_ref(&self) -> &[u8]

Converts this type into a shared reference of the (usually inferred) input type.
","AsRef<[u8]>","iroh_base::key::NodeId"],["
source§

impl Clone for PublicKey

source§

fn clone(&self) -> PublicKey

Returns a copy of the value. Read more
1.0.0 · source§

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

Performs copy-assignment from source. Read more
","Clone","iroh_base::key::NodeId"],["
source§

impl Debug for PublicKey

source§

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

Formats the value using the given formatter. Read more
","Debug","iroh_base::key::NodeId"],["
source§

impl<'de> Deserialize<'de> for PublicKey

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where\n D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
","Deserialize<'de>","iroh_base::key::NodeId"],["
source§

impl Display for PublicKey

source§

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

Formats the value using the given formatter. Read more
","Display","iroh_base::key::NodeId"],["
source§

impl From<VerifyingKey> for PublicKey

source§

fn from(verifying_key: VerifyingKey) -> Self

Converts to this type from the input type.
","From","iroh_base::key::NodeId"],["
source§

impl FromStr for PublicKey

Deserialises the PublicKey from it’s base32 encoding.

\n

Display is capable of serialising this format.

\n
§

type Err = KeyParsingError

The associated error which can be returned from parsing.
source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
","FromStr","iroh_base::key::NodeId"],["
source§

impl Hash for PublicKey

source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where\n H: Hasher,\n Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
","Hash","iroh_base::key::NodeId"],["
source§

impl Ord for PublicKey

source§

fn cmp(&self, other: &PublicKey) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where\n Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where\n Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where\n Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
","Ord","iroh_base::key::NodeId"],["
source§

impl PartialEq for PublicKey

source§

fn eq(&self, other: &PublicKey) -> bool

This method tests for self and other values to be equal, and is used\nby ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always\nsufficient, and should not be overridden without very good reason.
","PartialEq","iroh_base::key::NodeId"],["
source§

impl PartialOrd for PublicKey

source§

fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <=\noperator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >=\noperator. Read more
","PartialOrd","iroh_base::key::NodeId"],["
source§

impl PublicKey

source

pub fn as_bytes(&self) -> &[u8; 32]

Get this public key as a byte array.

\n
source

pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError>

Construct a PublicKey from a slice of bytes.

\n
§Warning
\n

This will return a [SignatureError] if the bytes passed into this method do not represent\na valid ed25519_dalek curve point. Will never fail for bytes return from Self::as_bytes.\nSee [VerifyingKey::from_bytes] for details.

\n
source

pub fn verify(\n &self,\n message: &[u8],\n signature: &Signature\n) -> Result<(), SignatureError>

Verify a signature on a message with this secret key’s public key.

\n
§Return
\n

Returns Ok(()) if the signature is valid, and Err otherwise.

\n
source

pub fn fmt_short(&self) -> String

Convert to a base32 string limited to the first 10 bytes for a friendly string\nrepresentation of the key.

\n
",0,"iroh_base::key::NodeId"],["
source§

impl Serialize for PublicKey

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where\n S: Serializer,

Serialize this value into the given Serde serializer. Read more
","Serialize","iroh_base::key::NodeId"],["
source§

impl TryFrom<&[u8]> for PublicKey

§

type Error = Error

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

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error>

Performs the conversion.
","TryFrom<&[u8]>","iroh_base::key::NodeId"],["
source§

impl TryFrom<&[u8; 32]> for PublicKey

§

type Error = Error

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

fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error>

Performs the conversion.
","TryFrom<&[u8; 32]>","iroh_base::key::NodeId"],["
source§

impl Copy for PublicKey

","Copy","iroh_base::key::NodeId"],["
source§

impl Eq for PublicKey

","Eq","iroh_base::key::NodeId"],["
source§

impl StructuralPartialEq for PublicKey

","StructuralPartialEq","iroh_base::key::NodeId"]] +};if (window.register_type_impls) {window.register_type_impls(type_impls);} else {window.pending_type_impls = type_impls;}})() \ No newline at end of file