tor-proto: Add a helper for adding a stream entry with a specific stream ID.

This adds a new `add_ent_with_id` function for adding a new entry to the
`StreamMap`. The existing `add_ent` function auto-generates a new stream
ID, which is not good if we're a hidden service, as stream IDs are
supposed to be chosen by the OP (client). When accepting a new stream,
services, exit relays, and dir auths need to use the stream ID received
in the BEGIN cell (instead of generating a new stream ID).
This commit is contained in:
Gabriela Moldovan 2023-07-28 20:33:28 +01:00
parent 4abfe30f41
commit 18b01f94cc
No known key found for this signature in database
GPG Key ID: 3946E0ADE72BAC99
2 changed files with 47 additions and 2 deletions

View File

@ -138,6 +138,41 @@ impl StreamMap {
Err(Error::IdRangeFull)
}
/// Add an entry to this map using the specified StreamId.
//
// TODO HSS: refacor this function and add_ent to reduce code duplication.
#[cfg(feature = "hs-service")]
pub(super) fn add_ent_with_id(
&mut self,
sink: mpsc::Sender<UnparsedRelayCell>,
rx: mpsc::Receiver<AnyRelayMsg>,
send_window: sendme::StreamSendWindow,
id: StreamId,
cmd_checker: AnyCmdChecker,
) -> Result<()> {
// TODO HSS: perhaps StreamId should be a NonZeroU16.
if id.is_zero() {
return Err(Error::StreamIdZero);
}
let stream_ent = StreamEnt::Open {
sink,
rx,
send_window,
dropped: 0,
cmd_checker,
};
let ent = self.m.entry(id);
if let Entry::Vacant(_) = ent {
ent.or_insert(stream_ent);
Ok(())
} else {
Err(Error::IdUnavailable(id))
}
}
/// Return the entry for `id` in this map, if any.
pub(super) fn get_mut(&mut self, id: StreamId) -> Option<&mut StreamEnt> {
self.m.get_mut(&id)

View File

@ -1,7 +1,7 @@
//! Define an error type for the tor-proto crate.
use std::{sync::Arc, time::Duration};
use thiserror::Error;
use tor_cell::relaycell::msg::EndReason;
use tor_cell::relaycell::{msg::EndReason, StreamId};
use tor_error::{ErrorKind, HasKind};
use tor_linkspec::RelayIdType;
@ -109,6 +109,12 @@ pub enum Error {
/// Can't allocate any more circuit or stream IDs on a channel.
#[error("Too many entries in map: can't allocate ID")]
IdRangeFull,
/// Received a stream request with a stream ID that is already in use for another stream.
#[error("Stream ID {0} is already in use")]
IdUnavailable(StreamId),
/// Received a cell with a stream ID of zero.
#[error("Received a cell with a stream ID of zero")]
StreamIdZero,
/// Couldn't extend a circuit because the extending relay or the
/// target relay refused our request.
#[error("Circuit extension refused: {0}")]
@ -228,7 +234,9 @@ impl From<Error> for std::io::Error {
| EncodeErr { .. }
| ChanMismatch(_)
| StreamProto(_)
| MissingId(_) => ErrorKind::InvalidData,
| MissingId(_)
| IdUnavailable(_)
| StreamIdZero => ErrorKind::InvalidData,
Bug(ref e) if e.kind() == tor_error::ErrorKind::BadApiUsage => ErrorKind::InvalidData,
@ -276,6 +284,8 @@ impl HasKind for Error {
E::ResolveError(ResolveError::Transient) => EK::RemoteHostResolutionFailed,
E::ResolveError(ResolveError::Unrecognized) => EK::RemoteHostResolutionFailed,
E::MissingId(_) => EK::BadApiUsage,
E::IdUnavailable(_) => EK::BadApiUsage,
E::StreamIdZero => EK::BadApiUsage,
E::Bug(e) => e.kind(),
}
}