Skip to content

Commit 9cb4020

Browse files
feat!: transport generic EndpointAddr (#3554)
## Description This marks the first public step towards generic transports. For now there are two types of `TransportAddr`s, `Relay` and `Ip` which, replace the previous explicit fields in `EndpointAddr` of `relay_url` and `direct_addrs`. Closes #3417 ## Breaking Changes - `direct_addresses` are now called `ip_addresses` - `EndpointAddr` type is completely changed - APIs with `addresse(s)` are now normalized to `addr(s)` to be consistent in the code base
1 parent 3ec554c commit 9cb4020

File tree

26 files changed

+478
-356
lines changed

26 files changed

+478
-356
lines changed

iroh-base/src/endpoint_addr.rs

Lines changed: 105 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,96 +18,103 @@ use crate::{EndpointId, PublicKey, RelayUrl};
1818
/// contact the endpoint.
1919
///
2020
/// To establish a network connection to an endpoint both the [`EndpointId`] and one or more network
21-
/// paths are needed. The network paths can come from various sources:
21+
/// paths are needed. The network paths can come from various sources, current sources can come from
2222
///
2323
/// - A [discovery] service which can provide routing information for a given [`EndpointId`].
2424
///
2525
/// - A [`RelayUrl`] of the endpoint's [home relay], this allows establishing the connection via
2626
/// the Relay server and is very reliable.
2727
///
28-
/// - One or more *direct addresses* on which the endpoint might be reachable. Depending on the
28+
/// - One or more *IP based addresses* on which the endpoint might be reachable. Depending on the
2929
/// network location of both endpoints it might not be possible to establish a direct
3030
/// connection without the help of a [Relay server].
3131
///
3232
/// This structure will always contain the required [`EndpointId`] and will contain an optional
33-
/// number of network-level addressing information. It is a generic addressing type used
34-
/// whenever a connection to other endpoints needs to be established.
33+
/// number of other addressing information. It is a generic addressing type used whenever a connection
34+
/// to other endpoints needs to be established.
3535
///
3636
/// [discovery]: https://docs.rs/iroh/*/iroh/index.html#endpoint-discovery
3737
/// [home relay]: https://docs.rs/iroh/*/iroh/relay/index.html
3838
/// [Relay server]: https://docs.rs/iroh/*/iroh/index.html#relay-servers
3939
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
4040
pub struct EndpointAddr {
4141
/// The endpoint's identifier.
42-
pub endpoint_id: EndpointId,
43-
/// The endpoint's home relay url.
44-
pub relay_url: Option<RelayUrl>,
45-
/// Socket addresses where the peer might be reached directly.
46-
pub direct_addresses: BTreeSet<SocketAddr>,
42+
pub id: EndpointId,
43+
/// The endpoint's addresses
44+
pub addrs: BTreeSet<TransportAddr>,
45+
}
46+
47+
/// Available address types.
48+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
49+
#[non_exhaustive]
50+
pub enum TransportAddr {
51+
/// Relays
52+
Relay(RelayUrl),
53+
/// IP based addresses
54+
Ip(SocketAddr),
4755
}
4856

4957
impl EndpointAddr {
50-
/// Creates a new [`EndpointAddr`] with no `relay_url` and no `direct_addresses`.
51-
pub fn new(endpoint_id: PublicKey) -> Self {
58+
/// Creates a new [`EndpointAddr`] with no network level addresses.
59+
///
60+
/// This still is usable with e.g. a discovery service to establish a connection,
61+
/// depending on the situation.
62+
pub fn new(id: PublicKey) -> Self {
5263
EndpointAddr {
53-
endpoint_id,
54-
relay_url: None,
55-
direct_addresses: Default::default(),
64+
id,
65+
addrs: Default::default(),
5666
}
5767
}
5868

59-
/// Adds a relay url.
69+
/// Creates a new [`EndpointAddr`] from its parts.
70+
pub fn from_parts(id: PublicKey, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
71+
Self {
72+
id,
73+
addrs: addrs.into_iter().collect(),
74+
}
75+
}
76+
77+
/// Adds a [`RelayUrl`] address.
6078
pub fn with_relay_url(mut self, relay_url: RelayUrl) -> Self {
61-
self.relay_url = Some(relay_url);
79+
self.addrs.insert(TransportAddr::Relay(relay_url));
6280
self
6381
}
6482

65-
/// Adds the given direct addresses.
66-
pub fn with_direct_addresses(
67-
mut self,
68-
addresses: impl IntoIterator<Item = SocketAddr>,
69-
) -> Self {
70-
self.direct_addresses = addresses.into_iter().collect();
83+
/// Adds an IP based address.
84+
pub fn with_ip_addr(mut self, addr: SocketAddr) -> Self {
85+
self.addrs.insert(TransportAddr::Ip(addr));
7186
self
7287
}
7388

74-
/// Creates a new [`EndpointAddr`] from its parts.
75-
pub fn from_parts(
76-
endpoint_id: PublicKey,
77-
relay_url: Option<RelayUrl>,
78-
direct_addresses: impl IntoIterator<Item = SocketAddr>,
79-
) -> Self {
80-
Self {
81-
endpoint_id,
82-
relay_url,
83-
direct_addresses: direct_addresses.into_iter().collect(),
89+
/// Adds a list of addresses.
90+
pub fn with_addrs(mut self, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
91+
for addr in addrs.into_iter() {
92+
self.addrs.insert(addr);
8493
}
94+
self
8595
}
8696

8797
/// Returns true, if only a [`EndpointId`] is present.
8898
pub fn is_empty(&self) -> bool {
89-
self.relay_url.is_none() && self.direct_addresses.is_empty()
90-
}
91-
92-
/// Returns the direct addresses of this peer.
93-
pub fn direct_addresses(&self) -> impl Iterator<Item = &SocketAddr> {
94-
self.direct_addresses.iter()
99+
self.addrs.is_empty()
95100
}
96101

97-
/// Returns the relay url of this peer.
98-
pub fn relay_url(&self) -> Option<&RelayUrl> {
99-
self.relay_url.as_ref()
102+
/// Returns a list of IP addresses of this peer.
103+
pub fn ip_addrs(&self) -> impl Iterator<Item = &SocketAddr> {
104+
self.addrs.iter().filter_map(|addr| match addr {
105+
TransportAddr::Ip(addr) => Some(addr),
106+
_ => None,
107+
})
100108
}
101-
}
102109

103-
impl From<(PublicKey, Option<RelayUrl>, &[SocketAddr])> for EndpointAddr {
104-
fn from(value: (PublicKey, Option<RelayUrl>, &[SocketAddr])) -> Self {
105-
let (endpoint_id, relay_url, direct_addresses_iter) = value;
106-
EndpointAddr {
107-
endpoint_id,
108-
relay_url,
109-
direct_addresses: direct_addresses_iter.iter().copied().collect(),
110-
}
110+
/// Returns a list of relay urls of this peer.
111+
///
112+
/// In practice this is expected to be zero or one home relay for all known cases currently.
113+
pub fn relay_urls(&self) -> impl Iterator<Item = &RelayUrl> {
114+
self.addrs.iter().filter_map(|addr| match addr {
115+
TransportAddr::Relay(url) => Some(url),
116+
_ => None,
117+
})
111118
}
112119
}
113120

@@ -116,3 +123,51 @@ impl From<EndpointId> for EndpointAddr {
116123
EndpointAddr::new(endpoint_id)
117124
}
118125
}
126+
127+
#[cfg(test)]
128+
mod tests {
129+
use super::*;
130+
131+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
132+
#[non_exhaustive]
133+
enum NewAddrType {
134+
/// Relays
135+
Relay(RelayUrl),
136+
/// IP based addresses
137+
Ip(SocketAddr),
138+
/// New addr type for testing
139+
Cool(u16),
140+
}
141+
142+
#[test]
143+
fn test_roundtrip_new_addr_type() {
144+
let old = vec![
145+
TransportAddr::Ip("127.0.0.1:9".parse().unwrap()),
146+
TransportAddr::Relay("https://example.com".parse().unwrap()),
147+
];
148+
let old_ser = postcard::to_stdvec(&old).unwrap();
149+
let old_back: Vec<TransportAddr> = postcard::from_bytes(&old_ser).unwrap();
150+
assert_eq!(old, old_back);
151+
152+
let new = vec![
153+
NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
154+
NewAddrType::Relay("https://example.com".parse().unwrap()),
155+
NewAddrType::Cool(4),
156+
];
157+
let new_ser = postcard::to_stdvec(&new).unwrap();
158+
let new_back: Vec<NewAddrType> = postcard::from_bytes(&new_ser).unwrap();
159+
160+
assert_eq!(new, new_back);
161+
162+
// serialize old into new
163+
let old_new_back: Vec<NewAddrType> = postcard::from_bytes(&old_ser).unwrap();
164+
165+
assert_eq!(
166+
old_new_back,
167+
vec![
168+
NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
169+
NewAddrType::Relay("https://example.com".parse().unwrap()),
170+
]
171+
);
172+
}
173+
}

iroh-base/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
44
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
55

6-
// TODO: move to own crate
76
#[cfg(feature = "ticket")]
87
pub mod ticket;
98

@@ -15,7 +14,7 @@ mod key;
1514
mod relay_url;
1615

1716
#[cfg(feature = "key")]
18-
pub use self::endpoint_addr::EndpointAddr;
17+
pub use self::endpoint_addr::{EndpointAddr, TransportAddr};
1918
#[cfg(feature = "key")]
2019
pub use self::key::{EndpointId, KeyParsingError, PublicKey, SecretKey, Signature, SignatureError};
2120
#[cfg(feature = "relay")]

iroh-base/src/ticket.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
//! ticket would contain the hash of the data as well as information about how to reach the
44
//! provider.
55
6-
use std::{collections::BTreeSet, net::SocketAddr};
6+
use std::collections::BTreeSet;
77

88
use nested_enum_utils::common_fields;
99
use serde::{Deserialize, Serialize};
1010
use snafu::{Backtrace, Snafu};
1111

12-
use crate::{key::EndpointId, relay_url::RelayUrl};
12+
use crate::{TransportAddr, key::EndpointId};
1313

1414
mod endpoint;
1515

@@ -103,13 +103,12 @@ impl ParseError {
103103
}
104104

105105
#[derive(Serialize, Deserialize)]
106-
struct Variant0NodeAddr {
107-
node_id: EndpointId,
108-
info: Variant0AddrInfo,
106+
struct Variant1EndpointAddr {
107+
id: EndpointId,
108+
info: Variant1AddrInfo,
109109
}
110110

111111
#[derive(Serialize, Deserialize)]
112-
struct Variant0AddrInfo {
113-
relay_url: Option<RelayUrl>,
114-
direct_addresses: BTreeSet<SocketAddr>,
112+
struct Variant1AddrInfo {
113+
addrs: BTreeSet<TransportAddr>,
115114
}

0 commit comments

Comments
 (0)