LCOV - code coverage report
Current view: top level - dns - rdatafields.h (source / functions) Hit Total Coverage
Test: report.info Lines: 1 9 11.1 %
Date: 2012-05-15 Functions: 0 6 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #ifndef __RDATAFIELDS_H
      16                 :            : #define __RDATAFIELDS_H 1
      17                 :            : 
      18                 :            : #include <stdint.h>
      19                 :            : 
      20                 :            : #include <cstddef>
      21                 :            : 
      22                 :            : namespace isc {
      23                 :            : namespace util {
      24                 :            : class OutputBuffer;
      25                 :            : }
      26                 :            : namespace dns {
      27                 :            : class AbstractMessageRenderer;
      28                 :            : 
      29                 :            : namespace rdata {
      30                 :            : class Rdata;
      31                 :            : 
      32                 :            : /// A low-level, RR type-independent representation of DNS RDATA.
      33                 :            : ///
      34                 :            : /// <b>Purpose of the Class</b>
      35                 :            : ///
      36                 :            : /// This class intends to help "serialization" of the content of RDATA
      37                 :            : /// in a space-efficient manner.  Specific derived classes of \c Rdata
      38                 :            : /// focus on the convenience of accessing RDATA fields for RR type-specific
      39                 :            : /// protocol operations, and can be inefficient in terms of space.
      40                 :            : /// For example, a DNS character string may be internally represented as a
      41                 :            : /// \c std::string object with all of the overhead of the richer class.
      42                 :            : /// If an application needs to maintain a very large number of RRs and it
      43                 :            : /// does not have to perform RR specific operation so often, it may make more
      44                 :            : /// sense to store the data in memory in a lower-level but space efficient
      45                 :            : /// form.
      46                 :            : ///
      47                 :            : /// Another purpose of this class is to improve rendering performance for
      48                 :            : /// RDATA.  If the only requirement were space efficiency, it would be just
      49                 :            : /// sufficient to convert the \c RDATA into a binary sequence in the wire
      50                 :            : /// format.  However, to render the data in a DNS message, we'd have to
      51                 :            : /// re-construct a corresponding \c Rdata object in the case where name
      52                 :            : /// compression is necessary.  This is not desirable, and this class is
      53                 :            : /// provided to avoid such unnecessary overhead.
      54                 :            : ///
      55                 :            : /// <b>Data Format</b>
      56                 :            : ///
      57                 :            : /// To meet these goals, this class helps convert an \c Rdata object into
      58                 :            : /// two pieces of information: Wire-format representation of the \c Rdata
      59                 :            : /// and associated meta information for efficient rendering.
      60                 :            : ///
      61                 :            : /// Specifically, it maintains the wire-format data as a sequence of typed
      62                 :            : /// fields.  The types are:
      63                 :            : /// - Compressible name: a domain name as an RDATA field that can be compressed
      64                 :            : /// - Incompressible name: a domain name as an RDATA field that cannot be
      65                 :            : ///   compressed
      66                 :            : /// - Other data: any other fields of RDATA, which should be treated as opaque
      67                 :            : ///
      68                 :            : /// (See also the description of \c RdataFields::Type)
      69                 :            : /// Whether a name can or cannot be compressed is determined according to
      70                 :            : /// RFC3597.
      71                 :            : ///
      72                 :            : /// A "other data" field may not always correspond to a single RDATA field.
      73                 :            : /// A \c RdataFields field (of other data) is just a contiguous region of the
      74                 :            : /// wire-format data that does not involve name compression.
      75                 :            : /// For example, the SOA RDATA begins with two "compressible" names followed
      76                 :            : /// by 5 32-bit fields.
      77                 :            : /// In \c RdataFields the last 5 fields would be considered a single 20-byte
      78                 :            : /// field.
      79                 :            : ///
      80                 :            : /// Each \c RdataFields field is identified by the \c FieldSpec structure,
      81                 :            : /// which provides the type and length of the field.
      82                 :            : /// An \c RdataFields object internally maintains a sequence of \c FieldSpec
      83                 :            : /// objects in a form of plain C-style array, which can be referenced via
      84                 :            : /// a pointer returned by the \c getFieldSpecData() method.
      85                 :            : /// The \c \c FieldSpec for a specific field can also be retrieved by the
      86                 :            : /// \c getFieldSpec() method.
      87                 :            : ///
      88                 :            : /// The following diagram shows the internal memory representation of
      89                 :            : /// an SOA RDATA in the form of \c RdataFields object and how an application
      90                 :            : /// can get access to the memory region.
      91                 :            : /** \verbatim
      92                 :            : accessible via      |0                               getDataLength() bytes
      93                 :            : getData()----------> <MNAME><RNAME><Rest of the data>
      94                 :            :                      <---------- 3 * sizeof(FieldSpec) bytes ------------->
      95                 :            : getFieldSpecData()-> { compressible name { compressible name { other data
      96                 :            :                        len: MNAME-len }    len: RNAME-len }    len: 20    }
      97                 :            : \endverbatim
      98                 :            :  */
      99                 :            : /// where MNAME and RNAME are wire format representations of the MNAME and
     100                 :            : /// RNAME fields of the SOA RDATA, respectively, and "Rest of the data"
     101                 :            : /// encodes the remaining 20 bytes of the RDATA in network byte order.
     102                 :            : ///
     103                 :            : /// <b>Usage of the Class</b>
     104                 :            : ///
     105                 :            : /// One major and common use case of the \c RdataFields class is to convert
     106                 :            : /// a \c Rdata object (possibly given from a DNS message or some configuration
     107                 :            : /// source such as a zone file) in the serialized format and store a copy of
     108                 :            : /// the data somewhere in memory.  The following code sample implements this
     109                 :            : /// scenario:
     110                 :            : /// \code // assume "rdata" is a reference type to Rdata
     111                 :            : /// const RdataFields fields(rdata);
     112                 :            : /// const unsigned int fields_size = fields.getFieldDataSize();
     113                 :            : /// memcpy(some_place, fields.getFieldSpecData(), fields_size);
     114                 :            : /// const size_t data_length = fields.getDataLength();
     115                 :            : /// memcpy(other_place, fields.getData(), data_length);
     116                 :            : /// // (fields_size and data_length should be stored somewhere, too)
     117                 :            : /// \endcode
     118                 :            : ///
     119                 :            : /// Another typical usage is to render the stored data in the wire format
     120                 :            : /// as efficiently as possible.  The following code is an example of such
     121                 :            : /// usage:
     122                 :            : /// \code // assume "renderer" is of type MessageRenderer
     123                 :            : /// // retrieve data_length and fields_size from the storage
     124                 :            : /// RdataFields(some_place, fields_size, other_place,
     125                 :            : ///             data_length).toWire(renderer);
     126                 :            : /// \endcode
     127                 :            : ///
     128                 :            : /// <b>Notes to Users</b>
     129                 :            : ///
     130                 :            : /// The main purposes of this class is to help efficient operation
     131                 :            : /// for some (limited classes of) performance sensitive application.
     132                 :            : /// For this reason the interface and implementation rely on relatively
     133                 :            : /// lower-level, riskier primitives such as passing around bare pointers.
     134                 :            : ///
     135                 :            : /// It is therefore discouraged to use this class for general purpose
     136                 :            : /// applications that do not need to maximize performance in terms of either
     137                 :            : /// memory footprint or rendering speed.
     138                 :            : /// All functionality provided by this class can be achieved via higher level
     139                 :            : /// interfaces such as the \c Rdata class variants.
     140                 :            : /// Normal applications should use those interfaces.
     141                 :            : ///
     142                 :            : /// The data format is public information so that an application can examine
     143                 :            : /// and use selected parts of data.  For example, an application may want to
     144                 :            : /// encode domain names in RDATA in a different way while storing the other
     145                 :            : /// data in a separate place.
     146                 :            : /// However, at this moment the format is still in flux, and it may not
     147                 :            : /// be compatible with future versions (see below).
     148                 :            : ///
     149                 :            : /// <b>Development Notes</b>
     150                 :            : ///
     151                 :            : /// We should conduct benchmark tests to measure rendering performance.
     152                 :            : ///
     153                 :            : /// The current implementation needs to re-construct name objects from
     154                 :            : /// compressible and incompressible name fields as wire-format data.
     155                 :            : /// This is not efficient, and we'll probably want to improve this in a
     156                 :            : /// future version.  One possibility is to store offset information as well
     157                 :            : /// as the name data (at the cost of increasing memory footprint), and
     158                 :            : /// to use the pair of data for faster rendering.
     159                 :            : class RdataFields {
     160                 :            : public:
     161                 :            :     /// Types of \c RdataFields fields.
     162                 :            :     ///
     163                 :            :     /// \c COMPRESSIBLE_NAME and \c INCOMPRESSIBLE_NAME represent a domain
     164                 :            :     /// name used as a field of an RDATA that can and cannot be compressed
     165                 :            :     /// per RFC3597.
     166                 :            :     /// \c DATA means all other types of fields.
     167                 :            :     enum Type {
     168                 :            :         DATA,              ///< Plain data.
     169                 :            :         COMPRESSIBLE_NAME, ///< A domain name subject to name compression.
     170                 :            :         INCOMPRESSIBLE_NAME ///< A domain name that shouldn't be compressed.
     171                 :            :     };
     172                 :            : 
     173                 :            :     /// Structure that specifies a single \c RdataFields field.
     174                 :            :     ///
     175                 :            :     /// This is a straightforward pair of the type and length of a single
     176                 :            :     /// \c RdataFields field.
     177                 :            :     ///
     178                 :            :     /// In some cases an application may want to do deeper inspection of
     179                 :            :     /// some \c RdataFields field(s).  For example, an application may want
     180                 :            :     /// to construct a \c Name object for each domain name field of an RDATA
     181                 :            :     /// and use it for some special purpose.
     182                 :            :     /// The \c FieldSpec structure provides necessary parameters to get access
     183                 :            :     /// to a specific \c RdataFields field.
     184                 :            :     ///
     185                 :            :     /// The following code snippet implements the above example scenario:
     186                 :            :     /// \code // assume "fields" is of type RdataFields
     187                 :            :     /// size_t offset = 0;
     188                 :            :     /// for (int i = 0; i < fields.getFieldCount(); ++i) {
     189                 :            :     ///     const FieldSpec spec = fields.getFieldSpec(i);
     190                 :            :     ///     if (spec.type == RdataFields::COMPRESSIBLE_NAME ||
     191                 :            :     ///         spec.type == RdataFields::INCOMPRESSIBLE_NAME) {
     192                 :            :     ///         InputBuffer ibuffer(fields.getData() + offset, spec.len);
     193                 :            :     ///         Name name(ibuffer);
     194                 :            :     ///         // do something with name
     195                 :            :     ///     }
     196                 :            :     ///     offset += spec.len;
     197                 :            :     /// } \endcode
     198                 :            :     ///
     199                 :            :     /// Note that the offset is not included in \c FieldSpec.
     200                 :            :     /// This is because such deeper inspection would be a relatively rare
     201                 :            :     /// operation while it is desirable to keep this structure as small as
     202                 :            :     /// possible for the purpose of space efficiency.
     203                 :            :     /// Also, if and when an application wants to look into a specific field,
     204                 :            :     /// it would be quite likely that the application iterates over all fields
     205                 :            :     /// and does something special for selected fields like the above example.
     206                 :            :     /// In that case the application can easily and efficiently identify the
     207                 :            :     /// necessary offset, again, as shown in the above code example.
     208                 :            :     ///
     209                 :            :     /// \todo We might find that 16bits per field is generally too much and
     210                 :            :     ///     squeeze the two bit type into it as well, having 14bit length
     211                 :            :     ///     (in the rare case of having too long field, it could be split into
     212                 :            :     ///     multiple ones). That would save 2 bytes per item (one for the type,
     213                 :            :     ///     one for padding).
     214                 :          0 :     struct FieldSpec {
     215                 :            :         FieldSpec(Type type_param, uint16_t len_param) :
     216                 :         20 :             type(type_param), len(len_param)
     217                 :            :         {}
     218                 :            :         Type type;              ///< The type of the field.
     219                 :            :         uint16_t len;           ///< The length of the field in bytes.
     220                 :            :     };
     221                 :            : 
     222                 :            :     ///
     223                 :            :     /// \name Constructors and Destructor.
     224                 :            :     ///
     225                 :            :     /// \b Note:
     226                 :            :     /// The copy constructor and the assignment operator are intentionally
     227                 :            :     /// defined as private, making this class non copyable.
     228                 :            :     //@{
     229                 :            : private:
     230                 :            :     RdataFields(const RdataFields& source);
     231                 :            :     RdataFields& operator=(const RdataFields& source);
     232                 :            : 
     233                 :            : public:
     234                 :            :     /// Constructor from Rdata.
     235                 :            :     ///
     236                 :            :     /// This constructor converts the data of a given \c Rdata object into
     237                 :            :     /// an \c RdataFields object so that the resulting data can be stored
     238                 :            :     /// in memory in a space-efficient way.
     239                 :            :     ///
     240                 :            :     /// It makes a local copy of the original data and dynamically allocates
     241                 :            :     /// necessary memory, so is not very efficient.
     242                 :            :     /// The basic idea is to perform the expensive conversion once and keep
     243                 :            :     /// using the result as long as possible to improve overall performance
     244                 :            :     /// in a longer term.
     245                 :            :     ///
     246                 :            :     /// If the internal resource allocation fails, a corresponding standard
     247                 :            :     /// exception will be thrown.
     248                 :            :     /// The current implementation of this constructor internally calls
     249                 :            :     /// the <code>Rdata::toWire(AbstractMessageRenderer&) const</code> method
     250                 :            :     /// for the conversion.
     251                 :            :     /// If that method throws an exception it will be propagated to the caller
     252                 :            :     /// of this constructor.
     253                 :            :     ///
     254                 :            :     /// \param rdata The RDATA for which the \c RdataFields to be constructed.
     255                 :            :     RdataFields(const Rdata& rdata);
     256                 :            : 
     257                 :            :     /// Constructor from field parameters.
     258                 :            :     ///
     259                 :            :     /// The intended usage of this version of constructor is to form a
     260                 :            :     /// structured representation of \c RDATA encoded by the other
     261                 :            :     /// constructor so that the resulting object can be used for subsequent
     262                 :            :     /// operations such as rendering in the wire format.
     263                 :            :     /// This version is intended to be efficient by not making any copy
     264                 :            :     /// of variable length data or expensive data inspection.
     265                 :            :     ///
     266                 :            :     /// This constructor is basically exception free, except against bogus
     267                 :            :     /// input parameters.
     268                 :            :     /// Specifically, the parameters must meet the following conditions;
     269                 :            :     /// otherwise an exception of class \c InvalidParameter will be thrown.
     270                 :            :     /// - \c fields can be \c NULL if and only if \c nfields is 0
     271                 :            :     /// - \c data can be \c NULL if and only if \c data_length is 0
     272                 :            :     /// - the sum of the lengths of \c fields entries must be equal to
     273                 :            :     ///   \c data_length
     274                 :            :     ///
     275                 :            :     /// This constructor assumes that the memory region pointed by \c data (if
     276                 :            :     /// non \c NULL) is encoded as a sequence of valid \c RdataFields fields,
     277                 :            :     /// and does not perform deep inspection on each field.
     278                 :            :     /// In particular, for fields of type \c COMPRESSIBLE_NAME or
     279                 :            :     /// \c INCOMPRESSIBLE_NAME, this constructor assumes the corresponding
     280                 :            :     /// memory region is a valid representation of domain name.
     281                 :            :     /// Otherwise, a subsequent method call such as
     282                 :            :     /// <code>toWire(AbstractMessageRenderer&) const</code>
     283                 :            :     /// may trigger an unexpected exception. It also expects the fields reside
     284                 :            :     /// on address that is valid for them (eg. it has valid alignment), see
     285                 :            :     /// getFieldSpecData() for details.
     286                 :            :     ///
     287                 :            :     /// It is the caller's responsibility to ensure this assumption.
     288                 :            :     /// In general, this constructor is expected to be used for serialized data
     289                 :            :     /// generated by the other constructor from a valid \c Rdata.
     290                 :            :     /// The result is not guaranteed if the data is generated in any other
     291                 :            :     /// ways.
     292                 :            :     ///
     293                 :            :     /// The resulting \c RdataFields object does not maintain a copy of
     294                 :            :     /// \c fields or \c data.  It is the caller's responsibility to ensure
     295                 :            :     /// the memory regions pointed to by these parameters are valid and intact
     296                 :            :     /// as long as the \c RdataFields object is used.
     297                 :            :     ///
     298                 :            :     /// \param fields An array of \c FieldSpec entries.  This can be \c NULL.
     299                 :            :     /// \param fields_length The total length of the \c fields.
     300                 :            :     /// \param data A pointer to memory region for the entire RDATA.  This can
     301                 :            :     /// be NULL.
     302                 :            :     /// \param data_length The length of \c data in bytes.
     303                 :            :     RdataFields(const void* fields, const unsigned int fields_length,
     304                 :            :                 const void* data, const size_t data_length);
     305                 :            : 
     306                 :            :     /// The destructor.
     307                 :            :     ~RdataFields();
     308                 :            :     //@}
     309                 :            : 
     310                 :            :     ///
     311                 :            :     /// \name Getter Methods
     312                 :            :     ///
     313                 :            :     //@{
     314                 :            :     /// \brief Return the length of the entire RDATA encoded in the
     315                 :            :     /// \c RdataFields in bytes.
     316                 :            :     ///
     317                 :            :     /// This method never throws an exception.
     318                 :          0 :     unsigned int getDataLength() const { return (data_length_); }
     319                 :            : 
     320                 :            :     /// \brief Return a pointer to the RDATA encoded in the \c RdataFields.
     321                 :            :     ///
     322                 :            :     /// The RdataFields holds ownership of the data.
     323                 :            :     ///
     324                 :            :     /// This method never throws an exception.
     325                 :          0 :     const void* getData() const { return (data_); }
     326                 :            : 
     327                 :            :     /// \brief Return the number of bytes the buffer returned by
     328                 :            :     ///      getFieldSpecData() will occupy.
     329                 :            :     ///
     330                 :            :     /// This method never throws an exception.
     331                 :          0 :     unsigned int getFieldSpecDataSize() const { return (nfields_ *
     332                 :          0 :                                                     sizeof (*fields_)); }
     333                 :            : 
     334                 :            :     /// \brief Return the number of specs fields.
     335                 :            :     ///
     336                 :            :     /// It specifies the range of parameter for getFieldSpec().
     337                 :            :     ///
     338                 :            :     /// This method never throws.
     339                 :          0 :     unsigned int getFieldCount() const { return (nfields_); }
     340                 :            : 
     341                 :            :     /// \brief Return a pointer to a sequence of \c FieldSpec for the
     342                 :            :     /// \c RdataFields.
     343                 :            :     ///
     344                 :            :     /// This should be treated as an opaque internal representation you can
     345                 :            :     /// just store off somewhere and use it to construct a new RdataFields.
     346                 :            :     /// from it. If you are really interested, you can typecast it to
     347                 :            :     /// FieldSpec * (which is what it really is internally).
     348                 :            :     ///
     349                 :            :     /// The RdataFields holds ownership of the data.
     350                 :            :     ///
     351                 :            :     /// \note You should, however, be aware of alignment issues. The pointer
     352                 :            :     ///     you pass to the constructor must be an address where the FieldSpec
     353                 :            :     ///     can live. If you store it at a wrong address (eg. even one with
     354                 :            :     ///     current implementation on most architectures), it might lead bad
     355                 :            :     ///     things from slow access to SIGBUS. The easiest way is not to
     356                 :            :     ///     interleave the fields with data from getData(). It is OK to place
     357                 :            :     ///     all the fields first (even from multiple RdataFields) and then
     358                 :            :     ///     place all the data after them.
     359                 :            :     ///
     360                 :            :     /// This method never throws an exception.
     361                 :          0 :     const void* getFieldSpecData() const {
     362                 :          0 :         return (fields_);
     363                 :            :     }
     364                 :            : 
     365                 :            :     /// \brief Return the specification of the field identified by the given
     366                 :            :     /// index.
     367                 :            :     ///
     368                 :            :     /// \c field_id is the field index, which must be in the range of
     369                 :            :     /// <code>[0, getFieldCount())</code>.  0 means the first field, and
     370                 :            :     /// <code>getFieldCount()-1</code> means the last.
     371                 :            :     ///
     372                 :            :     /// If the given index is not in the valid range, an exception of class
     373                 :            :     /// \c OutOfRange will be thrown.
     374                 :            :     /// This method never throws an exception otherwise.
     375                 :            :     ///
     376                 :            :     /// \param field_id The index of an \c RdataFields field to be returned.
     377                 :            :     /// \return A \c FieldSpec structure that contains the information of
     378                 :            :     /// the \c field_id-th field.
     379                 :            :     FieldSpec getFieldSpec(const unsigned int field_id) const;
     380                 :            :     //@}
     381                 :            : 
     382                 :            :     ///
     383                 :            :     /// \name Converter Methods
     384                 :            :     ///
     385                 :            :     //@{
     386                 :            :     /// \brief Render the RdataFields in the wire format with name compression.
     387                 :            :     ///
     388                 :            :     /// This method may require resource allocation in \c renderer.
     389                 :            :     /// If it fails, a corresponding standard exception will be thrown.
     390                 :            :     /// It should not throw any other exception as long as the \c RdataFields
     391                 :            :     /// object was constructed from valid parameters (see the description of
     392                 :            :     /// constructors).  The result is not guaranteed if it's constructed in
     393                 :            :     /// any other ways.
     394                 :            :     ///
     395                 :            :     /// \param renderer DNS message rendering context that encapsulates the
     396                 :            :     /// output buffer and name compression information.
     397                 :            :     void toWire(AbstractMessageRenderer& renderer) const;
     398                 :            : 
     399                 :            :     /// \brief Render the RdataFields in the wire format without name
     400                 :            :     /// compression.
     401                 :            :     ///
     402                 :            :     /// This method may require resource allocation in \c buffer.
     403                 :            :     /// If it fails, a corresponding standard exception will be thrown.
     404                 :            :     ///
     405                 :            :     /// \param buffer An output buffer to store the wire data.
     406                 :            :     void toWire(isc::util::OutputBuffer& buffer) const;
     407                 :            :     //@}
     408                 :            : 
     409                 :            : private:
     410                 :            :     const FieldSpec* fields_;
     411                 :            :     unsigned int nfields_;
     412                 :            :     const uint8_t* data_;
     413                 :            :     size_t data_length_;
     414                 :            : 
     415                 :            :     // hide further details within the implementation and don't create vectors
     416                 :            :     // every time we don't need them.
     417                 :            :     struct RdataFieldsDetail;
     418                 :            :     RdataFieldsDetail* detail_;
     419                 :            : };
     420                 :            : }
     421                 :            : }
     422                 :            : }
     423                 :            : #endif  // __RDATAFIELDS_H
     424                 :            : 
     425                 :            : // Local Variables:
     426                 :            : // mode: c++
     427                 :            : // End:

Generated by: LCOV version 1.9