atm0s_sdn_multiaddr/
protocol.rs

1use crate::{Error, Result};
2use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
3use std::{
4    borrow::Cow,
5    convert::From,
6    fmt,
7    io::{Cursor, Write},
8    net::{IpAddr, Ipv4Addr, Ipv6Addr},
9    str::{self, FromStr},
10};
11use unsigned_varint::{decode, encode};
12
13// All the values are obtained by converting hexadecimal protocol codes to u32.
14// Protocols as well as their corresponding codes are defined in
15// https://github.com/multiformats/multiaddr/blob/master/protocols.csv .
16const DCCP: u32 = 33;
17const DNS: u32 = 53;
18const DNS4: u32 = 54;
19const DNS6: u32 = 55;
20const DNSADDR: u32 = 56;
21const HTTP: u32 = 480;
22const HTTPS: u32 = 443;
23const IP4: u32 = 4;
24const IP6: u32 = 41;
25const P2P_WEBRTC_DIRECT: u32 = 276;
26const P2P_WEBRTC_STAR: u32 = 275;
27const WEBRTC_DIRECT: u32 = 280;
28const P2P_WEBSOCKET_STAR: u32 = 479;
29const MEMORY: u32 = 777;
30const P2P: u32 = 421;
31const P2P_CIRCUIT: u32 = 290;
32const QUIC: u32 = 460;
33const QUIC_V1: u32 = 461;
34const SCTP: u32 = 132;
35const TCP: u32 = 6;
36const TLS: u32 = 448;
37const NOISE: u32 = 454;
38const UDP: u32 = 273;
39const UDT: u32 = 301;
40const UNIX: u32 = 400;
41const UTP: u32 = 302;
42const WEBTRANSPORT: u32 = 465;
43const WS: u32 = 477;
44const WS_WITH_PATH: u32 = 4770; // Note: not standard
45const WSS: u32 = 478;
46const WSS_WITH_PATH: u32 = 4780; // Note: not standard
47
48const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
49    .add(b'%')
50    .add(b'/')
51    .add(b'`')
52    .add(b'?')
53    .add(b'{')
54    .add(b'}')
55    .add(b' ')
56    .add(b'"')
57    .add(b'#')
58    .add(b'<')
59    .add(b'>');
60
61/// `Protocol` describes all possible multiaddress protocols.
62///
63/// For `Unix`, `Ws` and `Wss` we use `&str` instead of `Path` to allow
64/// cross-platform usage of `Protocol` since encoding `Paths` to bytes is
65/// platform-specific. This means that the actual validation of paths needs to
66/// happen separately.
67#[derive(PartialEq, Eq, Clone, Debug)]
68#[non_exhaustive]
69pub enum Protocol<'a> {
70    Dccp(u16),
71    Dns(Cow<'a, str>),
72    Dns4(Cow<'a, str>),
73    Dns6(Cow<'a, str>),
74    Dnsaddr(Cow<'a, str>),
75    Http,
76    Https,
77    Ip4(Ipv4Addr),
78    Ip6(Ipv6Addr),
79    P2pWebRtcDirect,
80    P2pWebRtcStar,
81    WebRTCDirect,
82    P2pWebSocketStar,
83    /// Contains the "port" to contact. Similar to TCP or UDP, 0 means "assign me a port".
84    Memory(u64),
85    P2p(u32),
86    P2pCircuit,
87    Quic,
88    QuicV1,
89    Sctp(u16),
90    Tcp(u16),
91    Tls,
92    Noise,
93    Udp(u16),
94    Udt,
95    Unix(Cow<'a, str>),
96    Utp,
97    WebTransport,
98    Ws(Cow<'a, str>),
99    Wss(Cow<'a, str>),
100}
101
102impl<'a> Protocol<'a> {
103    /// Parse a protocol value from the given iterator of string slices.
104    ///
105    /// The parsing only consumes the minimum amount of string slices necessary to
106    /// produce a well-formed protocol. The same iterator can thus be used to parse
107    /// a sequence of protocols in succession. It is up to client code to check
108    /// that iteration has finished whenever appropriate.
109    pub fn from_str_parts<I>(mut iter: I) -> Result<Self>
110    where
111        I: Iterator<Item = &'a str>,
112    {
113        match iter.next().ok_or(Error::InvalidProtocolString)? {
114            "ip4" => {
115                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
116                Ok(Protocol::Ip4(Ipv4Addr::from_str(s)?))
117            }
118            "tcp" => {
119                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
120                Ok(Protocol::Tcp(s.parse()?))
121            }
122            "tls" => Ok(Protocol::Tls),
123            "noise" => Ok(Protocol::Noise),
124            "udp" => {
125                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
126                Ok(Protocol::Udp(s.parse()?))
127            }
128            "dccp" => {
129                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
130                Ok(Protocol::Dccp(s.parse()?))
131            }
132            "ip6" => {
133                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
134                Ok(Protocol::Ip6(Ipv6Addr::from_str(s)?))
135            }
136            "dns" => {
137                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
138                Ok(Protocol::Dns(Cow::Borrowed(s)))
139            }
140            "dns4" => {
141                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
142                Ok(Protocol::Dns4(Cow::Borrowed(s)))
143            }
144            "dns6" => {
145                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
146                Ok(Protocol::Dns6(Cow::Borrowed(s)))
147            }
148            "dnsaddr" => {
149                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
150                Ok(Protocol::Dnsaddr(Cow::Borrowed(s)))
151            }
152            "sctp" => {
153                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
154                Ok(Protocol::Sctp(s.parse()?))
155            }
156            "udt" => Ok(Protocol::Udt),
157            "utp" => Ok(Protocol::Utp),
158            "unix" => {
159                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
160                Ok(Protocol::Unix(Cow::Borrowed(s)))
161            }
162            "p2p" => {
163                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
164                Ok(Protocol::P2p(s.parse()?))
165            }
166            "http" => Ok(Protocol::Http),
167            "https" => Ok(Protocol::Https),
168            "quic" => Ok(Protocol::Quic),
169            "quic-v1" => Ok(Protocol::QuicV1),
170            "webtransport" => Ok(Protocol::WebTransport),
171            "ws" => Ok(Protocol::Ws(Cow::Borrowed("/"))),
172            "wss" => Ok(Protocol::Wss(Cow::Borrowed("/"))),
173            "x-parity-ws" => {
174                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
175                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
176                Ok(Protocol::Ws(decoded))
177            }
178            "x-parity-wss" => {
179                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
180                let decoded = percent_encoding::percent_decode(s.as_bytes()).decode_utf8()?;
181                Ok(Protocol::Wss(decoded))
182            }
183            "p2p-websocket-star" => Ok(Protocol::P2pWebSocketStar),
184            "p2p-webrtc-star" => Ok(Protocol::P2pWebRtcStar),
185            "webrtc-direct" => Ok(Protocol::WebRTCDirect),
186            "p2p-webrtc-direct" => Ok(Protocol::P2pWebRtcDirect),
187            "p2p-circuit" => Ok(Protocol::P2pCircuit),
188            "memory" => {
189                let s = iter.next().ok_or(Error::InvalidProtocolString)?;
190                Ok(Protocol::Memory(s.parse()?))
191            }
192            unknown => Err(Error::UnknownProtocolString(unknown.to_string())),
193        }
194    }
195
196    /// Parse a single `Protocol` value from its byte slice representation,
197    /// returning the protocol as well as the remaining byte slice.
198    pub fn from_bytes(input: &'a [u8]) -> Result<(Self, &'a [u8])> {
199        fn split_at(n: usize, input: &[u8]) -> Result<(&[u8], &[u8])> {
200            if input.len() < n {
201                return Err(Error::DataLessThanLen);
202            }
203            Ok(input.split_at(n))
204        }
205        let (id, input) = decode::u32(input)?;
206        match id {
207            DCCP => {
208                let (data, rest) = split_at(2, input)?;
209                let mut rdr = Cursor::new(data);
210                let num = rdr.read_u16::<BigEndian>()?;
211                Ok((Protocol::Dccp(num), rest))
212            }
213            DNS => {
214                let (n, input) = decode::usize(input)?;
215                let (data, rest) = split_at(n, input)?;
216                Ok((Protocol::Dns(Cow::Borrowed(str::from_utf8(data)?)), rest))
217            }
218            DNS4 => {
219                let (n, input) = decode::usize(input)?;
220                let (data, rest) = split_at(n, input)?;
221                Ok((Protocol::Dns4(Cow::Borrowed(str::from_utf8(data)?)), rest))
222            }
223            DNS6 => {
224                let (n, input) = decode::usize(input)?;
225                let (data, rest) = split_at(n, input)?;
226                Ok((Protocol::Dns6(Cow::Borrowed(str::from_utf8(data)?)), rest))
227            }
228            DNSADDR => {
229                let (n, input) = decode::usize(input)?;
230                let (data, rest) = split_at(n, input)?;
231                Ok((Protocol::Dnsaddr(Cow::Borrowed(str::from_utf8(data)?)), rest))
232            }
233            HTTP => Ok((Protocol::Http, input)),
234            HTTPS => Ok((Protocol::Https, input)),
235            IP4 => {
236                let (data, rest) = split_at(4, input)?;
237                Ok((Protocol::Ip4(Ipv4Addr::new(data[0], data[1], data[2], data[3])), rest))
238            }
239            IP6 => {
240                let (data, rest) = split_at(16, input)?;
241                let mut rdr = Cursor::new(data);
242                let mut seg = [0_u16; 8];
243
244                for x in seg.iter_mut() {
245                    *x = rdr.read_u16::<BigEndian>()?;
246                }
247
248                let addr = Ipv6Addr::new(seg[0], seg[1], seg[2], seg[3], seg[4], seg[5], seg[6], seg[7]);
249
250                Ok((Protocol::Ip6(addr), rest))
251            }
252            P2P_WEBRTC_DIRECT => Ok((Protocol::P2pWebRtcDirect, input)),
253            P2P_WEBRTC_STAR => Ok((Protocol::P2pWebRtcStar, input)),
254            WEBRTC_DIRECT => Ok((Protocol::WebRTCDirect, input)),
255            P2P_WEBSOCKET_STAR => Ok((Protocol::P2pWebSocketStar, input)),
256            MEMORY => {
257                let (data, rest) = split_at(8, input)?;
258                let mut rdr = Cursor::new(data);
259                let num = rdr.read_u64::<BigEndian>()?;
260                Ok((Protocol::Memory(num), rest))
261            }
262            P2P => {
263                let (data, rest) = split_at(4, input)?;
264                let mut rdr = Cursor::new(data);
265                let num = rdr.read_u32::<BigEndian>()?;
266                Ok((Protocol::P2p(num), rest))
267            }
268            P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
269            QUIC => Ok((Protocol::Quic, input)),
270            QUIC_V1 => Ok((Protocol::QuicV1, input)),
271            SCTP => {
272                let (data, rest) = split_at(2, input)?;
273                let mut rdr = Cursor::new(data);
274                let num = rdr.read_u16::<BigEndian>()?;
275                Ok((Protocol::Sctp(num), rest))
276            }
277            TCP => {
278                let (data, rest) = split_at(2, input)?;
279                let mut rdr = Cursor::new(data);
280                let num = rdr.read_u16::<BigEndian>()?;
281                Ok((Protocol::Tcp(num), rest))
282            }
283            TLS => Ok((Protocol::Tls, input)),
284            NOISE => Ok((Protocol::Noise, input)),
285            UDP => {
286                let (data, rest) = split_at(2, input)?;
287                let mut rdr = Cursor::new(data);
288                let num = rdr.read_u16::<BigEndian>()?;
289                Ok((Protocol::Udp(num), rest))
290            }
291            UDT => Ok((Protocol::Udt, input)),
292            UNIX => {
293                let (n, input) = decode::usize(input)?;
294                let (data, rest) = split_at(n, input)?;
295                Ok((Protocol::Unix(Cow::Borrowed(str::from_utf8(data)?)), rest))
296            }
297            UTP => Ok((Protocol::Utp, input)),
298            WEBTRANSPORT => Ok((Protocol::WebTransport, input)),
299            WS => Ok((Protocol::Ws(Cow::Borrowed("/")), input)),
300            WS_WITH_PATH => {
301                let (n, input) = decode::usize(input)?;
302                let (data, rest) = split_at(n, input)?;
303                Ok((Protocol::Ws(Cow::Borrowed(str::from_utf8(data)?)), rest))
304            }
305            WSS => Ok((Protocol::Wss(Cow::Borrowed("/")), input)),
306            WSS_WITH_PATH => {
307                let (n, input) = decode::usize(input)?;
308                let (data, rest) = split_at(n, input)?;
309                Ok((Protocol::Wss(Cow::Borrowed(str::from_utf8(data)?)), rest))
310            }
311            _ => Err(Error::UnknownProtocolId(id)),
312        }
313    }
314
315    /// Encode this protocol by writing its binary representation into
316    /// the given `Write` impl.
317    pub fn write_bytes<W: Write>(&self, w: &mut W) -> Result<()> {
318        let mut buf = encode::u32_buffer();
319        match self {
320            Protocol::Ip4(addr) => {
321                w.write_all(encode::u32(IP4, &mut buf))?;
322                w.write_all(&addr.octets())?
323            }
324            Protocol::Ip6(addr) => {
325                w.write_all(encode::u32(IP6, &mut buf))?;
326                for &segment in &addr.segments() {
327                    w.write_u16::<BigEndian>(segment)?
328                }
329            }
330            Protocol::Tcp(port) => {
331                w.write_all(encode::u32(TCP, &mut buf))?;
332                w.write_u16::<BigEndian>(*port)?
333            }
334            Protocol::Tls => w.write_all(encode::u32(TLS, &mut buf))?,
335            Protocol::Noise => w.write_all(encode::u32(NOISE, &mut buf))?,
336            Protocol::Udp(port) => {
337                w.write_all(encode::u32(UDP, &mut buf))?;
338                w.write_u16::<BigEndian>(*port)?
339            }
340            Protocol::Dccp(port) => {
341                w.write_all(encode::u32(DCCP, &mut buf))?;
342                w.write_u16::<BigEndian>(*port)?
343            }
344            Protocol::Sctp(port) => {
345                w.write_all(encode::u32(SCTP, &mut buf))?;
346                w.write_u16::<BigEndian>(*port)?
347            }
348            Protocol::Dns(s) => {
349                w.write_all(encode::u32(DNS, &mut buf))?;
350                let bytes = s.as_bytes();
351                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
352                w.write_all(bytes)?
353            }
354            Protocol::Dns4(s) => {
355                w.write_all(encode::u32(DNS4, &mut buf))?;
356                let bytes = s.as_bytes();
357                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
358                w.write_all(bytes)?
359            }
360            Protocol::Dns6(s) => {
361                w.write_all(encode::u32(DNS6, &mut buf))?;
362                let bytes = s.as_bytes();
363                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
364                w.write_all(bytes)?
365            }
366            Protocol::Dnsaddr(s) => {
367                w.write_all(encode::u32(DNSADDR, &mut buf))?;
368                let bytes = s.as_bytes();
369                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
370                w.write_all(bytes)?
371            }
372            Protocol::Unix(s) => {
373                w.write_all(encode::u32(UNIX, &mut buf))?;
374                let bytes = s.as_bytes();
375                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
376                w.write_all(bytes)?
377            }
378            Protocol::P2p(node_id) => {
379                w.write_all(encode::u32(P2P, &mut buf))?;
380                w.write_u32::<BigEndian>(*node_id)?
381            }
382            Protocol::Quic => w.write_all(encode::u32(QUIC, &mut buf))?,
383            Protocol::QuicV1 => w.write_all(encode::u32(QUIC_V1, &mut buf))?,
384            Protocol::Utp => w.write_all(encode::u32(UTP, &mut buf))?,
385            Protocol::Udt => w.write_all(encode::u32(UDT, &mut buf))?,
386            Protocol::Http => w.write_all(encode::u32(HTTP, &mut buf))?,
387            Protocol::Https => w.write_all(encode::u32(HTTPS, &mut buf))?,
388            Protocol::WebTransport => w.write_all(encode::u32(WEBTRANSPORT, &mut buf))?,
389            Protocol::Ws(ref s) if s == "/" => w.write_all(encode::u32(WS, &mut buf))?,
390            Protocol::Ws(s) => {
391                w.write_all(encode::u32(WS_WITH_PATH, &mut buf))?;
392                let bytes = s.as_bytes();
393                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
394                w.write_all(bytes)?
395            }
396            Protocol::Wss(ref s) if s == "/" => w.write_all(encode::u32(WSS, &mut buf))?,
397            Protocol::Wss(s) => {
398                w.write_all(encode::u32(WSS_WITH_PATH, &mut buf))?;
399                let bytes = s.as_bytes();
400                w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
401                w.write_all(bytes)?
402            }
403            Protocol::P2pWebSocketStar => w.write_all(encode::u32(P2P_WEBSOCKET_STAR, &mut buf))?,
404            Protocol::P2pWebRtcStar => w.write_all(encode::u32(P2P_WEBRTC_STAR, &mut buf))?,
405            Protocol::WebRTCDirect => w.write_all(encode::u32(WEBRTC_DIRECT, &mut buf))?,
406            Protocol::P2pWebRtcDirect => w.write_all(encode::u32(P2P_WEBRTC_DIRECT, &mut buf))?,
407            Protocol::P2pCircuit => w.write_all(encode::u32(P2P_CIRCUIT, &mut buf))?,
408            Protocol::Memory(port) => {
409                w.write_all(encode::u32(MEMORY, &mut buf))?;
410                w.write_u64::<BigEndian>(*port)?
411            }
412        }
413        Ok(())
414    }
415
416    /// Turn this `Protocol` into one that owns its data, thus being valid for any lifetime.
417    pub fn acquire<'b>(self) -> Protocol<'b> {
418        use self::Protocol::*;
419        match self {
420            Dccp(a) => Dccp(a),
421            Dns(cow) => Dns(Cow::Owned(cow.into_owned())),
422            Dns4(cow) => Dns4(Cow::Owned(cow.into_owned())),
423            Dns6(cow) => Dns6(Cow::Owned(cow.into_owned())),
424            Dnsaddr(cow) => Dnsaddr(Cow::Owned(cow.into_owned())),
425            Http => Http,
426            Https => Https,
427            Ip4(a) => Ip4(a),
428            Ip6(a) => Ip6(a),
429            P2pWebRtcDirect => P2pWebRtcDirect,
430            P2pWebRtcStar => P2pWebRtcStar,
431            WebRTCDirect => WebRTCDirect,
432            P2pWebSocketStar => P2pWebSocketStar,
433            Memory(a) => Memory(a),
434            P2p(a) => P2p(a),
435            P2pCircuit => P2pCircuit,
436            Quic => Quic,
437            QuicV1 => QuicV1,
438            Sctp(a) => Sctp(a),
439            Tcp(a) => Tcp(a),
440            Tls => Tls,
441            Noise => Noise,
442            Udp(a) => Udp(a),
443            Udt => Udt,
444            Unix(cow) => Unix(Cow::Owned(cow.into_owned())),
445            Utp => Utp,
446            WebTransport => WebTransport,
447            Ws(cow) => Ws(Cow::Owned(cow.into_owned())),
448            Wss(cow) => Wss(Cow::Owned(cow.into_owned())),
449        }
450    }
451
452    pub fn tag(&self) -> &'static str {
453        use self::Protocol::*;
454        match self {
455            Dccp(_) => "dccp",
456            Dns(_) => "dns",
457            Dns4(_) => "dns4",
458            Dns6(_) => "dns6",
459            Dnsaddr(_) => "dnsaddr",
460            Http => "http",
461            Https => "https",
462            Ip4(_) => "ip4",
463            Ip6(_) => "ip6",
464            P2pWebRtcDirect => "p2p-webrtc-direct",
465            P2pWebRtcStar => "p2p-webrtc-star",
466            WebRTCDirect => "webrtc-direct",
467            P2pWebSocketStar => "p2p-websocket-star",
468            Memory(_) => "memory",
469            P2p(_) => "p2p",
470            P2pCircuit => "p2p-circuit",
471            Quic => "quic",
472            QuicV1 => "quic-v1",
473            Sctp(_) => "sctp",
474            Tcp(_) => "tcp",
475            Tls => "tls",
476            Noise => "noise",
477            Udp(_) => "udp",
478            Udt => "udt",
479            Unix(_) => "unix",
480            Utp => "utp",
481            WebTransport => "webtransport",
482            Ws(ref s) if s == "/" => "ws",
483            Ws(_) => "x-parity-ws",
484            Wss(ref s) if s == "/" => "wss",
485            Wss(_) => "x-parity-wss",
486        }
487    }
488}
489
490impl<'a> fmt::Display for Protocol<'a> {
491    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492        use self::Protocol::*;
493        write!(f, "/{}", self.tag())?;
494        match self {
495            Dccp(port) => write!(f, "/{port}"),
496            Dns(s) => write!(f, "/{s}"),
497            Dns4(s) => write!(f, "/{s}"),
498            Dns6(s) => write!(f, "/{s}"),
499            Dnsaddr(s) => write!(f, "/{s}"),
500            Ip4(addr) => write!(f, "/{addr}"),
501            Ip6(addr) => write!(f, "/{addr}"),
502            Memory(port) => write!(f, "/{port}"),
503            P2p(node_id) => write!(f, "/{node_id}"),
504            Sctp(port) => write!(f, "/{port}"),
505            Tcp(port) => write!(f, "/{port}"),
506            Udp(port) => write!(f, "/{port}"),
507            Unix(s) => write!(f, "/{s}"),
508            Ws(s) if s != "/" => {
509                let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
510                write!(f, "/{encoded}")
511            }
512            Wss(s) if s != "/" => {
513                let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET);
514                write!(f, "/{encoded}")
515            }
516            _ => Ok(()),
517        }
518    }
519}
520
521impl<'a> From<IpAddr> for Protocol<'a> {
522    #[inline]
523    fn from(addr: IpAddr) -> Self {
524        match addr {
525            IpAddr::V4(addr) => Protocol::Ip4(addr),
526            IpAddr::V6(addr) => Protocol::Ip6(addr),
527        }
528    }
529}
530
531impl<'a> From<Ipv4Addr> for Protocol<'a> {
532    #[inline]
533    fn from(addr: Ipv4Addr) -> Self {
534        Protocol::Ip4(addr)
535    }
536}
537
538impl<'a> From<Ipv6Addr> for Protocol<'a> {
539    #[inline]
540    fn from(addr: Ipv6Addr) -> Self {
541        Protocol::Ip6(addr)
542    }
543}
544
545#[allow(unused_macros)]
546macro_rules! read_onion_impl {
547    ($name:ident, $len:expr, $encoded_len:expr) => {
548        fn $name(s: &str) -> Result<([u8; $len], u16)> {
549            let mut parts = s.split(':');
550
551            // address part (without ".onion")
552            let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
553            if b32.len() != $encoded_len {
554                return Err(Error::InvalidMultiaddr);
555            }
556
557            // port number
558            let port = parts.next().ok_or(Error::InvalidMultiaddr).and_then(|p| str::parse(p).map_err(From::from))?;
559
560            // port == 0 is not valid for onion
561            if port == 0 {
562                return Err(Error::InvalidMultiaddr);
563            }
564
565            // nothing else expected
566            if parts.next().is_some() {
567                return Err(Error::InvalidMultiaddr);
568            }
569
570            if $len != BASE32.decode_len(b32.len()).map_err(|_| Error::InvalidMultiaddr)? {
571                return Err(Error::InvalidMultiaddr);
572            }
573
574            let mut buf = [0u8; $len];
575            BASE32.decode_mut(b32.as_bytes(), &mut buf).map_err(|_| Error::InvalidMultiaddr)?;
576
577            Ok((buf, port))
578        }
579    };
580}