1
//! Implementation for parsing and encoding relay cells
2

            
3
use std::num::NonZeroU16;
4

            
5
use crate::chancell::{BoxedCellBody, CELL_DATA_LEN};
6
use derive_deftly::Deftly;
7
use smallvec::{smallvec, SmallVec};
8
use tor_bytes::{EncodeError, EncodeResult, Error, Result};
9
use tor_bytes::{Reader, Writer};
10
use tor_error::internal;
11
use tor_memquota::derive_deftly_template_HasMemoryCost;
12

            
13
use caret::caret_int;
14
use rand::{CryptoRng, Rng};
15

            
16
pub mod extend;
17
#[cfg(feature = "hs")]
18
pub mod hs;
19
pub mod msg;
20
#[cfg(feature = "experimental-udp")]
21
pub mod udp;
22

            
23
caret_int! {
24
    /// A command that identifies the type of a relay cell
25
    #[derive(Deftly)]
26
    #[derive_deftly(HasMemoryCost)]
27
    pub struct RelayCmd(u8) {
28
        /// Start a new stream
29
        BEGIN = 1,
30
        /// Data on a stream
31
        DATA = 2,
32
        /// Close a stream
33
        END = 3,
34
        /// Acknowledge a BEGIN; stream is open
35
        CONNECTED = 4,
36
        /// Used for flow control
37
        SENDME = 5,
38
        /// Extend a circuit to a new hop; deprecated
39
        EXTEND = 6,
40
        /// Reply to EXTEND handshake; deprecated
41
        EXTENDED = 7,
42
        /// Partially close a circuit
43
        TRUNCATE = 8,
44
        /// Circuit has been partially closed
45
        TRUNCATED = 9,
46
        /// Padding cell
47
        DROP = 10,
48
        /// Start a DNS lookup
49
        RESOLVE = 11,
50
        /// Reply to a DNS lookup
51
        RESOLVED = 12,
52
        /// Start a directory stream
53
        BEGIN_DIR = 13,
54
        /// Extend a circuit to a new hop
55
        EXTEND2 = 14,
56
        /// Reply to an EXTEND2 cell.
57
        EXTENDED2 = 15,
58

            
59
        /// NOTE: UDP command are reserved but only used with experimental-udp feature
60

            
61
        /// UDP: Start of a stream
62
        CONNECT_UDP = 16,
63
        /// UDP: Acknowledge a CONNECT_UDP. Stream is open.
64
        CONNECTED_UDP = 17,
65
        /// UDP: Data on a UDP stream.
66
        DATAGRAM = 18,
67

            
68
        /// HS: establish an introduction point.
69
        ESTABLISH_INTRO = 32,
70
        /// HS: establish a rendezvous point.
71
        ESTABLISH_RENDEZVOUS = 33,
72
        /// HS: send introduction (client to introduction point)
73
        INTRODUCE1 = 34,
74
        /// HS: send introduction (introduction point to service)
75
        INTRODUCE2 = 35,
76
        /// HS: connect rendezvous point (service to rendezvous point)
77
        RENDEZVOUS1 = 36,
78
        /// HS: connect rendezvous point (rendezvous point to client)
79
        RENDEZVOUS2 = 37,
80
        /// HS: Response to ESTABLISH_INTRO
81
        INTRO_ESTABLISHED = 38,
82
        /// HS: Response to ESTABLISH_RENDEZVOUS
83
        RENDEZVOUS_ESTABLISHED = 39,
84
        /// HS: Response to INTRODUCE1 from introduction point to client
85
        INTRODUCE_ACK = 40,
86

            
87
        /// Padding: declare what kind of padding we want
88
        PADDING_NEGOTIATE = 41,
89
        /// Padding: reply to a PADDING_NEGOTIATE
90
        PADDING_NEGOTIATED = 42,
91
    }
92
}
93

            
94
/// Possible requirements on stream IDs for a relay command.
95
enum StreamIdReq {
96
    /// Can only be used with a stream ID of 0
97
    WantNone,
98
    /// Can only be used with a stream ID that isn't 0
99
    WantSome,
100
    /// Can be used with any stream ID
101
    Any,
102
}
103

            
104
impl RelayCmd {
105
    /// Check whether this command requires a certain kind of
106
    /// StreamId, and return a corresponding StreamIdReq.
107
4500
    fn expects_streamid(self) -> StreamIdReq {
108
4500
        match self {
109
            RelayCmd::BEGIN
110
            | RelayCmd::DATA
111
            | RelayCmd::END
112
            | RelayCmd::CONNECTED
113
            | RelayCmd::RESOLVE
114
            | RelayCmd::RESOLVED
115
3100
            | RelayCmd::BEGIN_DIR => StreamIdReq::WantSome,
116
            #[cfg(feature = "experimental-udp")]
117
            RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
118
                StreamIdReq::WantSome
119
            }
120
            RelayCmd::EXTEND
121
            | RelayCmd::EXTENDED
122
            | RelayCmd::TRUNCATE
123
            | RelayCmd::TRUNCATED
124
            | RelayCmd::DROP
125
            | RelayCmd::EXTEND2
126
            | RelayCmd::EXTENDED2
127
            | RelayCmd::ESTABLISH_INTRO
128
            | RelayCmd::ESTABLISH_RENDEZVOUS
129
            | RelayCmd::INTRODUCE1
130
            | RelayCmd::INTRODUCE2
131
            | RelayCmd::RENDEZVOUS1
132
            | RelayCmd::RENDEZVOUS2
133
            | RelayCmd::INTRO_ESTABLISHED
134
            | RelayCmd::RENDEZVOUS_ESTABLISHED
135
1100
            | RelayCmd::INTRODUCE_ACK => StreamIdReq::WantNone,
136
300
            RelayCmd::SENDME => StreamIdReq::Any,
137
            _ => StreamIdReq::Any,
138
        }
139
4500
    }
