1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::{WebResult, Buf, http::http2::frame::{Kind, Flag}, Http2Error, Serialize, BufMut, MarkBuf};

use super::{FrameHeader, Frame, StreamIdentifier};


pub type Payload = [u8; 8];

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Ping {
    ack: bool,
    payload: Payload,
}

// This was just 8 randomly generated bytes. We use something besides just
// zeroes to distinguish this specific PING from any other.
const SHUTDOWN_PAYLOAD: Payload = [0x0b, 0x7b, 0xa2, 0xf0, 0x8b, 0x9b, 0xfe, 0x54];
const USER_PAYLOAD: Payload = [0x3b, 0x7c, 0xdb, 0x7a, 0x0b, 0x87, 0x16, 0xb4];

impl Ping {

    pub(crate) const SHUTDOWN: Payload = SHUTDOWN_PAYLOAD;
    pub(crate) const USER: Payload = USER_PAYLOAD;

    pub fn new(payload: Payload) -> Ping {
        Ping {
            ack: false,
            payload,
        }
    }

    pub fn pong(payload: Payload) -> Ping {
        Ping { ack: true, payload }
    }
    
    pub fn ret_pong(&self) -> Ping {
        Ping { ack: true, payload: self.payload }
    }

    pub fn is_ack(&self) -> bool {
        self.ack
    }

    pub fn payload(&self) -> &Payload {
        &self.payload
    }

    pub fn into_payload(self) -> Payload {
        self.payload
    }

    /// Builds a `Ping` frame from a raw frame.
    pub fn parse<B: Buf>(head: FrameHeader, bytes: &mut B) -> WebResult<Ping> {
        debug_assert_eq!(head.kind(), &Kind::Ping);

        // PING frames are not associated with any individual stream. If a PING
        // frame is received with a stream identifier field value other than
        // 0x0, the recipient MUST respond with a connection error
        // (Section 5.4.1) of type PROTOCOL_ERROR.
        if !head.stream_id().is_zero() {
            return Err(Http2Error::InvalidStreamId.into());
        }

        // In addition to the frame header, PING frames MUST contain 8 octets of opaque
        // data in the payload.
        if bytes.remaining() != 8 {
            return Err(Http2Error::BadFrameSize.into());
        }

        let mut payload = [0; 8];
        bytes.copy_to_slice(&mut payload);

        // The PING frame defines the following flags:
        //
        // ACK (0x1): When set, bit 0 indicates that this PING frame is a PING
        //    response. An endpoint MUST set this flag in PING responses. An
        //    endpoint MUST NOT respond to PING frames containing this flag.
        let ack = head.flag().contains(Flag::ack());

        Ok(Ping { ack, payload })
    }

    
    pub(crate) fn head(&self) -> FrameHeader {
        let flags = if self.ack { Flag::ack() } else { Flag::zero() };
        let mut head = FrameHeader::new(Kind::Ping, flags.into(), StreamIdentifier::zero());
        head.length = self.payload.len() as u32;
        head
    }

    
    pub fn encode<B: Buf+MarkBuf+BufMut>(&self, dst: &mut B) -> WebResult<usize> {
        let head = self.head();

        println!("encoding Ping; len={}", head.length);
        let mut size = 0;
        size += head.encode(dst)?;
        size += dst.put_slice(&self.payload);
        Ok(size)
    }

}

impl Serialize for Ping {
    fn serialize<B: Buf+BufMut+MarkBuf>(&mut self, buffer: &mut B) -> crate::WebResult<usize> {
        let mut size = 0;
        size += self.head().encode(buffer)?;
        size += buffer.put_slice(&self.payload);
        Ok(size)
    }
}

impl<T> From<Ping> for Frame<T> {
    fn from(src: Ping) -> Frame<T> {
        Frame::Ping(src)
    }
}