webrtc_sctp/chunk/chunk_heartbeat_ack.rs
1use std::fmt;
2
3use bytes::{Bytes, BytesMut};
4
5use super::chunk_header::*;
6use super::chunk_type::*;
7use super::*;
8use crate::param::param_header::*;
9use crate::param::param_type::ParamType;
10use crate::param::*;
11use crate::util::get_padding_size;
12
13///chunkHeartbeatAck represents an SCTP Chunk of type HEARTBEAT ACK
14///
15///An endpoint should send this chunk to its peer endpoint as a response
16///to a HEARTBEAT chunk (see Section 8.3). A HEARTBEAT ACK is always
17///sent to the source IP address of the IP datagram containing the
18///HEARTBEAT chunk to which this ack is responding.
19///
20///The parameter field contains a variable-length opaque data structure.
21///
22/// 0 1 2 3
23/// 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
24///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25///| Type = 5 | Chunk Flags | Heartbeat Ack Length |
26///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27///| |
28///| Heartbeat Information TLV (Variable-Length) |
29///| |
30///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31///
32///
33///Defined as a variable-length parameter using the format described
34///in Section 3.2.1, i.e.:
35///
36///Variable Parameters Status Type Value
37///-------------------------------------------------------------
38///Heartbeat Info Mandatory 1
39#[derive(Default, Debug)]
40pub(crate) struct ChunkHeartbeatAck {
41 pub(crate) params: Vec<Box<dyn Param + Send + Sync>>,
42}
43
44/// makes ChunkHeartbeatAck printable
45impl fmt::Display for ChunkHeartbeatAck {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "{}", self.header())
48 }
49}
50
51impl Chunk for ChunkHeartbeatAck {
52 fn header(&self) -> ChunkHeader {
53 ChunkHeader {
54 typ: CT_HEARTBEAT_ACK,
55 flags: 0,
56 value_length: self.value_length() as u16,
57 }
58 }
59
60 fn unmarshal(raw: &Bytes) -> Result<Self> {
61 let header = ChunkHeader::unmarshal(raw)?;
62
63 if header.typ != CT_HEARTBEAT_ACK {
64 return Err(Error::ErrChunkTypeNotHeartbeatAck);
65 }
66
67 if raw.len() <= CHUNK_HEADER_SIZE {
68 return Err(Error::ErrHeartbeatNotLongEnoughInfo);
69 }
70
71 let p =
72 build_param(&raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length()))?;
73 if p.header().typ != ParamType::HeartbeatInfo {
74 return Err(Error::ErrHeartbeatParam);
75 }
76 let params = vec![p];
77
78 Ok(ChunkHeartbeatAck { params })
79 }
80
81 fn marshal_to(&self, buf: &mut BytesMut) -> Result<usize> {
82 if self.params.len() != 1 {
83 return Err(Error::ErrHeartbeatAckParams);
84 }
85 if self.params[0].header().typ != ParamType::HeartbeatInfo {
86 return Err(Error::ErrHeartbeatAckNotHeartbeatInfo);
87 }
88
89 self.header().marshal_to(buf)?;
90 for (idx, p) in self.params.iter().enumerate() {
91 let pp = p.marshal()?;
92 let pp_len = pp.len();
93 buf.extend(pp);
94
95 // Chunks (including Type, Length, and Value fields) are padded out
96 // by the sender with all zero bytes to be a multiple of 4 bytes
97 // long. This PADDING MUST NOT be more than 3 bytes in total. The
98 // Chunk Length value does not include terminating PADDING of the
99 // chunk. *However, it does include PADDING of any variable-length
100 // parameter except the last parameter in the chunk.* The receiver
101 // MUST ignore the PADDING.
102 if idx != self.params.len() - 1 {
103 let cnt = get_padding_size(pp_len);
104 buf.extend(vec![0u8; cnt]);
105 }
106 }
107 Ok(buf.len())
108 }
109
110 fn check(&self) -> Result<()> {
111 Ok(())
112 }
113
114 fn value_length(&self) -> usize {
115 let mut l = 0;
116 for (idx, p) in self.params.iter().enumerate() {
117 let p_len = PARAM_HEADER_LENGTH + p.value_length();
118 l += p_len;
119 if idx != self.params.len() - 1 {
120 l += get_padding_size(p_len);
121 }
122 }
123 l
124 }
125
126 fn as_any(&self) -> &(dyn Any + Send + Sync) {
127 self
128 }
129}