xref: /webrtc/sctp/src/chunk/chunk_header.rs (revision ffe74184)
1 use super::{chunk_type::*, *};
2 
3 use bytes::{Buf, BufMut, Bytes, BytesMut};
4 use std::fmt;
5 
6 ///chunkHeader represents a SCTP Chunk header, defined in https://tools.ietf.org/html/rfc4960#section-3.2
7 ///The figure below illustrates the field format for the chunks to be
8 ///transmitted in the SCTP packet.  Each chunk is formatted with a Chunk
9 ///Type field, a chunk-specific Flag field, a Chunk Length field, and a
10 ///Value field.
11 ///
12 /// 0                   1                   2                   3
13 /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
14 ///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15 ///|   Chunk Type  | Chunk  Flags  |        Chunk Length           |
16 ///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17 ///|                                                               |
18 ///|                          Chunk Value                          |
19 ///|                                                               |
20 ///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21 #[derive(Debug, Clone)]
22 pub(crate) struct ChunkHeader {
23     pub(crate) typ: ChunkType,
24     pub(crate) flags: u8,
25     pub(crate) value_length: u16,
26 }
27 
28 pub(crate) const CHUNK_HEADER_SIZE: usize = 4;
29 
30 /// makes ChunkHeader printable
31 impl fmt::Display for ChunkHeader {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result32     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33         write!(f, "{}", self.typ)
34     }
35 }
36 
37 impl Chunk for ChunkHeader {
header(&self) -> ChunkHeader38     fn header(&self) -> ChunkHeader {
39         self.clone()
40     }
41 
unmarshal(raw: &Bytes) -> Result<Self>42     fn unmarshal(raw: &Bytes) -> Result<Self> {
43         if raw.len() < CHUNK_HEADER_SIZE {
44             return Err(Error::ErrChunkHeaderTooSmall);
45         }
46 
47         let reader = &mut raw.clone();
48 
49         let typ = ChunkType(reader.get_u8());
50         let flags = reader.get_u8();
51         let length = reader.get_u16();
52 
53         if length < CHUNK_HEADER_SIZE as u16 {
54             return Err(Error::ErrChunkHeaderInvalidLength);
55         }
56         if (length as usize) > raw.len() {
57             return Err(Error::ErrChunkHeaderInvalidLength);
58         }
59 
60         // Length includes Chunk header
61         let value_length = length as isize - CHUNK_HEADER_SIZE as isize;
62 
63         let length_after_value = raw.len() as isize - length as isize;
64         if length_after_value < 0 {
65             return Err(Error::ErrChunkHeaderNotEnoughSpace);
66         } else if length_after_value < 4 {
67             // https://tools.ietf.org/html/rfc4960#section-3.2
68             // The Chunk Length field does not count any chunk PADDING.
69             // Chunks (including Type, Length, and Value fields) are padded out
70             // by the sender with all zero bytes to be a multiple of 4 bytes
71             // long.  This PADDING MUST NOT be more than 3 bytes in total.  The
72             // Chunk Length value does not include terminating PADDING of the
73             // chunk.  However, it does include PADDING of any variable-length
74             // parameter except the last parameter in the chunk.  The receiver
75             // MUST ignore the PADDING.
76             for i in (1..=length_after_value).rev() {
77                 let padding_offset = CHUNK_HEADER_SIZE + (value_length + i - 1) as usize;
78                 if raw[padding_offset] != 0 {
79                     return Err(Error::ErrChunkHeaderPaddingNonZero);
80                 }
81             }
82         }
83 
84         Ok(ChunkHeader {
85             typ,
86             flags,
87             value_length: length - CHUNK_HEADER_SIZE as u16,
88         })
89     }
90 
marshal_to(&self, writer: &mut BytesMut) -> Result<usize>91     fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
92         writer.put_u8(self.typ.0);
93         writer.put_u8(self.flags);
94         writer.put_u16(self.value_length + CHUNK_HEADER_SIZE as u16);
95         Ok(writer.len())
96     }
97 
check(&self) -> Result<()>98     fn check(&self) -> Result<()> {
99         Ok(())
100     }
101 
value_length(&self) -> usize102     fn value_length(&self) -> usize {
103         self.value_length as usize
104     }
105 
as_any(&self) -> &(dyn Any + Send + Sync)106     fn as_any(&self) -> &(dyn Any + Send + Sync) {
107         self
108     }
109 }
110