ntex_h2/frame/
ping.rs

1use ntex_bytes::BufMut;
2
3use crate::frame::{Frame, FrameError, Head, Kind, StreamId};
4
5const ACK_FLAG: u8 = 0x1;
6
7pub type Payload = [u8; 8];
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct Ping {
11    ack: bool,
12    payload: Payload,
13}
14
15impl Ping {
16    pub fn new(payload: Payload) -> Ping {
17        Ping {
18            ack: false,
19            payload,
20        }
21    }
22
23    pub fn pong(payload: Payload) -> Ping {
24        Ping { ack: true, payload }
25    }
26
27    pub fn is_ack(&self) -> bool {
28        self.ack
29    }
30
31    pub fn payload(&self) -> &Payload {
32        &self.payload
33    }
34
35    pub fn into_payload(self) -> Payload {
36        self.payload
37    }
38
39    /// Builds a `Ping` frame from a raw frame.
40    pub fn load(head: Head, bytes: &[u8]) -> Result<Ping, FrameError> {
41        debug_assert_eq!(head.kind(), crate::frame::Kind::Ping);
42
43        // PING frames are not associated with any individual stream. If a PING
44        // frame is received with a stream identifier field value other than
45        // 0x0, the recipient MUST respond with a connection error
46        // (Section 5.4.1) of type PROTOCOL_ERROR.
47        if !head.stream_id().is_zero() {
48            return Err(FrameError::InvalidStreamId);
49        }
50
51        // In addition to the frame header, PING frames MUST contain 8 octets of opaque
52        // data in the payload.
53        if bytes.len() != 8 {
54            return Err(FrameError::BadFrameSize);
55        }
56
57        let mut payload = [0; 8];
58        payload.copy_from_slice(bytes);
59
60        // The PING frame defines the following flags:
61        //
62        // ACK (0x1): When set, bit 0 indicates that this PING frame is a PING
63        //    response. An endpoint MUST set this flag in PING responses. An
64        //    endpoint MUST NOT respond to PING frames containing this flag.
65        let ack = head.flag() & ACK_FLAG != 0;
66
67        Ok(Ping { ack, payload })
68    }
69
70    pub fn encode<B: BufMut>(&self, dst: &mut B) {
71        let sz = self.payload.len();
72        log::trace!("encoding PING; ack={} len={}", self.ack, sz);
73
74        let flags = if self.ack { ACK_FLAG } else { 0 };
75        let head = Head::new(Kind::Ping, flags, StreamId::zero());
76
77        head.encode(sz, dst);
78        dst.put_slice(&self.payload);
79    }
80}
81
82impl From<Ping> for Frame {
83    fn from(src: Ping) -> Frame {
84        Frame::Ping(src)
85    }
86}