use crate::bytes::{Reader, Writer};
use crate::error::Result;
use crate::message::{self, NAT_SERVERINFO};
use crate::version::{ParsePolicy, Version};
const NAME_FIELD: usize = 256;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConnectionInfo {
pub data_port: u16,
pub multicast: bool,
pub multicast_group: [u8; 4],
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ServerInfo {
pub application_name: String,
pub server_version: Version,
pub protocol_version: Version,
pub high_res_clock_frequency: u64,
pub connection: ConnectionInfo,
}
impl ServerInfo {
pub fn parse(datagram: &[u8]) -> Result<Self> {
Self::parse_payload(message::expect(datagram, NAT_SERVERINFO)?)
}
pub fn parse_with_policy(datagram: &[u8], policy: ParsePolicy) -> Result<Self> {
Self::parse_payload_with_policy(message::expect(datagram, NAT_SERVERINFO)?, policy)
}
pub fn parse_payload(payload: &[u8]) -> Result<Self> {
Self::parse_payload_with_policy(payload, ParsePolicy::Compatible)
}
pub fn parse_payload_with_policy(payload: &[u8], policy: ParsePolicy) -> Result<Self> {
let mut r = Reader::new(payload);
let application_name = r.fixed_cstr(NAME_FIELD)?;
let server_version = Version::from_bytes(r.array()?);
let protocol_version = Version::from_bytes(r.array()?);
let high_res_clock_frequency = r.u64()?;
let data_port = r.u16()?;
let multicast = r.u8()? != 0;
let multicast_group = r.array()?;
if policy == ParsePolicy::Strict {
r.finish()?;
}
Ok(Self {
application_name,
server_version,
protocol_version,
high_res_clock_frequency,
connection: ConnectionInfo {
data_port,
multicast,
multicast_group,
},
})
}
pub fn to_payload(&self) -> Result<Vec<u8>> {
let mut w = Writer::new();
w.try_fixed_cstr(&self.application_name, NAME_FIELD, "application_name")?;
w.bytes(&self.server_version.to_bytes());
w.bytes(&self.protocol_version.to_bytes());
w.u64(self.high_res_clock_frequency);
w.u16(self.connection.data_port);
w.u8(u8::from(self.connection.multicast));
w.bytes(&self.connection.multicast_group);
Ok(w.into_vec())
}
pub fn to_datagram(&self) -> Result<Vec<u8>> {
message::frame_checked(NAT_SERVERINFO, &self.to_payload()?)
}
#[must_use]
pub fn to_payload_lossy(&self) -> Vec<u8> {
let mut w = Writer::new();
w.fixed_cstr(&self.application_name, NAME_FIELD);
w.bytes(&self.server_version.to_bytes());
w.bytes(&self.protocol_version.to_bytes());
w.u64(self.high_res_clock_frequency);
w.u16(self.connection.data_port);
w.u8(u8::from(self.connection.multicast));
w.bytes(&self.connection.multicast_group);
w.into_vec()
}
#[must_use]
pub fn to_datagram_lossy(&self) -> Vec<u8> {
message::frame(NAT_SERVERINFO, &self.to_payload_lossy())
}
#[must_use]
pub fn multicast_group(&self) -> std::net::Ipv4Addr {
self.connection.multicast_group.into()
}
}