diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7235d7b95d..42bbece15f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -189,7 +189,7 @@ jobs: # uses: obi1kenobi/cargo-semver-checks-action@v2 uses: n0-computer/cargo-semver-checks-action@feat-baseline with: - package: iroh, iroh-base, iroh-dns-server, iroh-metrics, iroh-net, iroh-net-bench, iroh-node-util, iroh-router, netwatch, portmapper, iroh-relay, iroh-net-report + package: iroh, iroh-base, iroh-dns-server, iroh-metrics, iroh-net-bench, iroh-node-util, netwatch, portmapper, iroh-relay, iroh-net-report baseline-rev: ${{ env.HEAD_COMMIT_SHA }} use-cache: false diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 98efa3dba1..ad8edd8984 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,7 +23,7 @@ env: RUSTFLAGS: -Dwarnings RUSTDOCFLAGS: -Dwarnings SCCACHE_CACHE_SIZE: "50G" - CRATES_LIST: "iroh,iroh-node-util,iroh-metrics,iroh-net,iroh-net-bench,iroh-test,iroh-dns-server,iroh-router,netwatch,portmapper,iroh-relay,iroh-net-report" + CRATES_LIST: "iroh,iroh-node-util,iroh-metrics,iroh-net-bench,iroh-test,iroh-dns-server,netwatch,portmapper,iroh-relay,iroh-net-report" IROH_FORCE_STAGING_RELAYS: "1" jobs: diff --git a/Cargo.lock b/Cargo.lock index 95227a4017..61844d4dce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2404,17 +2404,93 @@ name = "iroh" version = "0.28.1" dependencies = [ "anyhow", + "axum", + "backoff", + "base64", "bytes", "clap", + "criterion", + "crypto_box", + "der", + "derive_more", + "futures-buffered", + "futures-concurrency", "futures-lite 2.5.0", + "futures-sink", + "futures-util", + "genawaiter", + "governor 0.7.0", + "hex", + "hickory-proto 0.25.0-alpha.2", + "hickory-resolver", + "hostname 0.4.0", + "http 1.1.0", + "http-body-util", + "hyper", + "hyper-util", + "igd-next", "indicatif", + "iroh", "iroh-base", - "iroh-net", - "iroh-router", + "iroh-metrics", + "iroh-net-report", + "iroh-quinn", + "iroh-quinn-proto", + "iroh-quinn-udp", + "iroh-relay", + "iroh-test", + "libc", + "netdev", + "netlink-packet-core", + "netlink-packet-route 0.19.0", + "netlink-packet-route 0.21.0", + "netlink-sys", + "netwatch", + "num_enum", + "once_cell", + "parking_lot", "parse-size", + "pin-project", + "pkarr", + "portmapper", + "postcard", + "pretty_assertions", + "rand", + "rand_chacha", + "rcgen", + "regex", + "reqwest", + "ring", + "rtnetlink 0.13.1", + "rtnetlink 0.14.1", + "rustls", + "rustls-webpki", + "serde", + "serde_json", + "smallvec", + "socket2", + "strum", + "stun-rs", + "surge-ping", + "swarm-discovery", + "testresult", + "thiserror 2.0.3", + "time", "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-tungstenite 0.24.0", + "tokio-tungstenite-wasm", + "tokio-util", "tracing", "tracing-subscriber", + "url", + "watchable", + "webpki-roots", + "windows 0.58.0", + "wmi", + "x509-parser", + "z32", ] [[package]] @@ -2479,8 +2555,8 @@ dependencies = [ "hickory-resolver", "hickory-server", "http 1.1.0", + "iroh", "iroh-metrics", - "iroh-net", "iroh-test", "lru", "parking_lot", @@ -2527,98 +2603,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "iroh-net" -version = "0.28.1" -dependencies = [ - "anyhow", - "axum", - "backoff", - "base64", - "bytes", - "clap", - "criterion", - "crypto_box", - "der", - "derive_more", - "futures-buffered", - "futures-concurrency", - "futures-lite 2.5.0", - "futures-sink", - "futures-util", - "genawaiter", - "governor 0.7.0", - "hex", - "hickory-proto 0.25.0-alpha.2", - "hickory-resolver", - "hostname 0.4.0", - "http 1.1.0", - "http-body-util", - "hyper", - "hyper-util", - "igd-next", - "iroh-base", - "iroh-metrics", - "iroh-net", - "iroh-net-report", - "iroh-quinn", - "iroh-quinn-proto", - "iroh-quinn-udp", - "iroh-relay", - "iroh-test", - "libc", - "netdev", - "netlink-packet-core", - "netlink-packet-route 0.19.0", - "netlink-packet-route 0.21.0", - "netlink-sys", - "netwatch", - "num_enum", - "once_cell", - "parking_lot", - "pin-project", - "pkarr", - "portmapper", - "postcard", - "pretty_assertions", - "rand", - "rand_chacha", - "rcgen", - "regex", - "reqwest", - "ring", - "rtnetlink 0.13.1", - "rtnetlink 0.14.1", - "rustls", - "rustls-webpki", - "serde", - "serde_json", - "smallvec", - "socket2", - "strum", - "stun-rs", - "surge-ping", - "swarm-discovery", - "testresult", - "thiserror 2.0.3", - "time", - "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-tungstenite 0.24.0", - "tokio-tungstenite-wasm", - "tokio-util", - "tracing", - "tracing-subscriber", - "url", - "watchable", - "webpki-roots", - "windows 0.58.0", - "wmi", - "x509-parser", - "z32", -] - [[package]] name = "iroh-net-bench" version = "0.28.0" @@ -2628,8 +2612,8 @@ dependencies = [ "clap", "futures-lite 2.5.0", "hdrhistogram", + "iroh", "iroh-metrics", - "iroh-net", "iroh-quinn", "rcgen", "rustls", @@ -2681,7 +2665,7 @@ dependencies = [ "dirs-next", "futures-lite 2.5.0", "human-time", - "iroh-net", + "iroh", "nested_enum_utils", "quic-rpc", "quic-rpc-derive", @@ -2811,22 +2795,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "iroh-router" -version = "0.28.0" -dependencies = [ - "anyhow", - "clap", - "futures-buffered", - "futures-lite 2.5.0", - "futures-util", - "iroh-net", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber", -] - [[package]] name = "iroh-test" version = "0.28.0" @@ -3861,9 +3829,9 @@ dependencies = [ [[package]] name = "postcard" -version = "1.0.10" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +checksum = "f63d01def49fc815900a83e7a4a5083d2abc81b7ddd569a3fa0477778ae9b3ec" dependencies = [ "cobs", "embedded-io 0.4.0", @@ -4529,9 +4497,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", @@ -4991,9 +4959,9 @@ checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5664,9 +5632,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", diff --git a/Cargo.toml b/Cargo.toml index 2574ed852a..fd102bb875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,12 @@ [workspace] members = [ - "iroh", "iroh-base", "iroh-dns-server", "iroh-metrics", - "iroh-net", + "iroh", "iroh-test", - "iroh-net/bench", + "iroh/bench", "iroh-relay", - "iroh-router", "net-tools/netwatch", "net-tools/portmapper", "iroh-net-report", @@ -50,8 +48,7 @@ unused-async = "warn" # Temporary fix for dependencies [patch.crates-io] +iroh = { path = "./iroh" } iroh-base = { path = "./iroh-base" } -iroh-net = { path = "./iroh-net" } iroh-metrics = { path = "./iroh-metrics" } iroh-test = { path = "./iroh-test" } -iroh-router = { path = "./iroh-router" } diff --git a/README.md b/README.md index 761c93d68a..b6bf10efee 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,7 @@ If you want to use iroh from other languages, make sure to check out [iroh-ffi], ## Repository Structure This repository contains a workspace of crates: -- `iroh`: Re-exports of stables APIs like `iroh-router` and `iroh-net`. -- `iroh-router`: APIs to compose multiple protocols in a node. -- `iroh-net`: The core networking code for hole-punching & connections to relays. +- `iroh`: The core library for hole-punching & communicating with relays. - `iroh-relay`: The relay server implementation. This is the code we run in production (and you can, too!). - `iroh-base`: Common types like `Hash`, key types or `RelayUrl`. - `iroh-metrics`: Helper library for adding metrics support to crates. @@ -140,8 +138,6 @@ This repository contains a workspace of crates: - `iroh-net-report`: Analyzes your host's networking ability & NAT. - `net-tools/*`: Networking utility crates -The main entry point for anyone interested in the inner workings should be `iroh-net`. - ## License Copyright 2024 N0, INC. diff --git a/iroh-base/src/key.rs b/iroh-base/src/key.rs index 84be6c7cb5..c7650e51c5 100644 --- a/iroh-base/src/key.rs +++ b/iroh-base/src/key.rs @@ -1,4 +1,4 @@ -//! Cryptographic key handling for `iroh-net`. +//! Cryptographic key handling for `iroh`. mod encryption; diff --git a/iroh-base/src/node_addr.rs b/iroh-base/src/node_addr.rs index c084f15f55..5929b49e20 100644 --- a/iroh-base/src/node_addr.rs +++ b/iroh-base/src/node_addr.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use crate::key::{NodeId, PublicKey}; pub use crate::relay_url::RelayUrl; -/// Network-level addressing information for an iroh-net node. +/// 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. @@ -34,9 +34,9 @@ pub use crate::relay_url::RelayUrl; /// 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_net/*/iroh_net/index.html#node-discovery -/// [home relay]: https://docs.rs/iroh_net/*/iroh_net/relay/index.html -/// [Relay server]: https://docs.rs/iroh_net/*/iroh_net/index.html#relay-servers +/// [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. @@ -90,7 +90,7 @@ impl 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_net/*/iroh_net/index.html#node-discovery + /// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery pub fn apply_options(&mut self, opts: AddrInfoOptions) { self.info.apply_options(opts); } @@ -125,13 +125,13 @@ impl From for NodeAddr { } } -/// Network paths to contact an iroh-net node. +/// Network paths to contact an iroh node. /// -/// This contains zero or more network paths to establish a connection to an iroh-net 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_net/*/iroh_net/index.html#node-discovery +/// [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. @@ -152,7 +152,7 @@ impl 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_net/*/iroh_net/index.html#node-discovery + /// [discovery]: https://docs.rs/iroh/*/iroh/index.html#node-discovery pub fn apply_options(&mut self, opts: AddrInfoOptions) { match opts { AddrInfoOptions::Id => { diff --git a/iroh-dns-server/Cargo.toml b/iroh-dns-server/Cargo.toml index 06b1f99083..06ddbe29fe 100644 --- a/iroh-dns-server/Cargo.toml +++ b/iroh-dns-server/Cargo.toml @@ -60,7 +60,7 @@ z32 = "1.1.1" [dev-dependencies] hickory-resolver = "=0.25.0-alpha.2" -iroh-net = { version = "0.28.0" } +iroh = { version = "0.28.0" } iroh-test = "0.28.0" pkarr = { version = "2.2.0", features = ["rand"] } diff --git a/iroh-dns-server/examples/convert.rs b/iroh-dns-server/examples/convert.rs index 3015726adf..79173d666b 100644 --- a/iroh-dns-server/examples/convert.rs +++ b/iroh-dns-server/examples/convert.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use clap::Parser; -use iroh_net::NodeId; +use iroh::NodeId; #[derive(Debug, Parser)] struct Cli { diff --git a/iroh-dns-server/examples/publish.rs b/iroh-dns-server/examples/publish.rs index ba059a35ef..d22da284f1 100644 --- a/iroh-dns-server/examples/publish.rs +++ b/iroh-dns-server/examples/publish.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use anyhow::{bail, Result}; use clap::{Parser, ValueEnum}; -use iroh_net::{ +use iroh::{ discovery::{ dns::{N0_DNS_NODE_ORIGIN_PROD, N0_DNS_NODE_ORIGIN_STAGING}, pkarr::{PkarrRelayClient, N0_DNS_PKARR_RELAY_PROD, N0_DNS_PKARR_RELAY_STAGING}, diff --git a/iroh-dns-server/examples/resolve.rs b/iroh-dns-server/examples/resolve.rs index b89f514185..0e10451dca 100644 --- a/iroh-dns-server/examples/resolve.rs +++ b/iroh-dns-server/examples/resolve.rs @@ -5,7 +5,7 @@ use hickory_resolver::{ config::{NameServerConfig, Protocol, ResolverConfig}, AsyncResolver, }; -use iroh_net::{ +use iroh::{ discovery::dns::{N0_DNS_NODE_ORIGIN_PROD, N0_DNS_NODE_ORIGIN_STAGING}, dns::{node_info::TxtAttrs, DnsResolver}, NodeId, @@ -46,11 +46,11 @@ async fn main() -> anyhow::Result<()> { let args = Cli::parse(); let (resolver, origin) = match args.env { Env::Staging => ( - iroh_net::dns::default_resolver().clone(), + iroh::dns::default_resolver().clone(), N0_DNS_NODE_ORIGIN_STAGING, ), Env::Prod => ( - iroh_net::dns::default_resolver().clone(), + iroh::dns::default_resolver().clone(), N0_DNS_NODE_ORIGIN_PROD, ), Env::Dev => ( diff --git a/iroh-dns-server/src/lib.rs b/iroh-dns-server/src/lib.rs index f706314163..d95b68b2a0 100644 --- a/iroh-dns-server/src/lib.rs +++ b/iroh-dns-server/src/lib.rs @@ -20,7 +20,7 @@ mod tests { config::{NameServerConfig, Protocol, ResolverConfig}, AsyncResolver, }; - use iroh_net::{ + use iroh::{ discovery::pkarr::PkarrRelayClient, dns::{node_info::NodeInfo, DnsResolver, ResolverExt}, key::SecretKey, diff --git a/iroh-net-report/src/reportgen.rs b/iroh-net-report/src/reportgen.rs index 307a806777..6ac94a60ff 100644 --- a/iroh-net-report/src/reportgen.rs +++ b/iroh-net-report/src/reportgen.rs @@ -1358,21 +1358,21 @@ mod tests { // // Build the test binary: // - // cargo nextest run -p iroh_net net_report::reportgen::tests --no-run + // 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 net_report::reportgen::tests \ - // | jq '."rust-suites"."iroh-net"."binary-path"' | tr -d \" + // 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_net-abc123 + // sudo setcap CAP_NET_RAW=eip target/debug/deps/iroh-abc123 // // Finally run the test: // - // cargo nextest run -p iroh_net net_report::reportgen::tests + // cargo nextest run -p iroh net_report::reportgen::tests // // This allows the pinger to create a SOCK_RAW socket for IPPROTO_ICMP. // diff --git a/iroh-net/Cargo.toml b/iroh-net/Cargo.toml deleted file mode 100644 index 7e4ed8836c..0000000000 --- a/iroh-net/Cargo.toml +++ /dev/null @@ -1,204 +0,0 @@ -[package] -name = "iroh-net" -version = "0.28.1" -edition = "2021" -readme = "README.md" -description = "networking support for iroh" -license = "MIT OR Apache-2.0" -authors = ["dignifiedquire ", "n0 team"] -repository = "https://github.com/n0-computer/iroh" -keywords = ["quic", "networking", "holepunching", "p2p"] - -# Sadly this also needs to be updated in .github/workflows/ci.yml -rust-version = "1.76" - -[lints] -workspace = true - -[dependencies] -anyhow = { version = "1" } -axum = { version = "0.7", optional = true } -backoff = "0.4.0" -base64 = "0.22.1" -bytes = "1.7" -clap = { version = "4", features = ["derive"], optional = true } -der = { version = "0.7", features = ["alloc", "derive"] } -derive_more = { version = "1.0.0", features = [ - "debug", - "display", - "from", - "try_into", - "deref", -] } -futures-buffered = "0.2.8" -futures-concurrency = "7.6" -futures-lite = "2.5" -futures-sink = "0.3" -futures-util = "0.3" -governor = "0.7.0" -hex = "0.4.3" -hickory-proto = "=0.25.0-alpha.2" -hickory-resolver = "=0.25.0-alpha.2" -hostname = "0.4" -http = "1" -http-body-util = "0.1.0" -hyper = { version = "1", features = ["server", "client", "http1"] } -hyper-util = "0.1.1" -igd-next = { version = "0.15.1", features = ["aio_tokio"] } -iroh-base = { version = "0.28.0", features = ["key"] } -iroh-relay = { version = "0.28", path = "../iroh-relay" } -libc = "0.2.139" -netdev = "0.31.0" -netwatch = { version = "0.1.0", path = "../net-tools/netwatch" } -num_enum = "0.7" -once_cell = "1.18.0" -parking_lot = "0.12.1" -pin-project = "1" -pkarr = { version = "2", default-features = false, features = [ - "async", - "relay", -] } -portmapper = { version = "0.1.0", path = "../net-tools/portmapper" } -postcard = { version = "1", default-features = false, features = [ - "alloc", - "use-std", - "experimental-derive", -] } -quinn = { package = "iroh-quinn", version = "0.12.0" } -quinn-proto = { package = "iroh-quinn-proto", version = "0.12.0" } -quinn-udp = { package = "iroh-quinn-udp", version = "0.5.5" } -rand = "0.8" -rcgen = "0.13" -regex = { version = "1.7.1", optional = true } -reqwest = { version = "0.12", default-features = false, features = [ - "rustls-tls", -] } -ring = "0.17" -rustls = { version = "0.23", default-features = false, features = ["ring"] } -serde = { version = "1", features = ["derive", "rc"] } -smallvec = "1.11.1" -socket2 = "0.5.3" -stun-rs = "0.1.5" -surge-ping = "0.8.0" -thiserror = "2" -time = "0.3.20" -tokio = { version = "1", features = [ - "io-util", - "macros", - "sync", - "rt", - "net", - "fs", - "io-std", - "signal", - "process", -] } -tokio-rustls = { version = "0.26", default-features = false, features = [ - "logging", - "ring", -] } -tokio-stream = { version = "0.1.15" } -tokio-tungstenite = "0.24" -tokio-tungstenite-wasm = "0.3" -tokio-util = { version = "0.7", features = ["io-util", "io", "codec", "rt"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = [ - "env-filter", -], optional = true } -url = { version = "2.5", features = ["serde"] } -watchable = "1.1.2" -webpki = { package = "rustls-webpki", version = "0.102" } -webpki-roots = "0.26" -x509-parser = "0.16" -z32 = "1.0.3" -net-report = { package = "iroh-net-report", path = "../iroh-net-report", version = "0.28" } - -# metrics -iroh-metrics = { version = "0.28.0", default-features = false } -strum = { version = "0.26", features = ["derive"] } - -# local-swarm-discovery -swarm-discovery = { version = "0.2.1", optional = true } - -# dht_discovery -genawaiter = { version = "0.99", features = ["futures03"], optional = true } - -[target.'cfg(all(target_os = "linux", not(target_os = "android")))'.dependencies] -netlink-packet-core = "0.7.0" -netlink-packet-route = "0.21" -netlink-sys = "0.8.6" -rtnetlink = "=0.14.1" # pinned because of https://github.com/rust-netlink/rtnetlink/issues/83 - -[target.'cfg(target_os = "android")'.dependencies] -netlink-packet-core = "0.7.0" -netlink-packet-route = "0.19" # 0.20/21 is blocked on rtnetlink bumping its dependency -netlink-sys = "0.8.6" -rtnetlink = "=0.13.1" # pinned because of https://github.com/rust-netlink/rtnetlink/issues/83 - -[target.'cfg(target_os = "windows")'.dependencies] -wmi = "0.14" -windows = { version = "0.58", features = [ - "Win32_NetworkManagement_IpHelper", - "Win32_Foundation", - "Win32_NetworkManagement_Ndis", - "Win32_Networking_WinSock", -] } - -[dev-dependencies] -axum = { version = "0.7" } -clap = { version = "4", features = ["derive"] } -criterion = "0.5.1" -crypto_box = { version = "0.9.1", features = ["serde", "chacha20"] } -pretty_assertions = "1.4" -rand_chacha = "0.3.1" -tokio = { version = "1", features = [ - "io-util", - "sync", - "rt", - "net", - "fs", - "macros", - "time", - "test-util", -] } -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -iroh-test = "0.28.0" -iroh-net = { path = "." } -serde_json = "1" -testresult = "0.4.0" -iroh-relay = { version = "0.28", path = "../iroh-relay", features = ["test-utils", "server"] } - -[[bench]] -name = "key" -harness = false - -[features] -default = ["metrics", "discovery-pkarr-dht"] -metrics = ["iroh-metrics/metrics"] -test-utils = ["iroh-relay/test-utils", "iroh-relay/server", "dep:axum"] -discovery-local-network = ["dep:swarm-discovery"] -discovery-pkarr-dht = ["pkarr/dht", "dep:genawaiter"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "iroh_docsrs"] - -[[example]] -name = "listen" - -[[example]] -name = "connect" - -[[example]] -name = "listen-unreliable" - -[[example]] -name = "connect-unreliable" - -[[example]] -name = "dht_discovery" -required-features = ["discovery-pkarr-dht"] - -[[example]] -name = "locally-discovered-nodes" -required-features = ["discovery-local-network"] diff --git a/iroh-net/README.md b/iroh-net/README.md deleted file mode 100644 index 2d6faa6f64..0000000000 --- a/iroh-net/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# iroh-net - -This crate contains the networking support for iroh. Iroh networking is built on direct peer-to-peer [QUIC](https://en.wikipedia.org/wiki/QUIC) connections that use relays and holepunching. The main structure for connection is the `Endpoint` entrypoint. - -Peer to peer connectivity is established with the help of a _relay server_. The relay server provides Session Traversal Utilities for NAT [(STUN)](https://en.wikipedia.org/wiki/STUN) for the peers and connection coordination using the [DERP protocol](https://pkg.go.dev/tailscale.com/derp) (Designated Relay for Encrypted Packets protocol). If no direct connection can be established, the connection is relayed via the server. - -Peers must know and do verify the PeerID of each other before they can connect. When using a relay server to aid the connection establishment they will register with a home relay server using their PublicKey. Other peers which can not establish a direct connection can then establish connection via this relay server. This will try to assist establishing a direct connection using STUN and holepunching but continue relaying if not possible. - -Peers can also connect directly without using a relay server. For this, however the listening peer must be directly reachable by the connecting peer via one of it's addresses. - -## Examples - -Examples for `iroh-net` are in `iroh-net/examples`, run them with `cargo run --example $NAME`. Details for each example are in the file/directory itself. - -## Structured Events - -The library uses [tracing](https://docs.rs/tracing) to for logging as -well as for **structured events**. Events are different from normal -logging by convention: - -- The [target] has a prefix of `events` and target names are dot-separated. - - For this library the target will always start with `events.net.`. - -- There is **no message**. - - Each event has a unique [target] which indicates the meaning. - -- The event [fields] are exclusively used for structured data. - -- The [Level] is always `DEBUG`. - -[target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target -[fields]: https://docs.rs/tracing/latest/tracing/#recording-fields -[Level]: https://docs.rs/tracing/latest/tracing/struct.Level.html - -### Using events - -If desired an application can use the `events.*` target to handle -events by a different subscriber. However with the default file -logging it is already easy to search for all events, e.g. using -ripgrep: - -`rg 'events\.[a-z_\-.]+' path/to/iroh/logs/iroh.YYYY-MM-DD-NN.log` - -Which will also highlight the full target name by default on a colour -supporting terminal. - -### Development - -Be cautious about adding new events. Events aim for a high -signal-to-noise ratio. Events should be designed to be able to -extract in an automated way. If multiple events need to be related, -fields with special values can be used. - -To make events distinct from normal logging in the code it is -recommended to write them using the `event!()` macro: - -```rust -event!( - target: "event.net.subject", - Level::DEBUG, - field = value, -); -``` - -# License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this project by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. diff --git a/iroh-net/src/lib.rs b/iroh-net/src/lib.rs deleted file mode 100644 index 478fb69e53..0000000000 --- a/iroh-net/src/lib.rs +++ /dev/null @@ -1,259 +0,0 @@ -//! Peer-to-peer QUIC connections. -//! -//! iroh-net 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-net node is created and controlled by the [`Endpoint`], e.g. connecting to -//! another node: -//! -//! ```no_run -//! # use iroh_net::{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_net::{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-net connection between two iroh-net 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-net 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-net node has a -//! unique [`SecretKey`] used to authenticate and encrypt the connection. When an iroh-net -//! 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-net 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-net nodes are always reachable. They accept -//! **encrypted** traffic for iroh-net 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-net 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-net 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-net 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-net 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. -//! -//!
-//! -//! 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-net 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_net::{Endpoint, NodeAddr}; -//! -//! async fn connect(addr: NodeAddr) -> Result<()> { -//! // The Endpoint is the central object that manages an iroh-net 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(0u8.into(), b"ep closing").await?; -//! println!("Client closed"); -//! Ok(()) -//! } -//! ``` -//! -//! Every [`Endpoint`] can also accept connections: -//! -//! ```no_run -//! use anyhow::{Context, Result}; -//! use futures_lite::StreamExt; -//! use iroh_net::{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(0u8.into(), b"ep closing").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 ticket; -pub mod tls; - -pub(crate) mod util; - -pub use endpoint::{AddrInfo, Endpoint, NodeAddr, RelayMode}; -pub use iroh_base::{ - key, - key::NodeId, - relay_map::{RelayMap, RelayNode, RelayUrl}, -}; -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; diff --git a/iroh-node-util/Cargo.toml b/iroh-node-util/Cargo.toml index 7398b5d7d3..a3df0145cc 100644 --- a/iroh-node-util/Cargo.toml +++ b/iroh-node-util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iroh-node-util" -description = "Utilities to build binaries containing an iroh-net endpoint" +description = "Utilities to build binaries containing an iroh endpoint" readme = "README.md" license = "MIT OR Apache-2.0" version = "0.28.0" @@ -19,7 +19,7 @@ workspace = true anyhow = "1" clap = { version = "4", features = ["derive"], optional = true } tokio = "1" -iroh-net = { path = "../iroh-net" } +iroh = { path = "../iroh" } tempfile = "3" strum = "0.26" nested_enum_utils = "0.1.0" diff --git a/iroh-node-util/README.md b/iroh-node-util/README.md index d045a7a0d2..c1b74200c2 100644 --- a/iroh-node-util/README.md +++ b/iroh-node-util/README.md @@ -1,6 +1,6 @@ # iroh-node-util -This crate provides utilities to build binaries containing an iroh-net endpoint. +This crate provides utilities to build binaries containing an iroh endpoint. # License diff --git a/iroh-node-util/src/cli/net.rs b/iroh-node-util/src/cli/net.rs index 9e004f4208..deedbca1e7 100644 --- a/iroh-node-util/src/cli/net.rs +++ b/iroh-node-util/src/cli/net.rs @@ -7,7 +7,7 @@ use colored::Colorize; use comfy_table::{presets::NOTHING, Cell, Table}; use futures_lite::{Stream, StreamExt}; use human_time::ToHumanTimeString; -use iroh_net::{ +use iroh::{ endpoint::{DirectAddrInfo, RemoteInfo}, NodeAddr, NodeId, RelayUrl, }; diff --git a/iroh-node-util/src/fs.rs b/iroh-node-util/src/fs.rs index a773797085..575ddcead8 100644 --- a/iroh-node-util/src/fs.rs +++ b/iroh-node-util/src/fs.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use anyhow::Context; -use iroh_net::key::SecretKey; +use iroh::key::SecretKey; use tokio::io::AsyncWriteExt; /// Loads a [`SecretKey`] from the provided file, or stores a newly generated one diff --git a/iroh-node-util/src/lib.rs b/iroh-node-util/src/lib.rs index 709b430bad..f8c8853d68 100644 --- a/iroh-node-util/src/lib.rs +++ b/iroh-node-util/src/lib.rs @@ -17,7 +17,7 @@ pub mod fs; use std::path::PathBuf; use anyhow::Context; -use iroh_net::key::SecretKey; +use iroh::key::SecretKey; use tokio::io::AsyncWriteExt; /// Loads a [`SecretKey`] from the provided file, or stores a newly generated one diff --git a/iroh-node-util/src/rpc.rs b/iroh-node-util/src/rpc.rs index 77d1d46cee..359ff66ac6 100644 --- a/iroh-node-util/src/rpc.rs +++ b/iroh-node-util/src/rpc.rs @@ -1,4 +1,4 @@ -//! RPC client, server and protocol to control iroh-net endpoints and iroh nodes +//! RPC client, server and protocol to control iroh endpoints and iroh nodes pub mod client; pub mod proto; pub mod server; diff --git a/iroh-node-util/src/rpc/client/net.rs b/iroh-node-util/src/rpc/client/net.rs index 19438f0d07..cf25c7642e 100644 --- a/iroh-node-util/src/rpc/client/net.rs +++ b/iroh-node-util/src/rpc/client/net.rs @@ -11,7 +11,7 @@ use std::net::SocketAddr; use anyhow::Result; use futures_lite::{Stream, StreamExt}; -use iroh_net::{endpoint::RemoteInfo, relay::RelayUrl, NodeAddr, NodeId}; +use iroh::{endpoint::RemoteInfo, relay::RelayUrl, NodeAddr, NodeId}; use quic_rpc::RpcClient; use serde::{Deserialize, Serialize}; @@ -49,7 +49,7 @@ impl Client { /// This streams a *current snapshot*. It does not keep the stream open after finishing /// transferring the snapshot. /// - /// See also [`Endpoint::remote_info_iter`](iroh_net::Endpoint::remote_info_iter). + /// See also [`Endpoint::remote_info_iter`](iroh::Endpoint::remote_info_iter). pub async fn remote_info_iter(&self) -> Result>> { let stream = self.rpc.server_streaming(RemoteInfosIterRequest {}).await?; Ok(flatten(stream).map(|res| res.map(|res| res.info))) @@ -57,7 +57,7 @@ impl Client { /// Fetches node information about a remote iroh node identified by its [`NodeId`]. /// - /// See also [`Endpoint::remote_info`](iroh_net::Endpoint::remote_info). + /// See also [`Endpoint::remote_info`](iroh::Endpoint::remote_info). pub async fn remote_info(&self, node_id: NodeId) -> Result> { let RemoteInfoResponse { info } = self.rpc.rpc(RemoteInfoRequest { node_id }).await??; Ok(info) @@ -65,7 +65,7 @@ impl Client { /// Fetches the node id of this node. /// - /// See also [`Endpoint::node_id`](iroh_net::Endpoint::node_id). + /// See also [`Endpoint::node_id`](iroh::Endpoint::node_id). pub async fn node_id(&self) -> Result { let id = self.rpc.rpc(IdRequest).await??; Ok(id) @@ -73,7 +73,7 @@ impl Client { /// Fetches the [`NodeAddr`] for this node. /// - /// See also [`Endpoint::node_addr`](iroh_net::Endpoint::node_addr). + /// See also [`Endpoint::node_addr`](iroh::Endpoint::node_addr). pub async fn node_addr(&self) -> Result { let addr = self.rpc.rpc(AddrRequest).await??; Ok(addr) @@ -81,7 +81,7 @@ impl Client { /// Adds a known node address to this node. /// - /// See also [`Endpoint::add_node_addr`](iroh_net::Endpoint::add_node_addr). + /// 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(()) @@ -89,7 +89,7 @@ impl Client { /// Returns the relay server we are connected to. /// - /// See also [`Endpoint::home_relay`](iroh_net::Endpoint::home_relay). + /// See also [`Endpoint::home_relay`](iroh::Endpoint::home_relay). pub async fn home_relay(&self) -> Result> { let relay = self.rpc.rpc(RelayRequest).await??; Ok(relay) diff --git a/iroh-node-util/src/rpc/proto.rs b/iroh-node-util/src/rpc/proto.rs index 88f5b662b5..23ea56af4f 100644 --- a/iroh-node-util/src/rpc/proto.rs +++ b/iroh-node-util/src/rpc/proto.rs @@ -1,4 +1,4 @@ -//! RPC protocol definitions for controlling iroh-net endpoints and iroh nodes +//! RPC protocol definitions for controlling iroh endpoints and iroh nodes use nested_enum_utils::enum_conversions; use serde::{Deserialize, Serialize}; diff --git a/iroh-node-util/src/rpc/proto/net.rs b/iroh-node-util/src/rpc/proto/net.rs index 75d79f6654..790103948e 100644 --- a/iroh-node-util/src/rpc/proto/net.rs +++ b/iroh-node-util/src/rpc/proto/net.rs @@ -1,6 +1,6 @@ -//! RPC calls to control an iroh-net endpoint. +//! RPC calls to control an iroh endpoint. #![allow(missing_docs)] -use iroh_net::{endpoint::RemoteInfo, key::PublicKey, relay::RelayUrl, NodeAddr, NodeId}; +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}; diff --git a/iroh-node-util/src/rpc/server.rs b/iroh-node-util/src/rpc/server.rs index dfdbce0efd..fc7681e671 100644 --- a/iroh-node-util/src/rpc/server.rs +++ b/iroh-node-util/src/rpc/server.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeMap, net::SocketAddr, sync::Arc, time::Duration}; use anyhow::{anyhow, Result}; use futures_lite::{Stream, StreamExt}; -use iroh_net::{Endpoint, NodeAddr, NodeId, RelayUrl}; +use iroh::{Endpoint, NodeAddr, NodeId, RelayUrl}; use quic_rpc::server::{ChannelTypes, RpcChannel, RpcServerError}; use tracing::{debug, info}; diff --git a/iroh-relay/src/defaults.rs b/iroh-relay/src/defaults.rs index f5446f8e02..1c6b48ace9 100644 --- a/iroh-relay/src/defaults.rs +++ b/iroh-relay/src/defaults.rs @@ -15,7 +15,7 @@ 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-net`. +/// Contains all timeouts that we use in `iroh`. pub(crate) mod timeouts { use std::time::Duration; diff --git a/iroh-relay/src/dns.rs b/iroh-relay/src/dns.rs index afd2d1c77e..ffe25af114 100644 --- a/iroh-relay/src/dns.rs +++ b/iroh-relay/src/dns.rs @@ -4,7 +4,7 @@ use anyhow::Result; use hickory_resolver::{AsyncResolver, TokioAsyncResolver}; use once_cell::sync::Lazy; -/// The DNS resolver type used throughout `iroh-net`. +/// The DNS resolver type used throughout `iroh`. pub(crate) type DnsResolver = TokioAsyncResolver; static DNS_RESOLVER: Lazy = diff --git a/iroh-relay/src/main.rs b/iroh-relay/src/main.rs index 94d81f095f..1adda1f69a 100644 --- a/iroh-relay/src/main.rs +++ b/iroh-relay/src/main.rs @@ -1,7 +1,7 @@ -//! A simple relay server for iroh-net. +//! The relay server for iroh. //! //! This handles only the CLI and config file loading, the server implementation lives in -//! [`iroh_net::relay::server`]. +//! [`iroh::relay::server`]. use std::{ net::{Ipv6Addr, SocketAddr}, @@ -22,7 +22,7 @@ use tracing_subscriber::{prelude::*, EnvFilter}; /// The default `http_bind_port` when using `--dev`. const DEV_MODE_HTTP_PORT: u16 = 3340; -/// A relay server for iroh-net. +/// A relay server for iroh. #[derive(Parser, Debug, Clone)] #[clap(version, about, long_about = None)] struct Cli { diff --git a/iroh-router/Cargo.toml b/iroh-router/Cargo.toml deleted file mode 100644 index a0b2a39b92..0000000000 --- a/iroh-router/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "iroh-router" -version = "0.28.0" -edition = "2021" -readme = "README.md" -description = "protocol router support for iroh" -license = "MIT OR Apache-2.0" -authors = ["dignifiedquire ", "n0 team"] -repository = "https://github.com/n0-computer/iroh" -keywords = ["quic", "networking", "holepunching", "p2p"] - - -[dependencies] -anyhow = "1.0.91" -futures-buffered = "0.2.9" -futures-lite = "2.5" -futures-util = "0.3.31" -iroh-net = { version = "0.28.1", path = "../iroh-net" } -tokio = "1" -tokio-util = "0.7" -tracing = "0.1" - -# Examples -clap = { version = "4", features = ["derive"], optional = true } -tracing-subscriber = { version = "0.3", features = ["env-filter"], optional = true } - -[lints] -workspace = true - - -[features] -default = [] -examples = ["dep:clap", "dep:tracing-subscriber"] - -[[example]] -name = "search" -required-features = ["examples"] - -[[example]] -name = "echo" -required-features = ["examples"] diff --git a/iroh-router/README.md b/iroh-router/README.md deleted file mode 100644 index 54639b5f9f..0000000000 --- a/iroh-router/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# iroh-router - -This crate contains the definitions for custom protocols for `iroh`. - -# License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this project by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. diff --git a/iroh-router/src/lib.rs b/iroh-router/src/lib.rs deleted file mode 100644 index 6bdd6cd565..0000000000 --- a/iroh-router/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod protocol; -mod router; - -pub use protocol::{ProtocolHandler, ProtocolMap}; -pub use router::{Router, RouterBuilder}; diff --git a/iroh-router/src/protocol.rs b/iroh-router/src/protocol.rs deleted file mode 100644 index 6ced048992..0000000000 --- a/iroh-router/src/protocol.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::{any::Any, collections::BTreeMap, sync::Arc}; - -use anyhow::Result; -use futures_buffered::join_all; -use futures_lite::future::Boxed as BoxedFuture; -use iroh_net::endpoint::Connecting; - -/// 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::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, conn: Connecting) -> BoxedFuture>; - - /// Called when the node shuts down. - fn shutdown(self: Arc) -> BoxedFuture<()> { - Box::pin(async move {}) - } -} - -/// Helper trait to facilite casting from `Arc` to `Arc`. -/// -/// This trait has a blanket implementation so there is no need to implement this yourself. -pub trait IntoArcAny { - fn into_arc_any(self: Arc) -> Arc; -} - -impl IntoArcAny for T { - fn into_arc_any(self: Arc) -> Arc { - self - } -} - -/// A typed map of protocol handlers, mapping them from ALPNs. -#[derive(Debug, Clone, Default)] -pub struct ProtocolMap(BTreeMap, Arc>); - -impl ProtocolMap { - /// Returns the registered protocol handler for an ALPN as a concrete type. - pub fn get_typed(&self, alpn: &[u8]) -> Option> { - let protocol: Arc = self.0.get(alpn)?.clone(); - let protocol_any: Arc = 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`]. - pub fn get(&self, alpn: &[u8]) -> Option> { - self.0.get(alpn).cloned() - } - - /// Inserts a protocol handler. - pub fn insert(&mut self, alpn: Vec, handler: Arc) { - self.0.insert(alpn, handler); - } - - /// Returns an iterator of all registered ALPN protocol identifiers. - pub fn alpns(&self) -> impl Iterator> { - 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; - } -} diff --git a/iroh/Cargo.toml b/iroh/Cargo.toml index 33c797151c..97007d5aab 100644 --- a/iroh/Cargo.toml +++ b/iroh/Cargo.toml @@ -3,11 +3,11 @@ name = "iroh" version = "0.28.1" edition = "2021" readme = "README.md" -description = "A toolkit for building distributed applications" +description = "p2p quic connections dialed by public key" license = "MIT OR Apache-2.0" authors = ["dignifiedquire ", "n0 team"] repository = "https://github.com/n0-computer/iroh" -keywords = ["networking", "p2p", "holepunching", "ipfs"] +keywords = ["quic", "networking", "holepunching", "p2p"] # Sadly this also needs to be updated in .github/workflows/ci.yml rust-version = "1.76" @@ -16,44 +16,211 @@ rust-version = "1.76" workspace = true [dependencies] +anyhow = { version = "1" } +axum = { version = "0.7", optional = true } +backoff = "0.4.0" +base64 = "0.22.1" +bytes = "1.7" +der = { version = "0.7", features = ["alloc", "derive"] } +derive_more = { version = "1.0.0", features = [ + "debug", + "display", + "from", + "try_into", + "deref", +] } +futures-buffered = "0.2.8" +futures-concurrency = "7.6" +futures-lite = "2.5" +futures-sink = "0.3" +futures-util = "0.3" +governor = "0.7.0" +hex = "0.4.3" +hickory-proto = "=0.25.0-alpha.2" +hickory-resolver = "=0.25.0-alpha.2" +hostname = "0.4" +http = "1" +http-body-util = "0.1.0" +hyper = { version = "1", features = ["server", "client", "http1"] } +hyper-util = "0.1.1" +igd-next = { version = "0.15.1", features = ["aio_tokio"] } iroh-base = { version = "0.28.0", features = ["key"] } -iroh-net = { version = "0.28.1", default-features = false } -iroh-router = { version = "0.28.0" } +iroh-relay = { version = "0.28", path = "../iroh-relay" } +libc = "0.2.139" +netdev = "0.31.0" +netwatch = { version = "0.1.0", path = "../net-tools/netwatch" } +num_enum = "0.7" +once_cell = "1.18.0" +parking_lot = "0.12.1" +pin-project = "1" +pkarr = { version = "2", default-features = false, features = [ + "async", + "relay", +] } +portmapper = { version = "0.1.0", path = "../net-tools/portmapper" } +postcard = { version = "1", default-features = false, features = [ + "alloc", + "use-std", + "experimental-derive", +] } +quinn = { package = "iroh-quinn", version = "0.12.0" } +quinn-proto = { package = "iroh-quinn-proto", version = "0.12.0" } +quinn-udp = { package = "iroh-quinn-udp", version = "0.5.5" } +rand = "0.8" +rcgen = "0.13" +regex = { version = "1.7.1", optional = true } +reqwest = { version = "0.12", default-features = false, features = [ + "rustls-tls", +] } +ring = "0.17" +rustls = { version = "0.23", default-features = false, features = ["ring"] } +serde = { version = "1", features = ["derive", "rc"] } +smallvec = "1.11.1" +socket2 = "0.5.3" +stun-rs = "0.1.5" +surge-ping = "0.8.0" +thiserror = "2" +time = "0.3.20" +tokio = { version = "1", features = [ + "io-util", + "macros", + "sync", + "rt", + "net", + "fs", + "io-std", + "signal", + "process", +] } +tokio-rustls = { version = "0.26", default-features = false, features = [ + "logging", + "ring", +] } +tokio-stream = { version = "0.1.15" } +tokio-tungstenite = "0.24" +tokio-tungstenite-wasm = "0.3" +tokio-util = { version = "0.7", features = ["io-util", "io", "codec", "rt"] } +tracing = "0.1" +url = { version = "2.5", features = ["serde"] } +watchable = "1.1.2" +webpki = { package = "rustls-webpki", version = "0.102" } +webpki-roots = "0.26" +x509-parser = "0.16" +z32 = "1.0.3" +net-report = { package = "iroh-net-report", path = "../iroh-net-report", version = "0.28" } + +# metrics +iroh-metrics = { version = "0.28.0", default-features = false } +strum = { version = "0.26", features = ["derive"] } + +# local-swarm-discovery +swarm-discovery = { version = "0.2.1", optional = true } + +# dht_discovery +genawaiter = { version = "0.99", features = ["futures03"], optional = true } # Examples -anyhow = { version = "1", optional = true } clap = { version = "4", features = ["derive"], optional = true } +tracing-subscriber = { version = "0.3", features = [ + "env-filter", +], optional = true } indicatif = { version = "0.17", features = ["tokio"], optional = true } parse-size = { version = "=1.0.0", optional = true } # pinned version to avoid bumping msrv to 1.81 -tokio = { version = "1", features = ["full"], optional = true } -tracing-subscriber = { version = "0.3", features = ["env-filter"], optional = true } -futures-lite = { version = "2.5", optional = true } -tracing = { version = "0.1", optional = true } -bytes = { version = "1.8", optional = true } +[target.'cfg(all(target_os = "linux", not(target_os = "android")))'.dependencies] +netlink-packet-core = "0.7.0" +netlink-packet-route = "0.21" +netlink-sys = "0.8.6" +rtnetlink = "=0.14.1" # pinned because of https://github.com/rust-netlink/rtnetlink/issues/83 + +[target.'cfg(target_os = "android")'.dependencies] +netlink-packet-core = "0.7.0" +netlink-packet-route = "0.19" # 0.20/21 is blocked on rtnetlink bumping its dependency +netlink-sys = "0.8.6" +rtnetlink = "=0.13.1" # pinned because of https://github.com/rust-netlink/rtnetlink/issues/83 + +[target.'cfg(target_os = "windows")'.dependencies] +wmi = "0.14" +windows = { version = "0.58", features = [ + "Win32_NetworkManagement_IpHelper", + "Win32_Foundation", + "Win32_NetworkManagement_Ndis", + "Win32_Networking_WinSock", +] } + +[dev-dependencies] +axum = { version = "0.7" } +clap = { version = "4", features = ["derive"] } +criterion = "0.5.1" +crypto_box = { version = "0.9.1", features = ["serde", "chacha20"] } +pretty_assertions = "1.4" +rand_chacha = "0.3.1" +tokio = { version = "1", features = [ + "io-util", + "sync", + "rt", + "net", + "fs", + "macros", + "time", + "test-util", +] } +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +iroh-test = "0.28.0" +iroh = { path = "." } +serde_json = "1" +testresult = "0.4.0" +iroh-relay = { version = "0.28", path = "../iroh-relay", features = ["test-utils", "server"] } + +[[bench]] +name = "key" +harness = false [features] default = ["metrics", "discovery-pkarr-dht"] -metrics = ["iroh-net/metrics"] -discovery-local-network = ["iroh-net/discovery-local-network"] -discovery-pkarr-dht = ["iroh-net/discovery-pkarr-dht"] - +metrics = ["iroh-metrics/metrics"] +test-utils = ["iroh-relay/test-utils", "iroh-relay/server", "dep:axum"] +discovery-local-network = ["dep:swarm-discovery"] +discovery-pkarr-dht = ["pkarr/dht", "dep:genawaiter"] examples = [ - "dep:anyhow", - "dep:clap", - "dep:indicatif", - "dep:parse-size", - "dep:tokio", - "dep:tracing-subscriber", - "dep:futures-lite", - "dep:tracing", - "dep:bytes", + "dep:clap", + "dep:tracing-subscriber", + "dep:indicatif", + "dep:parse-size", ] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "iroh_docsrs"] +[[example]] +name = "listen" + +[[example]] +name = "connect" + +[[example]] +name = "listen-unreliable" + +[[example]] +name = "connect-unreliable" + +[[example]] +name = "dht_discovery" +required-features = ["discovery-pkarr-dht"] + +[[example]] +name = "locally-discovered-nodes" +required-features = ["discovery-local-network"] + +[[example]] +name = "search" +required-features = ["examples"] + +[[example]] +name = "echo" +required-features = ["examples"] + [[example]] name = "transfer" required-features = ["examples"] diff --git a/iroh-net/LICENSE-BSD3 b/iroh/LICENSE-BSD3 similarity index 100% rename from iroh-net/LICENSE-BSD3 rename to iroh/LICENSE-BSD3 diff --git a/iroh/README.md b/iroh/README.md index c725f3c4de..1f851222e7 100644 --- a/iroh/README.md +++ b/iroh/README.md @@ -1,25 +1,70 @@ # iroh -The iroh crate defines both the `iroh` library and `iroh` command-line interface (CLI). +Iroh is a library to establish direct connectivity between peers. +It's built on peer-to-peer [QUIC](https://en.wikipedia.org/wiki/QUIC) using both relays and holepunching. +The main structure for connection is the `Endpoint` entrypoint. -For more details on Iroh, see https://iroh.computer. +Peer to peer connectivity is established with the help of a _relay server_. The relay server provides Session Traversal Utilities for NAT [(STUN)](https://en.wikipedia.org/wiki/STUN) for the peers. If no direct connection can be established, the connection is relayed via the server. -## Building the CLI +Peers must know and do verify the PeerID of each other before they can connect. When using a relay server to aid the connection establishment they will register with a home relay server using their PublicKey. Other peers which can not establish a direct connection can then establish connection via this relay server. This will try to assist establishing a direct connection using STUN and holepunching but continue relaying if not possible. -Simply run `cargo build` from the project root, it produces the `iroh` CLI by default. +Peers can also connect directly without using a relay server. For this, however the listening peer must be directly reachable by the connecting peer via one of it's addresses. -## Using as a rust crate +## Examples -Because iroh builds the CLI by default, you should disable `default-features` when importing the `iroh` crate via cargo: +Examples for `iroh` are in `iroh/examples`, run them with `cargo run --example $NAME`. Details for each example are in the file/directory itself. -```toml -[dependencies] -iroh = { version = "...", default-features = false } -``` +## Structured Events + +The library uses [tracing](https://docs.rs/tracing) to for logging as +well as for **structured events**. Events are different from normal +logging by convention: + +- The [target] has a prefix of `events` and target names are dot-separated. + + For this library the target will always start with `events.net.`. + +- There is **no message**. + + Each event has a unique [target] which indicates the meaning. + +- The event [fields] are exclusively used for structured data. + +- The [Level] is always `DEBUG`. -## Running Examples +[target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target +[fields]: https://docs.rs/tracing/latest/tracing/#recording-fields +[Level]: https://docs.rs/tracing/latest/tracing/struct.Level.html -Examples are located in `iroh/examples`. Run them with `cargo run --features=examples --example`. eg: `cargo run --features=examples --example hello-world`. At the top of each example file is a comment describing how to run the example. +### Using events + +If desired an application can use the `events.*` target to handle +events by a different subscriber. However with the default file +logging it is already easy to search for all events, e.g. using +ripgrep: + +`rg 'events\.[a-z_\-.]+' path/to/iroh/logs/iroh.YYYY-MM-DD-NN.log` + +Which will also highlight the full target name by default on a colour +supporting terminal. + +### Development + +Be cautious about adding new events. Events aim for a high +signal-to-noise ratio. Events should be designed to be able to +extract in an automated way. If multiple events need to be related, +fields with special values can be used. + +To make events distinct from normal logging in the code it is +recommended to write them using the `event!()` macro: + +```rust +event!( + target: "event.net.subject", + Level::DEBUG, + field = value, +); +``` # License diff --git a/iroh-net/bench/Cargo.toml b/iroh/bench/Cargo.toml similarity index 92% rename from iroh-net/bench/Cargo.toml rename to iroh/bench/Cargo.toml index 6c9d609241..72268a5b17 100644 --- a/iroh-net/bench/Cargo.toml +++ b/iroh/bench/Cargo.toml @@ -9,7 +9,7 @@ publish = false anyhow = "1.0.22" bytes = "1.7" hdrhistogram = { version = "7.2", default-features = false } -iroh-net = { path = ".." } +iroh = { path = ".." } iroh-metrics = { path = "../../iroh-metrics" } quinn = { package = "iroh-quinn", version = "0.12" } rcgen = "0.13" @@ -29,4 +29,4 @@ futures-lite = "2.5" [features] default = [] -local-relay = ["iroh-net/test-utils"] +local-relay = ["iroh/test-utils"] diff --git a/iroh-net/bench/src/bin/bulk.rs b/iroh/bench/src/bin/bulk.rs similarity index 89% rename from iroh-net/bench/src/bin/bulk.rs rename to iroh/bench/src/bin/bulk.rs index 83f039439d..d28215ba93 100644 --- a/iroh-net/bench/src/bin/bulk.rs +++ b/iroh/bench/src/bin/bulk.rs @@ -35,12 +35,12 @@ pub fn run_iroh(opt: Opt) -> Result<()> { // enable recording metrics iroh_metrics::core::Core::try_init(|reg, metrics| { use iroh_metrics::core::Metric; - metrics.insert(iroh_net::metrics::MagicsockMetrics::new(reg)); - metrics.insert(iroh_net::metrics::NetReportMetrics::new(reg)); - metrics.insert(iroh_net::metrics::PortmapMetrics::new(reg)); + 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_net::metrics::RelayMetrics::new(reg)); + metrics.insert(::iroh::metrics::RelayMetrics::new(reg)); } })?; } @@ -57,7 +57,7 @@ pub fn run_iroh(opt: Opt) -> Result<()> { #[cfg(feature = "local-relay")] let (relay_url, _guard) = if opt.with_relay { - let (_, relay_url, _guard) = runtime.block_on(iroh_net::test_utils::run_relay_server())?; + let (_, relay_url, _guard) = runtime.block_on(::iroh::test_utils::run_relay_server())?; (Some(relay_url), Some(_guard)) } else { @@ -110,21 +110,21 @@ pub fn run_iroh(opt: Opt) -> Result<()> { println!("\nMetrics:"); collect_and_print( "MagicsockMetrics", - core.get_collector::(), + core.get_collector::<::iroh::metrics::MagicsockMetrics>(), ); collect_and_print( "NetReportMetrics", - core.get_collector::(), + core.get_collector::<::iroh::metrics::NetReportMetrics>(), ); collect_and_print( "PortmapMetrics", - core.get_collector::(), + 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::(), + core.get_collector::<::iroh::metrics::RelayMetrics>(), ); } diff --git a/iroh-net/bench/src/iroh.rs b/iroh/bench/src/iroh.rs similarity index 99% rename from iroh-net/bench/src/iroh.rs rename to iroh/bench/src/iroh.rs index 702d8dc3f8..063a59bd63 100644 --- a/iroh-net/bench/src/iroh.rs +++ b/iroh/bench/src/iroh.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{Context, Result}; use bytes::Bytes; use futures_lite::StreamExt as _; -use iroh_net::{ +use iroh::{ endpoint::{Connection, ConnectionError, RecvStream, SendStream, TransportConfig}, Endpoint, NodeAddr, RelayMap, RelayMode, RelayUrl, }; diff --git a/iroh-net/bench/src/lib.rs b/iroh/bench/src/lib.rs similarity index 98% rename from iroh-net/bench/src/lib.rs rename to iroh/bench/src/lib.rs index 93e0c91e51..ce890e257b 100644 --- a/iroh-net/bench/src/lib.rs +++ b/iroh/bench/src/lib.rs @@ -56,7 +56,7 @@ pub struct Opt { /// Show connection stats the at the end of the benchmark #[clap(long = "stats")] pub stats: bool, - /// Show iroh-net library counter metrics at the end of the benchmark + /// 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. @@ -78,7 +78,7 @@ pub struct Opt { } pub enum EndpointSelector { - Iroh(iroh_net::Endpoint), + Iroh(::iroh::Endpoint), #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Quinn(::quinn::Endpoint), } @@ -99,7 +99,7 @@ impl EndpointSelector { } pub enum ConnectionSelector { - Iroh(iroh_net::endpoint::Connection), + Iroh(::iroh::endpoint::Connection), #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Quinn(::quinn::Connection), } diff --git a/iroh-net/bench/src/quinn.rs b/iroh/bench/src/quinn.rs similarity index 96% rename from iroh-net/bench/src/quinn.rs rename to iroh/bench/src/quinn.rs index fb579bf0f0..8fdca46069 100644 --- a/iroh-net/bench/src/quinn.rs +++ b/iroh/bench/src/quinn.rs @@ -14,15 +14,14 @@ use crate::{ client_handler, stats::TransferResult, ClientStats, ConnectionSelector, EndpointSelector, Opt, }; -/// Derived from the iroh-net udp SOCKET_BUFFER_SIZE +/// 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_net::key::SecretKey::generate(); - let crypto = - iroh_net::tls::make_server_config(&secret_key, vec![ALPN.to_vec()], false).unwrap(); + 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); @@ -67,9 +66,9 @@ pub async fn connect_client( server_addr: SocketAddr, opt: Opt, ) -> Result<(::quinn::Endpoint, Connection)> { - let secret_key = iroh_net::key::SecretKey::generate(); + let secret_key = iroh::key::SecretKey::generate(); let quic_client_config = - iroh_net::tls::make_client_config(&secret_key, None, vec![ALPN.to_vec()], false)?; + 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); diff --git a/iroh-net/bench/src/s2n.rs b/iroh/bench/src/s2n.rs similarity index 100% rename from iroh-net/bench/src/s2n.rs rename to iroh/bench/src/s2n.rs diff --git a/iroh-net/bench/src/stats.rs b/iroh/bench/src/stats.rs similarity index 100% rename from iroh-net/bench/src/stats.rs rename to iroh/bench/src/stats.rs diff --git a/iroh-net/benches/key.rs b/iroh/benches/key.rs similarity index 99% rename from iroh-net/benches/key.rs rename to iroh/benches/key.rs index 091984d032..f208efd612 100644 --- a/iroh-net/benches/key.rs +++ b/iroh/benches/key.rs @@ -1,6 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use crypto_box::aead::{AeadCore, AeadInPlace, OsRng}; -use iroh_net::key::SecretKey; +use iroh::key::SecretKey; use rand::RngCore; pub fn seal_to(c: &mut Criterion) { diff --git a/iroh-net/docs/local_relay_node.md b/iroh/docs/local_relay_node.md similarity index 100% rename from iroh-net/docs/local_relay_node.md rename to iroh/docs/local_relay_node.md diff --git a/iroh-net/docs/relay_nodes.md b/iroh/docs/relay_nodes.md similarity index 100% rename from iroh-net/docs/relay_nodes.md rename to iroh/docs/relay_nodes.md diff --git a/iroh-net/examples/connect-unreliable.rs b/iroh/examples/connect-unreliable.rs similarity index 89% rename from iroh-net/examples/connect-unreliable.rs rename to iroh/examples/connect-unreliable.rs index 188d4b0365..eb2d46a235 100644 --- a/iroh-net/examples/connect-unreliable.rs +++ b/iroh/examples/connect-unreliable.rs @@ -1,16 +1,16 @@ -//! The smallest example showing how to use iroh-net and [`iroh_net::Endpoint`] to connect to a remote node and pass bytes using unreliable datagrams. +//! The smallest example showing how to use iroh and [`iroh::Endpoint`] to connect to a remote node and pass bytes using unreliable datagrams. //! //! We use the node ID (the PublicKey of the remote node), the direct UDP addresses, and the relay url to achieve a connection. //! //! This example uses the default relay servers to attempt to holepunch, and will use that relay server to relay packets if the two devices cannot establish a direct UDP connection. //! -//! Run the `listen-unreliable` example first (`iroh-net/examples/listen-unreliable.rs`), which will give you instructions on how to run this example to watch two nodes connect and exchange bytes. +//! Run the `listen-unreliable` example first (`iroh/examples/listen-unreliable.rs`), which will give you instructions on how to run this example to watch two nodes connect and exchange bytes. use std::net::SocketAddr; use anyhow::Context; use clap::Parser; use futures_lite::StreamExt; -use iroh_net::{key::SecretKey, Endpoint, NodeAddr, RelayMode, RelayUrl}; +use iroh::{key::SecretKey, Endpoint, NodeAddr, RelayMode, RelayUrl}; use tracing::info; // An example ALPN that we are using to communicate over the `Endpoint` @@ -20,7 +20,7 @@ const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/magic/0"; struct Cli { /// The id of the remote node. #[clap(long)] - node_id: iroh_net::NodeId, + node_id: iroh::NodeId, /// The list of direct UDP addresses for the remote node. #[clap(long, value_parser, num_args = 1.., value_delimiter = ' ')] addrs: Vec, diff --git a/iroh-net/examples/connect.rs b/iroh/examples/connect.rs similarity index 91% rename from iroh-net/examples/connect.rs rename to iroh/examples/connect.rs index b20a12289e..01fd710fbb 100644 --- a/iroh-net/examples/connect.rs +++ b/iroh/examples/connect.rs @@ -1,16 +1,16 @@ -//! The smallest example showing how to use iroh-net and [`iroh_net::Endpoint`] to connect to a remote node. +//! The smallest example showing how to use iroh and [`iroh::Endpoint`] to connect to a remote node. //! //! We use the node ID (the PublicKey of the remote node), the direct UDP addresses, and the relay url to achieve a connection. //! //! This example uses the default relay servers to attempt to holepunch, and will use that relay server to relay packets if the two devices cannot establish a direct UDP connection. //! -//! Run the `listen` example first (`iroh-net/examples/listen.rs`), which will give you instructions on how to run this example to watch two nodes connect and exchange bytes. +//! Run the `listen` example first (`iroh/examples/listen.rs`), which will give you instructions on how to run this example to watch two nodes connect and exchange bytes. use std::net::SocketAddr; use anyhow::Context; use clap::Parser; use futures_lite::StreamExt; -use iroh_net::{key::SecretKey, Endpoint, NodeAddr, RelayMode, RelayUrl}; +use iroh::{key::SecretKey, Endpoint, NodeAddr, RelayMode, RelayUrl}; use tracing::info; // An example ALPN that we are using to communicate over the `Endpoint` @@ -20,7 +20,7 @@ const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/magic/0"; struct Cli { /// The id of the remote node. #[clap(long)] - node_id: iroh_net::NodeId, + node_id: iroh::NodeId, /// The list of direct UDP addresses for the remote node. #[clap(long, value_parser, num_args = 1.., value_delimiter = ' ')] addrs: Vec, diff --git a/iroh-net/examples/dht_discovery.rs b/iroh/examples/dht_discovery.rs similarity index 91% rename from iroh-net/examples/dht_discovery.rs rename to iroh/examples/dht_discovery.rs index bb7eecfdb7..ffe4b542dd 100644 --- a/iroh-net/examples/dht_discovery.rs +++ b/iroh/examples/dht_discovery.rs @@ -1,4 +1,4 @@ -//! An example chat application using the iroh-net endpoint and +//! An example chat application using the iroh endpoint and //! pkarr node discovery. //! //! Starting the example without args creates a server that publishes its @@ -11,7 +11,7 @@ use std::str::FromStr; use clap::Parser; -use iroh_net::{endpoint::get_remote_node_id, Endpoint, NodeId}; +use iroh::{endpoint::get_remote_node_id, Endpoint, NodeId}; use tracing::warn; use url::Url; @@ -51,8 +51,8 @@ impl FromStr for PkarrRelay { } } -fn build_discovery(args: Args) -> iroh_net::discovery::pkarr::dht::Builder { - let builder = iroh_net::discovery::pkarr::dht::DhtDiscovery::builder().dht(!args.disable_dht); +fn build_discovery(args: Args) -> iroh::discovery::pkarr::dht::Builder { + let builder = iroh::discovery::pkarr::dht::DhtDiscovery::builder().dht(!args.disable_dht); match args.pkarr_relay { PkarrRelay::Disabled => builder, PkarrRelay::Iroh => builder.n0_dns_pkarr_relay(), @@ -61,7 +61,7 @@ fn build_discovery(args: Args) -> iroh_net::discovery::pkarr::dht::Builder { } async fn chat_server(args: Args) -> anyhow::Result<()> { - let secret_key = iroh_net::key::SecretKey::generate(); + let secret_key = iroh::key::SecretKey::generate(); let node_id = secret_key.public(); let discovery = build_discovery(args) .secret_key(secret_key.clone()) @@ -107,7 +107,7 @@ async fn chat_server(args: Args) -> anyhow::Result<()> { async fn chat_client(args: Args) -> anyhow::Result<()> { let remote_node_id = args.node_id.unwrap(); - let secret_key = iroh_net::key::SecretKey::generate(); + let secret_key = iroh::key::SecretKey::generate(); let node_id = secret_key.public(); // note: we don't pass a secret key here, because we don't need to publish our address, don't spam the DHT let discovery = build_discovery(args).build()?; diff --git a/iroh-router/examples/echo.rs b/iroh/examples/echo.rs similarity index 94% rename from iroh-router/examples/echo.rs rename to iroh/examples/echo.rs index 1ace2cc628..d8bef70698 100644 --- a/iroh-router/examples/echo.rs +++ b/iroh/examples/echo.rs @@ -10,8 +10,11 @@ use std::sync::Arc; use anyhow::Result; use futures_lite::future::Boxed as BoxedFuture; -use iroh_net::{endpoint::Connecting, Endpoint, NodeAddr}; -use iroh_router::{ProtocolHandler, Router}; +use iroh::{ + endpoint::Connecting, + protocol::{ProtocolHandler, Router}, + Endpoint, NodeAddr, +}; /// Each protocol is identified by its ALPN string. /// @@ -82,7 +85,7 @@ impl ProtocolHandler for Echo { // Wait for the connection to be fully established. let connection = connecting.await?; // We can get the remote's node id from the connection. - let node_id = iroh_net::endpoint::get_remote_node_id(&connection)?; + let node_id = iroh::endpoint::get_remote_node_id(&connection)?; println!("accepted connection from {node_id}"); // Our protocol is a simple request-response protocol, so we expect the diff --git a/iroh-net/examples/listen-unreliable.rs b/iroh/examples/listen-unreliable.rs similarity index 94% rename from iroh-net/examples/listen-unreliable.rs rename to iroh/examples/listen-unreliable.rs index a963d44554..6f38827e52 100644 --- a/iroh-net/examples/listen-unreliable.rs +++ b/iroh/examples/listen-unreliable.rs @@ -1,11 +1,11 @@ -//! The smallest example showing how to use iroh-net and [`iroh_net::Endpoint`] to connect two devices and pass bytes using unreliable datagrams. +//! The smallest example showing how to use iroh and [`iroh::Endpoint`] to connect two devices and pass bytes using unreliable datagrams. //! //! This example uses the default relay servers to attempt to holepunch, and will use that relay server to relay packets if the two devices cannot establish a direct UDP connection. //! run this example from the project root: //! $ cargo run --example listen-unreliable use anyhow::Context; use futures_lite::StreamExt; -use iroh_net::{key::SecretKey, Endpoint, RelayMode}; +use iroh::{key::SecretKey, Endpoint, RelayMode}; use tracing::{info, warn}; // An example ALPN that we are using to communicate over the `Endpoint` @@ -74,7 +74,7 @@ async fn main() -> anyhow::Result<()> { }; let alpn = connecting.alpn().await?; let conn = connecting.await?; - let node_id = iroh_net::endpoint::get_remote_node_id(&conn)?; + let node_id = iroh::endpoint::get_remote_node_id(&conn)?; info!( "new (unreliable) connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(&alpn), diff --git a/iroh-net/examples/listen.rs b/iroh/examples/listen.rs similarity index 95% rename from iroh-net/examples/listen.rs rename to iroh/examples/listen.rs index e0c2f25f80..a27b5f3067 100644 --- a/iroh-net/examples/listen.rs +++ b/iroh/examples/listen.rs @@ -1,4 +1,4 @@ -//! The smallest example showing how to use iroh-net and [`iroh_net::Endpoint`] to connect two devices. +//! The smallest example showing how to use iroh and [`iroh::Endpoint`] to connect two devices. //! //! This example uses the default relay servers to attempt to holepunch, and will use that relay server to relay packets if the two devices cannot establish a direct UDP connection. //! run this example from the project root: @@ -7,7 +7,7 @@ use std::time::Duration; use anyhow::Context; use futures_lite::StreamExt; -use iroh_net::{endpoint::ConnectionError, key::SecretKey, Endpoint, RelayMode}; +use iroh::{endpoint::ConnectionError, key::SecretKey, Endpoint, RelayMode}; use tracing::{debug, info, warn}; // An example ALPN that we are using to communicate over the `Endpoint` @@ -75,7 +75,7 @@ async fn main() -> anyhow::Result<()> { }; let alpn = connecting.alpn().await?; let conn = connecting.await?; - let node_id = iroh_net::endpoint::get_remote_node_id(&conn)?; + let node_id = iroh::endpoint::get_remote_node_id(&conn)?; info!( "new connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(&alpn), diff --git a/iroh-net/examples/locally-discovered-nodes.rs b/iroh/examples/locally-discovered-nodes.rs similarity index 84% rename from iroh-net/examples/locally-discovered-nodes.rs rename to iroh/examples/locally-discovered-nodes.rs index a2217adfe8..45c9b924e4 100644 --- a/iroh-net/examples/locally-discovered-nodes.rs +++ b/iroh/examples/locally-discovered-nodes.rs @@ -1,11 +1,11 @@ -//! A small example showing how to get a list of nodes that were discovered via [`iroh_net::discovery::LocalSwarmDiscovery`]. LocalSwarmDiscovery uses [`swarm-discovery`](https://crates.io/crates/swarm-discovery) to discover other nodes in the local network ala mDNS. +//! A small example showing how to get a list of nodes that were discovered via [`iroh::discovery::LocalSwarmDiscovery`]. LocalSwarmDiscovery uses [`swarm-discovery`](https://crates.io/crates/swarm-discovery) to discover other nodes in the local network ala mDNS. //! -//! This example creates an iroh endpoint, a few additional iroh endpoints to discover, waits a few seconds, and reports all of the iroh NodeIds (also called `[iroh_net::key::PublicKey]`s) it has discovered. +//! This example creates an iroh endpoint, a few additional iroh endpoints to discover, waits a few seconds, and reports all of the iroh NodeIds (also called `[iroh::key::PublicKey]`s) it has discovered. //! //! This is an async, non-determinate process, so the number of NodeIDs discovered each time may be different. If you have other iroh endpoints or iroh nodes with [`LocalSwarmDiscovery`] enabled, it may discover those nodes as well. use std::time::Duration; -use iroh_net::{ +use iroh::{ discovery::local_swarm_discovery::LocalSwarmDiscovery, endpoint::Source, key::SecretKey, Endpoint, }; @@ -45,7 +45,7 @@ async fn main() -> anyhow::Result<()> { // get an iterator of all the remote nodes this endpoint knows about let remotes = ep.remote_info_iter(); // filter that list down to the nodes that have a `Source::Discovery` with - // the `service` name [`iroh_net::discovery::local_swarm_discovery::NAME`] + // the `service` name [`iroh::discovery::local_swarm_discovery::NAME`] // If you have a long running node and want to only get the nodes that were // discovered recently, you can also filter on the `Duration` of the source, // which indicates how long ago we got information from that source. @@ -53,7 +53,7 @@ async fn main() -> anyhow::Result<()> { .filter(|remote| { remote.sources().iter().any(|(source, _duration)| { if let Source::Discovery { name } = source { - name == iroh_net::discovery::local_swarm_discovery::NAME + name == iroh::discovery::local_swarm_discovery::NAME } else { false } diff --git a/iroh-router/examples/search.rs b/iroh/examples/search.rs similarity index 99% rename from iroh-router/examples/search.rs rename to iroh/examples/search.rs index 9d281ff16e..d707766734 100644 --- a/iroh-router/examples/search.rs +++ b/iroh/examples/search.rs @@ -34,11 +34,11 @@ use std::{collections::BTreeSet, sync::Arc}; use anyhow::Result; use clap::Parser; use futures_lite::future::Boxed as BoxedFuture; -use iroh_net::{ +use iroh::{ endpoint::{get_remote_node_id, Connecting}, + protocol::{ProtocolHandler, Router}, Endpoint, NodeId, }; -use iroh_router::{ProtocolHandler, Router}; use tokio::sync::Mutex; use tracing_subscriber::{prelude::*, EnvFilter}; diff --git a/iroh/examples/transfer.rs b/iroh/examples/transfer.rs index c1ca5c90e2..45aec76ebe 100644 --- a/iroh/examples/transfer.rs +++ b/iroh/examples/transfer.rs @@ -8,12 +8,11 @@ use bytes::Bytes; use clap::{Parser, Subcommand}; use futures_lite::StreamExt; use indicatif::HumanBytes; -use iroh_net::{ +use iroh::{ endpoint::ConnectionError, key::SecretKey, ticket::NodeTicket, Endpoint, NodeAddr, RelayMap, RelayMode, RelayUrl, }; use tracing::info; - // Transfer ALPN that we are using to communicate over the `Endpoint` const TRANSFER_ALPN: &[u8] = b"n0/iroh/transfer/example/0"; @@ -110,7 +109,7 @@ async fn provide(size: u64, relay_url: Option) -> anyhow::Result<()> { } }; let conn = connecting.await?; - let node_id = iroh_net::endpoint::get_remote_node_id(&conn)?; + let node_id = iroh::endpoint::get_remote_node_id(&conn)?; info!( "new connection from {node_id} with ALPN {} (coming from {})", String::from_utf8_lossy(TRANSFER_ALPN), @@ -233,7 +232,7 @@ async fn fetch(ticket: &str, relay_url: Option) -> anyhow::Result<()> { } async fn drain_stream( - stream: &mut iroh_net::endpoint::RecvStream, + stream: &mut iroh::endpoint::RecvStream, read_unordered: bool, ) -> Result<(usize, Duration, u64)> { let mut read = 0; @@ -281,7 +280,7 @@ async fn drain_stream( } async fn send_data_on_stream( - stream: &mut iroh_net::endpoint::SendStream, + stream: &mut iroh::endpoint::SendStream, stream_size: u64, ) -> Result<()> { const DATA: &[u8] = &[0xAB; 1024 * 1024]; diff --git a/iroh-net/src/defaults.rs b/iroh/src/defaults.rs similarity index 97% rename from iroh-net/src/defaults.rs rename to iroh/src/defaults.rs index 799dc078f3..b4650eaf68 100644 --- a/iroh-net/src/defaults.rs +++ b/iroh/src/defaults.rs @@ -1,4 +1,4 @@ -//! Default values used in [`iroh-net`][`crate`] +//! Default values used in [`iroh`][`crate`] use url::Url; @@ -126,7 +126,7 @@ pub mod staging { } } -/// Contains all timeouts that we use in `iroh-net`. +/// Contains all timeouts that we use in `iroh`. pub(crate) mod timeouts { use std::time::Duration; diff --git a/iroh-net/src/dialer.rs b/iroh/src/dialer.rs similarity index 100% rename from iroh-net/src/dialer.rs rename to iroh/src/dialer.rs diff --git a/iroh-net/src/disco.rs b/iroh/src/disco.rs similarity index 100% rename from iroh-net/src/disco.rs rename to iroh/src/disco.rs diff --git a/iroh-net/src/discovery.rs b/iroh/src/discovery.rs similarity index 98% rename from iroh-net/src/discovery.rs rename to iroh/src/discovery.rs index d05e07eb13..450bd60f6d 100644 --- a/iroh-net/src/discovery.rs +++ b/iroh/src/discovery.rs @@ -1,6 +1,6 @@ //! Node address discovery. //! -//! To connect to an iroh-net node a [`NodeAddr`] is needed, which may contain a +//! 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 @@ -11,7 +11,7 @@ //! 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-net node will automatically publish their own 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. //! @@ -31,7 +31,7 @@ //! - The [`PkarrResolver`] which can perform lookups from designated [pkarr relay servers] //! using HTTP. //! -//! - The [`LocalSwarmDiscovery`] discovers iroh-net nodes present on the local network, +//! - The [`LocalSwarmDiscovery`] discovers iroh nodes present on the local network, //! very similar to mdNS. //! //! - The [`DhtDiscovery`] also uses the [`pkarr`] system but can also publish and lookup @@ -46,7 +46,7 @@ //! [`PkarrPublisher`] and [`DnsDiscovery`]: //! //! ```no_run -//! use iroh_net::{ +//! use iroh::{ //! discovery::{dns::DnsDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery}, //! key::SecretKey, //! Endpoint, @@ -71,11 +71,11 @@ //! [`ConcurrentDiscovery`]: //! //! ```no_run -//! # use iroh_net::discovery::dns::DnsDiscovery; -//! # use iroh_net::discovery::local_swarm_discovery::LocalSwarmDiscovery; -//! # use iroh_net::discovery::pkarr::PkarrPublisher; -//! # use iroh_net::discovery::ConcurrentDiscovery; -//! # use iroh_net::key::SecretKey; +//! # 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(); diff --git a/iroh-net/src/discovery/dns.rs b/iroh/src/discovery/dns.rs similarity index 98% rename from iroh-net/src/discovery/dns.rs rename to iroh/src/discovery/dns.rs index 1d5d74d4ba..85d9ed58e0 100644 --- a/iroh-net/src/discovery/dns.rs +++ b/iroh/src/discovery/dns.rs @@ -1,4 +1,4 @@ -//! DNS node discovery for iroh-net +//! DNS node discovery for iroh use anyhow::Result; use futures_lite::stream::Boxed as BoxStream; diff --git a/iroh-net/src/discovery/local_swarm_discovery.rs b/iroh/src/discovery/local_swarm_discovery.rs similarity index 99% rename from iroh-net/src/discovery/local_swarm_discovery.rs rename to iroh/src/discovery/local_swarm_discovery.rs index 6d7dc79110..753848b212 100644 --- a/iroh-net/src/discovery/local_swarm_discovery.rs +++ b/iroh/src/discovery/local_swarm_discovery.rs @@ -8,7 +8,7 @@ //! ``` //! use std::time::Duration; //! -//! use iroh_net::endpoint::{Endpoint, Source}; +//! use iroh::endpoint::{Endpoint, Source}; //! //! #[tokio::main] //! async fn main() { @@ -20,8 +20,7 @@ //! .filter(|remote| { //! remote.sources().iter().any(|(source, duration)| { //! if let Source::Discovery { name } = source { -//! name == iroh_net::discovery::local_swarm_discovery::NAME -//! && *duration <= recent +//! name == iroh::discovery::local_swarm_discovery::NAME && *duration <= recent //! } else { //! false //! } diff --git a/iroh-net/src/discovery/pkarr.rs b/iroh/src/discovery/pkarr.rs similarity index 99% rename from iroh-net/src/discovery/pkarr.rs rename to iroh/src/discovery/pkarr.rs index c53904d483..c5aef5c619 100644 --- a/iroh-net/src/discovery/pkarr.rs +++ b/iroh/src/discovery/pkarr.rs @@ -19,9 +19,9 @@ //! 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-net the pkarr Resource Records contain the [`AddrInfo`] +//! 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-net node. +//! 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: diff --git a/iroh-net/src/discovery/pkarr/dht.rs b/iroh/src/discovery/pkarr/dht.rs similarity index 98% rename from iroh-net/src/discovery/pkarr/dht.rs rename to iroh/src/discovery/pkarr/dht.rs index 9e7db71065..209e8c4516 100644 --- a/iroh-net/src/discovery/pkarr/dht.rs +++ b/iroh/src/discovery/pkarr/dht.rs @@ -1,6 +1,6 @@ -//! Pkarr based node discovery for iroh-net, supporting both relay servers and the DHT. +//! Pkarr based node discovery for iroh, supporting both relay servers and the DHT. //! -//! This module contains pkarr-based node discovery for iroh-net which can use both pkarr +//! 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. //! diff --git a/iroh-net/src/discovery/static_provider.rs b/iroh/src/discovery/static_provider.rs similarity index 98% rename from iroh-net/src/discovery/static_provider.rs rename to iroh/src/discovery/static_provider.rs index a6169d2b1d..acff8ac41a 100644 --- a/iroh-net/src/discovery/static_provider.rs +++ b/iroh/src/discovery/static_provider.rs @@ -42,7 +42,7 @@ impl StaticProvider { /// use std::str::FromStr; /// /// use iroh_base::ticket::NodeTicket; - /// use iroh_net::{Endpoint, discovery::static_provider::StaticProvider}; + /// use iroh::{Endpoint, discovery::static_provider::StaticProvider}; /// /// # async fn example() -> anyhow::Result<()> { /// # #[derive(Default)] struct Args { tickets: Vec } diff --git a/iroh-net/src/dns.rs b/iroh/src/dns.rs similarity index 99% rename from iroh-net/src/dns.rs rename to iroh/src/dns.rs index 98e0ffc139..c5ea09ee91 100644 --- a/iroh-net/src/dns.rs +++ b/iroh/src/dns.rs @@ -19,7 +19,7 @@ use once_cell::sync::Lazy; pub mod node_info; -/// The DNS resolver type used throughout `iroh-net`. +/// The DNS resolver type used throughout `iroh`. pub type DnsResolver = TokioAsyncResolver; static DNS_RESOLVER: Lazy = @@ -33,7 +33,7 @@ pub fn default_resolver() -> &'static DnsResolver { &DNS_RESOLVER } -/// Get the DNS resolver used within iroh-net. +/// Get the DNS resolver used within iroh. pub fn resolver() -> &'static TokioAsyncResolver { Lazy::force(&DNS_RESOLVER) } diff --git a/iroh-net/src/dns/node_info.rs b/iroh/src/dns/node_info.rs similarity index 100% rename from iroh-net/src/dns/node_info.rs rename to iroh/src/dns/node_info.rs diff --git a/iroh-net/src/endpoint.rs b/iroh/src/endpoint.rs similarity index 98% rename from iroh-net/src/endpoint.rs rename to iroh/src/endpoint.rs index d194892f74..036229e350 100644 --- a/iroh-net/src/endpoint.rs +++ b/iroh/src/endpoint.rs @@ -1,12 +1,12 @@ -//! The [`Endpoint`] allows establishing connections to other iroh-net nodes. +//! The [`Endpoint`] allows establishing connections to other iroh nodes. //! -//! The [`Endpoint`] is the main API interface to manage a local iroh-net node. It allows +//! 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-net connections work. +//! more details on how iroh connections work. //! //! The main items in this module are: //! -//! - [`Endpoint`] to establish iroh-net connections with other nodes. +//! - [`Endpoint`] to establish iroh connections with other nodes. //! - [`Builder`] to create an [`Endpoint`]. //! //! [module docs]: crate @@ -215,7 +215,7 @@ impl Builder { /// Sets the relay servers to assist in establishing connectivity. /// - /// Relay servers are used to establish initial connection with another iroh-net node. + /// 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. /// @@ -455,15 +455,15 @@ pub fn make_server_config( Ok(server_config) } -/// Controls an iroh-net node, establishing connections with other nodes. +/// 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-net nodes. The connections are peer-to-peer and encrypted, a Relay server is +/// 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-net. +/// 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-net nodes, +/// 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. /// @@ -700,7 +700,7 @@ impl Endpoint { // # Methods for manipulating the internal state about other nodes. - /// Informs this [`Endpoint`] about addresses of the iroh-net node. + /// 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 @@ -718,7 +718,7 @@ impl Endpoint { self.add_node_addr_inner(node_addr, magicsock::Source::App) } - /// Informs this [`Endpoint`] about addresses of the iroh-net node, noting the source. + /// 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 @@ -792,7 +792,7 @@ impl Endpoint { /// /// 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-net nodes can use to reliably establish a connection + /// 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. @@ -820,11 +820,11 @@ impl Endpoint { /// Returns the direct addresses of this [`Endpoint`]. /// /// The direct addresses of the [`Endpoint`] are those that could be used by other - /// iroh-net nodes to establish direct connectivity, depending on the network + /// 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-net node. + /// 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 @@ -841,7 +841,7 @@ impl Endpoint { /// To get the current endpoints, drop the stream after the first item was received: /// ``` /// use futures_lite::StreamExt; - /// use iroh_net::Endpoint; + /// use iroh::Endpoint; /// /// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); /// # rt.block_on(async move { @@ -867,7 +867,7 @@ impl Endpoint { /// Returns information about the remote node identified by a [`NodeId`]. /// - /// The [`Endpoint`] keeps some information about remote iroh-net nodes, which it uses to find + /// 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 @@ -885,7 +885,7 @@ impl Endpoint { /// This returns the same information as [`Endpoint::remote_info`] for each node known to this /// [`Endpoint`]. /// - /// The [`Endpoint`] keeps some information about remote iroh-net nodes, which it uses to find + /// 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. /// diff --git a/iroh-net/src/endpoint/rtt_actor.rs b/iroh/src/endpoint/rtt_actor.rs similarity index 100% rename from iroh-net/src/endpoint/rtt_actor.rs rename to iroh/src/endpoint/rtt_actor.rs diff --git a/iroh/src/lib.rs b/iroh/src/lib.rs index c1fae16f90..6318eac34e 100644 --- a/iroh/src/lib.rs +++ b/iroh/src/lib.rs @@ -1,19 +1,260 @@ -//! Send data over the internet. +//! 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. //! -//! ## Reexports +//! An iroh node is created and controlled by the [`Endpoint`], e.g. connecting to +//! another node: //! -//! The iroh crate re-exports the following crates: -//! - [iroh_base] as [`base`] -//! - [iroh_net] as [`net`] -//! - [iroh_router] as [`router`] -#![cfg_attr(iroh_docsrs, feature(doc_cfg))] +//! ```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. +//! +//!
+//! +//! 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: +//! +//! ```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(0u8.into(), b"ep closing").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(0u8.into(), b"ep closing").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 ticket; +pub mod tls; + +pub(crate) mod util; + +pub use endpoint::{AddrInfo, Endpoint, NodeAddr, RelayMode}; +pub use iroh_base::{ + key, + key::NodeId, + relay_map::{RelayMap, RelayNode, RelayUrl}, +}; +pub use iroh_relay as relay; -// re-export the iroh crates -#[doc(inline)] -pub use iroh_base as base; -#[doc(inline)] -pub use iroh_net as net; -#[doc(inline)] -pub use iroh_router as router; +#[cfg(any(test, feature = "test-utils"))] +#[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))] +pub mod test_utils; diff --git a/iroh-net/src/magicsock.rs b/iroh/src/magicsock.rs similarity index 99% rename from iroh-net/src/magicsock.rs rename to iroh/src/magicsock.rs index 87964a3108..12dc5ed529 100644 --- a/iroh-net/src/magicsock.rs +++ b/iroh/src/magicsock.rs @@ -2682,9 +2682,9 @@ fn disco_message_sent(msg: &disco::Message) { /// A *direct address* on which an iroh-node might be contactable. /// -/// Direct addresses are UDP socket addresses on which an iroh-net node could potentially be +/// 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-net node, see [`DirectAddrType`] for the several kinds of sources. +/// iroh node, see [`DirectAddrType`] for the several kinds of sources. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct DirectAddr { /// The address. @@ -2695,7 +2695,7 @@ pub struct DirectAddr { /// The type of direct address. /// -/// These are the various sources or origins from which an iroh-net node might have found a +/// 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 { @@ -2705,19 +2705,19 @@ pub enum DirectAddrType { Local, /// Public internet address discovered via STUN. /// - /// When possible an iroh-net node will perform STUN to discover which is the address + /// 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-net node will request a port mapping from the local router to + /// 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-net to bound to a specific port and independently - /// configure the router to forward this port to the iroh-net node. This indicates a + /// 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, } diff --git a/iroh-net/src/magicsock/metrics.rs b/iroh/src/magicsock/metrics.rs similarity index 100% rename from iroh-net/src/magicsock/metrics.rs rename to iroh/src/magicsock/metrics.rs diff --git a/iroh-net/src/magicsock/node_map.rs b/iroh/src/magicsock/node_map.rs similarity index 100% rename from iroh-net/src/magicsock/node_map.rs rename to iroh/src/magicsock/node_map.rs diff --git a/iroh-net/src/magicsock/node_map/best_addr.rs b/iroh/src/magicsock/node_map/best_addr.rs similarity index 100% rename from iroh-net/src/magicsock/node_map/best_addr.rs rename to iroh/src/magicsock/node_map/best_addr.rs diff --git a/iroh-net/src/magicsock/node_map/node_state.rs b/iroh/src/magicsock/node_map/node_state.rs similarity index 99% rename from iroh-net/src/magicsock/node_map/node_state.rs rename to iroh/src/magicsock/node_map/node_state.rs index 2f23c1c6c3..42cd36941d 100644 --- a/iroh-net/src/magicsock/node_map/node_state.rs +++ b/iroh/src/magicsock/node_map/node_state.rs @@ -1255,7 +1255,7 @@ pub enum ControlMsg { /// Information about a *direct address*. /// -/// The *direct addresses* of an iroh-net node are those that could be used by other nodes to +/// 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)] @@ -1332,7 +1332,7 @@ impl From for RelayUrl { } } -/// Details about a remote iroh-net node which is known to this node. +/// 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 diff --git a/iroh-net/src/magicsock/node_map/path_state.rs b/iroh/src/magicsock/node_map/path_state.rs similarity index 100% rename from iroh-net/src/magicsock/node_map/path_state.rs rename to iroh/src/magicsock/node_map/path_state.rs diff --git a/iroh-net/src/magicsock/node_map/udp_paths.rs b/iroh/src/magicsock/node_map/udp_paths.rs similarity index 100% rename from iroh-net/src/magicsock/node_map/udp_paths.rs rename to iroh/src/magicsock/node_map/udp_paths.rs diff --git a/iroh-net/src/magicsock/relay_actor.rs b/iroh/src/magicsock/relay_actor.rs similarity index 100% rename from iroh-net/src/magicsock/relay_actor.rs rename to iroh/src/magicsock/relay_actor.rs diff --git a/iroh-net/src/magicsock/timer.rs b/iroh/src/magicsock/timer.rs similarity index 100% rename from iroh-net/src/magicsock/timer.rs rename to iroh/src/magicsock/timer.rs diff --git a/iroh-net/src/magicsock/udp_conn.rs b/iroh/src/magicsock/udp_conn.rs similarity index 100% rename from iroh-net/src/magicsock/udp_conn.rs rename to iroh/src/magicsock/udp_conn.rs diff --git a/iroh-net/src/metrics.rs b/iroh/src/metrics.rs similarity index 85% rename from iroh-net/src/metrics.rs rename to iroh/src/metrics.rs index e168a56a7a..ff431f9154 100644 --- a/iroh-net/src/metrics.rs +++ b/iroh/src/metrics.rs @@ -1,4 +1,4 @@ -//! Co-locating all of the iroh-net metrics structs +//! 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; diff --git a/iroh-router/src/router.rs b/iroh/src/protocol.rs similarity index 54% rename from iroh-router/src/router.rs rename to iroh/src/protocol.rs index bd39e9b5b0..2c3dd1b245 100644 --- a/iroh-router/src/router.rs +++ b/iroh/src/protocol.rs @@ -1,17 +1,92 @@ -use std::sync::Arc; +//! 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, connecting: Connecting) -> BoxedFuture> { +//! 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::{anyhow, Result}; +use futures_buffered::join_all; +use futures_lite::future::Boxed as BoxedFuture; use futures_util::{ future::{MapErr, Shared}, FutureExt, TryFutureExt, }; -use iroh_net::Endpoint; use tokio::task::{JoinError, JoinSet}; use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle}; use tracing::{debug, error, warn}; -use crate::{ProtocolHandler, ProtocolMap}; +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, ) +/// .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, @@ -28,7 +103,87 @@ pub struct Router { type JoinErrToStr = Box String + Send + Sync + 'static>; +/// 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, conn: Connecting) -> BoxedFuture>; + + /// Called when the node shuts down. + fn shutdown(self: Arc) -> BoxedFuture<()> { + Box::pin(async move {}) + } +} + +/// Helper trait to facilite casting from `Arc` to `Arc`. +/// +/// This trait has a blanket implementation so there is no need to implement this yourself. +pub trait IntoArcAny { + /// Casts `Arc` into `Arc`. + fn into_arc_any(self: Arc) -> Arc; +} + +impl IntoArcAny for T { + fn into_arc_any(self: Arc) -> Arc { + self + } +} + +/// A typed map of protocol handlers, mapping them from ALPNs. +#[derive(Debug, Clone, Default)] +pub struct ProtocolMap(BTreeMap, Arc>); + +impl ProtocolMap { + /// Returns the registered protocol handler for an ALPN as a concrete type. + pub fn get_typed(&self, alpn: &[u8]) -> Option> { + let protocol: Arc = self.0.get(alpn)?.clone(); + let protocol_any: Arc = 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`]. + pub fn get(&self, alpn: &[u8]) -> Option> { + self.0.get(alpn).cloned() + } + + /// Inserts a protocol handler. + pub fn insert(&mut self, alpn: Vec, handler: Arc) { + self.0.insert(alpn, handler); + } + + /// Returns an iterator of all registered ALPN protocol identifiers. + pub fn alpns(&self) -> impl Iterator> { + 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) } @@ -41,10 +196,15 @@ impl Router { self.protocols.get_typed(alpn) } + /// Returns the [`Endpoint`] stored in this router. pub fn endpoint(&self) -> &Endpoint { &self.endpoint } + /// Shuts down the accept loop cleanly. + /// + /// If some [`ProtocolHandler`] panicked in the accept loop, this will propagate + /// that panic into the result here. pub async fn shutdown(self) -> Result<()> { // Trigger shutdown of the main run task by activating the cancel token. self.cancel_token.cancel(); @@ -56,13 +216,8 @@ impl Router { } } -#[derive(Debug)] -pub struct RouterBuilder { - endpoint: Endpoint, - protocols: ProtocolMap, -} - impl RouterBuilder { + /// Creates a new router builder using given [`Endpoint`]. pub fn new(endpoint: Endpoint) -> Self { Self { endpoint, @@ -70,6 +225,8 @@ impl RouterBuilder { } } + /// 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) -> Self { self.protocols.insert(alpn.as_ref().to_vec(), handler); self @@ -88,6 +245,7 @@ impl RouterBuilder { 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 { // Update the endpoint with our alpns. let alpns = self @@ -187,7 +345,7 @@ async fn shutdown(endpoint: &Endpoint, protocols: Arc) { ); } -async fn handle_connection(incoming: iroh_net::endpoint::Incoming, protocols: Arc) { +async fn handle_connection(incoming: crate::endpoint::Incoming, protocols: Arc) { let mut connecting = match incoming.accept() { Ok(conn) => conn, Err(err) => { diff --git a/iroh-net/src/test_utils.rs b/iroh/src/test_utils.rs similarity index 100% rename from iroh-net/src/test_utils.rs rename to iroh/src/test_utils.rs diff --git a/iroh-net/src/ticket.rs b/iroh/src/ticket.rs similarity index 59% rename from iroh-net/src/ticket.rs rename to iroh/src/ticket.rs index 184c682bd7..d4db5e4347 100644 --- a/iroh-net/src/ticket.rs +++ b/iroh/src/ticket.rs @@ -1,2 +1,2 @@ -//! Tickets supported by iroh-net +//! Tickets supported by iroh pub use iroh_base::ticket::{NodeTicket, Ticket}; diff --git a/iroh-net/src/tls.rs b/iroh/src/tls.rs similarity index 100% rename from iroh-net/src/tls.rs rename to iroh/src/tls.rs diff --git a/iroh-net/src/tls/certificate.rs b/iroh/src/tls/certificate.rs similarity index 100% rename from iroh-net/src/tls/certificate.rs rename to iroh/src/tls/certificate.rs diff --git a/iroh-net/src/tls/verifier.rs b/iroh/src/tls/verifier.rs similarity index 100% rename from iroh-net/src/tls/verifier.rs rename to iroh/src/tls/verifier.rs diff --git a/iroh-net/src/util.rs b/iroh/src/util.rs similarity index 95% rename from iroh-net/src/util.rs rename to iroh/src/util.rs index 84af5b85c5..27c114c1b0 100644 --- a/iroh-net/src/util.rs +++ b/iroh/src/util.rs @@ -1,4 +1,4 @@ -//! Utilities used in [`iroh-net`][`crate`] +//! Utilities used in [`iroh`][`crate`] use std::{ future::Future,