diff options
author | Isis Lovecruft <isis@torproject.org> | 2018-03-21 01:18:02 +0000 |
---|---|---|
committer | Isis Lovecruft <isis@torproject.org> | 2018-04-02 19:20:26 +0000 |
commit | 88b2f170e451567a3b0095a420544a675a5826b0 (patch) | |
tree | f3b3ee572fb7bd6f57323f0d5993008bf21786c8 /src/rust | |
parent | 811178434eae16fd673b67ebda06b630aa27dec4 (diff) | |
download | tor-88b2f170e451567a3b0095a420544a675a5826b0.tar.gz tor-88b2f170e451567a3b0095a420544a675a5826b0.zip |
rust: Add new protover::ProtoEntry type which uses new datatypes.
This replaces the `protover::SupportedProtocols` (why would you have a type just
for things which are supported?) with a new, more generic type,
`protover::ProtoEntry`, which utilises the new, more memory-efficient datatype
in protover::protoset.
* REMOVE `get_supported_protocols()` and `SupportedProtocols::tor_supported()`
(since they were never used separately) and collapse their functionality into
a single `ProtoEntry::supported()` method.
* REMOVE `SupportedProtocols::from_proto_entries()` and reimplement its
functionality as the more rusty `impl FromStr for ProtoEntry`.
* REMOVE `get_proto_and_vers()` function and refactor it into the more rusty
`impl FromStr for ProtoEntry`.
* FIXES part of #24031: https://bugs.torproject.org/24031
Diffstat (limited to 'src/rust')
-rw-r--r-- | src/rust/protover/protover.rs | 160 |
1 files changed, 75 insertions, 85 deletions
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index 30d9e0a897..d507336cce 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -1,20 +1,20 @@ // Copyright (c) 2016-2017, The Tor Project, Inc. */ // See LICENSE for licensing information */ -use std::str; -use std::str::FromStr; +use std::collections::HashMap; +use std::collections::hash_map; use std::ffi::CStr; use std::fmt; -use std::collections::{HashMap, HashSet}; -use std::ops::Range; +use std::str; +use std::str::FromStr; use std::string::String; -use std::u32; use tor_log::{LogSeverity, LogDomain}; use external::c_tor_version_as_new_as; use errors::ProtoverError; use protoset::Version; +use protoset::ProtoSet; /// The first version of Tor that included "proto" entries in its descriptors. /// Authorities should use this to decide whether to guess proto lines. @@ -130,100 +130,90 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { Relay=1-2") } -/// Get a string representation of current supported protocols. -/// -/// # Returns -/// -/// An `&'a str` whose value is the existing protocols supported by tor. -/// Returned data is in the format as follows: -/// -/// "HSDir=1-1 LinkAuth=1" -pub fn get_supported_protocols<'a>() -> &'a str { - let supported_cstr: &'static CStr = get_supported_protocols_cstr(); - let supported: &str = match supported_cstr.to_str() { - Ok(x) => x, - Err(_) => "", - }; - - supported -} +/// A map of protocol names to the versions of them which are supported. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ProtoEntry(HashMap<Protocol, ProtoSet>); -pub struct SupportedProtocols(HashMap<Proto, Versions>); - -impl SupportedProtocols { - pub fn from_proto_entries<I, S>(protocol_strs: I) -> Result<Self, &'static str> - where - I: Iterator<Item = S>, - S: AsRef<str>, - { - let mut parsed = HashMap::new(); - for subproto in protocol_strs { - let (name, version) = get_proto_and_vers(subproto.as_ref())?; - parsed.insert(name, version); - } - Ok(SupportedProtocols(parsed)) +impl Default for ProtoEntry { + fn default() -> ProtoEntry { + ProtoEntry( HashMap::new() ) } +} - /// Translates a string representation of a protocol list to a - /// SupportedProtocols instance. - /// - /// # Examples - /// - /// ``` - /// use protover::SupportedProtocols; - /// - /// let supported_protocols = SupportedProtocols::from_proto_entries_string( - /// "HSDir=1-2 HSIntro=3-4" - /// ); - /// ``` - pub fn from_proto_entries_string( - proto_entries: &str, - ) -> Result<Self, &'static str> { - Self::from_proto_entries(proto_entries.split(" ")) +impl ProtoEntry { + /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`. + pub fn iter(&self) -> hash_map::Iter<Protocol, ProtoSet> { + self.0.iter() } /// Translate the supported tor versions from a string into a - /// HashMap, which is useful when looking up a specific + /// ProtoEntry, which is useful when looking up a specific /// subprotocol. - /// - fn tor_supported() -> Result<Self, &'static str> { - Self::from_proto_entries_string(get_supported_protocols()) + pub fn supported() -> Result<Self, ProtoverError> { + let supported_cstr: &'static CStr = get_supported_protocols_cstr(); + let supported: &str = supported_cstr.to_str().unwrap_or(""); + + supported.parse() + } + + pub fn get(&self, protocol: &Protocol) -> Option<&ProtoSet> { + self.0.get(protocol) + } + + pub fn insert(&mut self, key: Protocol, value: ProtoSet) { + self.0.insert(key, value); + } + + pub fn remove(&mut self, key: &Protocol) -> Option<ProtoSet> { + self.0.remove(key) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() } } -/// Parse the subprotocol type and its version numbers. -/// -/// # Inputs -/// -/// * A `protocol_entry` string, comprised of a keyword, an "=" sign, and one -/// or more version numbers. -/// -/// # Returns -/// -/// A `Result` whose `Ok` value is a tuple of `(Proto, HashSet<u32>)`, where the -/// first element is the subprotocol type (see `protover::Proto`) and the last -/// element is a(n unordered) set of unique version numbers which are supported. -/// Otherwise, the `Err` value of this `Result` is a description of the error -/// -fn get_proto_and_vers<'a>( - protocol_entry: &'a str, -) -> Result<(Proto, Versions), &'static str> { - let mut parts = protocol_entry.splitn(2, "="); +impl FromStr for ProtoEntry { + type Err = ProtoverError; - let proto = match parts.next() { - Some(n) => n, - None => return Err("invalid protover entry"), - }; + /// Parse a string of subprotocol types and their version numbers. + /// + /// # Inputs + /// + /// * A `protocol_entry` string, comprised of a keywords, an "=" sign, and + /// one or more version numbers, each separated by a space. For example, + /// `"Cons=3-4 HSDir=1"`. + /// + /// # Returns + /// + /// A `Result` whose `Ok` value is a `ProtoEntry`, where the + /// first element is the subprotocol type (see `protover::Protocol`) and the last + /// element is an ordered set of `(low, high)` unique version numbers which are supported. + /// Otherwise, the `Err` value of this `Result` is a `ProtoverError`. + fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> { + let mut proto_entry: ProtoEntry = ProtoEntry::default(); + let entries = protocol_entry.split(' '); + + for entry in entries { + let mut parts = entry.splitn(2, '='); + + let proto = match parts.next() { + Some(n) => n, + None => return Err(ProtoverError::Unparseable), + }; - let vers = match parts.next() { - Some(n) => n, - None => return Err("invalid protover entry"), - }; + let vers = match parts.next() { + Some(n) => n, + None => return Err(ProtoverError::Unparseable), + }; + let versions: ProtoSet = vers.parse()?; + let proto_name: Protocol = proto.parse()?; - let versions = Versions::from_version_string(vers)?; - let proto_name = proto.parse()?; + proto_entry.insert(proto_name, versions); + } - Ok((proto_name, versions)) + Ok(proto_entry) + } } /// Parses a single subprotocol entry string into subprotocol and version |