diff --git a/crates/tor-netdoc/src/doc.rs b/crates/tor-netdoc/src/doc.rs index bba117d916b173999da0ab57e80c4c4a44e924ce..b683f6c5363ddbbb4229fc1000089127c17b4223 100644 --- a/crates/tor-netdoc/src/doc.rs +++ b/crates/tor-netdoc/src/doc.rs @@ -29,6 +29,8 @@ //! Finally, there are the voting documents themselves that authorities //! use in order to calculate the consensus. +use crate::util::intern::InternCache; + pub mod authcert; pub mod microdesc; pub mod netstatus; @@ -42,3 +44,9 @@ pub mod routerdesc { /// The digest of a RouterDesc document, as reported in a NS consensus. pub type RdDigest = [u8; 20]; } + +/// Cache of Protocols objects, for saving memory. +// +/// This only holds weak references to the objects, so we don't +/// need to worry about running out of space because of stale entries. +static PROTOVERS_CACHE: InternCache<tor_protover::Protocols> = InternCache::new(); diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index 457198d7e090458ec28cf2644b697dedc78bb727..fde46fe3349e721b19ee5979757a26aa602eb77a 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -10,6 +10,7 @@ mod md; mod ns; use super::{NetstatusKwd, RelayFlags, RelayWeight}; +use crate::doc; use crate::parse::parser::Section; use crate::types::misc::*; use crate::types::version::TorVersion; @@ -44,7 +45,7 @@ struct GenericRouterStatus<D> { /// Version of the software that this relay is running. version: Option<Version>, /// List of subprotocol versions supported by this relay. - protos: Protocols, + protos: Arc<Protocols>, /// Information about how to weight this relay when choosing a /// relay at random. weight: RelayWeight, @@ -212,9 +213,11 @@ where // PR line let protos = { let tok = sec.required(RS_PR)?; - tok.args_as_str() - .parse::<Protocols>() - .map_err(|e| EK::BadArgument.at_pos(tok.pos()).with_source(e))? + doc::PROTOVERS_CACHE.intern( + tok.args_as_str() + .parse::<Protocols>() + .map_err(|e| EK::BadArgument.at_pos(tok.pos()).with_source(e))?, + ) }; // W line diff --git a/crates/tor-netdoc/src/doc/netstatus/rs/build.rs b/crates/tor-netdoc/src/doc/netstatus/rs/build.rs index d217eacf6b71e294017c8cc7e608c48dc9235c1a..6b6d843470646efb58ae6567e49036827b909bbe 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs/build.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs/build.rs @@ -1,6 +1,7 @@ //! Provide builder functionality for routerstatuses. use super::{GenericRouterStatus, MdConsensusRouterStatus}; +use crate::doc; use crate::doc::microdesc::MdDigest; use crate::doc::netstatus::{ConsensusBuilder, RelayFlags, RelayWeight}; use crate::{BuildError as Error, BuildResult as Result}; @@ -143,7 +144,7 @@ impl<D: Clone> RouterStatusBuilder<D> { addrs: self.addrs.clone(), doc_digest, version, - protos, + protos: doc::PROTOVERS_CACHE.intern(protos), flags: self.flags, weight, }) diff --git a/crates/tor-netdoc/src/doc/routerdesc.rs b/crates/tor-netdoc/src/doc/routerdesc.rs index 4fc0f1817ad686b0cd8b91b0caf2c1b90ede4ce6..7986e62ab13844f46e2d5a6c1bc56678450622e5 100644 --- a/crates/tor-netdoc/src/doc/routerdesc.rs +++ b/crates/tor-netdoc/src/doc/routerdesc.rs @@ -39,7 +39,7 @@ use crate::types::family::RelayFamily; use crate::types::misc::*; use crate::types::policy::*; use crate::types::version::TorVersion; -use crate::{AllowAnnotations, Error, ParseErrorKind as EK, Result}; +use crate::{doc, AllowAnnotations, Error, ParseErrorKind as EK, Result}; use once_cell::sync::Lazy; use std::sync::Arc; @@ -124,7 +124,7 @@ pub struct RouterDesc { /// (deprecated) TAP protocol. tap_onion_key: ll::pk::rsa::PublicKey, /// List of subprotocol versions supported by this relay. - proto: tor_protover::Protocols, + proto: Arc<tor_protover::Protocols>, /// True if this relay says it's a directory cache. is_dircache: bool, /// True if this relay says that it caches extrainfo documents. @@ -543,10 +543,12 @@ impl RouterDesc { // List of subprotocol versions let proto = { let proto_tok = body.required(PROTO)?; - proto_tok - .args_as_str() - .parse::<tor_protover::Protocols>() - .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))? + doc::PROTOVERS_CACHE.intern( + proto_tok + .args_as_str() + .parse::<tor_protover::Protocols>() + .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?, + ) }; // tunneled-dir-server diff --git a/crates/tor-protover/src/lib.rs b/crates/tor-protover/src/lib.rs index 70896460a7512d0f72600fb5a159d2547326b31f..83e8ff787b1d9f7f29ee85b46d9892aff202a941 100644 --- a/crates/tor-protover/src/lib.rs +++ b/crates/tor-protover/src/lib.rs @@ -77,6 +77,7 @@ caret_int! { /// cbor document format in the walking onions proposal. /// /// For the full semantics of each subprotocol, see tor-spec.txt. + #[derive(Hash,Ord,PartialOrd)] pub struct ProtoKind(u16) { /// Initiating and receiving channels, and getting cells on them. Link = 0, @@ -110,7 +111,7 @@ caret_int! { const N_RECOGNIZED: usize = 12; /// Representation for a known or unknown protocol. -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug, Hash, Ord, PartialOrd)] enum Protocol { /// A known protocol; represented by one of ProtoKind. Proto(ProtoKind), @@ -138,7 +139,7 @@ impl Protocol { /// Representation of a set of versions supported by a protocol. /// /// For now, we only use this type for unrecognized protocols. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] struct SubprotocolEntry { /// Which protocol's versions does this describe? proto: Protocol, @@ -157,7 +158,7 @@ struct SubprotocolEntry { /// use tor_protover::Protocols; /// let p: Result<Protocols,_> = "Link=1-3 LinkAuth=2-3 Relay=1-2".parse(); /// ``` -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)] pub struct Protocols { /// A mapping from protocols' integer encodings to bit-vectors. recognized: [u64; N_RECOGNIZED], @@ -398,6 +399,7 @@ impl std::str::FromStr for Protocols { let s: SubprotocolEntry = ent.parse()?; result.add(&mut foundmask, s)?; } + result.unrecognized.sort(); Ok(result) } } diff --git a/doc/semver_status.md b/doc/semver_status.md index 5e5d7349469425cc682cdcaa3a40c7e96626dacb..c2e641131f5669a896565e7ed0a5a3f13a628836 100644 --- a/doc/semver_status.md +++ b/doc/semver_status.md @@ -45,14 +45,17 @@ arti-client: &Arc, not Arc. tor-dirmgr: - new-api: DirMgrConfig object now has accessors. + tor-netdoc: new-api (experimental only): Can modify the set of relays in an unverified consensus. - -tor-netdoc: api-break: changed the return type of GenericRouterStatus::version() + +tor-protover: + new-api: Protocols now implements Eq, PartialEq, and Hash. + +