140
    /// Return true if this command is one that accepts the particular
141
    /// stream ID `id`
142
4500
    pub fn accepts_streamid_val(self, id: Option<StreamId>) -> bool {
143
4500
        match self.expects_streamid() {
144
1100
            StreamIdReq::WantNone => id.is_none(),
145
3100
            StreamIdReq::WantSome => id.is_some(),
146
300
            StreamIdReq::Any => true,
147
        }
148
4500
    }
149
}
150

            
151
/// Identify a single stream on a circuit.
152
///
153
/// These identifiers are local to each hop on a circuit.
154
/// This can't be zero; if you need something that can be zero in the protocol,
155
/// use `Option<StreamId>`.
156
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Deftly)]
157
#[derive_deftly(HasMemoryCost)]
158
pub struct StreamId(NonZeroU16);
159

            
160
impl From<NonZeroU16> for StreamId {
161
24350
    fn from(id: NonZeroU16) -> Self {
162
24350
        Self(id)
163
24350
    }
164
}
165

            
166
impl From<StreamId> for NonZeroU16 {
167
12298
    fn from(id: StreamId) -> NonZeroU16 {
168
12298
        id.0
169
12298
    }
170
}
171

            
172
impl From<StreamId> for u16 {
173
    fn from(id: StreamId) -> u16 {
174
        id.0.get()
175
    }
176
}
177

            
178
impl std::fmt::Display for StreamId {
179
1000
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
180
1000
        self.0.fmt(f)
181
1000
    }
