LCOV - code coverage report
Current view: top level - dns - rdatafields.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 69 75 92.0 %
Date: 2012-05-15 Functions: 10 17 58.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 52 70 74.3 %

           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                 :            : #include <stdint.h>
      16                 :            : 
      17                 :            : #include <cassert>
      18                 :            : #include <vector>
      19                 :            : 
      20                 :            : #include <exceptions/exceptions.h>
      21                 :            : 
      22                 :            : #include <util/buffer.h>
      23                 :            : #include <dns/messagerenderer.h>
      24                 :            : #include <dns/name.h>
      25                 :            : #include <dns/rdata.h>
      26                 :            : #include <dns/rdatafields.h>
      27                 :            : 
      28                 :            : using namespace std;
      29                 :            : using namespace isc::dns;
      30                 :            : using namespace isc::dns::rdata;
      31                 :            : using isc::util::OutputBuffer;
      32                 :            : using isc::util::InputBuffer;
      33                 :            : 
      34                 :            : namespace isc {
      35                 :            : namespace dns {
      36                 :            : namespace rdata {
      37                 :            : 
      38                 :            : /// This is a helper class for \c RdataFields.
      39                 :            : ///
      40                 :            : /// It manages a local storage for the data when \c RdataFields is constructed
      41                 :            : /// from an \c Rdata.
      42                 :            : /// To minimize construction overhead in the other case, an instance of
      43                 :            : /// this class is instantiated only when necessary - we don't need the vectors
      44                 :            : /// when only rendering.
      45                 :         12 : struct RdataFields::RdataFieldsDetail {
      46                 :            :     RdataFieldsDetail(const vector<FieldSpec>& fields,
      47                 :            :                       const uint8_t* data, size_t data_length) :
      48                 :            :         allocated_fields_(fields),
      49                 :         12 :         allocated_data_(data, data + data_length)
      50                 :            :     {}
      51                 :            :     const vector<FieldSpec> allocated_fields_;
      52                 :            :     const vector<uint8_t> allocated_data_;
      53                 :            : };
      54                 :            : 
      55                 :            : namespace {
      56                 :            : // This class is used to divide the content of RDATA into \c RdataField
      57                 :            : // fields via message rendering logic.
      58                 :            : // The idea is to identify domain name fields in the writeName() method,
      59                 :            : // and determine whether they are compressible using the "compress"
      60                 :            : // parameter.
      61                 :            : // Other types of data are simply copied into the internal buffer, and
      62                 :            : // consecutive such fields are combined into a single \c RdataField field.
      63                 :            : //
      64                 :            : // Technically, this use of inheritance may be considered a violation of
      65                 :            : // Liskov Substitution Principle in that it doesn't actually compress domain
      66                 :            : // names, and some of the methods are not expected to be used.
      67                 :            : // In fact, skip() or trim() may not be make much sense in this context.
      68                 :            : // Nevertheless we keep this idea at the moment.  Since the usage is limited
      69                 :            : // (it's only used within this file, and only used with \c Rdata variants),
      70                 :            : // it's hopefully an acceptable practice.
      71                 :            : class RdataFieldComposer : public AbstractMessageRenderer {
      72                 :            : public:
      73                 :            :     RdataFieldComposer() :
      74                 :            :         truncated_(false), length_limit_(65535),
      75                 :          8 :         mode_(CASE_INSENSITIVE), last_data_pos_(0)
      76                 :            :     {}
      77                 :          8 :     virtual ~RdataFieldComposer() {}
      78                 :          0 :     virtual bool isTruncated() const { return (truncated_); }
      79                 :          0 :     virtual size_t getLengthLimit() const { return (length_limit_); }
      80                 :          0 :     virtual CompressMode getCompressMode() const { return (mode_); }
      81                 :          0 :     virtual void setTruncated() { truncated_ = true; }
      82                 :          0 :     virtual void setLengthLimit(size_t len) { length_limit_ = len; }
      83                 :          0 :     virtual void setCompressMode(CompressMode mode) { mode_ = mode; }
      84                 :          3 :     virtual void writeName(const Name& name, bool compress) {
      85                 :          3 :         extendData();
      86                 :            :         const RdataFields::Type field_type =
      87                 :            :             compress ? RdataFields::COMPRESSIBLE_NAME :
      88         [ +  + ]:          3 :             RdataFields::INCOMPRESSIBLE_NAME;
      89                 :            :         // TODO: When we get rid of need for getBuffer, we can output the name
      90                 :            :         // to a buffer and then write the buffer inside
      91                 :          3 :         name.toWire(getBuffer());
      92                 :            :         fields_.push_back(RdataFields::FieldSpec(field_type,
      93                 :          3 :                                                  name.getLength()));
      94                 :          3 :         last_data_pos_ = getLength();
      95                 :          3 :     }
      96                 :            : 
      97                 :          1 :     virtual void clear() {
      98         [ +  - ]:          2 :         isc_throw(Unexpected, "unexpected clear() for RdataFieldComposer");
      99                 :            :     }
     100                 :            :     bool truncated_;
     101                 :            :     size_t length_limit_;
     102                 :            :     CompressMode mode_;
     103                 :            :     vector<RdataFields::FieldSpec> fields_;
     104                 :            :     vector<RdataFields::FieldSpec>& getFields() {
     105 [ +  - ][ +  - ]:         13 :         extendData();
     106                 :            :         return (fields_);
     107                 :            :     }
     108                 :            :     // We use generict write* methods, with the exception of writeName.
     109                 :            :     // So new data can arrive without us knowing it, this considers all new
     110                 :            :     // data to be just data and extends the fields to take it into account.
     111                 :            :     size_t last_data_pos_;
     112                 :         16 :     void extendData() {
     113                 :            :         // No news, return to work
     114         [ +  + ]:         16 :         if (getLength() == last_data_pos_) {
     115                 :         16 :             return;
     116                 :            :         }
     117                 :            :         // The new bytes are just ordinary uninteresting data
     118 [ +  + ][ -  + ]:          7 :         if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
                 [ +  - ]
     119                 :          7 :             fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
     120                 :            :         }
     121                 :            :         // We added this much data from last time
     122                 :         21 :         fields_.back().len += getLength() - last_data_pos_;
     123                 :          7 :         last_data_pos_ = getLength();
     124                 :            :     }
     125                 :            : };
     126                 :            : 
     127                 :            : }
     128                 :            : 
     129                 :          8 : RdataFields::RdataFields(const Rdata& rdata) {
     130                 :          8 :     RdataFieldComposer field_composer;
     131         [ +  + ]:          8 :     rdata.toWire(field_composer);
     132                 :          7 :     nfields_ = field_composer.getFields().size();
     133                 :         14 :     data_length_ = field_composer.getLength();
     134         [ +  + ]:          7 :     if (nfields_ > 0) {
     135         [ -  + ]:          6 :         assert(data_length_ > 0);
     136                 :            :         detail_ = new RdataFieldsDetail(field_composer.getFields(),
     137                 :            :                                         static_cast<const uint8_t*>
     138                 :          6 :                                         (field_composer.getData()),
     139         [ +  - ]:          6 :                                         field_composer.getLength());
     140                 :         12 :         data_ = &detail_->allocated_data_[0];
     141                 :          6 :         fields_ = &detail_->allocated_fields_[0];
     142                 :            :     } else {
     143         [ -  + ]:          1 :         assert(data_length_ == 0);
     144                 :          1 :         detail_ = NULL;
     145                 :          1 :         data_ = NULL;
     146                 :          1 :         fields_ = NULL;
     147                 :            :     }
     148                 :          7 : }
     149                 :            : 
     150                 :         12 : RdataFields::RdataFields(const void* fields, const unsigned int fields_length,
     151                 :            :                          const void* data, const size_t data_length) :
     152                 :            :     fields_(static_cast<const FieldSpec*>(fields)),
     153                 :            :     nfields_(fields_length / sizeof(*fields_)),
     154                 :            :     data_(static_cast<const uint8_t*>(data)),
     155                 :            :     data_length_(data_length),
     156                 :         12 :     detail_(NULL)
     157                 :            : {
     158 [ +  + ][ +  - ]:         12 :     if ((fields_ == NULL && nfields_ > 0) ||
         [ +  + ][ +  + ]
     159                 :            :         (fields_ != NULL && nfields_ == 0)) {
     160 [ +  - ][ +  - ]:         12 :         isc_throw(InvalidParameter,
     161                 :            :                   "Inconsistent parameters for RdataFields: fields_length ("
     162                 :            :                   << fields_length << ") and fields conflict each other");
     163                 :            :     }
     164 [ +  + ][ +  - ]:          8 :     if ((data_ == NULL && data_length_ > 0) ||
         [ +  + ][ +  + ]
     165                 :            :         (data_ != NULL && data_length_ == 0)) {
     166 [ +  - ][ +  - ]:          3 :         isc_throw(InvalidParameter,
     167                 :            :                   "Inconsistent parameters for RdataFields: data length ("
     168                 :            :                   << data_length_ << ") and data conflict each other");
     169                 :            :     }
     170                 :            : 
     171                 :            :     size_t total_length = 0;
     172         [ +  + ]:         16 :     for (unsigned int i = 0; i < nfields_; ++i) {
     173                 :          9 :         total_length += fields_[i].len;
     174                 :            :     }
     175         [ +  + ]:          7 :     if (total_length != data_length_) {
     176 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidParameter,
     177                 :            :                   "Inconsistent parameters for RdataFields; "
     178                 :            :                   "fields len: " << total_length <<
     179                 :            :                   " data len: " << data_length_);
     180                 :            :     }
     181                 :          6 : }
     182                 :            : 
     183                 :         13 : RdataFields::~RdataFields() {
     184         [ +  + ]:         19 :     delete detail_;
     185                 :         13 : }
     186                 :            : 
     187                 :            : RdataFields::FieldSpec
     188                 :         31 : RdataFields::getFieldSpec(const unsigned int field_id) const {
     189         [ +  + ]:         31 :     if (field_id >= nfields_) {
     190         [ +  - ]:          3 :         isc_throw(OutOfRange, "Rdata field ID is out of range: " << field_id);
     191                 :            :     }
     192                 :         30 :     return (fields_[field_id]);
     193                 :            : }
     194                 :            : 
     195                 :            : void
     196                 :         11 : RdataFields::toWire(AbstractMessageRenderer& renderer) const {
     197                 :         11 :     size_t offset = 0;
     198                 :            : 
     199         [ +  + ]:         26 :     for (unsigned int i = 0; i < nfields_; ++i) {
     200         [ +  + ]:         15 :         if (fields_[i].type == DATA) {
     201                 :         10 :             renderer.writeData(data_ + offset, fields_[i].len);
     202                 :            :         } else {
     203                 :            :             // XXX: this is inefficient.  Even if it's quite likely the
     204                 :            :             // data is a valid wire representation of a name we parse
     205                 :            :             // it to construct the Name object in the generic mode.
     206                 :            :             // This should be improved in a future version.
     207                 :          5 :             InputBuffer buffer(data_ + offset, fields_[i].len);
     208                 :          5 :             renderer.writeName(Name(buffer),
     209         [ +  - ]:          5 :                                fields_[i].type == COMPRESSIBLE_NAME);
     210                 :            :         }
     211                 :         15 :         offset += fields_[i].len;
     212                 :            :     }
     213                 :         11 : }
     214                 :            : 
     215                 :            : void
     216                 :         11 : RdataFields::toWire(OutputBuffer& buffer) const {
     217                 :         11 :     buffer.writeData(data_, data_length_);
     218                 :         11 : }
     219                 :            : } // end of namespace rdata
     220                 :            : } // end of namespace dns
     221                 :        229 : } // end of namespace isc

Generated by: LCOV version 1.9