use std::time::Duration;
use super::property::{
Property, PropertyFrame, property_decode, property_decode_non_zero, property_encode,
property_len,
};
use crate::Error;
use crate::codec::util::{decode_byte, decode_variable_integer, encode_variable_integer};
use crate::codec::{Decode, Encode, RawPacket};
use crate::protocol::util::len_bytes;
use crate::protocol::v5::reason::ReasonCode;
use crate::protocol::{FixedHeader, PacketType, QoS, traits};
use bit_field::BitField;
use bytes::{Buf, BufMut, Bytes, BytesMut};
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ConnAckProperties {
pub session_expiry_interval: Option<Duration>,
pub receive_maximum: Option<u16>,
pub maximum_qos: Option<QoS>,
pub retain_available: Option<bool>,
pub maximum_packet_size: Option<u32>,
pub assigned_client_id: Option<String>,
pub topic_alias_maximum: Option<u16>,
pub reason: Option<String>,
pub user_properties: Vec<(String, String)>,
pub wildcard_subscription_available: Option<bool>,
pub subscription_id_available: Option<bool>,
pub shared_subscription_available: Option<bool>,
pub server_keep_alive: Option<u16>,
pub response_info: Option<String>,
pub server_reference: Option<String>,
pub auth_method: Option<String>,
pub auth_data: Option<Bytes>,
}
impl PropertyFrame for ConnAckProperties {
fn encoded_len(&self) -> usize {
let mut len = 0;
len += property_len!(&self.session_expiry_interval);
len += property_len!(&self.receive_maximum);
len += property_len!(&self.maximum_qos);
len += property_len!(&self.retain_available);
len += property_len!(&self.maximum_packet_size);
len += property_len!(&self.assigned_client_id);
len += property_len!(&self.topic_alias_maximum);
len += property_len!(&self.reason);
len += property_len!(&self.user_properties);
len += property_len!(&self.wildcard_subscription_available);
len += property_len!(&self.subscription_id_available);
len += property_len!(&self.shared_subscription_available);
len += property_len!(&self.server_keep_alive);
len += property_len!(&self.response_info);
len += property_len!(&self.server_reference);
len += property_len!(&self.auth_method);
len += property_len!(&self.auth_data);
len
}
fn encode(&self, buf: &mut BytesMut) {
property_encode!(
&self.session_expiry_interval,
Property::SessionExpiryInterval,
buf
);
property_encode!(&self.receive_maximum, Property::ReceiveMaximum, buf);
property_encode!(&self.maximum_qos, Property::MaximumQoS, buf);
property_encode!(&self.retain_available, Property::RetainAvailable, buf);
property_encode!(&self.maximum_packet_size, Property::MaximumPacketSize, buf);
property_encode!(
&self.assigned_client_id,
Property::AssignedClientIdentifier,
buf
);
property_encode!(&self.topic_alias_maximum, Property::TopicAliasMaximum, buf);
property_encode!(&self.reason, Property::ReasonString, buf);
property_encode!(&self.user_properties, Property::UserProp, buf);
property_encode!(
&self.wildcard_subscription_available,
Property::WildcardSubscriptionAvailable,
buf
);
property_encode!(
&self.subscription_id_available,
Property::SubscriptionIdentifierAvailable,
buf
);
property_encode!(
&self.shared_subscription_available,
Property::SharedSubscriptionAvailable,
buf
);
property_encode!(&self.server_keep_alive, Property::ServerKeepAlive, buf);
property_encode!(&self.response_info, Property::ResponseInformation, buf);
property_encode!(&self.server_reference, Property::ServerReference, buf);
property_encode!(&self.auth_method, Property::AuthenticationMethod, buf);
property_encode!(&self.auth_data, Property::AuthenticationData, buf);
}
fn decode(buf: &mut Bytes) -> Result<Option<Self>, Error> {
if buf.is_empty() {
return Ok(None);
}
let mut properties = ConnAckProperties::default();
while buf.has_remaining() {
let property: Property = decode_byte(buf)?.try_into()?;
match property {
Property::SessionExpiryInterval => {
property_decode!(&mut properties.session_expiry_interval, buf);
}
Property::ReceiveMaximum => {
property_decode_non_zero!(&mut properties.receive_maximum, buf);
}
Property::MaximumQoS => {
property_decode!(&mut properties.maximum_qos, buf);
}
Property::RetainAvailable => {
property_decode!(&mut properties.retain_available, buf);
}
Property::MaximumPacketSize => {
property_decode_non_zero!(&mut properties.maximum_packet_size, buf);
}
Property::AssignedClientIdentifier => {
property_decode!(&mut properties.assigned_client_id, buf);
}
Property::TopicAliasMaximum => {
property_decode!(&mut properties.topic_alias_maximum, buf);
}
Property::ReasonString => {
property_decode!(&mut properties.reason, buf);
}
Property::UserProp => {
property_decode!(&mut properties.user_properties, buf);
}
Property::WildcardSubscriptionAvailable => {
property_decode!(&mut properties.wildcard_subscription_available, buf);
}
Property::SubscriptionIdentifierAvailable => {
property_decode!(&mut properties.subscription_id_available, buf);
}
Property::SharedSubscriptionAvailable => {
property_decode!(&mut properties.shared_subscription_available, buf);
}
Property::ServerKeepAlive => {
property_decode!(&mut properties.server_keep_alive, buf);
}
Property::ResponseInformation => {
property_decode!(&mut properties.response_info, buf);
}
Property::ServerReference => {
property_decode!(&mut properties.server_reference, buf);
}
Property::AuthenticationMethod => {
property_decode!(&mut properties.auth_method, buf);
}
Property::AuthenticationData => {
property_decode!(&mut properties.auth_data, buf);
}
_ => return Err(Error::PropertyMismatch),
}
}
Ok(Some(properties))
}
}
fn validate_connack_reason_code(code: ReasonCode) -> bool {
matches!(code.into(), 0 | 128..=138 | 140 | 144 | 149 | 151 | 153..=157 | 159)
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct ConnAckHeader {
code: ReasonCode,
session_present: bool,
properties: Option<ConnAckProperties>,
}
impl ConnAckHeader {
fn new(code: ReasonCode, session_present: bool, properties: Option<ConnAckProperties>) -> Self {
if !validate_connack_reason_code(code) {
panic!("Invalid reason code {code}");
}
ConnAckHeader {
code,
session_present,
properties,
}
}
fn encoded_len(&self) -> usize {
let properties_len = self
.properties
.as_ref()
.map(|properties| properties.encoded_len())
.unwrap_or(0);
1 + 1 + len_bytes(properties_len) + properties_len
}
fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
let mut flags = 0u8;
flags.set_bit(0, self.session_present);
buf.put_u8(flags);
buf.put_u8(self.code.into());
let properties_len = self
.properties
.as_ref()
.map(|properties| properties.encoded_len())
.unwrap_or(0) as u32;
encode_variable_integer(buf, properties_len)?;
if let Some(properties) = self.properties.as_ref() {
properties.encode(buf);
}
Ok(())
}
fn decode(payload: &mut Bytes) -> Result<Self, Error> {
let conn_ack_flag = decode_byte(payload)?;
let code = decode_byte(payload)?.try_into()?;
if !validate_connack_reason_code(code) {
return Err(Error::InvalidReasonCode(code.into()));
}
let session_present = conn_ack_flag.get_bit(0);
let properties_len = decode_variable_integer(payload)? as usize;
if payload.len() < properties_len + len_bytes(properties_len) {
return Err(Error::MalformedPacket);
}
payload.advance(len_bytes(properties_len));
let mut frame = payload.split_to(properties_len);
let properties = ConnAckProperties::decode(&mut frame)?;
Ok(ConnAckHeader {
code,
session_present,
properties,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConnAck {
header: ConnAckHeader,
}
impl ConnAck {
pub fn new(
code: ReasonCode,
session_present: bool,
properties: Option<ConnAckProperties>,
) -> Self {
ConnAck {
header: ConnAckHeader::new(code, session_present, properties),
}
}
pub fn code(&self) -> ReasonCode {
self.header.code
}
pub fn session_present(&self) -> bool {
self.header.session_present
}
pub fn properties(&self) -> Option<ConnAckProperties> {
self.header.properties.clone()
}
}
impl Encode for ConnAck {
fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
let header = FixedHeader::new(PacketType::ConnAck, self.payload_len());
header.encode(buf)?;
self.header.encode(buf)
}
fn payload_len(&self) -> usize {
self.header.encoded_len()
}
}
impl Decode for ConnAck {
fn decode(mut packet: RawPacket) -> Result<Self, Error> {
if packet.header.packet_type() != PacketType::ConnAck || !packet.header.flags().is_default()
{
return Err(Error::MalformedPacket);
}
let header = ConnAckHeader::decode(&mut packet.payload)?;
Ok(ConnAck { header })
}
}
impl traits::ConnAck for ConnAck {}