182
}
183

            
184
impl StreamId {
185
    /// Creates a `StreamId` for non-zero `stream_id`.
186
    ///
187
    /// Returns `None` when `stream_id` is zero. Messages with a zero/None stream ID
188
    /// apply to the circuit as a whole instead of a particular stream.
189
79100
    pub fn new(stream_id: u16) -> Option<Self> {
190
79100
        NonZeroU16::new(stream_id).map(Self)
191
79100
    }
192

            
193
    /// Convenience function to convert to a `u16`; `None` is mapped to 0.
194
79700
    pub fn get_or_zero(stream_id: Option<Self>) -> u16 {
195
79700
        match stream_id {
196
77050
            Some(stream_id) => stream_id.0.get(),
197
2650
            None => 0,
198
        }
199
79700
    }
200
}
201

            
202
/// Specifies which encoding version of RelayCell to use.
203
#[non_exhaustive]
204
#[derive(Copy, Clone, Debug)]
205
pub enum RelayCellFormat {
206
    /// This is the "legacy" pre-prop340 format. No packing or fragmentation.
207
    V0,
208
}
209

            
210
/// Specifies a relay cell format and associated types.
211
pub trait RelayCellFormatTrait {
212
    /// Which format this object is for.
213
    const FORMAT: RelayCellFormat;
214
    /// A `RelayCellFields` type for this format.
215
    type FIELDS: RelayCellFields;
216
    // TODO: Consider making a trait for the decoder as well and adding the
217
    // corresponding associated type here.
218
}
219

            
220
/// Format type corresponding to `RelayCellFormat::V0`.
221
#[non_exhaustive]
222
pub struct RelayCellFormatV0;
223

            
224
impl RelayCellFormatTrait for RelayCellFormatV0 {
225
    const FORMAT: RelayCellFormat = RelayCellFormat::V0;
226
    type FIELDS = RelayCellFieldsV0;
227
}
228

            
229
/// Specifies field layout for a particular relay cell format.
230
pub trait RelayCellFields {
231
    /// The range containing the `recognized` field, within a relay cell's body.
232
    const RECOGNIZED_RANGE: std::ops::Range<usize>;
233
    /// The range containing the `digest` field, within a relay cell's body.
234
    const DIGEST_RANGE: std::ops::Range<usize>;
235
    /// A static array of zeroes of the same size as this format uses for the
236
    /// digest field. e.g. this enables updating a comparison-digest in one
237
    /// hash-update method call, instead of having to loop over `DIGEST_RANGE`.
238
    const EMPTY_DIGEST: &'static [u8];
239
}
240

            
241
/// Specifies fields for `RelayCellFormat::V0`.
242
#[non_exhaustive]
243
pub struct RelayCellFieldsV0;
244

            
245
impl RelayCellFields for RelayCellFieldsV0 {
246
    const RECOGNIZED_RANGE: std::ops::Range<usize> = 1..3;
247
    const DIGEST_RANGE: std::ops::Range<usize> = 5..9;
248
    const EMPTY_DIGEST: &'static [u8] = &[0, 0, 0, 0];
249
}
250

            
251
/// Internal decoder state.
252
#[derive(Clone, Debug)]
253
enum RelayCellDecoderInternal {
254
    /// Internal state for `RelayCellFormat::V0`
255
    V0,
256
}
257

            
258
// TODO prop340: We should also fuzz RelayCellDecoder, but not in this fuzzer.
259

            
260
/// Decodes a stream of relay cell bodies into `UnparsedRelayMsg`s.
261
#[derive(Clone, Debug)]
262
pub struct RelayCellDecoder {
263
    /// Internal representation.
264
    internal: RelayCellDecoderInternal,
265
}
266

            
267
impl RelayCellDecoder {
268
    /// Returns a new `Decoder`, handling a stream of relay cells
269
    /// of the given `version`.
270
78550
    pub fn new(version: RelayCellFormat) -> Self {
271
78550
        match version {
272
78550
            RelayCellFormat::V0 => Self {
273
78550
                internal: RelayCellDecoderInternal::V0,
274
78550
            },
275
78550
        }
276
78550
    }
277
    /// Parse a RELAY or RELAY_EARLY cell body.
278
    ///
279
    /// Requires that the cryptographic checks on the message have already been
280
    /// performed
281
72850
    pub fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
282
72850
        match &self.internal {
283
72850
            RelayCellDecoderInternal::V0 => Ok(RelayCellDecoderResult {
284
72850
                msgs: smallvec![UnparsedRelayMsg {
285
                    internal: UnparsedRelayMsgInternal::V0(cell)
286
                }],
287
72850
                incomplete: None,
288
72850
            }),
289
72850
        }
290
72850
    }
291
    /// Returns the `IncompleteRelayMsgInfo` describing the partial
