rpc: Slightly refactor GenIdx encoding.

This commit is contained in:
Nick Mathewson 2023-05-25 14:39:56 -04:00
parent 545984b095
commit d6944bf003
3 changed files with 27 additions and 17 deletions

View File

@ -87,7 +87,7 @@ pub(crate) type BoxedResponseSink =
/// A random value used to identify an connection.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, derive_more::From, derive_more::Into)]
pub(crate) struct ConnectionId(u128);
pub(crate) struct ConnectionId([u8; 16]);
impl Connection {
/// Create a new connection.

View File

@ -62,7 +62,7 @@ impl RpcMgr {
/// be possible to invoke any of its methods. See #837.
#[allow(clippy::missing_panics_doc)]
pub fn new_session<R: Runtime>(&self, client: TorClient<R>) -> Arc<Connection> {
let connection_id = ConnectionId::from(rand::thread_rng().gen::<u128>());
let connection_id = ConnectionId::from(rand::thread_rng().gen::<[u8; 16]>());
let client_obj = Arc::new(client);
let mut inner = self.inner.lock().expect("poisoned lock");

View File

@ -181,6 +181,9 @@ impl TaggedAddr {
/// analyze these object IDs, please contact the Arti developers instead and let
/// us give you a better way to do whatever you want.
impl GenIdx {
/// The length of a byte-encoded (but not base-64 encoded) GenIdx.
pub(crate) const BYTE_LEN: usize = 24;
/// Return true if this is a strong (owning) reference.
pub(crate) fn is_strong(&self) -> bool {
matches!(self, GenIdx::Strong(_))
@ -194,6 +197,12 @@ impl GenIdx {
/// As `encode`, but take a Rng as an argument. For testing.
fn encode_with_rng<R: rand::RngCore>(self, rng: &mut R) -> rpc::ObjectId {
use base64ct::Encoding;
let bytes = self.to_bytes(rng);
rpc::ObjectId::from(base64ct::Base64UrlUnpadded::encode_string(&bytes[..]))
}
/// As `encode_with_rng`, but return an array of bytes.
pub(crate) fn to_bytes<R: rand::RngCore>(self, rng: &mut R) -> [u8; Self::BYTE_LEN] {
use rand::Rng;
use tor_bytes::Writer;
let (weak_bit, idx) = match self {
@ -202,41 +211,42 @@ impl GenIdx {
};
let (a, b) = idx.into_raw_parts();
let x = rng.gen::<u64>() << 1;
let mut bytes = Vec::new();
let mut bytes = Vec::with_capacity(Self::BYTE_LEN);
bytes.write_u64(x | weak_bit);
bytes.write_u64((a as u64).wrapping_add(x));
bytes.write_u64(b.wrapping_sub(x));
rpc::ObjectId::from(base64ct::Base64UrlUnpadded::encode_string(&bytes[..]))
bytes.try_into().expect("Length was wrong!")
}
/// Attempt to decode `id` into a `GenIdx` than an ObjMap can use.
pub(crate) fn try_decode(id: &rpc::ObjectId) -> Result<Self, rpc::LookupError> {
use base64ct::Encoding;
use tor_bytes::Reader;
let bytes = base64ct::Base64UrlUnpadded::decode_vec(id.as_ref())
.map_err(|_| rpc::LookupError::NoObject(id.clone()))?;
let mut r = Reader::from_slice(&bytes);
let mut get_u64 = || {
r.take_u64()
.map_err(|_| rpc::LookupError::NoObject(id.clone()))
};
let x = get_u64()?;
Self::from_bytes(&bytes).ok_or_else(|| rpc::LookupError::NoObject(id.clone()))
}
/// As `try_decode`, but take a slice of bytes.
pub(crate) fn from_bytes(bytes: &[u8]) -> Option<Self> {
use tor_bytes::Reader;
let mut r = Reader::from_slice(bytes);
let x = r.take_u64().ok()?;
let is_weak = (x & 1) == 1;
let x = x & !1;
let a = get_u64()?;
let b = get_u64()?;
r.should_be_exhausted()
.map_err(|_| rpc::LookupError::NoObject(id.clone()))?;
let a = r.take_u64().ok()?;
let b = r.take_u64().ok()?;
r.should_be_exhausted().ok()?;
let a = a.wrapping_sub(x) as usize;
let b = b.wrapping_add(x);
let idx = generational_arena::Index::from_raw_parts(a, b);
if is_weak {
Ok(GenIdx::Weak(idx))
Some(GenIdx::Weak(idx))
} else {
Ok(GenIdx::Strong(idx))
Some(GenIdx::Strong(idx))
}
}
}