sc_network_types/
multiaddr.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use litep2p::types::multiaddr::{
20	Error as LiteP2pError, Iter as LiteP2pIter, Multiaddr as LiteP2pMultiaddr,
21	Protocol as LiteP2pProtocol,
22};
23use multiaddr::Multiaddr as LibP2pMultiaddr;
24use std::{
25	fmt::{self, Debug, Display},
26	net::{IpAddr, Ipv4Addr, Ipv6Addr},
27	str::FromStr,
28};
29
30mod protocol;
31pub use protocol::Protocol;
32
33// Re-export the macro under shorter name under `multiaddr`.
34pub use crate::build_multiaddr as multiaddr;
35
36/// [`Multiaddr`] type used in Substrate. Converted to libp2p's `Multiaddr`
37/// or litep2p's `Multiaddr` when passed to the corresponding network backend.
38
39#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
40pub struct Multiaddr {
41	multiaddr: LiteP2pMultiaddr,
42}
43
44impl Multiaddr {
45	/// Create a new, empty multiaddress.
46	pub fn empty() -> Self {
47		Self { multiaddr: LiteP2pMultiaddr::empty() }
48	}
49
50	/// Adds an address component to the end of this multiaddr.
51	pub fn push(&mut self, p: Protocol<'_>) {
52		self.multiaddr.push(p.into())
53	}
54
55	/// Pops the last `Protocol` of this multiaddr, or `None` if the multiaddr is empty.
56	pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
57		self.multiaddr.pop().map(Into::into)
58	}
59
60	/// Like [`Multiaddr::push`] but consumes `self`.
61	pub fn with(self, p: Protocol<'_>) -> Self {
62		self.multiaddr.with(p.into()).into()
63	}
64
65	/// Returns the components of this multiaddress.
66	pub fn iter(&self) -> Iter<'_> {
67		self.multiaddr.iter().into()
68	}
69
70	/// Return a copy of this [`Multiaddr`]'s byte representation.
71	pub fn to_vec(&self) -> Vec<u8> {
72		self.multiaddr.to_vec()
73	}
74}
75
76impl Display for Multiaddr {
77	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78		Display::fmt(&self.multiaddr, f)
79	}
80}
81
82/// Remove an extra layer of nestedness by deferring to the wrapped value's [`Debug`].
83impl Debug for Multiaddr {
84	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85		Debug::fmt(&self.multiaddr, f)
86	}
87}
88
89impl AsRef<[u8]> for Multiaddr {
90	fn as_ref(&self) -> &[u8] {
91		self.multiaddr.as_ref()
92	}
93}
94
95impl From<LiteP2pMultiaddr> for Multiaddr {
96	fn from(multiaddr: LiteP2pMultiaddr) -> Self {
97		Self { multiaddr }
98	}
99}
100
101impl From<Multiaddr> for LiteP2pMultiaddr {
102	fn from(multiaddr: Multiaddr) -> Self {
103		multiaddr.multiaddr
104	}
105}
106
107impl From<LibP2pMultiaddr> for Multiaddr {
108	fn from(multiaddr: LibP2pMultiaddr) -> Self {
109		multiaddr.into_iter().map(Into::into).collect()
110	}
111}
112
113impl From<Multiaddr> for LibP2pMultiaddr {
114	fn from(multiaddr: Multiaddr) -> Self {
115		multiaddr.into_iter().map(Into::into).collect()
116	}
117}
118
119impl From<IpAddr> for Multiaddr {
120	fn from(v: IpAddr) -> Multiaddr {
121		match v {
122			IpAddr::V4(a) => a.into(),
123			IpAddr::V6(a) => a.into(),
124		}
125	}
126}
127
128impl From<Ipv4Addr> for Multiaddr {
129	fn from(v: Ipv4Addr) -> Multiaddr {
130		Protocol::Ip4(v).into()
131	}
132}
133
134impl From<Ipv6Addr> for Multiaddr {
135	fn from(v: Ipv6Addr) -> Multiaddr {
136		Protocol::Ip6(v).into()
137	}
138}
139
140impl TryFrom<Vec<u8>> for Multiaddr {
141	type Error = ParseError;
142
143	fn try_from(v: Vec<u8>) -> Result<Self, ParseError> {
144		let multiaddr = LiteP2pMultiaddr::try_from(v)?;
145		Ok(Self { multiaddr })
146	}
147}
148
149/// Error when parsing a [`Multiaddr`] from string.
150#[derive(Debug, thiserror::Error)]
151pub enum ParseError {
152	/// Less data provided than indicated by length.
153	#[error("less data than indicated by length")]
154	DataLessThanLen,
155	/// Invalid multiaddress.
156	#[error("invalid multiaddress")]
157	InvalidMultiaddr,
158	/// Invalid protocol specification.
159	#[error("invalid protocol string")]
160	InvalidProtocolString,
161	/// Unknown protocol string identifier.
162	#[error("unknown protocol '{0}'")]
163	UnknownProtocolString(String),
164	/// Unknown protocol numeric id.
165	#[error("unknown protocol id {0}")]
166	UnknownProtocolId(u32),
167	/// Failed to decode unsigned varint.
168	#[error("failed to decode unsigned varint: {0}")]
169	InvalidUvar(Box<dyn std::error::Error + Send + Sync>),
170	/// Other error emitted when parsing into the wrapped type.
171	#[error("multiaddr parsing error: {0}")]
172	ParsingError(Box<dyn std::error::Error + Send + Sync>),
173}
174
175impl From<LiteP2pError> for ParseError {
176	fn from(error: LiteP2pError) -> Self {
177		match error {
178			LiteP2pError::DataLessThanLen => ParseError::DataLessThanLen,
179			LiteP2pError::InvalidMultiaddr => ParseError::InvalidMultiaddr,
180			LiteP2pError::InvalidProtocolString => ParseError::InvalidProtocolString,
181			LiteP2pError::UnknownProtocolString(s) => ParseError::UnknownProtocolString(s),
182			LiteP2pError::UnknownProtocolId(n) => ParseError::UnknownProtocolId(n),
183			LiteP2pError::InvalidUvar(e) => ParseError::InvalidUvar(Box::new(e)),
184			LiteP2pError::ParsingError(e) => ParseError::ParsingError(e),
185			error => ParseError::ParsingError(Box::new(error)),
186		}
187	}
188}
189
190impl FromStr for Multiaddr {
191	type Err = ParseError;
192
193	fn from_str(s: &str) -> Result<Self, Self::Err> {
194		let multiaddr = LiteP2pMultiaddr::from_str(s)?;
195		Ok(Self { multiaddr })
196	}
197}
198
199impl TryFrom<String> for Multiaddr {
200	type Error = ParseError;
201
202	fn try_from(s: String) -> Result<Multiaddr, Self::Error> {
203		Self::from_str(&s)
204	}
205}
206
207impl<'a> TryFrom<&'a str> for Multiaddr {
208	type Error = ParseError;
209
210	fn try_from(s: &'a str) -> Result<Multiaddr, Self::Error> {
211		Self::from_str(s)
212	}
213}
214
215/// Iterator over `Multiaddr` [`Protocol`]s.
216pub struct Iter<'a>(LiteP2pIter<'a>);
217
218impl<'a> Iterator for Iter<'a> {
219	type Item = Protocol<'a>;
220
221	fn next(&mut self) -> Option<Self::Item> {
222		self.0.next().map(Into::into)
223	}
224}
225
226impl<'a> From<LiteP2pIter<'a>> for Iter<'a> {
227	fn from(iter: LiteP2pIter<'a>) -> Self {
228		Self(iter)
229	}
230}
231
232impl<'a> IntoIterator for &'a Multiaddr {
233	type Item = Protocol<'a>;
234	type IntoIter = Iter<'a>;
235
236	fn into_iter(self) -> Iter<'a> {
237		self.multiaddr.into_iter().into()
238	}
239}
240
241impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
242	fn from_iter<T>(iter: T) -> Self
243	where
244		T: IntoIterator<Item = Protocol<'a>>,
245	{
246		LiteP2pMultiaddr::from_iter(iter.into_iter().map(Into::into)).into()
247	}
248}
249
250impl<'a> From<Protocol<'a>> for Multiaddr {
251	fn from(p: Protocol<'a>) -> Multiaddr {
252		let protocol: LiteP2pProtocol = p.into();
253		let multiaddr: LiteP2pMultiaddr = protocol.into();
254		multiaddr.into()
255	}
256}
257
258/// Easy way for a user to create a `Multiaddr`.
259///
260/// Example:
261///
262/// ```rust
263/// use sc_network_types::build_multiaddr;
264/// let addr = build_multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16));
265/// ```
266///
267/// Each element passed to `multiaddr!` should be a variant of the `Protocol` enum. The
268/// optional parameter is turned into the proper type with the `Into` trait.
269///
270/// For example, `Ip4([127, 0, 0, 1])` works because `Ipv4Addr` implements `From<[u8; 4]>`.
271#[macro_export]
272macro_rules! build_multiaddr {
273    ($($comp:ident $(($param:expr))*),+) => {
274        {
275            use std::iter;
276            let elem = iter::empty::<$crate::multiaddr::Protocol>();
277            $(
278                let elem = {
279                    let cmp = $crate::multiaddr::Protocol::$comp $(( $param.into() ))*;
280                    elem.chain(iter::once(cmp))
281                };
282            )+
283            elem.collect::<$crate::multiaddr::Multiaddr>()
284        }
285    }
286}