292
    /// (fragmented) relay message at the end of the so-far-processed relay cell
293
    /// stream.
294
    pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
295
        match &self.internal {
296
            // V0 doesn't support fragmentation, so there is never a pending fragment.
297
            RelayCellDecoderInternal::V0 => None,
298
        }
299
    }
300
}
301

            
302
/// Result of calling `RelayCellDecoder::decode`.
303
#[derive(Debug)]
304
pub struct RelayCellDecoderResult {
305
    /// Complete messages obtained by decoding the cell. i.e. messages
306
    /// that were completely contained within the cell, or for which the cell
307
    /// contained the final fragment.
308
    msgs: SmallVec<[UnparsedRelayMsg; 1]>,
309
    /// Description of the partial message at the end of the cell, if any.
310
    incomplete: Option<IncompleteRelayMsgInfo>,
311
}
312

            
313
impl RelayCellDecoderResult {
314
    /// Returns a non-empty iterator over commands in relay messages that the
315
    /// cell producing this result contained *any* part of. i.e. this includes
316
    /// the command of "head", "middle", and/or "tail" message fragments that
317
    /// were in the cell.
318
4300
    pub fn cmds(&self) -> impl Iterator<Item = RelayCmd> + '_ {
319
4386
        let complete_msg_cmds = self.msgs.iter().map(|m| m.cmd());
320
4300
        let partial_msg_cmd = self.incomplete.as_ref().map(|c| c.cmd());
321
4300
        complete_msg_cmds.chain(partial_msg_cmd)
322
4300
    }
323
    /// Converts `self` to an iterator over the complete messages, and metadata
324
    /// about the trailing incomplete message (as for `Self::incomplete_info`),
325
    /// if any.
326
72850
    pub fn into_parts(
327
72850
        self,
328
72850
    ) -> (
329
72850
        impl Iterator<Item = UnparsedRelayMsg>,
330
72850
        Option<IncompleteRelayMsgInfo>,
331
72850
    ) {
332
72850
        (self.msgs.into_iter(), self.incomplete)
333
72850
    }
334
    /// Returns the `IncompleteRelayMsgInfo` describing the incomplete
335
    /// relay message that this cell contained a fragment of, if any.
336
    ///
337
    /// Note that:
338
    /// * This does not describe a fragment that includes the end of the relay
339
    ///   message, since the message is then complete.
340
    /// * This *does* include a fragment that continues, but does not complete,
341
    ///   a message started in an earlier relay cell.
342
    /// * There is at most one such incomplete relay message, since no current
343
    ///   relay cell format supports starting a new message before completing the
344
    ///   previous one.
345
    pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
346
        self.incomplete.clone()
347
    }
