use std::cmp::Ordering;
use serialize::binary::*;
use error::*;
use rr::dns_class::DNSClass;
use rr::domain;
use rr::IntoRecordSet;
use rr::rdata::NULL;
use rr::RData;
use rr::RecordType;
use rr::RecordSet;
#[derive(Eq, Ord, Debug, Clone)]
pub struct Record {
name_labels: domain::Name,
rr_type: RecordType,
dns_class: DNSClass,
ttl: u32,
rdata: RData,
}
impl Record {
pub fn new() -> Record {
Record {
name_labels: domain::Name::new(),
rr_type: RecordType::A,
dns_class: DNSClass::IN,
ttl: 0,
rdata: RData::NULL(NULL::new()),
}
}
pub fn with(name: domain::Name, rr_type: RecordType, ttl: u32) -> Record {
Record {
name_labels: name,
rr_type: rr_type,
dns_class: DNSClass::IN,
ttl: ttl,
rdata: RData::NULL(NULL::new()),
}
}
pub fn from_rdata(
name: domain::Name,
ttl: u32,
record_type: RecordType,
rdata: RData,
) -> Record {
Record {
name_labels: name,
rr_type: record_type,
dns_class: DNSClass::IN,
ttl: ttl,
rdata: rdata,
}
}
pub fn set_name(&mut self, name: domain::Name) -> &mut Self {
self.name_labels = name;
self
}
#[deprecated]
pub fn add_name(&mut self, label: String) -> &mut Self {
let name = self.name_labels.clone();
self.name_labels = name.append_label(label);
self
}
pub fn set_rr_type(&mut self, rr_type: RecordType) -> &mut Self {
self.rr_type = rr_type;
self
}
pub fn set_dns_class(&mut self, dns_class: DNSClass) -> &mut Self {
self.dns_class = dns_class;
self
}
pub fn set_ttl(&mut self, ttl: u32) -> &mut Self {
self.ttl = ttl;
self
}
pub fn set_rdata(&mut self, rdata: RData) -> &mut Self {
self.rdata = rdata;
self
}
pub fn name(&self) -> &domain::Name {
&self.name_labels
}
pub fn rr_type(&self) -> RecordType {
self.rr_type
}
pub fn dns_class(&self) -> DNSClass {
self.dns_class
}
pub fn ttl(&self) -> u32 {
self.ttl
}
pub fn rdata(&self) -> &RData {
&self.rdata
}
pub fn rdata_mut(&mut self) -> &mut RData {
&mut self.rdata
}
pub fn unwrap_rdata(self) -> RData {
self.rdata
}
}
impl IntoRecordSet for Record {
fn into_record_set(self) -> RecordSet {
RecordSet::from(self)
}
}
impl BinSerializable<Record> for Record {
fn read(decoder: &mut BinDecoder) -> DecodeResult<Record> {
let name_labels: domain::Name = try!(domain::Name::read(decoder));
let record_type: RecordType = try!(RecordType::read(decoder));
let class: DNSClass = if record_type == RecordType::OPT {
if !name_labels.is_root() {
return Err(DecodeErrorKind::EdnsNameNotRoot(name_labels).into());
}
DNSClass::for_opt(try!(decoder.read_u16()))
} else {
try!(DNSClass::read(decoder))
};
let ttl: u32 = try!(decoder.read_u32());
let rd_length: u16 = try!(decoder.read_u16());
let rdata: RData = if rd_length == 0 {
RData::NULL(NULL::new())
} else {
try!(RData::read(decoder, record_type, rd_length))
};
Ok(Record {
name_labels: name_labels,
rr_type: record_type,
dns_class: class,
ttl: ttl,
rdata: rdata,
})
}
fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult {
try!(self.name_labels.emit(encoder));
try!(self.rr_type.emit(encoder));
try!(self.dns_class.emit(encoder));
try!(encoder.emit_u32(self.ttl));
let mut tmp_buf: Vec<u8> = Vec::with_capacity(512);
{
let mut tmp_encoder: BinEncoder = BinEncoder::with_offset(
&mut tmp_buf,
encoder.offset() + 2,
EncodeMode::Normal,
);
try!(self.rdata.emit(&mut tmp_encoder));
}
assert!(tmp_buf.len() <= u16::max_value() as usize);
try!(encoder.emit_u16(tmp_buf.len() as u16));
encoder.reserve(tmp_buf.len());
tmp_buf.reverse();
while let Some(byte) = tmp_buf.pop() {
try!(encoder.emit(byte));
}
Ok(())
}
}
impl PartialEq for Record {
fn eq(&self, other: &Self) -> bool {
self.name_labels == other.name_labels && self.rr_type == other.rr_type &&
self.dns_class == other.dns_class && self.rdata == other.rdata
}
fn ne(&self, other: &Self) -> bool {
!self.eq(other)
}
}
macro_rules! compare_or_equal {
( $x:ident, $y:ident, $z:ident ) => (
match $x.$z.partial_cmp(&$y.$z) {
o @ Some(Ordering::Less) | o @ Some(Ordering::Greater) => return o,
None => return None,
Some(Ordering::Equal) => (),
}
);
}
impl PartialOrd<Record> for Record {
fn partial_cmp(&self, other: &Record) -> Option<Ordering> {
compare_or_equal!(self, other, name_labels);
compare_or_equal!(self, other, rr_type);
compare_or_equal!(self, other, dns_class);
compare_or_equal!(self, other, ttl);
compare_or_equal!(self, other, rdata);
Some(Ordering::Equal)
}
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use std::net::Ipv4Addr;
use std::str::FromStr;
use super::*;
#[allow(unused)]
use serialize::binary::*;
use rr::record_data::RData;
use rr::record_type::RecordType;
use rr::dns_class::DNSClass;
use rr::Name;
#[test]
fn test_emit_and_read() {
let mut record = Record::new();
record
.set_name(Name::from_str("www.example.com").unwrap())
.set_rr_type(RecordType::A)
.set_dns_class(DNSClass::IN)
.set_ttl(5)
.set_rdata(RData::A(Ipv4Addr::new(192, 168, 0, 1)));
let mut vec_bytes: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut vec_bytes);
record.emit(&mut encoder).unwrap();
}
let mut decoder = BinDecoder::new(&vec_bytes);
let got = Record::read(&mut decoder).unwrap();
assert_eq!(got, record);
}
#[test]
fn test_order() {
let mut record = Record::new();
record
.set_name(Name::from_str("www.example.com").unwrap())
.set_rr_type(RecordType::A)
.set_dns_class(DNSClass::IN)
.set_ttl(5)
.set_rdata(RData::A(Ipv4Addr::new(192, 168, 0, 1)));
let mut greater_name = record.clone();
greater_name.set_name(Name::from_str("zzz.example.com").unwrap());
let mut greater_type = record.clone();
greater_type.set_rr_type(RecordType::AAAA);
let mut greater_class = record.clone();
greater_class.set_dns_class(DNSClass::NONE);
let mut greater_rdata = record.clone();
greater_rdata.set_rdata(RData::A(Ipv4Addr::new(192, 168, 0, 255)));
let compares = vec![
(&record, &greater_name),
(&record, &greater_type),
(&record, &greater_class),
(&record, &greater_rdata),
];
assert_eq!(record.clone(), record.clone());
for (r, g) in compares {
println!("r, g: {:?}, {:?}", r, g);
assert_eq!(r.cmp(g), Ordering::Less);
}
}
}