diff --git a/misc/multiaddr/Cargo.toml b/misc/multiaddr/Cargo.toml index fbe679c8..6ee14950 100644 --- a/misc/multiaddr/Cargo.toml +++ b/misc/multiaddr/Cargo.toml @@ -12,8 +12,8 @@ version = "0.3.0" bs58 = "0.2.0" byteorder = "~0.4" multihash = { path = "../multihash" } -integer-encoding = "~1.0.3" serde = "1.0.70" +unsigned-varint = "0.1" [dev-dependencies] data-encoding = "~1.1.2" diff --git a/misc/multiaddr/src/errors.rs b/misc/multiaddr/src/errors.rs index b6262444..fa82b54e 100644 --- a/misc/multiaddr/src/errors.rs +++ b/misc/multiaddr/src/errors.rs @@ -1,7 +1,8 @@ -use std::{net, fmt, error, io, num, string}; +use std::{net, fmt, error, io, num, str, string}; use bs58; use multihash; use byteorder; +use unsigned_varint::decode; pub type Result = ::std::result::Result; @@ -13,30 +14,29 @@ pub enum Error { InvalidMultiaddr, MissingAddress, ParsingError(Box), + InvalidUvar(decode::Error) } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(error::Error::description(self)) + match self { + Error::UnknownProtocol => f.write_str("unknown protocol"), + Error::UnknownProtocolString => f.write_str("unknown protocol string"), + Error::InvalidMultiaddr => f.write_str("invalid multiaddr"), + Error::MissingAddress => f.write_str("protocol requires address, none given"), + Error::ParsingError(e) => write!(f, "failed to parse: {}", e), + Error::InvalidUvar(e) => write!(f, "failed to decode unsigned varint: {}", e) + } } } impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::UnknownProtocol => "unknown protocol", - Error::UnknownProtocolString => "unknown protocol string", - Error::InvalidMultiaddr => "invalid multiaddr", - Error::MissingAddress => "protocol requires address, none given", - Error::ParsingError(_) => "failed to parse", - } - } - #[inline] - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::ParsingError(ref err) => Some(&**err), - _ => None + fn cause(&self) -> Option<&dyn error::Error> { + if let Error::ParsingError(e) = self { + Some(&**e) + } else { + None } } } @@ -59,7 +59,6 @@ impl From for Error { } } - impl From for Error { fn from(err: net::AddrParseError) -> Error { Error::ParsingError(err.into()) @@ -83,3 +82,16 @@ impl From for Error { Error::ParsingError(err.into()) } } + +impl From for Error { + fn from(err: str::Utf8Error) -> Error { + Error::ParsingError(err.into()) + } +} + +impl From for Error { + fn from(e: decode::Error) -> Error { + Error::InvalidUvar(e) + } +} + diff --git a/misc/multiaddr/src/lib.rs b/misc/multiaddr/src/lib.rs index 4d3ebe07..63cf8b5b 100644 --- a/misc/multiaddr/src/lib.rs +++ b/misc/multiaddr/src/lib.rs @@ -5,8 +5,8 @@ extern crate bs58; extern crate byteorder; -extern crate integer_encoding; extern crate serde; +extern crate unsigned_varint; pub extern crate multihash; mod protocol; @@ -266,16 +266,16 @@ impl Multiaddr { /// assert_eq!(address.pop().unwrap(), AddrComponent::UDT); /// ``` /// - pub fn pop(&mut self) -> Option { + pub fn pop<'a>(&mut self) -> Option> { // Note: could be more optimized - let mut list = self.iter().collect::>(); + let mut list = self.iter().map(AddrComponent::acquire).collect::>(); let last_elem = list.pop(); *self = list.into_iter().collect(); last_elem } } -impl From for Multiaddr { +impl<'a> From> for Multiaddr { fn from(addr: AddrComponent) -> Multiaddr { let mut out = Vec::new(); addr.write_bytes(&mut out).expect( @@ -286,7 +286,7 @@ impl From for Multiaddr { } impl<'a> IntoIterator for &'a Multiaddr { - type Item = AddrComponent; + type Item = AddrComponent<'a>; type IntoIter = Iter<'a>; #[inline] @@ -295,10 +295,10 @@ impl<'a> IntoIterator for &'a Multiaddr { } } -impl FromIterator for Multiaddr { +impl<'a> FromIterator> for Multiaddr { fn from_iter(iter: T) -> Self where - T: IntoIterator, + T: IntoIterator>, { let mut bytes = Vec::new(); for cmp in iter { @@ -348,9 +348,9 @@ impl FromStr for Multiaddr { pub struct Iter<'a>(&'a [u8]); impl<'a> Iterator for Iter<'a> { - type Item = AddrComponent; + type Item = AddrComponent<'a>; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { if self.0.is_empty() { return None; } diff --git a/misc/multiaddr/src/protocol.rs b/misc/multiaddr/src/protocol.rs index 402caa57..bc1f6a86 100644 --- a/misc/multiaddr/src/protocol.rs +++ b/misc/multiaddr/src/protocol.rs @@ -1,12 +1,15 @@ use bs58; -use std::net::{Ipv4Addr, Ipv6Addr}; -use std::str::FromStr; -use std::convert::From; -use std::io::{Cursor, Write, Result as IoResult}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use std::{ + borrow::Cow, + convert::From, + fmt, + io::{Cursor, Write, Result as IoResult}, + net::{Ipv4Addr, Ipv6Addr}, + str::{self, FromStr} +}; use multihash::Multihash; -use integer_encoding::{VarInt, VarIntWriter}; - +use unsigned_varint::{encode, decode}; use {Result, Error}; ///! # Protocol @@ -55,33 +58,33 @@ impl From for u64 { } } -impl ToString for Protocol { - fn to_string(&self) -> String { - match *self { - Protocol::IP4 => "ip4", - Protocol::TCP => "tcp", - Protocol::UDP => "udp", - Protocol::DCCP => "dccp", - Protocol::IP6 => "ip6", - Protocol::DNS4 => "dns4", - Protocol::DNS6 => "dns6", - Protocol::SCTP => "sctp", - Protocol::UDT => "udt", - Protocol::UTP => "utp", - Protocol::UNIX => "unix", - Protocol::P2P => "p2p", - Protocol::HTTP => "http", - Protocol::HTTPS => "https", - Protocol::ONION => "onion", - Protocol::QUIC => "quic", - Protocol::WS => "ws", - Protocol::WSS => "wss", - Protocol::Libp2pWebsocketStar => "p2p-websocket-star", - Protocol::Libp2pWebrtcStar => "p2p-webrtc-star", - Protocol::Libp2pWebrtcDirect => "p2p-webrtc-direct", - Protocol::P2pCircuit => "p2p-circuit", - Protocol::Memory => "memory", - }.to_owned() +impl fmt::Display for Protocol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Protocol::IP4 => f.write_str("ip4"), + Protocol::TCP => f.write_str("tcp"), + Protocol::UDP => f.write_str("udp"), + Protocol::DCCP => f.write_str("dccp"), + Protocol::IP6 => f.write_str("ip6"), + Protocol::DNS4 => f.write_str("dns4"), + Protocol::DNS6 => f.write_str("dns6"), + Protocol::SCTP => f.write_str("sctp"), + Protocol::UDT => f.write_str("udt"), + Protocol::UTP => f.write_str("utp"), + Protocol::UNIX => f.write_str("unix"), + Protocol::P2P => f.write_str("p2p"), + Protocol::HTTP => f.write_str("http"), + Protocol::HTTPS => f.write_str("https"), + Protocol::ONION => f.write_str("onion"), + Protocol::QUIC => f.write_str("quic"), + Protocol::WS => f.write_str("ws"), + Protocol::WSS => f.write_str("wss"), + Protocol::Libp2pWebsocketStar => f.write_str("p2p-websocket-star"), + Protocol::Libp2pWebrtcStar => f.write_str("p2p-webrtc-star"), + Protocol::Libp2pWebrtcDirect => f.write_str("p2p-webrtc-direct"), + Protocol::P2pCircuit => f.write_str("p2p-circuit"), + Protocol::Memory => f.write_str("memory"), + } } } @@ -223,7 +226,7 @@ impl Protocol { /// AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1))); /// ``` /// - pub fn parse_data(&self, a: &str) -> Result { + pub fn parse_data<'a>(&self, a: &'a str) -> Result> { match *self { Protocol::IP4 => { let addr = Ipv4Addr::from_str(a)?; @@ -233,12 +236,8 @@ impl Protocol { let addr = Ipv6Addr::from_str(a)?; Ok(AddrComponent::IP6(addr)) } - Protocol::DNS4 => { - Ok(AddrComponent::DNS4(a.to_owned())) - } - Protocol::DNS6 => { - Ok(AddrComponent::DNS6(a.to_owned())) - } + Protocol::DNS4 => Ok(AddrComponent::DNS4(Cow::Borrowed(a))), + Protocol::DNS6 => Ok(AddrComponent::DNS6(Cow::Borrowed(a))), Protocol::TCP => { let parsed: u16 = a.parse()?; Ok(AddrComponent::TCP(parsed)) @@ -262,9 +261,7 @@ impl Protocol { Protocol::ONION => unimplemented!(), // TODO: Protocol::QUIC => Ok(AddrComponent::QUIC), Protocol::UTP => Ok(AddrComponent::UTP), - Protocol::UNIX => { - Ok(AddrComponent::UNIX(a.to_owned())) - } + Protocol::UNIX => Ok(AddrComponent::UNIX(Cow::Borrowed(a))), Protocol::UDT => Ok(AddrComponent::UDT), Protocol::HTTP => Ok(AddrComponent::HTTP), Protocol::HTTPS => Ok(AddrComponent::HTTPS), @@ -280,22 +277,22 @@ impl Protocol { } #[derive(PartialEq, Eq, Clone, Debug)] -pub enum AddrComponent { +pub enum AddrComponent<'a> { IP4(Ipv4Addr), TCP(u16), UDP(u16), DCCP(u16), IP6(Ipv6Addr), - DNS4(String), - DNS6(String), + DNS4(Cow<'a, str>), + DNS6(Cow<'a, str>), SCTP(u16), UDT, UTP, - UNIX(String), + UNIX(Cow<'a, str>), P2P(Multihash), HTTP, HTTPS, - ONION(Vec), + ONION(Cow<'a, [u8]>), QUIC, WS, WSS, @@ -306,7 +303,37 @@ pub enum AddrComponent { Memory, } -impl AddrComponent { +impl<'a> AddrComponent<'a> { + /// Turn this `AddrComponent` into one that owns its data, thus being valid for any lifetime. + pub fn acquire<'b>(self) -> AddrComponent<'b> { + use AddrComponent::*; + match self { + DNS4(cow) => DNS4(Cow::Owned(cow.into_owned())), + DNS6(cow) => DNS6(Cow::Owned(cow.into_owned())), + UNIX(cow) => UNIX(Cow::Owned(cow.into_owned())), + ONION(cow) => ONION(Cow::Owned(cow.into_owned())), + IP4(a) => IP4(a), + TCP(a) => TCP(a), + UDP(a) => UDP(a), + DCCP(a) => DCCP(a), + IP6(a) => IP6(a), + SCTP(a) => SCTP(a), + UDT => UDT, + UTP => UTP, + P2P(a) => P2P(a), + HTTP => HTTP, + HTTPS => HTTPS, + QUIC => QUIC, + WS => WS, + WSS => WSS, + Libp2pWebsocketStar => Libp2pWebsocketStar, + Libp2pWebrtcStar => Libp2pWebrtcStar, + Libp2pWebrtcDirect => Libp2pWebrtcDirect, + P2pCircuit => P2pCircuit, + Memory => Memory + } + } + /// Returns the `Protocol` corresponding to this `AddrComponent`. #[inline] pub fn protocol_id(&self) -> Protocol { @@ -340,20 +367,13 @@ impl AddrComponent { /// Builds an `AddrComponent` from an array that starts with a bytes representation. On /// success, also returns the rest of the slice. pub fn from_bytes(input: &[u8]) -> Result<(AddrComponent, &[u8])> { - let (proto_num, proto_id_len) = u64::decode_var(input); // TODO: will panic if ID too large - + let (proto_num, input) = decode::u64(input)?; let protocol_id = Protocol::from(proto_num)?; - let (data_offset, data_size) = match protocol_id.size() { - ProtocolArgSize::Fixed { bytes } => { - (0, bytes) - }, - ProtocolArgSize::Variable => { - let (data_size, varint_len) = u64::decode_var(&input[proto_id_len..]); // TODO: will panic if ID too large - (varint_len, data_size as usize) - }, + let (data_size, input) = match protocol_id.size() { + ProtocolArgSize::Fixed { bytes } => (bytes, input), + ProtocolArgSize::Variable => decode::usize(input)? }; - - let (data, rest) = input[proto_id_len..][data_offset..].split_at(data_size); + let (data, rest) = input.split_at(data_size); let addr_component = match protocol_id { Protocol::IP4 => { @@ -361,10 +381,10 @@ impl AddrComponent { }, Protocol::IP6 => { let mut rdr = Cursor::new(data); - let mut seg = vec![]; + let mut seg = [0; 8]; - for _ in 0..8 { - seg.push(rdr.read_u16::()?); + for i in 0..8 { + seg[i] = rdr.read_u16::()?; } let addr = Ipv6Addr::new(seg[0], @@ -378,10 +398,10 @@ impl AddrComponent { AddrComponent::IP6(addr) } Protocol::DNS4 => { - AddrComponent::DNS4(String::from_utf8(data.to_owned())?) + AddrComponent::DNS4(Cow::Borrowed(str::from_utf8(data)?)) } Protocol::DNS6 => { - AddrComponent::DNS6(String::from_utf8(data.to_owned())?) + AddrComponent::DNS6(Cow::Borrowed(str::from_utf8(data)?)) } Protocol::TCP => { let mut rdr = Cursor::new(data); @@ -404,7 +424,7 @@ impl AddrComponent { AddrComponent::SCTP(num) } Protocol::UNIX => { - AddrComponent::UNIX(String::from_utf8(data.to_owned())?) + AddrComponent::UNIX(Cow::Borrowed(str::from_utf8(data)?)) } Protocol::P2P => { AddrComponent::P2P(Multihash::from_bytes(data.to_owned())?) @@ -429,7 +449,7 @@ impl AddrComponent { /// Turns this address component into bytes by writing it to a `Write`. pub fn write_bytes(self, out: &mut W) -> IoResult<()> { - out.write_varint(Into::::into(self.protocol_id()))?; + out.write_all(encode::u64(self.protocol_id().into(), &mut encode::u64_buffer()))?; match self { AddrComponent::IP4(addr) => { @@ -446,12 +466,12 @@ impl AddrComponent { } AddrComponent::DNS4(s) | AddrComponent::DNS6(s) | AddrComponent::UNIX(s) => { let bytes = s.as_bytes(); - out.write_varint(bytes.len())?; + out.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?; out.write_all(&bytes)?; } AddrComponent::P2P(multihash) => { let bytes = multihash.into_bytes(); - out.write_varint(bytes.len())?; + out.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?; out.write_all(&bytes)?; } AddrComponent::ONION(_) => { @@ -475,46 +495,46 @@ impl AddrComponent { } } -impl ToString for AddrComponent { - fn to_string(&self) -> String { - match *self { - AddrComponent::IP4(ref addr) => format!("/ip4/{}", addr), - AddrComponent::TCP(port) => format!("/tcp/{}", port), - AddrComponent::UDP(port) => format!("/udp/{}", port), - AddrComponent::DCCP(port) => format!("/dccp/{}", port), - AddrComponent::IP6(ref addr) => format!("/ip6/{}", addr), - AddrComponent::DNS4(ref s) => format!("/dns4/{}", s.clone()), - AddrComponent::DNS6(ref s) => format!("/dns6/{}", s.clone()), - AddrComponent::SCTP(port) => format!("/sctp/{}", port), - AddrComponent::UDT => format!("/udt"), - AddrComponent::UTP => format!("/utp"), - AddrComponent::UNIX(ref s) => format!("/unix/{}", s.clone()), - AddrComponent::P2P(ref c) => format!("/p2p/{}", bs58::encode(c.as_bytes()).into_string()), - AddrComponent::HTTP => format!("/http"), - AddrComponent::HTTPS => format!("/https"), - AddrComponent::ONION(_) => unimplemented!(),//format!("/onion"), // TODO: - AddrComponent::QUIC => format!("/quic"), - AddrComponent::WS => format!("/ws"), - AddrComponent::WSS => format!("/wss"), - AddrComponent::Libp2pWebsocketStar => format!("/p2p-websocket-star"), - AddrComponent::Libp2pWebrtcStar => format!("/p2p-webrtc-star"), - AddrComponent::Libp2pWebrtcDirect => format!("/p2p-webrtc-direct"), - AddrComponent::P2pCircuit => format!("/p2p-circuit"), - AddrComponent::Memory => format!("/memory"), +impl<'a> fmt::Display for AddrComponent<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AddrComponent::IP4(addr) => write!(f, "/ip4/{}", addr), + AddrComponent::TCP(port) => write!(f, "/tcp/{}", port), + AddrComponent::UDP(port) => write!(f, "/udp/{}", port), + AddrComponent::DCCP(port) => write!(f, "/dccp/{}", port), + AddrComponent::IP6(addr) => write!(f, "/ip6/{}", addr), + AddrComponent::DNS4(s) => write!(f, "/dns4/{}", s), + AddrComponent::DNS6(s) => write!(f, "/dns6/{}", s), + AddrComponent::SCTP(port) => write!(f, "/sctp/{}", port), + AddrComponent::UDT => f.write_str("/udt"), + AddrComponent::UTP => f.write_str("/utp"), + AddrComponent::UNIX(s) => write!(f, "/unix/{}", s), + AddrComponent::P2P(c) => write!(f, "/p2p/{}", bs58::encode(c.as_bytes()).into_string()), + AddrComponent::HTTP => f.write_str("/http"), + AddrComponent::HTTPS => f.write_str("/https"), + AddrComponent::ONION(_) => unimplemented!(),//write!("/onion"), // TODO: + AddrComponent::QUIC => f.write_str("/quic"), + AddrComponent::WS => f.write_str("/ws"), + AddrComponent::WSS => f.write_str("/wss"), + AddrComponent::Libp2pWebsocketStar => f.write_str("/p2p-websocket-star"), + AddrComponent::Libp2pWebrtcStar => f.write_str("/p2p-webrtc-star"), + AddrComponent::Libp2pWebrtcDirect => f.write_str("/p2p-webrtc-direct"), + AddrComponent::P2pCircuit => f.write_str("/p2p-circuit"), + AddrComponent::Memory => f.write_str("/memory"), } } } -impl From for AddrComponent { +impl<'a> From for AddrComponent<'a> { #[inline] - fn from(addr: Ipv4Addr) -> AddrComponent { + fn from(addr: Ipv4Addr) -> Self { AddrComponent::IP4(addr) } } -impl From for AddrComponent { +impl<'a> From for AddrComponent<'a> { #[inline] - fn from(addr: Ipv6Addr) -> AddrComponent { + fn from(addr: Ipv6Addr) -> Self { AddrComponent::IP6(addr) } } diff --git a/protocols/identify/src/peer_id_transport.rs b/protocols/identify/src/peer_id_transport.rs index 1d1d3536..c564a9a2 100644 --- a/protocols/identify/src/peer_id_transport.rs +++ b/protocols/identify/src/peer_id_transport.rs @@ -284,13 +284,11 @@ pub struct PeerIdTransportOutput { // If the multiaddress is in the form `/p2p/...`, turn it into a `PeerId`. // Otherwise, return it as-is. fn multiaddr_to_peerid(addr: Multiaddr) -> Result { - let components = addr.iter().collect::>(); - if components.len() < 1 { - return Err(addr); + if addr.iter().next().is_none() { + return Err(addr) } - - match components.last() { - Some(&AddrComponent::P2P(ref peer_id)) => { + match addr.iter().last() { + Some(AddrComponent::P2P(ref peer_id)) => { match PeerId::from_multihash(peer_id.clone()) { Ok(peer_id) => Ok(peer_id), Err(_) => Err(addr), diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index cdff70b0..b556f61b 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -149,7 +149,7 @@ where AddrComponent::DNS6(ref name) => { future::Either::A(resolve_dns(name, &resolver, ResolveTy::Dns6)) } - cmp => future::Either::B(future::ok(cmp)), + cmp => future::Either::B(future::ok(cmp.acquire())), }) .collect::>() .into_iter(); @@ -188,11 +188,11 @@ enum ResolveTy { } // Resolve a DNS name and returns a future with the result. -fn resolve_dns( +fn resolve_dns<'a>( name: &str, resolver: &CpuPoolResolver, ty: ResolveTy, -) -> impl Future { +) -> impl Future, Error = IoError> { let debug_name = if log_enabled!(Level::Trace) { Some(name.to_owned()) } else { diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index 4a754f28..e85ce3bf 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -148,7 +148,7 @@ fn multiaddr_to_path(addr: &Multiaddr) -> Result { } match path { - Some(AddrComponent::UNIX(ref path)) => Ok(path.into()), + Some(AddrComponent::UNIX(ref path)) => Ok(path.as_ref().into()), _ => Err(()) } } @@ -159,8 +159,7 @@ mod tests { use futures::stream::Stream; use futures::Future; use multiaddr::{AddrComponent, Multiaddr}; - use std; - use std::path::Path; + use std::{self, borrow::Cow, path::Path}; use libp2p_core::Transport; use tempfile; use tokio_current_thread; @@ -189,7 +188,7 @@ mod tests { let temp_dir = tempfile::tempdir().unwrap(); let socket = temp_dir.path().join("socket"); - let addr = Multiaddr::from(AddrComponent::UNIX(socket.to_string_lossy().into_owned())); + let addr = Multiaddr::from(AddrComponent::UNIX(Cow::Owned(socket.to_string_lossy().into_owned()))); let addr2 = addr.clone(); std::thread::spawn(move || {