348
}
349

            
350
/// Information about a relay message for which we don't yet have the complete body.
351
#[derive(Clone, Debug)]
352
pub struct IncompleteRelayMsgInfo {
353
    /// The message's command.
354
    cmd: RelayCmd,
355
    /// The message's stream ID, if any.
356
    stream_id: Option<StreamId>,
357
    /// The total number of bytes in the body of the message.
358
    total_msg_len: usize,
359
    /// The number of bytes of the body of the message that we've decoded so
360
    /// far.
361
    num_bytes_present: usize,
362
}
363

            
364
impl IncompleteRelayMsgInfo {
365
    /// Returns the message's command.
366
    pub fn cmd(&self) -> RelayCmd {
367
        self.cmd
368
    }
369
    /// Returns the message's `StreamId`, if any.
370
    pub fn stream_id(&self) -> Option<StreamId> {
371
        self.stream_id
372
    }
373
    /// Returns the total size of the complete message body.
374
    pub fn total_msg_len(&self) -> usize {
375
        self.total_msg_len
376
    }
377
    /// Returns the number of bytes of the message body that we have so far.
378
    pub fn num_bytes_present(&self) -> usize {
379
        self.num_bytes_present
380
    }
381
    /// Returns the number of bytes of the message body that we still need.
382
    pub fn num_bytes_missing(&self) -> usize {
383
        self.total_msg_len - self.num_bytes_present
384
    }
385
}
386

            
387
/// Internal representation of an `UnparsedRelayMsg`.
388
#[derive(Clone, Debug, Deftly)]
389
#[derive_deftly(HasMemoryCost)]
390
enum UnparsedRelayMsgInternal {
391
    /// For `RelayCellFormat::V0` we can avoid copying data around by just
392
    /// storing the original cell body here.
393
    // NOTE: we could also have a separate command and stream ID field here, but
394
    // we expect to be working with a TON of these, so we will be mildly
395
    // over-optimized and just peek into the body.
396
    //
397
    // It *is* a bit ugly to have to encode so much knowledge about the format in
398
    // different functions here, but that information shouldn't leak out of this module.
399
    V0(BoxedCellBody),
400
}
401

            
402
/// An enveloped relay message that has not yet been fully parsed, but where we
403
/// have access to the command and stream ID, for dispatching purposes.
404
#[derive(Clone, Debug, Deftly)]
405
#[derive_deftly(HasMemoryCost)]
406
pub struct UnparsedRelayMsg {
407
    /// The internal representation.
408
    internal: UnparsedRelayMsgInternal,
409
}
410

            
411
/// Position of the stream ID within the cell body.
412
const STREAM_ID_OFFSET: usize = 3;
413

            
414
impl UnparsedRelayMsg {
415
    /// Wrap a BoxedCellBody as an UnparsedRelayMsg.
416
    ///
417
    /// Fails if the body doesn't correspond to exactly one relay message, but
418
    /// doesn't parse the message itself.
419
    ///
420
    /// Non-test code should generally use `RelayCellDecoder` instead.
421
    // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
422
    // to use it in integration tests.
423
    // https://github.com/rust-lang/rust/issues/84629
424
68550
    pub fn from_singleton_body(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
425
68550
        let mut decoder = RelayCellDecoder::new(version);
426
68550
        let res = decoder.decode(body)?;
427
68550
        let (mut msgs, incomplete) = res.into_parts();
428
68550
        let Some(msg) = msgs.next() else {
429
            // There was no complete message in the cell.
430
            return Err(Error::MissingData);
431
        };
432
68550
        if incomplete.is_some() {
433
            // There was an incomplete message at the end of the cell.
434
            return Err(Error::ExtraneousBytes);
435
68550
        }
436
68550
        if msgs.next().is_some() {
437
            // There was more than one message in the cell.
438
            return Err(Error::ExtraneousBytes);
439
68550
        }
440
68550
        Ok(msg)
441
68550
    }
442

            
443
    /// Return the command for this cell.
444
26650
    pub fn cmd(&self) -> RelayCmd {
445
26650
        match &self.internal {
446
26650
            UnparsedRelayMsgInternal::V0(body) => {
447
                /// Position of the command within the cell body.
448
                const CMD_OFFSET: usize = 0;
449
26650
                body[CMD_OFFSET].into()
450
26650
            }
451
26650
        }
452
26650
    }
453
    /// Return the stream ID for the stream that this msg corresponds to, if any.
454
4300
    pub fn stream_id(&self) -> Option<StreamId> {
455
4300
        match &self.internal {
456
4300
            UnparsedRelayMsgInternal::V0(body) => StreamId::new(u16::from_be_bytes(
457
4300
                body[STREAM_ID_OFFSET..STREAM_ID_OFFSET + 2]
458
4300
                    .try_into()
459
4300
                    .expect("two-byte slice was not two bytes long!?"),
460
4300
            )),
461
4300
        }
462
4300
    }
463
    /// Decode this unparsed cell into a given cell type.
464
2876
    pub fn decode<M: RelayMsg>(self) -> Result<RelayMsgOuter<M>> {
465
2876
        match self.internal {
466
2876
            UnparsedRelayMsgInternal::V0(body) => {
467
2876
                let mut reader = Reader::from_slice(body.as_ref());
468
2876
                RelayMsgOuter::decode_v0_from_reader(&mut reader)
469
2876
            }
470
2876
        }
471
2876
    }
472
}
473

            
474
/// A decoded and parsed relay message of unrestricted type,
475
/// with an accompanying optional Stream ID.
476
pub type AnyRelayMsgOuter = RelayMsgOuter<msg::AnyRelayMsg>;
477

            
478
/// A deprecated name for AnyRelayMsgOuter.
479
#[deprecated(note = "Use AnyRelayMsgOuter instead.")]
480
pub type AnyRelayCell = AnyRelayMsgOuter;
481

            
482
/// Trait implemented by anything that can serve as a relay message.
483
///
484
/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
485
/// message), or a restricted subset of `RelayMsg`.
486
pub trait RelayMsg {
487
    /// Return the stream command associated with this message.
488
    fn cmd(&self) -> RelayCmd;
489
    /// Encode the body of this message, not including command or length
490
    fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
491
    /// Extract the body of a message with command `cmd` from reader `r`.
492
    fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
493
    where
494
        Self: Sized;
495
}
496

            
497
/// A decoded and parsed relay message, along with an optional Stream ID.
498
///
499
/// This type represents a message that can be sent along a
500
/// circuit, along with the ID for an associated stream that the
501
/// message is meant for.
502
///
503
/// NOTE: This name is a placeholder; we intend to replace it once we have
504
/// standardized our vocabulary in this area.
505
#[derive(Debug)]
506
pub struct RelayMsgOuter<M> {
507
    /// The stream ID for the stream that this cell corresponds to.
508
    streamid: Option<StreamId>,
509
    /// The relay message for this cell.
510
    msg: M,
511
}
512

            
513
/// A deprecated name for RelayMsgOuter.
514
#[deprecated(note = "Use RelayMsgOuter instead.")]
515
pub type RelayCell<M> = RelayMsgOuter<M>;
516

            
517
impl<M: RelayMsg> RelayMsgOuter<M> {
518
    /// Construct a new relay cell.
519
3182
    pub fn new(streamid: Option<StreamId>, msg: M) -> Self {
520
3182
        RelayMsgOuter { streamid, msg }
521
3182
    }
522
    /// Consume this cell and return its components.
523
2650
    pub fn into_streamid_and_msg(self) -> (Option<StreamId>, M) {
524
2650
        (self.streamid, self.msg)
525
2650
    }
526
    /// Return the command for this cell.
527
2952
    pub fn cmd(&self) -> RelayCmd {
528
2952
        self.msg.cmd()
529
2952
    }
530
    /// Return the stream ID for the stream that this cell corresponds to.
531
2950
    pub fn stream_id(&self) -> Option<StreamId> {
532
2950
        self.streamid
533
2950
    }
534
    /// Return the underlying message for this cell.
535
2806
    pub fn msg(&self) -> &M {
536
2806
        &self.msg
537
2806
    }
538
    /// Consume this cell and return the underlying message.
539
148
    pub fn into_msg(self) -> M {
540
148
        self.msg
541
148
    }
542
    /// Consume this relay message and encode it as a 509-byte padded cell
543
    /// body.
544
3184
    pub fn encode<R: Rng + CryptoRng>(self, rng: &mut R) -> crate::Result<BoxedCellBody> {
545
        /// We skip this much space before adding any random padding to the
546
        /// end of the cell
547
        const MIN_SPACE_BEFORE_PADDING: usize = 4;
548

            
549
3184
        let (mut body, enc_len) = self.encode_to_cell()?;
550
3184
        debug_assert!(enc_len <= CELL_DATA_LEN);
551
3184
        if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
552
412
            rng.fill_bytes(&mut body[enc_len + MIN_SPACE_BEFORE_PADDING..]);
553
2776
        }
554

            
555
3184
        Ok(body)
556
3184
    }
