use std::fmt;
use bytes::{BigEndian, BufMut, ByteOrder};
use failure::Fail;
use ::iana::{Class, Rtype};
use super::compose::{Compose, Compress, Compressor};
use super::name::{ParsedDname, ParsedDnameError, ToDname};
use super::parse::{Parse, Parser, ShortBuf};
use super::rdata::{ParseRecordData, RecordData};
#[derive(Clone, Debug)]
pub struct Record<N: ToDname, D: RecordData> {
owner: N,
class: Class,
ttl: u32,
data: D
}
impl<N: ToDname, D: RecordData> Record<N, D> {
pub fn new(owner: N, class: Class, ttl: u32, data: D) -> Self {
Record { owner, class, ttl, data }
}
pub fn owner(&self) -> &N {
&self.owner
}
pub fn rtype(&self) -> Rtype where D: RecordData {
self.data.rtype()
}
pub fn class(&self) -> Class {
self.class
}
pub fn set_class(&mut self, class: Class) {
self.class = class
}
pub fn ttl(&self) -> u32 {
self.ttl
}
pub fn set_ttl(&mut self, ttl: u32) {
self.ttl = ttl
}
pub fn data(&self) -> &D {
&self.data
}
pub fn data_mut(&mut self) -> &mut D {
&mut self.data
}
pub fn into_data(self) -> D {
self.data
}
}
impl<N: ToDname, D: RecordData> From<(N, Class, u32, D)> for Record<N, D> {
fn from((owner, class, ttl, data): (N, Class, u32, D)) -> Self {
Self::new(owner, class, ttl, data)
}
}
impl<N: ToDname, D: RecordData> From<(N, u32, D)> for Record<N, D> {
fn from((owner, ttl, data): (N, u32, D)) -> Self {
Self::new(owner, Class::In, ttl, data)
}
}
impl<D: ParseRecordData> Parse for Option<Record<ParsedDname, D>> {
type Err = RecordParseError<ParsedDnameError, D::Err>;
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
let header = match RecordHeader::parse(parser) {
Ok(header) => header,
Err(err) => return Err(RecordParseError::Name(err)),
};
match D::parse_data(header.rtype(), parser, header.rdlen() as usize) {
Ok(Some(data)) => {
Ok(Some(header.into_record(data)))
}
Ok(None) => {
parser.advance(header.rdlen() as usize)?;
Ok(None)
}
Err(err) => {
Err(RecordParseError::Data(err))
}
}
}
fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
ParsedRecord::skip(parser)
.map_err(RecordParseError::Name)
}
}
impl<N: ToDname, D: RecordData> Compose for Record<N, D> {
fn compose_len(&self) -> usize {
self.owner.compose_len() + self.data.compose_len() + 10
}
fn compose<B: BufMut>(&self, buf: &mut B) {
RecordHeader::new(&self.owner, self.data.rtype(), self.class, self.ttl,
self.data.compose_len() as u16)
.compose(buf);
self.data.compose(buf);
}
}
impl<N: ToDname, D: RecordData + Compress> Compress
for Record<N, D> {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
self.owner.compress(buf)?;
buf.compose(&self.rtype())?;
buf.compose(&self.class)?;
buf.compose(&self.ttl)?;
let pos = buf.len();
buf.compose(&0u16)?;
self.data.compress(buf)?;
let len = buf.len() - pos - 2;
assert!(len <= (::std::u16::MAX as usize));
BigEndian::write_u16(&mut buf.as_slice_mut()[pos..], len as u16);
Ok(())
}
}
impl<N, D> fmt::Display for Record<N, D>
where N: ToDname + fmt::Display, D: RecordData + fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}. {} {} {} {}",
self.owner, self.ttl, self.class, self.data.rtype(),
self.data)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RecordHeader<N> {
owner: N,
rtype: Rtype,
class: Class,
ttl: u32,
rdlen: u16,
}
impl<N> RecordHeader<N> {
pub fn new(owner: N, rtype: Rtype, class: Class, ttl: u32, rdlen: u16)
-> Self {
RecordHeader { owner, rtype, class, ttl, rdlen }
}
}
impl RecordHeader<ParsedDname> {
pub fn parse_and_skip(parser: &mut Parser)
-> Result<Self, ParsedDnameError> {
let header = Self::parse(parser)?;
match parser.advance(header.rdlen() as usize) {
Ok(()) => Ok(header),
Err(_) => Err(ShortBuf.into()),
}
}
#[allow(type_complexity)] pub fn parse_into_record<D: ParseRecordData>(self, parser: &mut Parser)
-> Result<Option<Record<ParsedDname, D>>,
RecordParseError<ParsedDnameError,
D::Err>> {
let end = parser.pos() + self.rdlen as usize;
match D::parse_data(self.rtype, parser, self.rdlen as usize)
.map_err(RecordParseError::Data)? {
Some(data) => Ok(Some(self.into_record(data))),
None => {
parser.seek(end)?;
Ok(None)
}
}
}
fn parse_rdlen(parser: &mut Parser) -> Result<u16, ParsedDnameError> {
ParsedDname::skip(parser)?;
Rtype::skip(parser)?;
Class::skip(parser)?;
u32::skip(parser)?;
Ok(u16::parse(parser)?)
}
}
impl<N: ToDname> RecordHeader<N> {
pub fn owner(&self) -> &N {
&self.owner
}
pub fn rtype(&self) -> Rtype {
self.rtype
}
pub fn class(&self) -> Class {
self.class
}
pub fn ttl(&self) -> u32 {
self.ttl
}
pub fn rdlen(&self) -> u16 {
self.rdlen
}
pub fn into_record<D: RecordData>(self, data: D) -> Record<N, D> {
Record::new(self.owner, self.class, self.ttl, data)
}
}
impl Parse for RecordHeader<ParsedDname> {
type Err = ParsedDnameError;
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
Ok(RecordHeader::new(
ParsedDname::parse(parser)?,
Rtype::parse(parser)?,
Class::parse(parser)?,
u32::parse(parser)?,
parser.parse_u16()?
))
}
fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
ParsedDname::skip(parser)?;
Rtype::skip(parser)?;
Class::skip(parser)?;
u32::skip(parser)?;
u16::skip(parser)?;
Ok(())
}
}
impl<N: Compose> Compose for RecordHeader<N> {
fn compose_len(&self) -> usize {
self.owner.compose_len() + 10
}
fn compose<B: BufMut>(&self, buf: &mut B) {
self.owner.compose(buf);
self.rtype.compose(buf);
self.class.compose(buf);
self.ttl.compose(buf);
self.rdlen.compose(buf);
}
}
impl<N: Compress> Compress for RecordHeader<N> {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
self.owner.compress(buf)?;
buf.compose(&self.rtype)?;
buf.compose(&self.class)?;
buf.compose(&self.ttl)?;
buf.compose(&self.rdlen)
}
}
#[derive(Clone, Debug)]
pub struct ParsedRecord {
header: RecordHeader<ParsedDname>,
data: Parser,
}
impl ParsedRecord {
pub fn new(header: RecordHeader<ParsedDname>, data: Parser) -> Self {
ParsedRecord { header, data }
}
pub fn owner(&self) -> &ParsedDname {
self.header.owner()
}
pub fn rtype(&self) -> Rtype {
self.header.rtype()
}
pub fn class(&self) -> Class {
self.header.class()
}
pub fn ttl(&self) -> u32 {
self.header.ttl()
}
pub fn rdlen(&self) -> u16 {
self.header.rdlen()
}
}
impl ParsedRecord {
#[allow(type_complexity)] pub fn to_record<D>(
&self
) -> Result<Option<Record<ParsedDname, D>>,
RecordParseError<ParsedDnameError, D::Err>>
where D: ParseRecordData
{
match D::parse_data(self.header.rtype(), &mut self.data.clone(),
self.header.rdlen() as usize)
.map_err(RecordParseError::Data)? {
Some(data) => Ok(Some(self.header.clone().into_record(data))),
None => Ok(None)
}
}
#[allow(type_complexity)] pub fn into_record<D>(
mut self
) -> Result<Option<Record<ParsedDname, D>>,
RecordParseError<ParsedDnameError, D::Err>>
where D: ParseRecordData
{
match D::parse_data(self.header.rtype(), &mut self.data,
self.header.rdlen() as usize)
.map_err(RecordParseError::Data)? {
Some(data) => Ok(Some(self.header.into_record(data))),
None => Ok(None)
}
}
}
impl Parse for ParsedRecord {
type Err = ParsedDnameError;
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
let header = RecordHeader::parse(parser)?;
let data = parser.clone();
parser.advance(header.rdlen() as usize)?;
Ok(Self::new(header, data))
}
fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
let rdlen = RecordHeader::parse_rdlen(parser)?;
parser.advance(rdlen as usize)?;
Ok(())
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum RecordParseError<N: Fail, D: Fail> {
#[fail(display="{}", _0)]
Name(N),
#[fail(display="{}", _0)]
Data(D),
#[fail(display="unexpected end of buffer")]
ShortBuf,
}
impl<N: Fail, D: Fail> From<ShortBuf> for RecordParseError<N, D> {
fn from(_: ShortBuf) -> Self {
RecordParseError::ShortBuf
}
}