tor_cell/relaycell.rs
1//! Implementation for parsing and encoding relay cells
2
3use std::num::NonZeroU16;
4
5use crate::chancell::{BoxedCellBody, CELL_DATA_LEN};
6use derive_deftly::Deftly;
7use smallvec::{smallvec, SmallVec};
8use tor_bytes::{EncodeError, EncodeResult, Error, Result};
9use tor_bytes::{Reader, Writer};
10use tor_error::internal;
11use tor_memquota::derive_deftly_template_HasMemoryCost;
12
13use caret::caret_int;
14use rand::{CryptoRng, Rng};
15
16#[cfg(feature = "conflux")]
17pub mod conflux;
18pub mod extend;
19#[cfg(feature = "hs")]
20pub mod hs;
21pub mod msg;
22#[cfg(feature = "experimental-udp")]
23pub mod udp;
24
25caret_int! {
26 /// A command that identifies the type of a relay cell
27 #[derive(Deftly)]
28 #[derive_deftly(HasMemoryCost)]
29 pub struct RelayCmd(u8) {
30 /// Start a new stream
31 BEGIN = 1,
32 /// Data on a stream
33 DATA = 2,
34 /// Close a stream
35 END = 3,
36 /// Acknowledge a BEGIN; stream is open
37 CONNECTED = 4,
38 /// Used for flow control
39 SENDME = 5,
40 /// Extend a circuit to a new hop; deprecated
41 EXTEND = 6,
42 /// Reply to EXTEND handshake; deprecated
43 EXTENDED = 7,
44 /// Partially close a circuit
45 TRUNCATE = 8,
46 /// Circuit has been partially closed
47 TRUNCATED = 9,
48 /// Padding cell
49 DROP = 10,
50 /// Start a DNS lookup
51 RESOLVE = 11,
52 /// Reply to a DNS lookup
53 RESOLVED = 12,
54 /// Start a directory stream
55 BEGIN_DIR = 13,
56 /// Extend a circuit to a new hop
57 EXTEND2 = 14,
58 /// Reply to an EXTEND2 cell.
59 EXTENDED2 = 15,
60
61 /// NOTE: UDP command are reserved but only used with experimental-udp feature
62
63 /// UDP: Start of a stream
64 CONNECT_UDP = 16,
65 /// UDP: Acknowledge a CONNECT_UDP. Stream is open.
66 CONNECTED_UDP = 17,
67 /// UDP: Data on a UDP stream.
68 DATAGRAM = 18,
69
70 /// CONFLUX: Link circuits together at the receiving endpoint.
71 CONFLUX_LINK = 19,
72 /// CONFLUX: Confirm that the circuits were linked.
73 CONFLUX_LINKED = 20,
74 /// CONFLUX: Acknowledge the linkage of the circuits, for RTT measurement.
75 CONFLUX_LINKED_ACK = 21,
76 /// CONFLUX: Switch to another leg in an already linked circuit construction.
77 CONFLUX_SWITCH = 22,
78
79 /// HS: establish an introduction point.
80 ESTABLISH_INTRO = 32,
81 /// HS: establish a rendezvous point.
82 ESTABLISH_RENDEZVOUS = 33,
83 /// HS: send introduction (client to introduction point)
84 INTRODUCE1 = 34,
85 /// HS: send introduction (introduction point to service)
86 INTRODUCE2 = 35,
87 /// HS: connect rendezvous point (service to rendezvous point)
88 RENDEZVOUS1 = 36,
89 /// HS: connect rendezvous point (rendezvous point to client)
90 RENDEZVOUS2 = 37,
91 /// HS: Response to ESTABLISH_INTRO
92 INTRO_ESTABLISHED = 38,
93 /// HS: Response to ESTABLISH_RENDEZVOUS
94 RENDEZVOUS_ESTABLISHED = 39,
95 /// HS: Response to INTRODUCE1 from introduction point to client
96 INTRODUCE_ACK = 40,
97
98 /// Padding: declare what kind of padding we want
99 PADDING_NEGOTIATE = 41,
100 /// Padding: reply to a PADDING_NEGOTIATE
101 PADDING_NEGOTIATED = 42,
102 }
103}
104
105/// Possible requirements on stream IDs for a relay command.
106enum StreamIdReq {
107 /// Can only be used with a stream ID of 0
108 WantNone,
109 /// Can only be used with a stream ID that isn't 0
110 WantSome,
111 /// Can be used with any stream ID
112 Any,
113}
114
115impl RelayCmd {
116 /// Check whether this command requires a certain kind of
117 /// StreamId, and return a corresponding StreamIdReq.
118 fn expects_streamid(self) -> StreamIdReq {
119 match self {
120 RelayCmd::BEGIN
121 | RelayCmd::DATA
122 | RelayCmd::END
123 | RelayCmd::CONNECTED
124 | RelayCmd::RESOLVE
125 | RelayCmd::RESOLVED
126 | RelayCmd::BEGIN_DIR => StreamIdReq::WantSome,
127 #[cfg(feature = "experimental-udp")]
128 RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
129 StreamIdReq::WantSome
130 }
131 RelayCmd::EXTEND
132 | RelayCmd::EXTENDED
133 | RelayCmd::TRUNCATE
134 | RelayCmd::TRUNCATED
135 | RelayCmd::DROP
136 | RelayCmd::EXTEND2
137 | RelayCmd::EXTENDED2
138 | RelayCmd::CONFLUX_LINK
139 | RelayCmd::CONFLUX_LINKED
140 | RelayCmd::CONFLUX_LINKED_ACK
141 | RelayCmd::CONFLUX_SWITCH
142 | RelayCmd::ESTABLISH_INTRO
143 | RelayCmd::ESTABLISH_RENDEZVOUS
144 | RelayCmd::INTRODUCE1
145 | RelayCmd::INTRODUCE2
146 | RelayCmd::RENDEZVOUS1
147 | RelayCmd::RENDEZVOUS2
148 | RelayCmd::INTRO_ESTABLISHED
149 | RelayCmd::RENDEZVOUS_ESTABLISHED
150 | RelayCmd::INTRODUCE_ACK => StreamIdReq::WantNone,
151 RelayCmd::SENDME => StreamIdReq::Any,
152 _ => StreamIdReq::Any,
153 }
154 }
155 /// Return true if this command is one that accepts the particular
156 /// stream ID `id`
157 pub fn accepts_streamid_val(self, id: Option<StreamId>) -> bool {
158 match self.expects_streamid() {
159 StreamIdReq::WantNone => id.is_none(),
160 StreamIdReq::WantSome => id.is_some(),
161 StreamIdReq::Any => true,
162 }
163 }
164}
165
166/// Identify a single stream on a circuit.
167///
168/// These identifiers are local to each hop on a circuit.
169/// This can't be zero; if you need something that can be zero in the protocol,
170/// use `Option<StreamId>`.
171#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Deftly)]
172#[derive_deftly(HasMemoryCost)]
173pub struct StreamId(NonZeroU16);
174
175impl From<NonZeroU16> for StreamId {
176 fn from(id: NonZeroU16) -> Self {
177 Self(id)
178 }
179}
180
181impl From<StreamId> for NonZeroU16 {
182 fn from(id: StreamId) -> NonZeroU16 {
183 id.0
184 }
185}
186
187impl From<StreamId> for u16 {
188 fn from(id: StreamId) -> u16 {
189 id.0.get()
190 }
191}
192
193impl std::fmt::Display for StreamId {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
195 self.0.fmt(f)
196 }
197}
198
199impl StreamId {
200 /// Creates a `StreamId` for non-zero `stream_id`.
201 ///
202 /// Returns `None` when `stream_id` is zero. Messages with a zero/None stream ID
203 /// apply to the circuit as a whole instead of a particular stream.
204 pub fn new(stream_id: u16) -> Option<Self> {
205 NonZeroU16::new(stream_id).map(Self)
206 }
207
208 /// Convenience function to convert to a `u16`; `None` is mapped to 0.
209 pub fn get_or_zero(stream_id: Option<Self>) -> u16 {
210 match stream_id {
211 Some(stream_id) => stream_id.0.get(),
212 None => 0,
213 }
214 }
215}
216
217/// Specifies which encoding version of RelayCell to use.
218#[non_exhaustive]
219#[derive(Copy, Clone, Debug)]
220pub enum RelayCellFormat {
221 /// This is the "legacy" pre-prop340 format. No packing or fragmentation.
222 V0,
223}
224
225/// Specifies a relay cell format and associated types.
226pub trait RelayCellFormatTrait {
227 /// Which format this object is for.
228 const FORMAT: RelayCellFormat;
229 /// A `RelayCellFields` type for this format.
230 type FIELDS: RelayCellFields;
231 // TODO: Consider making a trait for the decoder as well and adding the
232 // corresponding associated type here.
233}
234
235/// Format type corresponding to `RelayCellFormat::V0`.
236#[non_exhaustive]
237pub struct RelayCellFormatV0;
238
239impl RelayCellFormatTrait for RelayCellFormatV0 {
240 const FORMAT: RelayCellFormat = RelayCellFormat::V0;
241 type FIELDS = RelayCellFieldsV0;
242}
243
244/// Specifies field layout for a particular relay cell format.
245pub trait RelayCellFields {
246 /// The range containing the `recognized` field, within a relay cell's body.
247 const RECOGNIZED_RANGE: std::ops::Range<usize>;
248 /// The range containing the `digest` field, within a relay cell's body.
249 const DIGEST_RANGE: std::ops::Range<usize>;
250 /// A static array of zeroes of the same size as this format uses for the
251 /// digest field. e.g. this enables updating a comparison-digest in one
252 /// hash-update method call, instead of having to loop over `DIGEST_RANGE`.
253 const EMPTY_DIGEST: &'static [u8];
254}
255
256/// Specifies fields for `RelayCellFormat::V0`.
257#[non_exhaustive]
258pub struct RelayCellFieldsV0;
259
260impl RelayCellFields for RelayCellFieldsV0 {
261 const RECOGNIZED_RANGE: std::ops::Range<usize> = 1..3;
262 const DIGEST_RANGE: std::ops::Range<usize> = 5..9;
263 const EMPTY_DIGEST: &'static [u8] = &[0, 0, 0, 0];
264}
265
266/// Internal decoder state.
267#[derive(Clone, Debug)]
268enum RelayCellDecoderInternal {
269 /// Internal state for `RelayCellFormat::V0`
270 V0,
271}
272
273// TODO prop340: We should also fuzz RelayCellDecoder, but not in this fuzzer.
274
275/// Decodes a stream of relay cell bodies into `UnparsedRelayMsg`s.
276#[derive(Clone, Debug)]
277pub struct RelayCellDecoder {
278 /// Internal representation.
279 internal: RelayCellDecoderInternal,
280}
281
282impl RelayCellDecoder {
283 /// Returns a new `Decoder`, handling a stream of relay cells
284 /// of the given `version`.
285 pub fn new(version: RelayCellFormat) -> Self {
286 match version {
287 RelayCellFormat::V0 => Self {
288 internal: RelayCellDecoderInternal::V0,
289 },
290 }
291 }
292 /// Parse a RELAY or RELAY_EARLY cell body.
293 ///
294 /// Requires that the cryptographic checks on the message have already been
295 /// performed
296 pub fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
297 match &self.internal {
298 RelayCellDecoderInternal::V0 => Ok(RelayCellDecoderResult {
299 msgs: smallvec![UnparsedRelayMsg {
300 internal: UnparsedRelayMsgInternal::V0(cell)
301 }],
302 incomplete: None,
303 }),
304 }
305 }
306 /// Returns the `IncompleteRelayMsgInfo` describing the partial
307 /// (fragmented) relay message at the end of the so-far-processed relay cell
308 /// stream.
309 pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
310 match &self.internal {
311 // V0 doesn't support fragmentation, so there is never a pending fragment.
312 RelayCellDecoderInternal::V0 => None,
313 }
314 }
315}
316
317/// Result of calling `RelayCellDecoder::decode`.
318#[derive(Debug)]
319pub struct RelayCellDecoderResult {
320 /// Complete messages obtained by decoding the cell. i.e. messages
321 /// that were completely contained within the cell, or for which the cell
322 /// contained the final fragment.
323 msgs: SmallVec<[UnparsedRelayMsg; 1]>,
324 /// Description of the partial message at the end of the cell, if any.
325 incomplete: Option<IncompleteRelayMsgInfo>,
326}
327
328impl RelayCellDecoderResult {
329 /// Returns a non-empty iterator over commands in relay messages that the
330 /// cell producing this result contained *any* part of. i.e. this includes
331 /// the command of "head", "middle", and/or "tail" message fragments that
332 /// were in the cell.
333 pub fn cmds(&self) -> impl Iterator<Item = RelayCmd> + '_ {
334 let complete_msg_cmds = self.msgs.iter().map(|m| m.cmd());
335 let partial_msg_cmd = self.incomplete.as_ref().map(|c| c.cmd());
336 complete_msg_cmds.chain(partial_msg_cmd)
337 }
338 /// Converts `self` to an iterator over the complete messages, and metadata
339 /// about the trailing incomplete message (as for `Self::incomplete_info`),
340 /// if any.
341 pub fn into_parts(
342 self,
343 ) -> (
344 impl Iterator<Item = UnparsedRelayMsg>,
345 Option<IncompleteRelayMsgInfo>,
346 ) {
347 (self.msgs.into_iter(), self.incomplete)
348 }
349 /// Returns the `IncompleteRelayMsgInfo` describing the incomplete
350 /// relay message that this cell contained a fragment of, if any.
351 ///
352 /// Note that:
353 /// * This does not describe a fragment that includes the end of the relay
354 /// message, since the message is then complete.
355 /// * This *does* include a fragment that continues, but does not complete,
356 /// a message started in an earlier relay cell.
357 /// * There is at most one such incomplete relay message, since no current
358 /// relay cell format supports starting a new message before completing the
359 /// previous one.
360 pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
361 self.incomplete.clone()
362 }
363}
364
365/// Information about a relay message for which we don't yet have the complete body.
366#[derive(Clone, Debug)]
367pub struct IncompleteRelayMsgInfo {
368 /// The message's command.
369 cmd: RelayCmd,
370 /// The message's stream ID, if any.
371 stream_id: Option<StreamId>,
372 /// The total number of bytes in the body of the message.
373 total_msg_len: usize,
374 /// The number of bytes of the body of the message that we've decoded so
375 /// far.
376 num_bytes_present: usize,
377}
378
379impl IncompleteRelayMsgInfo {
380 /// Returns the message's command.
381 pub fn cmd(&self) -> RelayCmd {
382 self.cmd
383 }
384 /// Returns the message's `StreamId`, if any.
385 pub fn stream_id(&self) -> Option<StreamId> {
386 self.stream_id
387 }
388 /// Returns the total size of the complete message body.
389 pub fn total_msg_len(&self) -> usize {
390 self.total_msg_len
391 }
392 /// Returns the number of bytes of the message body that we have so far.
393 pub fn num_bytes_present(&self) -> usize {
394 self.num_bytes_present
395 }
396 /// Returns the number of bytes of the message body that we still need.
397 pub fn num_bytes_missing(&self) -> usize {
398 self.total_msg_len - self.num_bytes_present
399 }
400}
401
402/// Internal representation of an `UnparsedRelayMsg`.
403#[derive(Clone, Debug, Deftly)]
404#[derive_deftly(HasMemoryCost)]
405enum UnparsedRelayMsgInternal {
406 /// For `RelayCellFormat::V0` we can avoid copying data around by just
407 /// storing the original cell body here.
408 // NOTE: we could also have a separate command and stream ID field here, but
409 // we expect to be working with a TON of these, so we will be mildly
410 // over-optimized and just peek into the body.
411 //
412 // It *is* a bit ugly to have to encode so much knowledge about the format in
413 // different functions here, but that information shouldn't leak out of this module.
414 V0(BoxedCellBody),
415}
416
417/// An enveloped relay message that has not yet been fully parsed, but where we
418/// have access to the command and stream ID, for dispatching purposes.
419#[derive(Clone, Debug, Deftly)]
420#[derive_deftly(HasMemoryCost)]
421pub struct UnparsedRelayMsg {
422 /// The internal representation.
423 internal: UnparsedRelayMsgInternal,
424}
425
426/// Position of the stream ID within the cell body.
427const STREAM_ID_OFFSET: usize = 3;
428
429impl UnparsedRelayMsg {
430 /// Wrap a BoxedCellBody as an UnparsedRelayMsg.
431 ///
432 /// Fails if the body doesn't correspond to exactly one relay message, but
433 /// doesn't parse the message itself.
434 ///
435 /// Non-test code should generally use `RelayCellDecoder` instead.
436 // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
437 // to use it in integration tests.
438 // https://github.com/rust-lang/rust/issues/84629
439 pub fn from_singleton_body(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
440 let mut decoder = RelayCellDecoder::new(version);
441 let res = decoder.decode(body)?;
442 let (mut msgs, incomplete) = res.into_parts();
443 let Some(msg) = msgs.next() else {
444 // There was no complete message in the cell.
445 return Err(Error::MissingData);
446 };
447 if incomplete.is_some() {
448 // There was an incomplete message at the end of the cell.
449 return Err(Error::ExtraneousBytes);
450 }
451 if msgs.next().is_some() {
452 // There was more than one message in the cell.
453 return Err(Error::ExtraneousBytes);
454 }
455 Ok(msg)
456 }
457
458 /// Return the command for this cell.
459 pub fn cmd(&self) -> RelayCmd {
460 match &self.internal {
461 UnparsedRelayMsgInternal::V0(body) => {
462 /// Position of the command within the cell body.
463 const CMD_OFFSET: usize = 0;
464 body[CMD_OFFSET].into()
465 }
466 }
467 }
468 /// Return the stream ID for the stream that this msg corresponds to, if any.
469 pub fn stream_id(&self) -> Option<StreamId> {
470 match &self.internal {
471 UnparsedRelayMsgInternal::V0(body) => StreamId::new(u16::from_be_bytes(
472 body[STREAM_ID_OFFSET..STREAM_ID_OFFSET + 2]
473 .try_into()
474 .expect("two-byte slice was not two bytes long!?"),
475 )),
476 }
477 }
478 /// Decode this unparsed cell into a given cell type.
479 pub fn decode<M: RelayMsg>(self) -> Result<RelayMsgOuter<M>> {
480 match self.internal {
481 UnparsedRelayMsgInternal::V0(body) => {
482 let mut reader = Reader::from_slice(body.as_ref());
483 RelayMsgOuter::decode_v0_from_reader(&mut reader)
484 }
485 }
486 }
487}
488
489/// A decoded and parsed relay message of unrestricted type,
490/// with an accompanying optional Stream ID.
491pub type AnyRelayMsgOuter = RelayMsgOuter<msg::AnyRelayMsg>;
492
493/// A deprecated name for AnyRelayMsgOuter.
494#[deprecated(note = "Use AnyRelayMsgOuter instead.")]
495pub type AnyRelayCell = AnyRelayMsgOuter;
496
497/// Trait implemented by anything that can serve as a relay message.
498///
499/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
500/// message), or a restricted subset of `RelayMsg`.
501pub trait RelayMsg {
502 /// Return the stream command associated with this message.
503 fn cmd(&self) -> RelayCmd;
504 /// Encode the body of this message, not including command or length
505 fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
506 /// Extract the body of a message with command `cmd` from reader `r`.
507 fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
508 where
509 Self: Sized;
510}
511
512/// A decoded and parsed relay message, along with an optional Stream ID.
513///
514/// This type represents a message that can be sent along a
515/// circuit, along with the ID for an associated stream that the
516/// message is meant for.
517///
518/// NOTE: This name is a placeholder; we intend to replace it once we have
519/// standardized our vocabulary in this area.
520#[derive(Debug)]
521pub struct RelayMsgOuter<M> {
522 /// The stream ID for the stream that this cell corresponds to.
523 streamid: Option<StreamId>,
524 /// The relay message for this cell.
525 msg: M,
526}
527
528/// A deprecated name for RelayMsgOuter.
529#[deprecated(note = "Use RelayMsgOuter instead.")]
530pub type RelayCell<M> = RelayMsgOuter<M>;
531
532impl<M: RelayMsg> RelayMsgOuter<M> {
533 /// Construct a new relay cell.
534 pub fn new(streamid: Option<StreamId>, msg: M) -> Self {
535 RelayMsgOuter { streamid, msg }
536 }
537 /// Consume this cell and return its components.
538 pub fn into_streamid_and_msg(self) -> (Option<StreamId>, M) {
539 (self.streamid, self.msg)
540 }
541 /// Return the command for this cell.
542 pub fn cmd(&self) -> RelayCmd {
543 self.msg.cmd()
544 }
545 /// Return the stream ID for the stream that this cell corresponds to.
546 pub fn stream_id(&self) -> Option<StreamId> {
547 self.streamid
548 }
549 /// Return the underlying message for this cell.
550 pub fn msg(&self) -> &M {
551 &self.msg
552 }
553 /// Consume this cell and return the underlying message.
554 pub fn into_msg(self) -> M {
555 self.msg
556 }
557 /// Consume this relay message and encode it as a 509-byte padded cell
558 /// body.
559 pub fn encode<R: Rng + CryptoRng>(self, rng: &mut R) -> crate::Result<BoxedCellBody> {
560 /// We skip this much space before adding any random padding to the
561 /// end of the cell
562 const MIN_SPACE_BEFORE_PADDING: usize = 4;
563
564 let (mut body, enc_len) = self.encode_to_cell()?;
565 debug_assert!(enc_len <= CELL_DATA_LEN);
566 if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
567 rng.fill_bytes(&mut body[enc_len + MIN_SPACE_BEFORE_PADDING..]);
568 }
569
570 Ok(body)
571 }
572
573 /// Consume a relay cell and return its contents, encoded for use
574 /// in a RELAY or RELAY_EARLY cell.
575 fn encode_to_cell(self) -> EncodeResult<(BoxedCellBody, usize)> {
576 // NOTE: This implementation is a bit optimized, since it happens to
577 // literally every relay cell that we produce.
578
579 // TODO -NM: Add a specialized implementation for making a DATA cell from
580 // a body?
581
582 /// Wrap a BoxedCellBody and implement AsMut<[u8]>
583 struct BodyWrapper(BoxedCellBody);
584 impl AsMut<[u8]> for BodyWrapper {
585 fn as_mut(&mut self) -> &mut [u8] {
586 self.0.as_mut()
587 }
588 }
589 /// The position of the length field within a relay cell.
590 const LEN_POS: usize = 9;
591 /// The position of the body a relay cell.
592 const BODY_POS: usize = 11;
593
594 let body = BodyWrapper(Box::new([0_u8; 509]));
595
596 let mut w = crate::slicewriter::SliceWriter::new(body);
597 w.write_u8(self.msg.cmd().into());
598 w.write_u16(0); // "Recognized"
599 debug_assert_eq!(
600 w.offset().expect("Overflowed a cell with just the header!"),
601 STREAM_ID_OFFSET
602 );
603 w.write_u16(StreamId::get_or_zero(self.streamid));
604 w.write_u32(0); // Digest
605 // (It would be simpler to use NestedWriter at this point, but it uses an internal Vec that we are trying to avoid.)
606 debug_assert_eq!(
607 w.offset().expect("Overflowed a cell with just the header!"),
608 LEN_POS
609 );
610 w.write_u16(0); // Length.
611 debug_assert_eq!(
612 w.offset().expect("Overflowed a cell with just the header!"),
613 BODY_POS
614 );
615 self.msg.encode_onto(&mut w)?; // body
616 let (mut body, written) = w.try_unwrap().map_err(|_| {
617 EncodeError::Bug(internal!(
618 "Encoding of relay message was too long to fit into a cell!"
619 ))
620 })?;
621 let payload_len = written - BODY_POS;
622 debug_assert!(payload_len < u16::MAX as usize);
623 *(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS..LEN_POS + 2])
624 .expect("Two-byte slice was not two bytes long!?")) =
625 (payload_len as u16).to_be_bytes();
626 Ok((body.0, written))
627 }
628
629 /// Parse a RELAY or RELAY_EARLY cell body into a RelayMsgOuter.
630 /// Requires that the cryptographic checks on the message have already been
631 /// performed
632 ///
633 /// Fails if the cell doesn't contain exactly one message.
634 ///
635 /// Non-test code should generally use `RelayCellDecoder` instead.
636 // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
637 // to use it in integration tests.
638 // https://github.com/rust-lang/rust/issues/84629
639 #[allow(clippy::needless_pass_by_value)] // TODO this will go away soon.
640 pub fn decode_singleton(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
641 let unparsed_msg = UnparsedRelayMsg::from_singleton_body(version, body)?;
642 unparsed_msg.decode()
643 }
644 /// Parse a `RelayCellFormat::V0` RELAY or RELAY_EARLY cell body into a
645 /// RelayMsgOuter from a reader.
646 ///
647 /// Requires that the cryptographic checks on the message have already been
648 /// performed
649 fn decode_v0_from_reader(r: &mut Reader<'_>) -> Result<Self> {
650 let cmd = r.take_u8()?.into();
651 r.advance(2)?; // "recognized"
652 let streamid = StreamId::new(r.take_u16()?);
653 r.advance(4)?; // digest
654 let len = r.take_u16()? as usize;
655 if r.remaining() < len {
656 return Err(Error::InvalidMessage(
657 "Insufficient data in relay cell".into(),
658 ));
659 }
660 r.truncate(len);
661 let msg = M::decode_from_reader(cmd, r)?;
662 Ok(Self { streamid, msg })
663 }
664}