domain_core/bits/
message_builder.rs

1//! Building a new DNS message.
2//!
3//! DNS messages consist of five sections. The first, the *header section*
4//! contain, among other things, the number of entries in the following four
5//! section which then contain these entries without any further
6//! delimitation. In order to safely build a correct message, it thus needs
7//! to be assembled step by step, entry by entry. This module provides a
8//! number of types that can be used to assembling entries in these sections.
9//!
10//! Message building happens by appending data to a [`BytesMut`] buffer. This
11//! buffer is automatically grown to accomodate the data if necessary. It
12//! does, however, consider the size limit that all DNS messages have. Thus,
13//! when you start building by creating a [`MessageBuilder`], you can pass
14//! an initial buffer size, a size limit, and a strategy for growing to its
15//! [`with_params`][`MessageBuilder::with_params`] function. Alternatively,
16//! you can create the message atop an existing buffer via
17//! [`from_buf`][`MessageBuilder::from_buf`]. In this case you can adjust the
18//! limits via methods such as [`set_limit`][`MessageBuilder::set_limit`].
19//! 
20//! All types allow to change the limit later. This is useful if you know
21//! already that your message will have to end with an OPT or TSIG record.
22//! Since for these you also know the size in advance, you can reserve space
23//! by setting a lower limit and increase it only when finally adding those
24//! records.
25//!
26//! Because domain name compression is somewhat expensive, it needs to be
27//! enable explicitely through the 
28//! [`enable_compression`][`MessageBuilder::enable_compression`] method.
29//!
30//! The inital [`MessageBuilder`] allows access to the two first sections of
31//! the new message. The header section can be accessed via
32//! [`header`][`MessageBuilder::header`] and
33//! [`header_mut`][`MessageBuilder::header_mut`]. In addition, it is used for
34//! building the *question section* of the message. This section contains
35//! [`Question`]s to be asked of a name server, normally exactly one. You
36//! can add questions using the [`push`][`MessageBuilder::push`] method.
37//!
38//! Once you are happy with the question section, you can proceed to the
39//! next section, the *answer section,* by calling the
40//! [`answer`][`MessageBuilder::answer`] method.
41//! In a response, this section contains those resource records that answer
42//! the question. The section is represented by the [`AnswerBuilder`] type.
43//! It, too, has a [`push`][`AnswerBuilder::push`] method, but for adding
44//! [`Record`]s.
45//!
46//! A call to [`authority`][`AnswerBuilder::authority`] moves on to the
47//! *authority section,* represented by an [`AuthorityBuilder`]. It contains
48//! resource records that allow to identify the name servers that are
49//! authoritative for the records requested in the question. As with the
50//! answer section, [`push`][`AdditionalBuilder`] adds records to this
51//! section.
52//!
53//! The final section is the *additional section.* Here a name server can add
54//! information it believes will help the client to get to the answer it
55//! really wants. Which these are depends on the question and is generally
56//! given in RFCs that define the record types. Unsurprisingly, you will
57//! arrive at an [`AdditionalBuilder`] by calling the
58//! [`additional`][`AuthorityBuilder::additional`] method once you are done
59//! with the authority section. Adding records, once again, happens via the
60//! [`push`][`AdditionalBuilder::push`] method.
61//! 
62//! Once you are done with the additional section, too, you call
63//! [`finish`][`AdditionalBuilder::finish`] to retrieve the bytes buffer with
64//! the message data or [`freeze`][`AdditionalBuilder::freeze`] to get the
65//! [`Message`] instead.
66//!
67//! Since some of the sections are empty in many messages – for instance, a
68//! simple request only contains a single question – there are
69//! shortcuts in place to skip over sections. Each type can go to any later
70//! section through the methods named above. Each type also has the `finish`
71//! and `freeze` methods to arrive at the final data quickly.
72//!
73//! There is one more type: [`OptBuilder`]. It can be used to assemble an
74//! OPT record in the additional section. This is helpful because the OPT
75//! record in turn is a sequence of options that need to be assembled one
76//! by one.
77//!
78//! Since OPT records are part of the additional section, an [`OptBuilder`]
79//! can be retrieved from an [`AdditionalBuilder`] via its
80//! [`opt`][`AdditionalBuilder::opt`] method. Options can then be added as
81//! usually via [`push`][`OptBuilder::push`]. Once done, you can return to
82//! the additional section with [`additional`][`OptBuilder::additional`] or,
83//! if your OPT record is the final record, conclude message construction
84//! via [`finish`][`OptBuilder::finish`] or [`freeze`][`OptBuilder::freeze`].
85//!
86//! # Example
87//!
88//! To summarize all of this, here is an example that builds a
89//! response to an A query for example.com that contains two A records and
90//! and empty OPT record setting the UDP payload size.
91//!
92//! ```
93//! use std::str::FromStr;
94//! use domain_core::bits::{Dname, MessageBuilder, SectionBuilder, RecordSectionBuilder};
95//! use domain_core::iana::Rtype;
96//! use domain_core::rdata::A;
97//!
98//! let name = Dname::from_str("example.com.").unwrap();
99//! let mut msg = MessageBuilder::new_udp();
100//! msg.header_mut().set_rd(true);
101//! msg.push((&name, Rtype::A));
102//! let mut msg = msg.answer();
103//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 1))).unwrap();
104//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 2))).unwrap();
105//! let mut msg = msg.opt().unwrap();
106//! msg.set_udp_payload_size(4096);
107//! let _ = msg.freeze(); // get the message
108//! ```
109//!
110//! [`BytesMut`]: ../../../bytes/struct.BytesMut.html
111//! [`AdditionalBuilder`]: struct.AdditionalBuilder.html
112//! [`AdditionalBuilder::opt`]: struct.AdditionalBuilder.html#method.opt
113//! [`AdditionalBuilder::push`]: struct.AdditionalBuilder.html#method.push
114//! [`AdditionalBuilder::finish`]: struct.AdditionalBuilder.html#method.finish
115//! [`AdditionalBuilder::freeze`]: struct.AdditionalBuilder.html#method.freeze
116//! [`AnswerBuilder`]: struct.AnswerBuilder.html
117//! [`AnswerBuilder::authority`]: struct.AnswerBuilder.html#method.authority
118//! [`AnswerBuilder::push`]: struct.AnswerBuilder.html#method.push
119//! [`AuthorityBuilder`]: struct.AuthorityBuilder.html
120//! [`AuthorityBuilder::additional`]: struct.AuthorityBuilder.html#method.additional
121//! [`AuthorityBuilder::push`]: struct.AuthorityBuilder.html#method.push
122//! [`Composer`]: ../compose/Composer.html
123//! [`Message`]: ../message/struct.Messsage.html
124//! [`MessageBuilder`]: struct.MessageBuilder.html
125//! [`MessageBuilder::answer`]: struct.MessageBuilder.html#method.answer
126//! [`MessageBuilder::enable_compression`]: struct.MessageBuilder.html#method.enable_compression
127//! [`MessageBuilder::from_buf`]: struct.MessageBuilder.html#method.from_buf
128//! [`MessageBuilder::header`]: struct.MessageBuilder.html#method.header
129//! [`MessageBuilder::header_mut`]: struct.MessageBuilder.html#method.header_mut
130//! [`MessageBuilder::push`]: struct.MessageBuilder.html#method.push
131//! [`MessageBuilder::with_params`]: struct.MessageBuilder.html#method.with_params
132//! [`MessageBuilder::set_limit`]: struct.MessageBuilder.html#method.set_limit
133//! [`OptBuilder`]: struct.OptBuilder.html
134//! [`OptBuilder::additional`]: struct.OptBuilder.html#method.additional
135//! [`OptBuilder::finish`]: struct.OptBuilder.html#method.finish
136//! [`OptBuilder::freeze`]: struct.OptBuilder.html#method.freeze
137//! [`OptBuilder::push`]: struct.OptBuilder.html#method.push
138//! [`Question`]: ../question/struct.Question.html
139//! [`Record`]: ../record/struct.Record.html
140
141use std::{mem, ops};
142use std::marker::PhantomData;
143use bytes::{BigEndian, BufMut, ByteOrder, BytesMut};
144use iana::opt::OptionCode;
145use super::compose::{Compose, Compress, Compressor};
146use super::header::{Header, HeaderCounts, HeaderSection};
147use super::message::Message;
148use super::name::ToDname;
149use super::opt::{OptData, OptHeader};
150use super::parse::ShortBuf;
151use super::question::Question;
152use super::rdata::RecordData;
153use super::record::Record;
154
155
156//------------ MessageBuilder -----------------------------------------------
157
158/// Starts building a DNS message.
159///
160/// This type starts building a DNS message and allows adding questions to
161/// its question section. See the [module documentation] for an overview of 
162/// how to build a message.
163///
164/// Message builders operate atop a [`BytesMut`] byte buffer. There are a
165/// number of functions to create a builder either using an existing
166/// buffer or with a newly created buffer. 
167/// 
168/// Once created, it is possible to access the message header or append
169/// questions to the question section before proceeding to the subsequent
170/// parts of the message.
171///
172/// [module documentation]: index.html
173/// [`BytesMut`]: ../../../bytes/struct.BytesMut.html
174#[derive(Clone, Debug)]
175pub struct MessageBuilder {
176    target: MessageTarget,
177}
178
179
180/// # Creation and Preparation
181///
182impl MessageBuilder {
183    /// Creates a new builder for a UDP message.
184    ///
185    /// The builder will use a new bytes buffer. The buffer will have a
186    /// capacity of 512 bytes and will also be limited to that.
187    ///
188    /// This will result in a UDP message following the original limit. If you
189    /// want to create larger messages, you should signal this through the use
190    /// of EDNS.
191    pub fn new_udp() -> Self {
192        Self::with_params(512, 512, 0)
193    }
194
195    /// Creates a new builder for a TCP message.
196    ///
197    /// The builder will use a new buffer. It will be limited to 65535 bytes,
198    /// starting with the capacity given and also growing by that amount.
199    ///
200    /// Since DNS messages are preceded on TCP by a two octet length
201    /// inicator, the function will add two bytes with zero before the
202    /// message. Once you have completed your message, you can use can set
203    /// these two bytes to the size of the message. But remember that they
204    /// are in network byte order.
205    pub fn new_tcp(capacity: usize) -> Self {
206        let mut buf = BytesMut::with_capacity(capacity + 2);
207        buf.put_u16_be(0);
208        let mut res = Self::from_buf(buf);
209        res.set_limit(::std::u16::MAX as usize);
210        res.set_page_size(capacity);
211        res
212    }
213
214    /// Creates a new message builder using an existing bytes buffer.
215    ///
216    /// The builder’s initial limit will be equal to whatever capacity is
217    /// left in the buffer. As a consequence, the builder will never grow
218    /// beyond that remaining capacity.
219    pub fn from_buf(buf: BytesMut) -> Self {
220        MessageBuilder { target: MessageTarget::from_buf(buf) }
221    }
222
223    /// Creates a message builder with the given capacity.
224    ///
225    /// The builder will have its own newly created bytes buffer. Its inital
226    /// limit will be equal to the capacity of that buffer. This may be larger
227    /// than `capacity`. If you need finer control over the limit, use
228    /// [`with_params`] instead.
229    ///
230    /// [`with_params`]: #method.with_params
231    pub fn with_capacity(capacity: usize) -> Self {
232        Self::from_buf(BytesMut::with_capacity(capacity))
233    }
234
235    /// Creates a new message builder.
236    ///
237    /// A new buffer will be created for this builder. It will initially
238    /// allocate space for at least `initial` bytes. The message will never
239    /// exceed a size of `limit` bytes. Whenever the buffer’s capacity is
240    /// exhausted, the builder will allocate at least another `page_size`
241    /// bytes. If `page_size` is set to `0`, the builder will allocate at
242    /// most once and then enough bytes to have room for the limit.
243    pub fn with_params(initial: usize, limit: usize, page_size: usize)
244                       -> Self {
245        let mut res = Self::with_capacity(initial);
246        res.set_limit(limit);
247        res.set_page_size(page_size);
248        res
249    }
250
251    /// Enables support for domain name compression.
252    ///
253    /// After this method is called, the domain names in questions, the owner
254    /// domain names of resource records, and domain names appearing in the
255    /// record data of record types defined in [RFC 1035] will be compressed.
256    ///
257    /// [RFC 1035]: ../../rdata/rfc1035.rs
258    pub fn enable_compression(&mut self) {
259        self.target.buf.enable_compression()
260    }
261
262    /// Sets the maximum size of the constructed DNS message.
263    ///
264    /// After this method was called, additional data will not be added to the
265    /// message if that would result in the message exceeding a size of
266    /// `limit` bytes. If the message is already larger than `limit` when the
267    /// method is called, it will _not_ be truncated. That is, you can never
268    /// actually set a limit smaller than the current message size.
269    ///
270    /// Note also that the limit only regards the message constructed by the
271    /// builder itself. If a builder was created atop a buffer that already
272    /// contained some data, this pre-existing data is not considered.
273    pub fn set_limit(&mut self, limit: usize) {
274        self.target.buf.set_limit(limit)
275    }
276
277    /// Sets the amount of data by which to grow the underlying buffer.
278    ///
279    /// Whenever the buffer runs out of space but the message size limit has
280    /// not yet been reached, the builder will grow the buffer by at least
281    /// `page_size` bytes.
282    ///
283    /// A special case is a page size of zero, in which case the buffer will
284    /// be grown only once to have enough space to reach the current limit.
285    pub fn set_page_size(&mut self, page_size: usize) {
286        self.target.buf.set_page_size(page_size)
287    }
288}
289
290
291/// # Building
292///
293impl MessageBuilder {
294    /// Appends a new question to the message.
295    ///
296    /// This function is generic over anything that can be converted into a
297    /// [`Question`]. In particular, triples of a domain name, a record type,
298    /// and a class as well as pairs of just a domain name and a record type
299    /// fulfill this requirement with the class assumed to be `Class::In` in
300    /// the latter case.
301    ///
302    /// The method will fail if by appending the question the message would
303    /// exceed its size limit.
304    ///
305    /// [`Question`]: ../question/struct.Question.html
306    pub fn push<N: ToDname, Q: Into<Question<N>>>(&mut self, question: Q)
307                                                  -> Result<(), ShortBuf> {
308        self.target.push(|target| question.into().compress(target),
309                         |counts| counts.inc_qdcount())
310    }
311
312    /// Proceeds to building the answer section.
313    pub fn answer(self) -> AnswerBuilder {
314        AnswerBuilder::new(self.target)
315    }
316
317    /// Proceeds to building the authority section, skipping the answer.
318    pub fn authority(self) -> AuthorityBuilder {
319        self.answer().authority()
320    }
321
322    /// Proceeds to building the additional section.
323    ///
324    /// Leaves the answer and additional sections empty.
325    pub fn additional(self) -> AdditionalBuilder {
326        self.answer().authority().additional()
327    }
328}
329
330impl SectionBuilder for MessageBuilder {
331    fn into_target(self) -> MessageTarget { self.target }
332    fn get_target(&self) -> &MessageTarget { &self.target }
333    fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
334}
335
336//------------ AnswerBuilder -------------------------------------------------
337
338/// Builds the answer section of a DNS message.
339///
340/// This type is typically constructed by calling [`answer`] on a
341/// [`MessageBuilder`]. See the [module documentation] for an overview of how
342/// to build a message.
343///
344/// Once acquired, you can access a message’s header or append resource
345/// records to the message’s answer section with the [`push`] method.
346///
347/// [`answer`]: struct.MessageBuilder.html#method.answer
348/// [`MessageBuilder`]: struct.MessageBuilder.html
349/// [`push`]: #method.push
350/// [module documentation]: index.html
351#[derive(Clone, Debug)]
352pub struct AnswerBuilder {
353    target: MessageTarget,
354}
355
356
357impl AnswerBuilder {
358    /// Creates a new answer builder from a message target.
359    fn new(target: MessageTarget) -> Self {
360        AnswerBuilder { target }
361    }
362
363    /// Proceeds to building the authority section.
364    pub fn authority(self) -> AuthorityBuilder {
365        AuthorityBuilder::new(self.target)
366    }
367
368    /// Proceeds to building the additional section, skipping authority.
369    pub fn additional(self) -> AdditionalBuilder {
370        self.authority().additional()
371    }
372
373    /// Proceeds to building the OPT record.
374    ///
375    /// The method will start by adding the record header. Since this may
376    /// exceed the message limit, the method may fail.
377    /// If you have saved space for the OPT record via [`set_limit`] earlier,
378    /// remember to increase the limit again before calling `opt`.
379    ///
380    /// [`set_limit`]: #method.set_limit
381    pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
382        OptBuilder::new(self.into_target())
383    }
384}
385
386impl SectionBuilder for AnswerBuilder {
387    fn into_target(self) -> MessageTarget { self.target }
388    fn get_target(&self) -> &MessageTarget { &self.target }
389    fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
390}
391
392impl RecordSectionBuilder for AnswerBuilder {
393    fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
394                where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
395        self.target.push(|target| record.into().compress(target),
396                         |counts| counts.inc_ancount())
397    }
398}
399
400
401//------------ AuthorityBuilder ---------------------------------------------
402
403/// Builds the authority section of a DNS message.
404///
405/// This type can be constructed by calling `authority()` on a
406/// [`MessageBuilder`] or [`AnswerBuilder`]. See the [module documentation]
407/// for details on constructing messages.
408///
409/// Once acquired, you can use this type to add records to the authority
410/// section of a message via the [`push`] method.
411///
412/// [`AnswerBuilder`]: struct.AnswerBuilder.html
413/// [`MessageBuilder`]: struct.MessageBuilder.html
414/// [`push`]: #method.push
415/// [module documentation]: index.html
416#[derive(Clone, Debug)]
417pub struct AuthorityBuilder {
418    target: MessageTarget,
419}
420
421
422impl AuthorityBuilder {
423    /// Creates a new authority builder from a compser.
424    fn new(target: MessageTarget) -> Self {
425        AuthorityBuilder { target }
426    }
427
428    /// Proceeds to building the additional section.
429    pub fn additional(self) -> AdditionalBuilder {
430        AdditionalBuilder::new(self.target)
431    }
432
433    /// Proceeds to building the OPT record.
434    ///
435    /// The method will start by adding the record header. Since this may
436    /// exceed the message limit, the method may fail.
437    /// If you have saved space for the OPT record via [`set_limit`] earlier,
438    /// remember to increase the limit again before calling `opt`.
439    ///
440    /// [`set_limit`]: #method.set_limit
441    pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
442        OptBuilder::new(self.into_target())
443    }
444}
445
446impl SectionBuilder for AuthorityBuilder {
447    fn into_target(self) -> MessageTarget { self.target }
448    fn get_target(&self) -> &MessageTarget { &self.target }
449    fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
450}
451
452impl RecordSectionBuilder for AuthorityBuilder {
453    fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
454                where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
455        self.target.push(|target| record.into().compress(target),
456                         |counts| counts.inc_nscount())
457    }
458}
459
460
461//------------ AdditionalBuilder --------------------------------------------
462
463/// Builds the additional section of a DNS message.
464///
465/// This type can be constructed by calling `additional` on a
466/// [`MessageBuilder`], [`AnswerBuilder`], or [`AuthorityBuilder`]. See the
467/// [module documentation] for on overview on building messages.
468///
469/// Once aquired, you can add records to the additional section via the
470/// [`push`] method. If the record you want to add is an OPT record, you
471/// can also use the [`OptBuilder`] type which you can acquire via the
472/// [`opt`] method.
473///
474/// [`AnswerBuilder`]: struct.AnswerBuilder.html
475/// [`AuthorityBuilder`]: struct.AuthorityBuilder.html
476/// [`MessageBuilder`]: struct.MessageBuilder.html
477/// [`OptBuilder`]: struct.OptBuilder.html
478/// [`push`]: #method.push
479/// [`opt`]: #method.opt
480/// [module documentation]: index.html
481#[derive(Clone, Debug)]
482pub struct AdditionalBuilder {
483    target: MessageTarget,
484}
485
486
487impl AdditionalBuilder {
488    /// Creates a new additional builder from a compser.
489    fn new(target: MessageTarget) -> Self {
490        AdditionalBuilder { target }
491    }
492
493    /// Proceeds to building the OPT record.
494    ///
495    /// The method will start by adding the record header. Since this may
496    /// exceed the message limit, the method may fail.
497    /// If you have saved space for the OPT record via [`set_limit`] earlier,
498    /// remember to increase the limit again before calling `opt`.
499    ///
500    /// [`set_limit`]: #method.set_limit
501    pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
502        OptBuilder::new(self.into_target())
503    }
504}
505
506impl SectionBuilder for AdditionalBuilder {
507    fn into_target(self) -> MessageTarget { self.target }
508    fn get_target(&self) -> &MessageTarget { &self.target }
509    fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
510}
511
512impl RecordSectionBuilder for AdditionalBuilder {
513    fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
514                where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
515        self.target.push(|target| record.into().compress(target),
516                         |counts| counts.inc_nscount())
517    }
518}
519
520//------------ OptBuilder ----------------------------------------------------
521
522/// Builds an OPT record as part of the additional section of a DNS message,
523///
524/// This type can be constructed by calling the `opt` method on any other
525/// builder type.  See the [module documentation] for on overview
526/// on building messages.
527///
528/// As OPT records are part of the additional section, this type will, when
529/// constructed proceed to this section and append an OPT record without any
530/// options to it. Options can be appened via the [`push`] method.
531///
532/// The type also deref-muts to [`OptHeader`] allowing you to modify the
533/// header’s fields such as setting the
534/// [UDP payload size][`OptHeader::set_udp_payload_size`] or the
535/// [DO bit][`OptHeader::set_dnssec_ok`].
536///
537/// Once you have adjusted the OPT record to your liking, you can return to
538/// the additional section via [`additional`]. Note, however, that the OPT
539/// record should be the last record except for a possible TSIG record. You
540/// can also finish the message via [`finish`] or [`freeze`].
541///
542/// [module documentation]: index.html
543/// [`OptHeader`]: ../opt/struct.OptHeader.html
544/// [`additional`]: #method.additional
545/// [`finish`]: #method.finish
546/// [`freeze`]: #method.freeze
547/// [`push`]: #method.push
548/// [`OptHeader::set_udp_payload_size`]: ../opt/struct.OptHeader.html#method.set_udp_payload_size
549/// [`OptHeader::set_dnssec_ok`]: ../opt/struct.OptHeader.html#method.set_dnssec_ok
550#[derive(Clone, Debug)]
551pub struct OptBuilder {
552    target: MessageTarget,
553
554    /// The position of in `target` of the start of the OPT record.
555    pos: usize,
556}
557
558impl OptBuilder {
559    /// Creates a new OPT builder atop the given target.
560    ///
561    /// This appends the OPT header to the message and increases the
562    /// ARCOUNT of the message.
563    fn new(mut target: MessageTarget) -> Result<Self, ShortBuf> {
564        let pos = target.len();
565        target.compose(&OptHeader::default())?;
566        target.compose(&0u16)?;
567        target.counts_mut().inc_arcount();
568        Ok(OptBuilder { pos, target })
569    }
570
571    /// Pushes an option to the OPT record.
572    ///
573    /// The method is generic over anything that implements the `OptData`
574    /// trait representing an option. Alternatively, most of these types
575    /// provide a `push` associated function that allows to construct an
576    /// option directly into a record from its data.
577    pub fn push<O: OptData>(&mut self, option: &O) -> Result<(), ShortBuf> {
578        self.target.compose(&option.code())?;
579        let len = option.compose_len();
580        assert!(len <= ::std::u16::MAX as usize);
581        self.target.compose(&(len as u16))?;
582        self.target.compose(option)?;
583        self.complete();
584        Ok(())
585    }
586
587    /// Builds an option into the record.
588    ///
589    /// The option will have the option code `code`. Its data will be `len`
590    /// octets long and appened to the record via the `op` closure.
591    pub(super) fn build<F>(&mut self, code: OptionCode, len: u16, op: F)
592                           -> Result<(), ShortBuf>
593                        where F: FnOnce(&mut Compressor)
594                                        -> Result<(), ShortBuf> {
595        self.target.compose(&code)?;
596        self.target.compose(&len)?;
597        op(&mut self.target.buf)?;
598        self.complete();
599        Ok(())
600    }
601
602    /// Completes the OPT record and returns to the additional section builder.
603    pub fn additional(self) -> AdditionalBuilder {
604        AdditionalBuilder::new(self.target)
605    }
606
607    /// Completes building the OPT record.
608    ///
609    /// This will update the RDLEN field of the record header.
610    fn complete(&mut self) {
611        let len = self.target.len()
612                - (self.pos + mem::size_of::<OptHeader>() + 2);
613        assert!(len <= ::std::u16::MAX as usize);
614        let count_pos = self.pos + mem::size_of::<OptHeader>();
615        BigEndian::write_u16(&mut self.target.as_slice_mut()[count_pos..],
616                             len as u16);
617    }
618}
619
620impl SectionBuilder for OptBuilder {
621    fn into_target(self) -> MessageTarget { self.target }
622    fn get_target(&self) -> &MessageTarget { &self.target }
623    fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
624}
625
626impl ops::Deref for OptBuilder {
627    type Target = OptHeader;
628
629    fn deref(&self) -> &Self::Target {
630        OptHeader::for_record_slice(&self.target.as_slice()[self.pos..])
631    }
632}
633
634impl ops::DerefMut for OptBuilder {
635    fn deref_mut(&mut self) -> &mut Self::Target {
636        OptHeader::for_record_slice_mut(&mut self.target.as_slice_mut()
637                                                                 [self.pos..])
638    }
639}
640
641
642//------------ MessageTarget -------------------------------------------------
643
644/// Underlying data for constructing a DNS message.
645///
646/// This private type does all the heavy lifting for constructing messages.
647#[derive(Clone, Debug)]
648pub struct MessageTarget {
649    buf: Compressor,
650    start: usize,
651}
652
653
654impl MessageTarget {
655    /// Creates a new message target atop a given buffer.
656    fn from_buf(mut buf: BytesMut) -> Self {
657        let start = buf.len();
658        if buf.remaining_mut() < mem::size_of::<HeaderSection>() {
659            let additional = mem::size_of::<HeaderSection>()
660                           - buf.remaining_mut();
661            buf.reserve(additional)
662        }
663        let mut buf = Compressor::from_buf(buf);
664        HeaderSection::default().compose(&mut buf);
665        MessageTarget { buf, start }
666    }
667
668    /// Returns a reference to the message’s header.
669    fn header(&self) -> &Header {
670        Header::for_message_slice(self.buf.so_far())
671    }
672
673    /// Returns a mutable reference to the message’s header.
674    fn header_mut(&mut self) -> &mut Header {
675        Header::for_message_slice_mut(self.buf.so_far_mut())
676    }
677
678    fn counts(&self) -> &HeaderCounts {
679        HeaderCounts::for_message_slice(self.buf.so_far())
680    }
681
682    /// Returns a mutable reference to the message’s header counts.
683    fn counts_mut(&mut self) -> &mut HeaderCounts {
684        HeaderCounts::for_message_slice_mut(self.buf.so_far_mut())
685    }
686
687    /// Pushes something to the end of the message.
688    ///
689    /// There’s two closures here. The first one, `composeop` actually
690    /// writes the data. The second, `incop` increments the counter in the
691    /// messages header to reflect the new element.
692    fn push<O, I, E>(&mut self, composeop: O, incop: I) -> Result<(), E>
693            where O: FnOnce(&mut Compressor) -> Result<(), E>,
694                  I: FnOnce(&mut HeaderCounts) {
695        composeop(&mut self.buf).map(|()| incop(self.counts_mut()))
696    }
697
698    fn snapshot<T>(&self) -> Snapshot<T> {
699        Snapshot {
700            pos: self.buf.len(),
701            counts: *self.counts(),
702            marker: PhantomData,
703        }
704    }
705
706    fn rewind<T>(&mut self, snapshot: &Snapshot<T>) {
707        self.buf.truncate(snapshot.pos);
708        self.counts_mut().set(snapshot.counts);
709    }
710
711    /// Returns a reference to the message assembled so far.
712    ///
713    /// In case the builder was created from a buffer with pre-existing
714    /// content, the returned reference is for the complete content of this
715    /// buffer.
716    fn preview(&self) -> &[u8] {
717        self.buf.as_slice()
718    }
719
720    fn prelude(&self) -> &[u8] {
721        &self.buf.as_slice()[..self.start]
722    }
723
724    fn prelude_mut(&mut self) -> &mut [u8] {
725        &mut self.buf.as_slice_mut()[..self.start]
726    }
727
728    fn unwrap(self) -> BytesMut {
729        self.buf.unwrap()
730    }
731
732    fn freeze(self) -> Message {
733        let bytes = if self.start == 0 {
734            self.buf.unwrap().freeze()
735        }
736        else {
737            self.buf.unwrap().freeze().slice_from(self.start)
738        };
739        unsafe { Message::from_bytes_unchecked(bytes) }
740    }
741}
742
743impl ops::Deref for MessageTarget {
744    type Target = Compressor;
745
746    fn deref(&self) -> &Self::Target {
747        &self.buf
748    }
749}
750
751impl ops::DerefMut for MessageTarget {
752    fn deref_mut(&mut self) -> &mut Self::Target {
753        &mut self.buf
754    }
755}
756
757
758//------------ Snapshot ------------------------------------------------------
759
760/// Contains information about the state of a message.
761///
762/// This type is returned by the `snapshot` method of the various builders and
763/// allows to later return to that state through the `rewind` method.
764#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
765pub struct Snapshot<T> {
766    pos: usize,
767    counts: HeaderCounts,
768    marker: PhantomData<T>,
769}
770
771//------------ SectionBuilder ------------------------------------------------
772
773/// Trait that implements common interface for building message sections
774pub trait SectionBuilder : Sized {
775    /// Updates the message’s size limit.
776    ///
777    /// After this method was called, additional data will not be added to the
778    /// message if that would result in the message exceeding a size of
779    /// `limit` bytes. If the message is already larger than `limit` when the
780    /// method is called, it will _not_ be truncated. That is, you can never
781    /// actually set a limit smaller than the current message size.
782    ///
783    /// Note also that the limit only regards the message constructed by the
784    /// builder itself. If a builder was created atop a buffer that already
785    /// contained some data, this pre-existing data is not considered.
786    fn set_limit(&mut self, limit: usize) {
787        self.get_target_mut().buf.set_limit(limit)
788    }
789
790    /// Returns a reference to the messages header.
791    fn header(&self) -> &Header {
792        self.get_target().header()
793    }
794
795    /// Returns a mutable reference to the messages header.
796    fn header_mut(&mut self) -> &mut Header {
797        self.get_target_mut().header_mut()
798    }
799
800    /// Returns a reference to the message assembled so far.
801    ///
802    /// In case the builder was created from a buffer with pre-existing
803    /// content, the returned reference is for the complete content of this
804    /// buffer.
805    fn preview(&self) -> &[u8] {
806        self.get_target().preview()
807    }
808
809    /// Returns a reference to the slice preceeding the message.
810    ///
811    /// The slice is may be empty.
812    fn prelude(&self) -> &[u8] {
813        self.get_target().prelude()
814    }
815
816    /// Returns a mutable reference to the slice preceeding the message.
817    fn prelude_mut(&mut self) -> &mut [u8] {
818        self.get_target_mut().prelude_mut()
819    }
820
821    /// Finishes the message and returns the underlying bytes buffer.
822    ///
823    /// This will result in a message with empty authority and additional
824    /// sections.
825    fn finish(self) -> BytesMut {
826        self.into_target().unwrap()
827    }
828
829    /// Finishes the message and returns the resulting bytes value.
830    ///
831    /// This will result in a message with empty authority and additional
832    /// sections.
833    fn freeze(self) -> Message {
834        self.into_target().freeze()
835    }
836
837    /// Returns a snapshot indicating the current state of the message.
838    ///
839    /// The returned value can be used to later return the message to the
840    /// state at the time the method was called through the [`rewind`]
841    /// method.
842    ///
843    /// [`rewind`]: #method.rewind
844    fn snapshot(&self) -> Snapshot<Self> {
845        self.get_target().snapshot()
846    }
847
848    /// Rewinds the message to the state it had at `snapshot`.
849    ///
850    /// This will truncate the message to the size it had at the time the
851    /// [`snapshot`] method was called, making it forget all records added
852    /// since.
853    ///
854    /// [`snapshot`]: #method.snapshot
855    fn rewind(&mut self, snapshot: &Snapshot<Self>) {
856        self.get_target_mut().rewind(snapshot)
857    }
858
859    /// Converts into target
860    fn into_target(self) -> MessageTarget;
861
862    /// Returns message target
863    fn get_target(&self) -> &MessageTarget;
864
865    /// Returns message target
866    fn get_target_mut(&mut self) -> &mut MessageTarget;
867}
868
869/// Trait for pushing resource records into a section
870pub trait RecordSectionBuilder : SectionBuilder {
871    /// Appends a new resource record to the section.
872    ///
873    /// This method is generic over anything that can be converted into a
874    /// [`Record`]. In particular, you can use four-tuples consisting of
875    /// a domain name, class, TTL, and record data or triples leaving out
876    /// the class which will then be assumed to be `Class::In`.
877    ///
878    /// If appending the record would result in the message exceeding its
879    /// size limit, the method will fail.
880    ///
881    /// [`Record`]: ../record/struct.Record.html
882    fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
883                where N: ToDname, D: RecordData, R: Into<Record<N, D>>;
884}
885
886//============ Testing ======================================================
887
888#[cfg(test)]
889mod test {
890    use std::str::FromStr;
891    use super::*;
892    use rdata::*;
893    use bits::name::*;
894    use bits::rdata::*;
895    use bits::message::*;
896
897    fn get_built_message() -> Message {
898        let msg = MessageBuilder::with_capacity(512);
899        let mut msg = msg.answer();
900        msg.push((Dname::from_str("foo.example.com.").unwrap(), 86000,
901                     Cname::new(Dname::from_str("baz.example.com.")
902                                         .unwrap()))).unwrap();
903        let mut msg = msg.authority();
904        msg.push((Dname::from_str("bar.example.com.").unwrap(), 86000,
905                     Cname::new(Dname::from_str("baz.example.com.")
906                                         .unwrap()))).unwrap();
907        msg.freeze()
908    }
909
910    #[test]
911    fn build_message() {
912        let msg = get_built_message();
913        assert_eq!(1, msg.header_counts().ancount());
914        assert_eq!(1, msg.header_counts().nscount());
915    }
916}