557

            
558
    /// Consume a relay cell and return its contents, encoded for use
559
    /// in a RELAY or RELAY_EARLY cell.
560
3184
    fn encode_to_cell(self) -> EncodeResult<(BoxedCellBody, usize)> {
561
        // NOTE: This implementation is a bit optimized, since it happens to
562
        // literally every relay cell that we produce.
563

            
564
        // TODO -NM: Add a specialized implementation for making a DATA cell from
565
        // a body?
566

            
567
        /// Wrap a BoxedCellBody and implement AsMut<[u8]>
568
        struct BodyWrapper(BoxedCellBody);
569
        impl AsMut<[u8]> for BodyWrapper {
570
993400
            fn as_mut(&mut self) -> &mut [u8] {
571
993400
                self.0.as_mut()
572
993400
            }
573
        }
574
        /// The position of the length field within a relay cell.
575
        const LEN_POS: usize = 9;
576
        /// The position of the body a relay cell.
577
        const BODY_POS: usize = 11;
578

            
579
3184
        let body = BodyWrapper(Box::new([0_u8; 509]));
580
3184

            
581
3184
        let mut w = crate::slicewriter::SliceWriter::new(body);
582
3184
        w.write_u8(self.msg.cmd().into());
583
3184
        w.write_u16(0); // "Recognized"
584
3184
        debug_assert_eq!(
585
3184
            w.offset().expect("Overflowed a cell with just the header!"),
586
            STREAM_ID_OFFSET
587
        );
588
3184
        w.write_u16(StreamId::get_or_zero(self.streamid));
589
3184
        w.write_u32(0); // Digest
590
3184
                        // (It would be simpler to use NestedWriter at this point, but it uses an internal Vec that we are trying to avoid.)
591
3184
        debug_assert_eq!(
592
3184
            w.offset().expect("Overflowed a cell with just the header!"),
593
            LEN_POS
594
        );
595
3184
        w.write_u16(0); // Length.
596
3184
        debug_assert_eq!(
597
3184
            w.offset().expect("Overflowed a cell with just the header!"),
598
            BODY_POS
599
        );
600
3184
        self.msg.encode_onto(&mut w)?; // body
601
3184
        let (mut body, written) = w.try_unwrap().map_err(|_| {
602
            EncodeError::Bug(internal!(
603
                "Encoding of relay message was too long to fit into a cell!"
604
            ))
605
3184
        })?;
606
3184
        let payload_len = written - BODY_POS;
607
3184
        debug_assert!(payload_len < u16::MAX as usize);
608
3184
        *(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS..LEN_POS + 2])
