#[cfg(test)]
use alloc::vec::Vec;
use core::fmt::{self, Display, Formatter};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dns_class::DNSClass;
use crate::rr::domain::Name;
use crate::rr::record_type::RecordType;
use crate::serialize::binary::*;
#[cfg(feature = "mdns")]
const MDNS_UNICAST_RESPONSE: u16 = 1 << 15;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub struct Query {
pub name: Name,
pub query_type: RecordType,
pub query_class: DNSClass,
#[cfg(feature = "mdns")]
pub mdns_unicast_response: bool,
}
impl Default for Query {
fn default() -> Self {
Self {
name: Name::root(),
query_type: RecordType::A,
query_class: DNSClass::IN,
#[cfg(feature = "mdns")]
mdns_unicast_response: false,
}
}
}
impl Query {
pub fn new() -> Self {
Self::default()
}
#[allow(clippy::self_named_constructors)]
pub fn query(name: Name, query_type: RecordType) -> Self {
Self {
name,
query_type,
query_class: DNSClass::IN,
#[cfg(feature = "mdns")]
mdns_unicast_response: false,
}
}
pub fn set_name(&mut self, name: Name) -> &mut Self {
self.name = name;
self
}
pub fn set_query_type(&mut self, query_type: RecordType) -> &mut Self {
self.query_type = query_type;
self
}
pub fn set_query_class(&mut self, query_class: DNSClass) -> &mut Self {
self.query_class = query_class;
self
}
#[cfg(feature = "mdns")]
pub fn set_mdns_unicast_response(&mut self, flag: bool) -> &mut Self {
self.mdns_unicast_response = flag;
self
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn query_type(&self) -> RecordType {
self.query_type
}
pub fn query_class(&self) -> DNSClass {
self.query_class
}
#[cfg(feature = "mdns")]
pub fn mdns_unicast_response(&self) -> bool {
self.mdns_unicast_response
}
}
impl BinEncodable for Query {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
self.name.emit(encoder)?;
self.query_type.emit(encoder)?;
#[cfg(not(feature = "mdns"))]
self.query_class.emit(encoder)?;
#[cfg(feature = "mdns")]
{
if self.mdns_unicast_response {
encoder.emit_u16(u16::from(self.query_class()) | MDNS_UNICAST_RESPONSE)?;
} else {
self.query_class.emit(encoder)?;
}
}
Ok(())
}
}
impl<'r> BinDecodable<'r> for Query {
fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
let name = Name::read(decoder)?;
let query_type = RecordType::read(decoder)?;
#[cfg(feature = "mdns")]
let mut mdns_unicast_response = false;
#[cfg(not(feature = "mdns"))]
let query_class = DNSClass::read(decoder)?;
#[cfg(feature = "mdns")]
let query_class = {
let query_class_value =
decoder.read_u16()?.unverified();
if query_class_value & MDNS_UNICAST_RESPONSE > 0 {
mdns_unicast_response = true;
DNSClass::from(query_class_value & !MDNS_UNICAST_RESPONSE)
} else {
DNSClass::from(query_class_value)
}
};
Ok(Self {
name,
query_type,
query_class,
#[cfg(feature = "mdns")]
mdns_unicast_response,
})
}
}
impl Display for Query {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
#[cfg(not(feature = "mdns"))]
{
write!(
f,
"{name} {class} {ty}",
name = self.name,
class = self.query_class,
ty = self.query_type,
)
}
#[cfg(feature = "mdns")]
{
write!(
f,
"{name} {class} {ty}; mdns_unicast_response: {mdns}",
name = self.name,
class = self.query_class,
ty = self.query_type,
mdns = self.mdns_unicast_response
)
}
}
}
#[test]
fn test_read_and_emit() {
let expect = Query {
name: Name::from_ascii("WWW.example.com.").unwrap(),
query_type: RecordType::AAAA,
query_class: DNSClass::IN,
..Query::default()
};
let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut byte_vec);
expect.emit(&mut encoder).unwrap();
}
let mut decoder = BinDecoder::new(&byte_vec);
let got = Query::read(&mut decoder).unwrap();
assert_eq!(got, expect);
}
#[cfg(feature = "mdns")]
#[test]
fn test_mdns_unicast_response_bit_handling() {
const QCLASS_OFFSET: usize = 1 +
size_of::<u16>() ;
let mut query = Query::new();
query.set_mdns_unicast_response(true);
let mut vec_bytes: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut vec_bytes);
query.emit(&mut encoder).unwrap();
let query_class_slice = encoder.slice_of(QCLASS_OFFSET, QCLASS_OFFSET + 2);
assert_eq!(query_class_slice, &[0x80, 0x01]);
}
let mut decoder = BinDecoder::new(&vec_bytes);
let got = Query::read(&mut decoder).unwrap();
assert_eq!(got.query_class(), DNSClass::IN);
assert!(got.mdns_unicast_response());
}