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