609
3184
            .expect("Two-byte slice was not two bytes long!?")) =
610
3184
            (payload_len as u16).to_be_bytes();
611
3184
        Ok((body.0, written))
612
3184
    }
613

            
614
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayMsgOuter.
615
    /// Requires that the cryptographic checks on the message have already been
616
    /// performed
617
    ///
618
    /// Fails if the cell doesn't contain exactly one message.
619
    ///
620
    /// Non-test code should generally use `RelayCellDecoder` instead.
621
    // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
622
    // to use it in integration tests.
623
    // https://github.com/rust-lang/rust/issues/84629
624
    #[allow(clippy::needless_pass_by_value)] // TODO this will go away soon.
625
2670
    pub fn decode_singleton(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
626
2670
        let unparsed_msg = UnparsedRelayMsg::from_singleton_body(version, body)?;
627
2670
        unparsed_msg.decode()
628
2670
    }
629
    /// Parse a `RelayCellFormat::V0` RELAY or RELAY_EARLY cell body into a
630
    /// RelayMsgOuter from a reader.
631
    ///
632
    /// Requires that the cryptographic checks on the message have already been
633
    /// performed
634
2876
    fn decode_v0_from_reader(r: &mut Reader<'_>) -> Result<Self> {
635
2876
        let cmd = r.take_u8()?.into();
636
2876
        r.advance(2)?; // "recognized"
637
2876
        let streamid = StreamId::new(r.take_u16()?);
638
2876
        r.advance(4)?; // digest
639
2876
        let len = r.take_u16()? as usize;
640
2876
        if r.remaining() < len {
641
2
            return Err(Error::InvalidMessage(
642
2
                "Insufficient data in relay cell".into(),
643
2
            ));
644
2874
        }
645
2874
        r.truncate(len);
646
2874
        let msg = M::decode_from_reader(cmd, r)?;
647
2866
        Ok(Self { streamid, msg })
648
2876
    }
649
}