rumqttc/mqttbytes/v4/
connack.rs

1use super::*;
2use bytes::{Buf, BufMut, Bytes, BytesMut};
3
4/// Return code in connack
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[repr(u8)]
7pub enum ConnectReturnCode {
8    Success = 0,
9    RefusedProtocolVersion,
10    BadClientId,
11    ServiceUnavailable,
12    BadUserNamePassword,
13    NotAuthorized,
14}
15
16/// Acknowledgement to connect packet
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ConnAck {
19    pub session_present: bool,
20    pub code: ConnectReturnCode,
21}
22
23impl ConnAck {
24    pub fn new(code: ConnectReturnCode, session_present: bool) -> ConnAck {
25        ConnAck {
26            session_present,
27            code,
28        }
29    }
30
31    fn len(&self) -> usize {
32        // sesssion present + code
33
34        1 + 1
35    }
36
37    pub fn read(fixed_header: FixedHeader, mut bytes: Bytes) -> Result<Self, Error> {
38        let variable_header_index = fixed_header.fixed_header_len;
39        bytes.advance(variable_header_index);
40
41        let flags = read_u8(&mut bytes)?;
42        let return_code = read_u8(&mut bytes)?;
43
44        let session_present = (flags & 0x01) == 1;
45        let code = connect_return(return_code)?;
46        let connack = ConnAck {
47            session_present,
48            code,
49        };
50
51        Ok(connack)
52    }
53
54    pub fn write(&self, buffer: &mut BytesMut) -> Result<usize, Error> {
55        let len = self.len();
56        buffer.put_u8(0x20);
57
58        let count = write_remaining_length(buffer, len)?;
59        buffer.put_u8(self.session_present as u8);
60        buffer.put_u8(self.code as u8);
61
62        Ok(1 + count + len)
63    }
64}
65
66/// Connection return code type
67fn connect_return(num: u8) -> Result<ConnectReturnCode, Error> {
68    match num {
69        0 => Ok(ConnectReturnCode::Success),
70        1 => Ok(ConnectReturnCode::RefusedProtocolVersion),
71        2 => Ok(ConnectReturnCode::BadClientId),
72        3 => Ok(ConnectReturnCode::ServiceUnavailable),
73        4 => Ok(ConnectReturnCode::BadUserNamePassword),
74        5 => Ok(ConnectReturnCode::NotAuthorized),
75        num => Err(Error::InvalidConnectReturnCode(num)),
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use super::*;
82    use bytes::BytesMut;
83    use pretty_assertions::assert_eq;
84
85    #[test]
86    fn connack_parsing_works() {
87        let mut stream = bytes::BytesMut::new();
88        let packetstream = &[
89            0b0010_0000,
90            0x02, // packet type, flags and remaining len
91            0x01,
92            0x00, // variable header. connack flags, connect return code
93            0xDE,
94            0xAD,
95            0xBE,
96            0xEF, // extra packets in the stream
97        ];
98
99        stream.extend_from_slice(&packetstream[..]);
100        let fixed_header = parse_fixed_header(stream.iter()).unwrap();
101        let connack_bytes = stream.split_to(fixed_header.frame_length()).freeze();
102        let connack = ConnAck::read(fixed_header, connack_bytes).unwrap();
103
104        assert_eq!(
105            connack,
106            ConnAck {
107                session_present: true,
108                code: ConnectReturnCode::Success,
109            }
110        );
111    }
112
113    #[test]
114    fn connack_encoding_works() {
115        let connack = ConnAck {
116            session_present: true,
117            code: ConnectReturnCode::Success,
118        };
119
120        let mut buf = BytesMut::new();
121        connack.write(&mut buf).unwrap();
122        assert_eq!(buf, vec![0b0010_0000, 0x02, 0x01, 0x00]);
123    }
124}