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}