domain_core/bits/
compose.rs

1//! Assembling wire-format DNS data.
2//!
3//! Assembling DNS data for transmission over the wire is being called
4//! *composing* to distinguish it from other procedures that turn data into
5//! some output such as formatting it into human-readable text.
6//!
7//! Data is being assembled directly into values implementing the [`BufMut`]
8//! trait. Because such buffers do not reallocate, the overall size of the
9//! assembled data needs to be known beforehand. This module provides the
10//! trait [`Compose`] for types that know how to compose themselves into a
11//! buffer.
12//!
13//! There is, however, the matter of domain name compression which allows a
14//! domain name to indicate that it continues elsewhere in an assembled
15//! message. A consequence is that for a given name, the length of its
16//! assembled representation depends on what is present in the message
17//! already and thus cannot be given in general.
18//!
19//! Because of this differing behaviour when using domain name compression,
20//! we call the process of assembling a messgage *compressing* instead.
21//! Consequently, the module also defines a trait [`Compress`] for type that
22//! know how to compress itself. This happens atop a helper type
23//! [`Compressor`] that wraps a [`BytesMut`] and all the information
24//! necessary for compressing names.
25//!
26//!
27//! [`BufMut`]: ../../../bytes/trait.BufMut.html
28//! [`BytesMut`]: ../../../bytes/struct.BytesMut.html
29//! [`Compose`]: trait.Compose.html
30//! [`Compress`]: trait.Compress.html
31//! [`Compressor`]: struct.Compressor.html
32
33use std::ops;
34use std::collections::HashMap;
35use std::net::{Ipv4Addr, Ipv6Addr};
36use bytes::{BufMut, Bytes, BytesMut};
37use super::name::{Dname, Label, ToDname};
38use super::parse::ShortBuf;
39
40
41//------------ Compose -------------------------------------------------------
42
43/// A type that knows how to compose itself.
44///
45/// The term ‘composing’ refers to the process of creating a DNS wire-format
46/// representation of a value’s data. This happens by appending appending
47/// this data to the end of a type implementing the [`BufMut`] trait.
48///
49/// [`BufMut`]: ../../../bytes/trait.BufMut.html
50pub trait Compose {
51    /// Returns the number of bytes this value will need without compression.
52    fn compose_len(&self) -> usize;
53
54    /// Appends the uncompressed representation of this value to `buf`.
55    ///
56    /// An implementation may assume that the buffer has at least as many
57    /// bytes remaining as the amount a call to `compose_len()` would return
58    /// right now. If that’s not the case, the implementation should panic.
59    /// That is, the implementation can use `buf`‘s `put_*()` methods
60    /// unchecked.
61    fn compose<B: BufMut>(&self, buf: &mut B);
62}
63
64impl<'a, C: Compose> Compose for &'a C {
65    fn compose_len(&self) -> usize {
66        (*self).compose_len()
67    }
68
69    fn compose<B: BufMut>(&self, buf: &mut B) {
70        (*self).compose(buf)
71    }
72}
73
74
75impl Compose for i8 {
76    fn compose_len(&self) -> usize {
77        1
78    }
79
80    fn compose<B: BufMut>(&self, buf: &mut B) {
81        buf.put_i8(*self)
82    }
83}
84
85impl Compose for u8 {
86    fn compose_len(&self) -> usize {
87        1
88    }
89
90    fn compose<B: BufMut>(&self, buf: &mut B) {
91        buf.put_u8(*self)
92    }
93}
94
95impl Compose for i16 {
96    fn compose_len(&self) -> usize {
97        2
98    }
99
100    fn compose<B: BufMut>(&self, buf: &mut B) {
101        buf.put_i16_be(*self)
102    }
103}
104
105impl Compose for u16 {
106    fn compose_len(&self) -> usize {
107        2
108    }
109
110    fn compose<B: BufMut>(&self, buf: &mut B) {
111        buf.put_u16_be(*self)
112    }
113}
114
115impl Compose for i32 {
116    fn compose_len(&self) -> usize {
117        4
118    }
119
120    fn compose<B: BufMut>(&self, buf: &mut B) {
121        buf.put_i32_be(*self)
122    }
123}
124
125impl Compose for u32 {
126    fn compose_len(&self) -> usize {
127        4
128    }
129
130    fn compose<B: BufMut>(&self, buf: &mut B) {
131        buf.put_u32_be(*self)
132    }
133}
134
135impl Compose for [u8] {
136    fn compose_len(&self) -> usize {
137        self.len()
138    }
139
140    fn compose<B: BufMut>(&self, buf: &mut B) {
141        buf.put_slice(self)
142    }
143}
144
145impl Compose for Bytes {
146    fn compose_len(&self) -> usize {
147        self.len()
148    }
149
150    fn compose<B: BufMut>(&self, buf: &mut B) {
151        buf.put_slice(self.as_ref())
152    }
153}
154
155impl Compose for Ipv4Addr {
156    fn compose_len(&self) -> usize {
157        4
158    }
159
160    fn compose<B: BufMut>(&self, buf: &mut B) {
161        buf.put_slice(&self.octets())
162    }
163}
164
165impl Compose for Ipv6Addr {
166    fn compose_len(&self) -> usize {
167        16
168    }
169
170    fn compose<B: BufMut>(&self, buf: &mut B) {
171        buf.put_slice(&self.octets())
172    }
173}
174        
175
176//------------ Compress ------------------------------------------------------
177
178/// A type that knows how to compress itself.
179///
180/// The term `compressing` refers to the process of producing the DNS
181/// wire-format representation of a value’s data allowing it to optionally
182/// employ domain name compression.
183///
184/// Because [`BufMut`] doesn’t allow looking back at the data added to the
185/// message before, compression cannot be implemented using just [`Compose`].
186/// Instead, a special type, [`Compressor`] is provided that implements all
187/// the necessary logic for name compression.
188///
189/// `Compress` should only be implemented for domain name types or types that
190/// contain or may contain domain names and want to support name compression.
191/// For all other types, [`Compressor::compose`] uses their [`Compose`]
192/// implementation for appending.
193///
194/// [`BufMut`]: ../../../bytes/trait.BufMut.html
195/// [`Compose`]: trait.Compose.html
196/// [`Compressor`]: struct.Compressor.html
197/// [`Compressor::compose`]: struct.Compressor.html#method.compose
198pub trait Compress {
199    /// Appends the wire-format representation of the value to `buf`.
200    ///
201    /// If `buf` does not have enough space available for appending the
202    /// representation, the method returns an error. If this happens, some
203    /// data may have been appended to the buffer.
204    ///
205    /// For implementers of composite types, this means that they can simply
206    /// compress or compose their consitutent types onto `buf` bailing out
207    /// if that fails. There is no need to truncate `buf` back to its prior
208    /// state on failure.
209    fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf>;
210}
211
212impl<'a, C: Compress + 'a> Compress for &'a C {
213    fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
214        (*self).compress(buf)
215    }
216}
217
218
219//------------ Compressor ----------------------------------------------------
220
221/// A buffer for composing a compressed DNS message.
222///
223/// This type wraps a [`BytesMut`] value into which it composes a message,
224/// growing it as necessary. It provides an implementation for [`BufMut`]
225/// allowing it to be used like any other buffer. In addition, it provides
226/// special handling for types that implement [`Compose`] via the
227/// [`compose`][`Compressor::compose`] method, appending them if there’s
228/// enough space.
229///
230/// The whole point of this type is, of course, name compression. This is
231/// being provided via the [`compress_name`] method which appends any domain
232/// name. Since compression is actually rather expensive as we need to keep
233/// track of names that have been written so far, it needs to be explicitely
234/// enabled via the [`enable_compression`] method.
235///
236/// Two more methods for tweaking the behaviour of `Compressor` are available. 
237/// The maximum size of a message can be set via the [`set_limit`]. A value
238/// will grow its underlying buffer as needed up to at most this size. It
239/// will re-allocate memory if necessary by the amount set through
240/// [`set_page_size`]. By default, or if the page size is set to 0, it will
241/// only allocate exactly once to have enough space to reach the current
242/// limit.
243///
244/// Once you are done composing your message, you can either extract the
245/// underlying [`BytesMut`] via [`unwrap`] or get it as a frozen [`Bytes`]
246/// directly via [`freeze`].
247///
248/// Note: Name compression is currently implemented in a rather naive way
249///       by simply storing each compressed name’s position in a hash map
250///       (also considering all its parents). This can probably be optimized.
251///       In addition, this approach doesn’t
252///       consider non-compressed names (since they are appended via their
253///       `Compose` implementation).
254///
255/// [`BufMut`]: ../../../bytes/trait.BufMut.html
256/// [`Bytes`]: ../../../bytes/struct.Bytes.html
257/// [`BytesMut`]: ../../../bytes/struct.BytesMut.html
258/// [`Compose`]: trait.Compose.html
259/// [`Compressor::compose`]: #method.compose
260/// [`compress_name`]: #method.compress_name
261/// [`enable_compression`]: #method.enable_compression
262/// [`freeze`]: #method.freeze
263/// [`set_limit`]: #method.set_limit
264/// [`set_page_size`]: #method.set_page_size
265/// [`unwrap`]: #method.unwrap
266#[derive(Clone, Debug, )]
267pub struct Compressor {
268    /// The bytes buffer we work on.
269    buf: BytesMut,
270
271    /// Index of where in `buf` the message starts.
272    start: usize,
273
274    /// The maximum size of `buf` in bytes.
275    /// 
276    /// This is is whatever is set via `set_limit` plus `start`.
277    limit: usize,
278
279    /// The number of bytes to grow each time we run out of space.
280    ///
281    /// If this is 0, we grow exactly once to the size given by `limit`.
282    page_size: usize,
283
284    /// The optional compression map.
285    ///
286    /// This keeps the position relative to the start of the message for each
287    /// name we’ve ever written.
288    map: Option<HashMap<Dname, u16>>,
289}
290
291impl Compressor {
292    /// Creates a compressor from the given bytes buffer.
293    ///
294    /// The compressor will have a default limit equal to the buffer’s current
295    /// capacity and a page size of 0.
296    pub fn from_buf(buf: BytesMut) -> Self {
297        Compressor {
298            start: buf.len(),
299            limit: buf.capacity(),
300            page_size: 0,
301            buf,
302            map: None }
303    }
304
305    /// Creates a new compressor with a default capacity and limit.
306    ///
307    /// The compressor will be created atop a new buffer which will use its
308    /// default capacity. This is the largest capacity it can use without
309    /// having to allocate. The compressor will start out with a limit equal
310    /// to this capacity and a page size of 0.
311    pub fn new() -> Self {
312        Self::from_buf(BytesMut::new())
313    }
314
315    /// Creates a new compressor with the given capacity.
316    ///
317    /// The compressor will be created atop a new buffer with at least the
318    /// given capacity. The compressor’s initial limit will be the actual
319    /// capacity of the buffer which may be larger than `capacity`. The
320    /// initial page size will be 0.
321    pub fn with_capacity(capacity: usize) -> Self {
322        Self::from_buf(BytesMut::with_capacity(capacity))
323    }
324
325    /// Enable name compression.
326    ///
327    /// By default, a compressor will not actually compress domain names,
328    /// but rather append them like any other data. Instead, compression
329    /// needs to be enable once via this method.
330    pub fn enable_compression(&mut self) {
331        if self.map.is_none() {
332            self.map = Some(HashMap::new())
333        }
334    }
335
336    /// Sets the size limit for the compressor.
337    ///
338    /// This limit only regards the part of the underlying buffer that is
339    /// being built by the compressor. That is, if the compressor was created
340    /// on top of a buffer that already contained data, the buffer will never
341    /// exceed that amount of data plus `limit`.
342    ///
343    /// If you try to set the limit to a value smaller than what has already
344    /// been added so far, the limit will silently be increased to that
345    /// amount.
346    ///
347    /// A new compressor starts out with a size limit equal to the
348    /// remaining capacity of the buffer it is being created with.
349    pub fn set_limit(&mut self, limit: usize) {
350        let limit = limit + self.start;
351        self.limit = ::std::cmp::max(limit, self.buf.len())
352    }
353
354    /// Sets the number of bytes by which the buffer should be grown.
355    ///
356    /// Each time the buffer runs out of capacity and is still below its
357    /// size limit, it will be grown by `page_size` bytes. This may result in
358    /// a buffer with more capacity than the limit.
359    ///
360    /// If `page_size` is set to 0, the buffer will be expanded only once to
361    /// match the size limit.
362    ///
363    /// A new compressor starts out with this specia page size of 0.
364    pub fn set_page_size(&mut self, page_size: usize) {
365        self.page_size = page_size
366    }
367
368    /// Trades in the compressor for its underlying bytes buffer.
369    pub fn unwrap(self) -> BytesMut {
370        self.buf
371    }
372
373    /// Trades in the compressor for the frozen underlying buffer.
374    pub fn freeze(self) -> Bytes {
375        self.buf.freeze()
376    }
377
378    /// Returns a reference to the bytes that have been assembled so far.
379    ///
380    /// This differs from [`as_slice`](#method.as_slice) if the compressor
381    /// was created atop an existing buffer in that the slice does not
382    /// contain the data that was in the buffer before.
383    pub fn so_far(&self) -> &[u8] {
384        &self.buf.as_ref()[self.start..]
385    }
386
387    /// Returns a mutable reference to the data assembled so far.
388    ///
389    /// This differs from [`as_slice_mut`](#method.as_slice_mut) if the
390    /// compressor was created atop an existing buffer in that the slice
391    /// does not contain the data that was in the buffer before.
392    pub fn so_far_mut(&mut self) -> &mut [u8] {
393        &mut self.buf.as_mut()[self.start..]
394    }
395
396    /// Composes a the given name compressed into the buffer.
397    ///
398    /// If compression hasn’t been enable yet via
399    /// [`enable_compression`](#method.enable_compression), the name will be
400    /// appended without compression. It will also not be remembered as a
401    /// compression target for later names.
402    pub fn compress_name<N: ToDname>(&mut self, name: &N)
403                                     -> Result<(), ShortBuf> {
404        let mut name = name.to_name();
405        while !name.is_root() {
406            if let Some(pos) = self.get_pos(&name) {
407                return self.compose_compress_target(pos)
408            }
409            let pos = {
410                let first = name.first();
411                let pos = self.buf.len() - self.start;
412                self.compose(first)?;
413                pos
414            };
415            self.add_name(&name, pos);
416            name.parent();
417        }
418        self.compose(Label::root())
419    }
420
421    /// Appends a compression label pointing to position `pos`.
422    fn compose_compress_target(&mut self, pos: u16)
423                               -> Result<(), ShortBuf> {
424        if self.buf.remaining_mut() < 2 {
425            return Err(ShortBuf)
426        }
427        (pos | 0xC000).compose(&mut self.buf);
428        Ok(())
429    }
430
431    /// Appends something composable to the end of the buffer.
432    ///
433    /// This method can be used to append something and short circuit via the
434    /// question mark operator if it doesn’t fit. This is most helpful when
435    /// implementing the [`Compress`](trait.Compress.html) trait for a
436    /// composite type.
437    pub fn compose<C>(&mut self, what: &C) -> Result<(), ShortBuf>
438                   where C: Compose + ?Sized {
439        if self.remaining_mut() < what.compose_len() {
440            return Err(ShortBuf)
441        }
442        what.compose(self);
443        Ok(())
444    }
445
446    /// Remembers that `name` started at position `pos`.
447    ///
448    /// Doesn’t do that, though, if compression hasn’t been enabled yet.
449    fn add_name(&mut self, name: &Dname, pos: usize) {
450        if let Some(ref mut map) = self.map {
451            if pos > 0x3FFF {
452                // Position exceeds encodable position. Don’t add.
453                return
454            }
455            map.insert(name.clone(), pos as u16);
456        }
457    }
458
459    /// Returns the index of a name if it is known.
460    fn get_pos(&self, name: &Dname) -> Option<u16> {
461        match self.map {
462            Some(ref map) => map.get(name).cloned(),
463            None => None
464        }
465    }
466
467    /// Returns a reference to the complete data of the underlying buffer.
468    ///
469    /// This may be more than the assembled data if the compressor was
470    /// created atop a buffer that already contained data.
471    pub fn as_slice(&self) -> &[u8] {
472        self.buf.as_ref()
473    }
474
475    /// Returns a mutable reference to the data of the underlying buffer.
476    ///
477    /// This may be more than the assembled data if the compressor was
478    /// created atop a buffer that already contained data.
479    pub fn as_slice_mut(&mut self) -> &mut [u8] {
480        self.buf.as_mut()
481    }
482
483    /// Grows the buffer size once.
484    ///
485    /// This may panic if used to grow beyond the limit.
486    fn grow(&mut self) {
487        if self.page_size == 0 {
488            let additional = self.limit.checked_sub(self.buf.capacity())
489                                 .unwrap();
490            self.buf.reserve(additional)
491        }
492        else {
493            self.buf.reserve(self.page_size)
494        }
495    }
496}
497
498
499//--- Default
500
501impl Default for Compressor {
502    fn default() -> Self {
503        Self::new()
504    }
505}
506
507
508//--- AsRef and AsMut
509
510impl AsRef<BytesMut> for Compressor {
511    fn as_ref(&self) -> &BytesMut {
512        &self.buf
513    }
514}
515
516impl AsMut<BytesMut> for Compressor {
517    fn as_mut(&mut self) -> &mut BytesMut {
518        &mut self.buf
519    }
520}
521
522impl AsRef<[u8]> for Compressor {
523    fn as_ref(&self) -> &[u8] {
524        self.buf.as_ref()
525    }
526}
527
528impl AsMut<[u8]> for Compressor {
529    fn as_mut(&mut self) -> &mut [u8] {
530        self.buf.as_mut()
531    }
532}
533
534
535//--- Deref and DerefMut
536
537impl ops::Deref for Compressor {
538    type Target = BytesMut;
539
540    fn deref(&self) -> &Self::Target {
541        &self.buf
542    }
543}
544
545impl ops::DerefMut for Compressor {
546    fn deref_mut(&mut self) -> &mut Self::Target {
547        &mut self.buf
548    }
549}
550
551
552//--- BufMut
553
554impl BufMut for Compressor {
555    fn remaining_mut(&self) -> usize {
556        self.limit - self.buf.len()
557    }
558
559    unsafe fn advance_mut(&mut self, cnt: usize) {
560        assert!(cnt <= self.remaining_mut());
561        while cnt > self.buf.remaining_mut() {
562            self.grow();
563        }
564        self.buf.advance_mut(cnt)
565    }
566
567    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
568        if self.buf.remaining_mut() == 0 && self.remaining_mut() > 0 {
569            self.grow()
570        }
571        self.buf.bytes_mut()
572    }
573}
574
575
576//============ Testing, One, Two =============================================
577
578#[cfg(test)]
579mod test {
580    use super::*;
581    use bytes::BytesMut;
582
583
584    //-------- Compose impls -------------------------------------------------
585
586    #[test]
587    fn compose_endian() {
588        let mut buf = BytesMut::with_capacity(20);
589        0x1234u16.compose(&mut buf);
590        (-0x1234i16).compose(&mut buf);
591        0x12345678u32.compose(&mut buf);
592        (-0x12345678i32).compose(&mut buf);
593        assert_eq!(buf.as_ref(),
594                   b"\x12\x34\xed\xcc\x12\x34\x56\x78\xed\xcb\xa9\x88");
595    }
596
597
598    //-------- Compressor ----------------------------------------------------
599
600    #[test]
601    fn limit() {
602        let mut buf = Compressor::new();
603        buf.set_limit(2);
604        assert_eq!(buf.remaining_mut(), 2);
605        assert!(buf.compose(&0u32).is_err());
606        buf.compose(&0u16).unwrap();
607        assert!(buf.compose(&0u16).is_err());
608
609        buf.set_limit(512); // definitely needs to realloc
610        assert_eq!(buf.remaining_mut(), 510);
611        buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 508])).unwrap();
612        assert!(buf.compose(&0u32).is_err());
613        buf.compose(&0u16).unwrap();
614        assert!(buf.compose(&0u16).is_err());
615
616        let mut buf = Compressor::from_buf(buf.unwrap());
617        assert_eq!(buf.so_far().len(), 0);
618        buf.set_limit(512);
619        buf.set_page_size(16);
620        assert_eq!(buf.remaining_mut(), 512);
621        buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 510])).unwrap();
622        assert_eq!(buf.remaining_mut(), 2);
623        assert_eq!(buf.so_far().len(), 510);
624    }
625
626    #[test]
627    fn compressed_names() {
628        // Same name again
629        //
630        let mut buf = Compressor::with_capacity(1024);
631        buf.enable_compression();
632        buf.compose(&7u8).unwrap();
633        let name = Dname::from_slice(b"\x03foo\x03bar\x00").unwrap();
634        buf.compress_name(&name).unwrap();
635        buf.compress_name(&name).unwrap();
636        assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\xC0\x01");
637
638        // Prefixed name.
639        //
640        let mut buf = Compressor::with_capacity(1024);
641        buf.enable_compression();
642        buf.compose(&7u8).unwrap();
643        Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
644              .compress(&mut buf).unwrap();
645        Dname::from_slice(b"\x03baz\x03foo\x03bar\x00").unwrap()
646              .compress(&mut buf).unwrap();
647        assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x01");
648
649        // Suffixed name.
650        //
651        let mut buf = Compressor::with_capacity(1024);
652        buf.enable_compression();
653        buf.compose(&7u8).unwrap();
654        Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
655              .compress(&mut buf).unwrap();
656        Dname::from_slice(b"\x03baz\x03bar\x00").unwrap()
657              .compress(&mut buf).unwrap();
658        assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x05");
659
660        // Don’t compress the root label.
661        //
662        let mut buf = Compressor::with_capacity(1024);
663        buf.enable_compression();
664        buf.compose(&7u8).unwrap();
665        Dname::root().compress(&mut buf).unwrap();
666        Dname::from_slice(b"\x03foo\x00").unwrap()
667              .compress(&mut buf).unwrap();
668        Dname::root().compress(&mut buf).unwrap();
669        assert_eq!(buf.so_far(), b"\x07\x00\x03foo\x00\x00");
670    }
671}