LCOV - code coverage report
Current view: top level - dns - message.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 437 454 96.3 %
Date: 2012-05-15 Functions: 62 70 88.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 370 598 61.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2009  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 <algorithm>
      18                 :            : #include <cassert>
      19                 :            : #include <string>
      20                 :            : #include <sstream>
      21                 :            : #include <vector>
      22                 :            : 
      23                 :            : #include <boost/foreach.hpp>
      24                 :            : #include <boost/lexical_cast.hpp>
      25                 :            : #include <boost/shared_ptr.hpp>
      26                 :            : 
      27                 :            : #include <exceptions/exceptions.h>
      28                 :            : 
      29                 :            : #include <util/buffer.h>
      30                 :            : 
      31                 :            : #include <dns/edns.h>
      32                 :            : #include <dns/exceptions.h>
      33                 :            : #include <dns/message.h>
      34                 :            : #include <dns/messagerenderer.h>
      35                 :            : #include <dns/name.h>
      36                 :            : #include <dns/opcode.h>
      37                 :            : #include <dns/rcode.h>
      38                 :            : #include <dns/question.h>
      39                 :            : #include <dns/rdataclass.h>
      40                 :            : #include <dns/rrclass.h>
      41                 :            : #include <dns/rrtype.h>
      42                 :            : #include <dns/rrttl.h>
      43                 :            : #include <dns/rrset.h>
      44                 :            : #include <dns/tsig.h>
      45                 :            : 
      46                 :            : using namespace std;
      47                 :            : using namespace boost;
      48                 :            : using namespace isc::dns::rdata;
      49                 :            : using namespace isc::util;
      50                 :            : 
      51                 :            : namespace isc {
      52                 :            : namespace dns {
      53                 :            : 
      54                 :            : namespace {
      55                 :            : // protocol constants
      56                 :            : const size_t HEADERLEN = 12;
      57                 :            : 
      58                 :            : const unsigned int OPCODE_MASK = 0x7800;
      59                 :            : const unsigned int OPCODE_SHIFT = 11;
      60                 :            : const unsigned int RCODE_MASK = 0x000f;
      61                 :            : 
      62                 :            : // This diagram shows the wire-format representation of the 2nd 16 bits of
      63                 :            : // the DNS header section, which contain all defined flag bits.
      64                 :            : //
      65                 :            : //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      66                 :            : //    |QR|   Opcode  |AA|TC|RD|RA|  |AD|CD|   RCODE   |
      67                 :            : //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      68                 :            : //      1  0  0  0| 0  1  1  1| 1  0  1  1| 0  0  0  0|
      69                 :            : //         0x8         0x7         0xb         0x0
      70                 :            : //
      71                 :            : // This mask covers all the flag bits, and those bits only.
      72                 :            : // Note: we reject a "flag" the is not covered by this mask in some of the
      73                 :            : // public methods.  This means our current definition is not fully extendable;
      74                 :            : // applications cannot introduce a new flag bit temporarily without modifying
      75                 :            : // the source code.
      76                 :            : const unsigned int HEADERFLAG_MASK = 0x87b0;
      77                 :            : 
      78                 :            : // This is a set of flag bits that should be preserved when building a reply
      79                 :            : // from a request.
      80                 :            : // Note: we assume the specific definition of HEADERFLAG_xx.  We may change
      81                 :            : // the definition in future, in which case we need to adjust this definition,
      82                 :            : // too (see also the description about the Message::HeaderFlag type).
      83                 :            : const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
      84                 :            :                                         Message::HEADERFLAG_CD);
      85                 :            : 
      86                 :            : const char* const sectiontext[] = {
      87                 :            :     "QUESTION",
      88                 :            :     "ANSWER",
      89                 :            :     "AUTHORITY",
      90                 :            :     "ADDITIONAL"
      91                 :            : };
      92                 :            : }
      93                 :            : 
      94 [ +  - ][ +  + ]:       7965 : class MessageImpl {
         [ +  - ][ #  # ]
                 [ #  # ]
      95                 :            : public:
      96                 :            :     MessageImpl(Message::Mode mode);
      97                 :            :     // Open issues: should we rather have a header in wire-format
      98                 :            :     // for efficiency?
      99                 :            :     Message::Mode mode_;
     100                 :            :     qid_t qid_;
     101                 :            : 
     102                 :            :     // We want to use NULL for [op,r]code_ to mean the code being not
     103                 :            :     // correctly parsed or set.  We store the real code object in
     104                 :            :     // xxcode_placeholder_ and have xxcode_ refer to it when the object
     105                 :            :     // is valid.
     106                 :            :     const Rcode* rcode_;
     107                 :            :     Rcode rcode_placeholder_;
     108                 :            :     const Opcode* opcode_;
     109                 :            :     Opcode opcode_placeholder_;
     110                 :            : 
     111                 :            :     uint16_t flags_;            // wire-format representation of header flags.
     112                 :            : 
     113                 :            :     bool header_parsed_;
     114                 :            :     static const unsigned int NUM_SECTIONS = 4; // TODO: revisit this design
     115                 :            :     int counts_[NUM_SECTIONS];   // TODO: revisit this definition
     116                 :            :     vector<QuestionPtr> questions_;
     117                 :            :     vector<RRsetPtr> rrsets_[NUM_SECTIONS];
     118                 :            :     ConstEDNSPtr edns_;
     119                 :            :     ConstTSIGRecordPtr tsig_rr_;
     120                 :            : 
     121                 :            :     // RRsetsSorter* sorter_; : TODO
     122                 :            : 
     123                 :            :     void init();
     124                 :            :     void setOpcode(const Opcode& opcode);
     125                 :            :     void setRcode(const Rcode& rcode);
     126                 :            :     int parseQuestion(InputBuffer& buffer);
     127                 :            :     int parseSection(const Message::Section section, InputBuffer& buffer,
     128                 :            :                      Message::ParseOptions options);
     129                 :            :     void addRR(Message::Section section, const Name& name,
     130                 :            :                const RRClass& rrclass, const RRType& rrtype,
     131                 :            :                const RRTTL& ttl, ConstRdataPtr rdata,
     132                 :            :                Message::ParseOptions options);
     133                 :            :     void addEDNS(Message::Section section, const Name& name,
     134                 :            :                  const RRClass& rrclass, const RRType& rrtype,
     135                 :            :                  const RRTTL& ttl, const Rdata& rdata);
     136                 :            :     void addTSIG(Message::Section section, unsigned int count,
     137                 :            :                  const InputBuffer& buffer, size_t start_position,
     138                 :            :                  const Name& name, const RRClass& rrclass,
     139                 :            :                  const RRTTL& ttl, const Rdata& rdata);
     140                 :            :     void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
     141                 :            : };
     142                 :            : 
     143                 :       1613 : MessageImpl::MessageImpl(Message::Mode mode) :
     144                 :            :     mode_(mode),
     145                 :            :     rcode_placeholder_(Rcode(0)), // as a placeholder the value doesn't matter
     146         [ +  + ]:       8065 :     opcode_placeholder_(Opcode(0)) // ditto
     147                 :            : {
     148         [ +  - ]:       1613 :     init();
     149 [ #  # ][ #  # ]:       1613 : }
     150                 :            : 
     151                 :            : void
     152                 :       2343 : MessageImpl::init() {
     153                 :       2343 :     flags_ = 0;
     154                 :       2343 :     qid_ = 0;
     155                 :       2343 :     rcode_ = NULL;
     156                 :       2343 :     opcode_ = NULL;
     157         [ +  - ]:       2343 :     edns_ = EDNSPtr();
     158         [ +  - ]:       2343 :     tsig_rr_ = ConstTSIGRecordPtr();
     159                 :            : 
     160         [ +  + ]:      11715 :     for (int i = 0; i < NUM_SECTIONS; ++i) {
     161                 :       9372 :         counts_[i] = 0;
     162                 :            :     }
     163                 :            : 
     164                 :       2343 :     header_parsed_ = false;
     165                 :       2343 :     questions_.clear();
     166                 :       2343 :     rrsets_[Message::SECTION_ANSWER].clear();
     167                 :       2343 :     rrsets_[Message::SECTION_AUTHORITY].clear();
     168                 :       2343 :     rrsets_[Message::SECTION_ADDITIONAL].clear();
     169                 :       2343 : }
     170                 :            : 
     171                 :            : void
     172                 :       1893 : MessageImpl::setOpcode(const Opcode& opcode) {
     173                 :       1893 :     opcode_placeholder_ = opcode;
     174                 :       1893 :     opcode_ = &opcode_placeholder_;
     175                 :       1893 : }
     176                 :            : 
     177                 :            : void
     178                 :       2118 : MessageImpl::setRcode(const Rcode& rcode) {
     179                 :       2118 :     rcode_placeholder_ = rcode;
     180                 :       2118 :     rcode_ = &rcode_placeholder_;
     181                 :       2118 : }
     182                 :            : 
     183                 :            : namespace {
     184                 :            : // This helper class is used by MessageImpl::toWire() to render a set of
     185                 :            : // RRsets of a specific section of message to a given MessageRenderer.
     186                 :            : //
     187                 :            : // A RenderSection object is expected to be used with a QuestionIterator or
     188                 :            : // SectionIterator.  Its operator() is called for each RRset as the iterator
     189                 :            : // iterates over the corresponding section, and it renders the RRset to
     190                 :            : // the given MessageRenderer, while counting the number of RRs (note: not
     191                 :            : // RRsets) successfully rendered.  If the MessageRenderer reports the need
     192                 :            : // for truncation (via its isTruncated() method), the RenderSection object
     193                 :            : // stops rendering further RRsets.  In addition, unless partial_ok (given on
     194                 :            : // construction) is true, it removes any RRs that are partially rendered
     195                 :            : // from the MessageRenderer.
     196                 :            : //
     197                 :            : // On the completion of rendering the entire section, the owner of the
     198                 :            : // RenderSection object can get the number of rendered RRs via the
     199                 :            : // getTotalCount() method.
     200                 :            : template <typename T>
     201                 :            : struct RenderSection {
     202                 :            :     RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
     203                 :            :         counter_(0), renderer_(renderer), partial_ok_(partial_ok),
     204                 :       3632 :         truncated_(false)
     205                 :            :     {}
     206                 :            :     void operator()(const T& entry) {
     207                 :            :         // If it's already truncated, ignore the rest of the section.
     208 [ +  - ][ +  - ]:       1366 :         if (truncated_) {
     209                 :            :             return;
     210                 :            :         }
     211                 :       1366 :         const size_t pos0 = renderer_.getLength();
     212                 :       1366 :         counter_ += entry->toWire(renderer_);
     213   [ +  +  +  + ]:       1364 :         if (renderer_.isTruncated()) {
     214                 :         16 :             truncated_ = true;
     215 [ -  + ][ +  - ]:         16 :             if (!partial_ok_) {
     216                 :            :                 // roll back to the end of the previous RRset.
     217                 :          4 :                 renderer_.trim(renderer_.getLength() - pos0);
     218                 :            :             }
     219                 :            :         }
     220                 :            :     }
     221                 :          0 :     unsigned int getTotalCount() { return (counter_); }
     222                 :            :     unsigned int counter_;
     223                 :            :     AbstractMessageRenderer& renderer_;
     224                 :            :     const bool partial_ok_;
     225                 :            :     bool truncated_;
     226                 :            : };
     227                 :            : }
     228                 :            : 
     229                 :            : void
     230                 :        923 : MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
     231         [ +  + ]:        923 :     if (mode_ != Message::RENDER) {
     232 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     233                 :            :                   "Message rendering attempted in non render mode");
     234                 :            :     }
     235         [ +  + ]:        921 :     if (rcode_ == NULL) {
     236 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     237                 :            :                   "Message rendering attempted without Rcode set");
     238                 :            :     }
     239         [ +  + ]:        919 :     if (opcode_ == NULL) {
     240 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     241                 :            :                   "Message rendering attempted without Opcode set");
     242                 :            :     }
     243                 :            : 
     244                 :            :     // Reserve the space for TSIG (if needed) so that we can handle truncation
     245                 :            :     // case correctly later when that happens.  orig_xxx variables remember
     246                 :            :     // some configured parameters of renderer in case they are needed in
     247                 :            :     // truncation processing below.
     248         [ +  + ]:        917 :     const size_t tsig_len = (tsig_ctx != NULL) ? tsig_ctx->getTSIGLength() : 0;
     249                 :        917 :     const size_t orig_msg_len_limit = renderer.getLengthLimit();
     250                 :            :     const AbstractMessageRenderer::CompressMode orig_compress_mode =
     251                 :        917 :         renderer.getCompressMode();
     252         [ +  + ]:        917 :     if (tsig_len > 0) {
     253         [ +  + ]:        160 :         if (tsig_len > orig_msg_len_limit) {
     254 [ +  - ][ +  - ]:          6 :             isc_throw(InvalidParameter, "Failed to render DNS message: "
     255                 :            :                       "too small limit for a TSIG (" <<
     256                 :            :                       orig_msg_len_limit << ")");
     257                 :            :         }
     258                 :        158 :         renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
     259                 :            :     }
     260                 :            : 
     261                 :            :     // reserve room for the header
     262         [ +  + ]:        915 :     if (renderer.getLengthLimit() < HEADERLEN) {
     263         [ +  - ]:          4 :         isc_throw(InvalidParameter, "Failed to render DNS message: "
     264                 :            :                   "too small limit for a Header");
     265                 :            :     }
     266                 :        913 :     renderer.skip(HEADERLEN);
     267                 :            : 
     268                 :            :     uint16_t qdcount =
     269                 :       1826 :         for_each(questions_.begin(), questions_.end(),
     270                 :        913 :                  RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
     271                 :            : 
     272                 :            :     // TODO: sort RRsets in each section based on configuration policy.
     273                 :        913 :     uint16_t ancount = 0;
     274         [ +  + ]:        913 :     if (!renderer.isTruncated()) {
     275                 :            :         ancount =
     276                 :        911 :             for_each(rrsets_[Message::SECTION_ANSWER].begin(),
     277                 :        911 :                      rrsets_[Message::SECTION_ANSWER].end(),
     278                 :        911 :                      RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
     279                 :            :     }
     280                 :        911 :     uint16_t nscount = 0;
     281         [ +  + ]:        911 :     if (!renderer.isTruncated()) {
     282                 :            :         nscount =
     283                 :        905 :             for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
     284                 :        905 :                      rrsets_[Message::SECTION_AUTHORITY].end(),
     285                 :        905 :                      RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
     286                 :            :     }
     287                 :        911 :     uint16_t arcount = 0;
     288         [ +  + ]:        911 :     if (renderer.isTruncated()) {
     289                 :         14 :         flags_ |= Message::HEADERFLAG_TC;
     290                 :            :     } else {
     291                 :            :         arcount =
     292                 :        897 :             for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
     293                 :        897 :                      rrsets_[Message::SECTION_ADDITIONAL].end(),
     294                 :        897 :                      RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
     295                 :            :     }
     296                 :            : 
     297                 :            :     // Add EDNS OPT RR if necessary.  Basically, we add it only when EDNS
     298                 :            :     // has been explicitly set.  However, if the RCODE would require it and
     299                 :            :     // no EDNS has been set we generate a temporary local EDNS and use it.
     300         [ +  + ]:        911 :     if (!renderer.isTruncated()) {
     301                 :        897 :         ConstEDNSPtr local_edns = edns_;
     302 [ +  + ][ +  - ]:        897 :         if (!local_edns && rcode_->getExtendedCode() != 0) {
         [ +  + ][ +  + ]
     303 [ +  - ][ +  - ]:          2 :             local_edns = ConstEDNSPtr(new EDNS());
         [ +  - ][ +  - ]
     304                 :            :         }
     305         [ +  + ]:        897 :         if (local_edns) {
     306 [ +  - ][ +  - ]:        262 :             arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
     307                 :            :         }
     308                 :            :     }
     309                 :            : 
     310                 :            :     // If we're adding a TSIG to a truncated message, clear all RRsets
     311                 :            :     // from the message except for the question before adding the TSIG.
     312                 :            :     // If even (some of) the question doesn't fit, don't include it.
     313 [ +  + ][ +  + ]:        911 :     if (tsig_ctx != NULL && renderer.isTruncated()) {
                 [ +  + ]
     314                 :          6 :         renderer.clear();
     315                 :          6 :         renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
     316                 :          6 :         renderer.setCompressMode(orig_compress_mode);
     317                 :          6 :         renderer.skip(HEADERLEN);
     318                 :         12 :         qdcount = for_each(questions_.begin(), questions_.end(),
     319                 :            :                            RenderSection<QuestionPtr>(renderer,
     320                 :          6 :                                                       false)).getTotalCount();
     321                 :          6 :         ancount = 0;
     322                 :          6 :         nscount = 0;
     323                 :          6 :         arcount = 0;
     324                 :            :     }
     325                 :            : 
     326                 :            :     // Adjust the counter buffer.
     327                 :            :     // XXX: these may not be equal to the number of corresponding entries
     328                 :            :     // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
     329                 :            :     // was inserted.  This is not good, and we should revisit the entire
     330                 :            :     // design.
     331                 :        911 :     counts_[Message::SECTION_QUESTION] = qdcount;
     332                 :        911 :     counts_[Message::SECTION_ANSWER] = ancount;
     333                 :        911 :     counts_[Message::SECTION_AUTHORITY] = nscount;
     334                 :        911 :     counts_[Message::SECTION_ADDITIONAL] = arcount;
     335                 :            : 
     336                 :            :     // fill in the header
     337                 :        911 :     size_t header_pos = 0;
     338                 :        911 :     renderer.writeUint16At(qid_, header_pos);
     339                 :        911 :     header_pos += sizeof(uint16_t);
     340                 :            : 
     341                 :            :     uint16_t codes_and_flags =
     342                 :       1822 :         (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
     343                 :       1822 :     codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
     344                 :        911 :     codes_and_flags |= (flags_ & HEADERFLAG_MASK);
     345                 :        911 :     renderer.writeUint16At(codes_and_flags, header_pos);
     346                 :        911 :     header_pos += sizeof(uint16_t);
     347                 :            :     // TODO: should avoid repeated pattern
     348                 :        911 :     renderer.writeUint16At(qdcount, header_pos);
     349                 :        911 :     header_pos += sizeof(uint16_t);
     350                 :        911 :     renderer.writeUint16At(ancount, header_pos);
     351                 :        911 :     header_pos += sizeof(uint16_t);
     352                 :        911 :     renderer.writeUint16At(nscount, header_pos);
     353                 :        911 :     header_pos += sizeof(uint16_t);
     354                 :        911 :     renderer.writeUint16At(arcount, header_pos);
     355                 :            : 
     356                 :            :     // Add TSIG, if necessary, at the end of the message.
     357         [ +  + ]:        911 :     if (tsig_ctx != NULL) {
     358                 :            :         // Release the reserved space in the renderer.
     359                 :        156 :         renderer.setLengthLimit(orig_msg_len_limit);
     360                 :            : 
     361                 :            :         const int tsig_count =
     362                 :            :             tsig_ctx->sign(qid_, renderer.getData(),
     363         [ +  - ]:        312 :                            renderer.getLength())->toWire(renderer);
     364         [ +  + ]:        156 :         if (tsig_count != 1) {
     365         [ +  - ]:          2 :             isc_throw(Unexpected, "Failed to render a TSIG RR");
     366                 :            :         }
     367                 :            : 
     368                 :            :         // update the ARCOUNT for the TSIG RR.  Note that for a sane DNS
     369                 :            :         // message arcount should never overflow to 0.
     370                 :        155 :         renderer.writeUint16At(++arcount, header_pos);
     371                 :            :     }
     372                 :        910 : }
     373                 :            : 
     374                 :       1613 : Message::Message(Mode mode) :
     375         [ +  - ]:       1613 :     impl_(new MessageImpl(mode))
     376                 :       1613 : {}
     377                 :            : 
     378                 :       1593 : Message::~Message() {
     379         [ +  - ]:       3186 :     delete impl_;
     380                 :       1593 : }
     381                 :            : 
     382                 :            : bool
     383                 :       5472 : Message::getHeaderFlag(const HeaderFlag flag) const {
     384 [ +  - ][ -  + ]:       5472 :     if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
     385 [ #  # ][ #  # ]:          0 :         isc_throw(InvalidParameter,
     386                 :            :                   "Message::getHeaderFlag:: Invalid flag is specified: " <<
     387                 :            :                   flag);
     388                 :            :     }
     389                 :       5472 :     return ((impl_->flags_ & flag) != 0);
     390                 :            : }
     391                 :            : 
     392                 :            : void
     393                 :       1458 : Message::setHeaderFlag(const HeaderFlag flag, const bool on) {
     394         [ +  + ]:       1458 :     if (impl_->mode_ != Message::RENDER) {
     395 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     396                 :            :                   "setHeaderFlag performed in non-render mode");
     397                 :            :     }
     398 [ +  + ][ +  + ]:       1456 :     if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
     399 [ +  - ][ +  - ]:         18 :         isc_throw(InvalidParameter,
     400                 :            :                   "Message::getHeaderFlag:: Invalid flag is specified: " <<
     401                 :            :                   flag);
     402                 :            :     }
     403         [ +  + ]:       1447 :     if (on) {
     404                 :       1315 :         impl_->flags_ |= flag;
     405                 :            :     } else {
     406                 :        132 :         impl_->flags_ &= ~flag;
     407                 :            :     }
     408                 :       1447 : }
     409                 :            : 
     410                 :            : qid_t
     411                 :        826 : Message::getQid() const {
     412                 :        826 :     return (impl_->qid_);
     413                 :            : }
     414                 :            : 
     415                 :            : void
     416                 :        862 : Message::setQid(qid_t qid) {
     417         [ +  + ]:        862 :     if (impl_->mode_ != Message::RENDER) {
     418 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidMessageOperation,
     419                 :            :                   "setQid performed in non-render mode");
     420                 :            :     }
     421                 :        861 :     impl_->qid_ = qid;
     422                 :        861 : }
     423                 :            : 
     424                 :            : const Rcode&
     425                 :        899 : Message::getRcode() const {
     426         [ +  + ]:        899 :     if (impl_->rcode_ == NULL) {
     427 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidMessageOperation, "getRcode attempted before set");
     428                 :            :     }
     429                 :        898 :     return (*impl_->rcode_);
     430                 :            : }
     431                 :            : 
     432                 :            : void
     433                 :       1367 : Message::setRcode(const Rcode& rcode) {
     434         [ +  + ]:       1367 :     if (impl_->mode_ != Message::RENDER) {
     435 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidMessageOperation,
     436                 :            :                   "setRcode performed in non-render mode");
     437                 :            :     }
     438                 :       1366 :     impl_->setRcode(rcode);
     439                 :       1366 : }
     440                 :            : 
     441                 :            : const Opcode&
     442                 :       1404 : Message::getOpcode() const {
     443         [ +  + ]:       1404 :     if (impl_->opcode_ == NULL) {
     444 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
     445                 :            :     }
     446                 :       1403 :     return (*impl_->opcode_);
     447                 :            : }
     448                 :            : 
     449                 :            : void
     450                 :       1176 : Message::setOpcode(const Opcode& opcode) {
     451         [ +  + ]:       1176 :     if (impl_->mode_ != Message::RENDER) {
     452 [ +  - ][ +  - ]:          6 :         isc_throw(InvalidMessageOperation,
     453                 :            :                   "setOpcode performed in non-render mode");
     454                 :            :     }
     455                 :       1173 :     impl_->setOpcode(opcode);
     456                 :       1173 : }
     457                 :            : 
     458                 :            : ConstEDNSPtr
     459                 :         60 : Message::getEDNS() const {
     460                 :         60 :     return (impl_->edns_);
     461                 :            : }
     462                 :            : 
     463                 :            : void
     464                 :        110 : Message::setEDNS(ConstEDNSPtr edns) {
     465         [ +  + ]:        110 :     if (impl_->mode_ != Message::RENDER) {
     466 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     467                 :            :                   "setEDNS performed in non-render mode");
     468                 :            :     }
     469                 :        108 :     impl_->edns_ = edns;
     470                 :        108 : }
     471                 :            : 
     472                 :            : const TSIGRecord*
     473                 :        564 : Message::getTSIGRecord() const {
     474         [ +  + ]:        564 :     if (impl_->mode_ != Message::PARSE) {
     475 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     476                 :            :                   "getTSIGRecord performed in non-parse mode");
     477                 :            :     }
     478                 :            : 
     479                 :        562 :     return (impl_->tsig_rr_.get());
     480                 :            : }
     481                 :            : 
     482                 :            : unsigned int
     483                 :       1474 : Message::getRRCount(const Section section) const {
     484         [ +  + ]:       1474 :     if (section >= MessageImpl::NUM_SECTIONS) {
     485 [ +  - ][ +  - ]:          4 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
     486                 :            :     }
     487                 :       1472 :     return (impl_->counts_[section]);
     488                 :            : }
     489                 :            : 
     490                 :            : void
     491                 :       1140 : Message::addRRset(const Section section, RRsetPtr rrset, const bool sign) {
     492         [ +  + ]:       1140 :     if (!rrset) {
     493         [ +  - ]:          2 :         isc_throw(InvalidParameter,
     494                 :            :                   "NULL RRset is given to Message::addRRset");
     495                 :            :     }
     496         [ +  + ]:       1139 :     if (impl_->mode_ != Message::RENDER) {
     497 [ +  - ][ +  - ]:          6 :         isc_throw(InvalidMessageOperation,
     498                 :            :                   "addRRset performed in non-render mode");
     499                 :            :     }
     500         [ +  + ]:       1136 :     if (section >= MessageImpl::NUM_SECTIONS) {
     501 [ +  - ][ +  - ]:          6 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
     502                 :            :     }
     503                 :            : 
     504                 :       1133 :     impl_->rrsets_[section].push_back(rrset);
     505                 :       1133 :     impl_->counts_[section] += rrset->getRdataCount();
     506                 :            : 
     507                 :       1133 :     RRsetPtr sp = rrset->getRRsig();
     508 [ +  + ][ +  + ]:       1316 :     if (sign && sp != NULL) {
                 [ +  + ]
     509         [ +  - ]:        159 :         impl_->rrsets_[section].push_back(sp);
     510         [ +  - ]:        159 :         impl_->counts_[section] += sp->getRdataCount();
     511                 :            :     }
     512                 :       1133 : }
     513                 :            : 
     514                 :            : bool
     515                 :        293 : Message::hasRRset(const Section section, const Name& name,
     516                 :            :                   const RRClass& rrclass, const RRType& rrtype)
     517                 :            : {
     518         [ +  + ]:        293 :     if (section >= MessageImpl::NUM_SECTIONS) {
     519 [ +  - ][ +  - ]:          4 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
     520                 :            :     }
     521                 :            : 
     522   [ +  +  +  - ]:       1335 :     BOOST_FOREACH(ConstRRsetPtr r, impl_->rrsets_[section]) {
         [ +  - ][ +  + ]
                 [ +  + ]
     523 [ +  - ][ +  + ]:        759 :         if (r->getClass() == rrclass &&
         [ +  + ][ +  + ]
                 [ +  + ]
     524         [ +  - ]:        291 :             r->getType() == rrtype &&
     525         [ +  - ]:        175 :             r->getName() == name) {
     526                 :         64 :             return (true);
     527                 :            :         }
     528                 :            :     }
     529                 :            : 
     530                 :            :     return (false);
     531                 :            : }
     532                 :            : 
     533                 :            : bool
     534                 :         72 : Message::hasRRset(const Section section, const RRsetPtr& rrset) {
     535                 :         72 :     return (hasRRset(section, rrset->getName(), rrset->getClass(), rrset->getType()));
     536                 :            : }
     537                 :            : 
     538                 :            : bool
     539                 :         16 : Message::removeRRset(const Section section, RRsetIterator& iterator) {
     540         [ -  + ]:         16 :     if (section >= MessageImpl::NUM_SECTIONS) {
     541 [ #  # ][ #  # ]:          0 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ #  # ]
     542                 :            :     }
     543                 :            : 
     544                 :         16 :     bool removed = false;
     545         [ +  - ]:         30 :     for (vector<RRsetPtr>::iterator i = impl_->rrsets_[section].begin();
     546                 :         60 :             i != impl_->rrsets_[section].end(); ++i) {
     547   [ +  +  +  -  :         94 :         if (((*i)->getName() == (*iterator)->getName()) &&
           +  + ][ +  + ]
     548                 :         17 :             ((*i)->getClass() == (*iterator)->getClass()) &&
     549                 :         17 :             ((*i)->getType() == (*iterator)->getType())) {
     550                 :            : 
     551                 :            :             // Found the matching RRset so remove it & ignore rest
     552                 :         16 :             impl_->counts_[section] -= (*iterator)->getRdataCount();
     553                 :         16 :             impl_->rrsets_[section].erase(i);
     554                 :            :             removed = true;
     555                 :            :             break;
     556                 :            :         }
     557                 :            :     }
     558                 :            : 
     559                 :         16 :     return (removed);
     560                 :            : }
     561                 :            : 
     562                 :            : void
     563                 :         25 : Message::clearSection(const Section section) {
     564         [ -  + ]:         25 :     if (section >= MessageImpl::NUM_SECTIONS) {
     565 [ #  # ][ #  # ]:          0 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ #  # ]
     566                 :            :     }
     567                 :         25 :     impl_->rrsets_[section].clear();
     568                 :         25 :     impl_->counts_[section] = 0;
     569                 :         25 : }
     570                 :            : 
     571                 :            : void
     572                 :        826 : Message::addQuestion(const QuestionPtr question) {
     573         [ -  + ]:        826 :     if (impl_->mode_ != Message::RENDER) {
     574 [ #  # ][ #  # ]:          0 :         isc_throw(InvalidMessageOperation,
     575                 :            :                   "addQuestion performed in non-render mode");
     576                 :            :     }
     577                 :            : 
     578                 :        826 :     impl_->questions_.push_back(question);
     579                 :        826 :     ++impl_->counts_[SECTION_QUESTION];
     580                 :        826 : }
     581                 :            : 
     582                 :            : void
     583                 :        775 : Message::addQuestion(const Question& question) {
     584         [ +  - ]:       1550 :     addQuestion(QuestionPtr(new Question(question)));
     585                 :        775 : }
     586                 :            : 
     587                 :            : void
     588                 :        763 : Message::toWire(AbstractMessageRenderer& renderer) {
     589                 :        763 :     impl_->toWire(renderer, NULL);
     590                 :        755 : }
     591                 :            : 
     592                 :            : void
     593                 :        160 : Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) {
     594                 :        160 :     impl_->toWire(renderer, &tsig_ctx);
     595                 :        155 : }
     596                 :            : 
     597                 :            : void
     598                 :        731 : Message::parseHeader(InputBuffer& buffer) {
     599         [ +  + ]:        731 :     if (impl_->mode_ != Message::PARSE) {
     600 [ +  - ][ +  - ]:          2 :         isc_throw(InvalidMessageOperation,
     601                 :            :                   "Message parse attempted in non parse mode");
     602                 :            :     }
     603                 :            : 
     604         [ +  + ]:        730 :     if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
     605         [ +  - ]:         30 :         isc_throw(MessageTooShort, "Malformed DNS message (short length): "
     606                 :            :                   << buffer.getLength() - buffer.getPosition());
     607                 :            :     }
     608                 :            : 
     609                 :        720 :     impl_->qid_ = buffer.readUint16();
     610                 :        720 :     const uint16_t codes_and_flags = buffer.readUint16();
     611                 :        720 :     impl_->setOpcode(Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
     612                 :        720 :     impl_->setRcode(Rcode(codes_and_flags & RCODE_MASK));
     613                 :        720 :     impl_->flags_ = (codes_and_flags & HEADERFLAG_MASK);
     614                 :        720 :     impl_->counts_[SECTION_QUESTION] = buffer.readUint16();
     615                 :        720 :     impl_->counts_[SECTION_ANSWER] = buffer.readUint16();
     616                 :        720 :     impl_->counts_[SECTION_AUTHORITY] = buffer.readUint16();
     617                 :        720 :     impl_->counts_[SECTION_ADDITIONAL] = buffer.readUint16();
     618                 :            : 
     619                 :        720 :     impl_->header_parsed_ = true;
     620                 :        720 : }
     621                 :            : 
     622                 :            : void
     623                 :        723 : Message::fromWire(InputBuffer& buffer, ParseOptions options) {
     624         [ +  + ]:        723 :     if (impl_->mode_ != Message::PARSE) {
     625 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     626                 :            :                   "Message parse attempted in non parse mode");
     627                 :            :     }
     628                 :            : 
     629         [ +  + ]:        721 :     if (!impl_->header_parsed_) {
     630                 :        488 :         parseHeader(buffer);
     631                 :            :     }
     632                 :            : 
     633                 :        713 :     impl_->counts_[SECTION_QUESTION] = impl_->parseQuestion(buffer);
     634                 :            :     impl_->counts_[SECTION_ANSWER] =
     635                 :        711 :         impl_->parseSection(SECTION_ANSWER, buffer, options);
     636                 :            :     impl_->counts_[SECTION_AUTHORITY] =
     637                 :        705 :         impl_->parseSection(SECTION_AUTHORITY, buffer, options);
     638                 :            :     impl_->counts_[SECTION_ADDITIONAL] =
     639                 :        705 :         impl_->parseSection(SECTION_ADDITIONAL, buffer, options);
     640                 :        690 : }
     641                 :            : 
     642                 :            : int
     643                 :        713 : MessageImpl::parseQuestion(InputBuffer& buffer) {
     644                 :        713 :     unsigned int added = 0;
     645                 :            : 
     646         [ +  + ]:       1443 :     for (unsigned int count = 0;
     647                 :       1443 :          count < counts_[Message::SECTION_QUESTION];
     648                 :            :          ++count) {
     649                 :       1464 :         const Name name(buffer);
     650                 :            : 
     651         [ +  + ]:        732 :         if ((buffer.getLength() - buffer.getPosition()) <
     652                 :            :             2 * sizeof(uint16_t)) {
     653 [ +  - ][ +  - ]:          6 :             isc_throw(DNSMessageFORMERR, "Question section too short: " <<
                 [ +  - ]
     654                 :            :                       (buffer.getLength() - buffer.getPosition()) << " bytes");
     655                 :            :         }
     656         [ +  - ]:        730 :         const RRType rrtype(buffer.readUint16());
     657         [ +  - ]:        730 :         const RRClass rrclass(buffer.readUint16());
     658                 :            : 
     659                 :            :         // XXX: need a duplicate check.  We might also want to have an
     660                 :            :         // optimized algorithm that requires the question section contain
     661                 :            :         // exactly one RR.
     662                 :            : 
     663 [ +  - ][ +  - ]:       1460 :         questions_.push_back(QuestionPtr(new Question(name, rrclass, rrtype)));
                 [ +  - ]
     664                 :        730 :         ++added;
     665                 :            :     }
     666                 :            : 
     667                 :        711 :     return (added);
     668                 :            : }
     669                 :            : 
     670                 :            : namespace {
     671                 :            : struct MatchRR : public unary_function<RRsetPtr, bool> {
     672                 :            :     MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
     673                 :            :         name_(name), rrtype_(rrtype), rrclass_(rrclass) {}
     674                 :        366 :     bool operator()(const RRsetPtr& rrset) const {
     675                 :        366 :         return (rrset->getType() == rrtype_ &&
     676                 :        345 :                 rrset->getClass() == rrclass_ &&
     677   [ +  +  +  - ]:       1056 :                 rrset->getName() == name_);
                 [ +  + ]
     678                 :            :     }
     679                 :            :     const Name& name_;
     680                 :            :     const RRType& rrtype_;
     681                 :            :     const RRClass& rrclass_;
     682                 :            : };
     683                 :            : }
     684                 :            : 
     685                 :            : // Note about design decision:
     686                 :            : // we need some type specific processing here, including EDNS and TSIG.
     687                 :            : // how much we should generalize/hardcode the special logic is subject
     688                 :            : // to discussion.  In terms of modularity it would be ideal to introduce
     689                 :            : // an abstract class (say "MessageAttribute") and let other such
     690                 :            : // concrete notions as EDNS or TSIG inherit from it.  Then we would
     691                 :            : // just do:
     692                 :            : // message->addAttribute(rrtype, rrclass, buffer);
     693                 :            : // to create and attach type-specific concrete object to the message.
     694                 :            : //
     695                 :            : // A major downside of this approach is, as usual, complexity due to
     696                 :            : // indirection and performance penalty.  Also, it may not be so easy
     697                 :            : // to separate the processing logic because in many cases we'll need
     698                 :            : // parse context for which the message class is responsible (e.g.
     699                 :            : // to check the EDNS OPT RR only appears in the additional section,
     700                 :            : // and appears only once).
     701                 :            : //
     702                 :            : // Another point to consider is that we may not need so many special
     703                 :            : // types other than EDNS and TSIG (and when and if we implement it,
     704                 :            : // SIG(0)); newer optional attributes of the message would more likely
     705                 :            : // be standardized as new flags or options of EDNS.  If that's the case,
     706                 :            : // introducing an abstract class with all the overhead and complexity
     707                 :            : // may not make much sense.
     708                 :            : //
     709                 :            : // Conclusion: don't over-generalize type-specific logic for now.
     710                 :            : // introduce separate concrete classes, and move context-independent
     711                 :            : // logic to that class; processing logic dependent on parse context
     712                 :            : // is hardcoded here.
     713                 :            : int
     714                 :       2121 : MessageImpl::parseSection(const Message::Section section,
     715                 :            :                           InputBuffer& buffer, Message::ParseOptions options)
     716                 :            : {
     717         [ +  - ]:       2121 :     assert(section < MessageImpl::NUM_SECTIONS);
     718                 :            : 
     719                 :            :     unsigned int added = 0;
     720                 :            : 
     721         [ +  + ]:       3025 :     for (unsigned int count = 0; count < counts_[section]; ++count) {
     722                 :            :         // We need to remember the start position for TSIG processing
     723                 :        925 :         const size_t start_position = buffer.getPosition();
     724                 :            : 
     725                 :       1847 :         const Name name(buffer);
     726                 :            : 
     727                 :            :         // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
     728         [ -  + ]:        922 :         if ((buffer.getLength() - buffer.getPosition()) <
     729                 :            :             3 * sizeof(uint16_t) + sizeof(uint32_t)) {
     730 [ #  # ][ #  # ]:          0 :             isc_throw(DNSMessageFORMERR, sectiontext[section] <<
         [ #  # ][ #  # ]
     731                 :            :                       " section too short: " <<
     732                 :            :                       (buffer.getLength() - buffer.getPosition()) << " bytes");
     733                 :            :         }
     734                 :            : 
     735         [ +  - ]:        922 :         const RRType rrtype(buffer.readUint16());
     736         [ +  - ]:        922 :         const RRClass rrclass(buffer.readUint16());
     737                 :        922 :         const RRTTL ttl(buffer.readUint32());
     738         [ +  - ]:        922 :         const size_t rdlen = buffer.readUint16();
     739         [ +  + ]:        922 :         ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
     740                 :            : 
     741         [ +  + ]:        920 :         if (rrtype == RRType::OPT()) {
     742         [ +  + ]:         40 :             addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
     743         [ +  + ]:        880 :         } else if (rrtype == RRType::TSIG()) {
     744                 :            :             addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
     745         [ +  + ]:        192 :                     *rdata);
     746                 :            :         } else {
     747         [ +  - ]:        688 :             addRR(section, name, rrclass, rrtype, ttl, rdata, options);
     748                 :        688 :             ++added;
     749                 :            :         }
     750                 :            :     }
     751                 :            : 
     752                 :       2100 :     return (added);
     753                 :            : }
     754                 :            : 
     755                 :            : void
     756                 :        688 : MessageImpl::addRR(Message::Section section, const Name& name,
     757                 :            :                    const RRClass& rrclass, const RRType& rrtype,
     758                 :            :                    const RRTTL& ttl, ConstRdataPtr rdata,
     759                 :            :                    Message::ParseOptions options)
     760                 :            : {
     761         [ +  + ]:        688 :     if ((options & Message::PRESERVE_ORDER) == 0) {
     762                 :            :         vector<RRsetPtr>::iterator it =
     763                 :        924 :             find_if(rrsets_[section].begin(), rrsets_[section].end(),
     764                 :        462 :                     MatchRR(name, rrtype, rrclass));
     765         [ +  + ]:        462 :         if (it != rrsets_[section].end()) {
     766                 :        246 :             (*it)->setTTL(min((*it)->getTTL(), ttl));
     767         [ +  - ]:        246 :             (*it)->addRdata(rdata);
     768                 :        688 :             return;
     769                 :            :         }
     770                 :            :     }
     771         [ +  - ]:        565 :     RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
     772         [ +  - ]:       1130 :     rrset->addRdata(rdata);
     773         [ +  - ]:        565 :     rrsets_[section].push_back(rrset);
     774                 :            : }
     775                 :            : 
     776                 :            : void
     777                 :         40 : MessageImpl::addEDNS(Message::Section section,  const Name& name,
     778                 :            :                      const RRClass& rrclass, const RRType& rrtype,
     779                 :            :                      const RRTTL& ttl, const Rdata& rdata)
     780                 :            : {
     781         [ +  + ]:         40 :     if (section != Message::SECTION_ADDITIONAL) {
     782         [ +  - ]:          4 :         isc_throw(DNSMessageFORMERR,
     783                 :            :                   "EDNS OPT RR found in an invalid section");
     784                 :            :     }
     785         [ +  + ]:         38 :     if (edns_) {
     786         [ +  - ]:          4 :         isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
     787                 :            :     }
     788                 :            : 
     789                 :            :     uint8_t extended_rcode;
     790                 :            :     edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
     791         [ +  - ]:         36 :                                           extended_rcode));
     792                 :         32 :     setRcode(Rcode(rcode_->getCode(), extended_rcode));
     793                 :         32 : }
     794                 :            : 
     795                 :            : void
     796                 :        192 : MessageImpl::addTSIG(Message::Section section, unsigned int count,
     797                 :            :                      const InputBuffer& buffer, size_t start_position,
     798                 :            :                      const Name& name, const RRClass& rrclass,
     799                 :            :                      const RRTTL& ttl, const Rdata& rdata)
     800                 :            : {
     801         [ +  + ]:        192 :     if (section != Message::SECTION_ADDITIONAL) {
     802         [ +  - ]:          4 :         isc_throw(DNSMessageFORMERR,
     803                 :            :                   "TSIG RR found in an invalid section");
     804                 :            :     }
     805         [ +  + ]:        190 :     if (count != counts_[section] - 1) {
     806         [ +  - ]:          8 :         isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
     807                 :            :     }
     808         [ -  + ]:        186 :     if (tsig_rr_) {
     809         [ #  # ]:          0 :         isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
     810                 :            :     }
     811                 :            :     tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
     812                 :            :                                                  ttl, rdata,
     813                 :            :                                                  buffer.getPosition() -
     814 [ +  + ][ +  - ]:        370 :                                                  start_position));
     815                 :        184 : }
     816                 :            : 
     817                 :            : namespace {
     818                 :            : template <typename T>
     819                 :            : struct SectionFormatter {
     820                 :            :     SectionFormatter(const Message::Section section, string& output) :
     821                 :        307 :         section_(section), output_(output) {}
     822                 :          0 :     void operator()(const T& entry) {
     823 [ #  # ][ #  # ]:        315 :         if (section_ == Message::SECTION_QUESTION) {
         [ -  + ][ +  - ]
     824                 :        280 :             output_ += ";";
     825                 :            :         }
     826                 :        630 :         output_ += entry->toText();
     827                 :          0 :     }
     828                 :            :     const Message::Section section_;
     829                 :            :     string& output_;
     830                 :            : };
     831                 :            : }
     832                 :            : 
     833                 :            : string
     834                 :        429 : Message::toText() const {
     835         [ +  + ]:        429 :     if (impl_->rcode_ == NULL) {
     836 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     837                 :            :                   "Message::toText() attempted without Rcode set");
     838                 :            :     }
     839         [ +  + ]:        427 :     if (impl_->opcode_ == NULL) {
     840 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidMessageOperation,
     841                 :            :                   "Message::toText() attempted without Opcode set");
     842                 :            :     }
     843                 :            : 
     844                 :          0 :     string s;
     845                 :            : 
     846 [ +  - ][ +  - ]:        850 :     s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
     847                 :            :     // for simplicity we don't consider extended rcode (unlike BIND9)
     848 [ +  - ][ +  - ]:        850 :     s += ", status: " + impl_->rcode_->toText();
     849         [ +  - ]:        850 :     s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
     850                 :            :     s += "\n;; flags:";
     851 [ +  - ][ +  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_QR)) {
     852                 :            :         s += " qr";
     853                 :            :     }
     854 [ +  - ][ +  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_AA)) {
     855                 :            :         s += " aa";
     856                 :            :     }
     857 [ +  - ][ -  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_TC)) {
     858                 :            :         s += " tc";
     859                 :            :     }
     860 [ +  - ][ +  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_RD)) {
     861                 :            :         s += " rd";
     862                 :            :     }
     863 [ +  - ][ -  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_RA)) {
     864                 :            :         s += " ra";
     865                 :            :     }
     866 [ +  - ][ -  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_AD)) {
     867                 :            :         s += " ad";
     868                 :            :     }
     869 [ +  - ][ -  + ]:        425 :     if (getHeaderFlag(HEADERFLAG_CD)) {
     870                 :            :         s += " cd";
     871                 :            :     }
     872                 :            : 
     873                 :            :     // for simplicity, don't consider the update case for now
     874                 :            :     s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
     875         [ +  - ]:        850 :         lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
     876                 :            :     s += ", ANSWER: " +
     877         [ +  - ]:        850 :         lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
     878                 :            :     s += ", AUTHORITY: " +
     879         [ +  - ]:        850 :         lexical_cast<string>(impl_->counts_[SECTION_AUTHORITY]);
     880                 :            : 
     881                 :        425 :     unsigned int arcount = impl_->counts_[SECTION_ADDITIONAL];
     882         [ +  + ]:        425 :     if (impl_->edns_ != NULL) {
     883                 :         13 :         ++arcount;
     884                 :            :     }
     885         [ +  + ]:        425 :     if (impl_->tsig_rr_ != NULL) {
     886                 :          6 :         ++arcount;
     887                 :            :     }
     888 [ +  - ][ +  - ]:        850 :     s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
     889                 :            : 
     890         [ +  + ]:        425 :     if (impl_->edns_ != NULL) {
     891                 :            :         s += "\n;; OPT PSEUDOSECTION:\n";
     892         [ +  - ]:         26 :         s += impl_->edns_->toText();
     893                 :            :     }
     894                 :            : 
     895         [ +  + ]:        425 :     if (!impl_->questions_.empty()) {
     896                 :            :         s += "\n;; " +
     897 [ +  - ][ +  - ]:        550 :             string(sectiontext[SECTION_QUESTION]) + " SECTION:\n";
                 [ +  - ]
     898                 :        550 :         for_each(impl_->questions_.begin(), impl_->questions_.end(),
     899         [ +  - ]:        275 :                  SectionFormatter<QuestionPtr>(SECTION_QUESTION, s));
     900                 :            :     }
     901         [ +  + ]:        425 :     if (!impl_->rrsets_[SECTION_ANSWER].empty()) {
     902                 :            :         s += "\n;; " +
     903 [ +  - ][ +  - ]:         28 :             string(sectiontext[SECTION_ANSWER]) + " SECTION:\n";
                 [ +  - ]
     904                 :         14 :         for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
     905                 :         14 :                  impl_->rrsets_[SECTION_ANSWER].end(),
     906         [ +  - ]:         14 :                  SectionFormatter<RRsetPtr>(SECTION_ANSWER, s));
     907                 :            :     }
     908         [ +  + ]:        425 :     if (!impl_->rrsets_[SECTION_AUTHORITY].empty()) {
     909                 :            :         s += "\n;; " +
     910 [ +  - ][ +  - ]:         24 :             string(sectiontext[SECTION_AUTHORITY]) + " SECTION:\n";
                 [ +  - ]
     911                 :         12 :         for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
     912                 :         12 :                  impl_->rrsets_[SECTION_AUTHORITY].end(),
     913         [ +  - ]:         12 :                  SectionFormatter<RRsetPtr>(SECTION_AUTHORITY, s));
     914                 :            :     }
     915         [ +  + ]:        425 :     if (!impl_->rrsets_[SECTION_ADDITIONAL].empty()) {
     916                 :            :         s += "\n;; " +
     917                 :          6 :             string(sectiontext[SECTION_ADDITIONAL]) +
     918 [ +  - ][ +  - ]:         12 :             " SECTION:\n";
                 [ +  - ]
     919                 :          6 :         for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
     920                 :          6 :                  impl_->rrsets_[SECTION_ADDITIONAL].end(),
     921         [ +  - ]:          6 :                  SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
     922                 :            :     }
     923                 :            : 
     924         [ +  + ]:        425 :     if (impl_->tsig_rr_ != NULL) {
     925                 :            :         s += "\n;; TSIG PSEUDOSECTION:\n";
     926         [ +  - ]:         12 :         s += impl_->tsig_rr_->toText();
     927                 :            :     }
     928                 :            : 
     929                 :        425 :     return (s);
     930                 :            : }
     931                 :            : 
     932                 :            : void
     933                 :        730 : Message::clear(Mode mode) {
     934                 :        730 :     impl_->init();
     935                 :        730 :     impl_->mode_ = mode;
     936                 :        730 : }
     937                 :            : 
     938                 :            : void
     939                 :         20 : Message::appendSection(const Section section, const Message& source) {
     940         [ +  + ]:         20 :     if (section >= MessageImpl::NUM_SECTIONS) {
     941 [ +  - ][ +  - ]:          2 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
     942                 :            :     }
     943                 :            : 
     944         [ +  + ]:         19 :     if (section == SECTION_QUESTION) {
     945 [ +  - ][ +  - ]:         15 :         for (QuestionIterator qi = source.beginQuestion();
                 [ +  + ]
     946 [ +  - ][ +  - ]:         10 :              qi != source.endQuestion();
     947                 :            :              ++qi) {
     948 [ +  - ][ +  - ]:          4 :             addQuestion(*qi);
     949                 :            :         }
     950                 :            :     } else {
     951 [ +  - ][ +  - ]:         87 :         for (RRsetIterator rrsi = source.beginSection(section);
                 [ +  + ]
     952 [ +  - ][ +  - ]:         58 :              rrsi != source.endSection(section);
     953                 :            :              ++rrsi) {
     954 [ +  - ][ +  - ]:         26 :             addRRset(section, *rrsi);
     955                 :            :         }
     956                 :            :     }
     957                 :         19 : }
     958                 :            : 
     959                 :            : void
     960                 :        123 : Message::makeResponse() {
     961         [ -  + ]:        123 :     if (impl_->mode_ != Message::PARSE) {
     962 [ #  # ][ #  # ]:          0 :         isc_throw(InvalidMessageOperation,
     963                 :            :                   "makeResponse() is performed in non-parse mode");
     964                 :            :     }
     965                 :            : 
     966                 :        123 :     impl_->mode_ = Message::RENDER;
     967                 :            : 
     968         [ +  - ]:        123 :     impl_->edns_ = EDNSPtr();
     969                 :        123 :     impl_->flags_ &= MESSAGE_REPLYPRESERVE;
     970                 :        123 :     setHeaderFlag(HEADERFLAG_QR, true);
     971                 :            : 
     972                 :        123 :     impl_->rrsets_[SECTION_ANSWER].clear();
     973                 :        123 :     impl_->counts_[SECTION_ANSWER] = 0;
     974                 :        123 :     impl_->rrsets_[SECTION_AUTHORITY].clear();
     975                 :        123 :     impl_->counts_[SECTION_AUTHORITY] = 0;
     976                 :        123 :     impl_->rrsets_[SECTION_ADDITIONAL].clear();
     977                 :        123 :     impl_->counts_[SECTION_ADDITIONAL] = 0;
     978                 :        123 : }
     979                 :            : 
     980                 :            : ///
     981                 :            : /// Template version of Section Iterator
     982                 :            : ///
     983                 :            : template <typename T>
     984                 :            : struct SectionIteratorImpl {
     985                 :            :     SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
     986                 :       7318 :         it_(it) {}
     987                 :            :     typename vector<T>::const_iterator it_;
     988                 :            : };
     989                 :            : 
     990                 :            : template <typename T>
     991                 :       2502 : SectionIterator<T>::SectionIterator(const SectionIteratorImpl<T>& impl) {
     992                 :       2502 :     impl_ = new SectionIteratorImpl<T>(impl.it_);
     993                 :       2502 : }
     994                 :            : 
     995                 :            : template <typename T>
     996                 :       4780 : SectionIterator<T>::~SectionIterator() {
     997                 :       4780 :     delete impl_;
     998                 :       4780 : }
     999                 :            : 
    1000                 :            : template <typename T>
    1001                 :       2056 : SectionIterator<T>::SectionIterator(const SectionIterator<T>& source) :
    1002                 :       2056 :     impl_(new SectionIteratorImpl<T>(source.impl_->it_))
    1003                 :       2056 : {}
    1004                 :            : 
    1005                 :            : template <typename T>
    1006                 :            : void
    1007                 :        258 : SectionIterator<T>::operator=(const SectionIterator<T>& source) {
    1008 [ +  - ][ +  - ]:        258 :     if (impl_ == source.impl_) {
    1009                 :        258 :         return;
    1010                 :            :     }
    1011                 :            :     SectionIteratorImpl<T>* newimpl =
    1012                 :        258 :         new SectionIteratorImpl<T>(source.impl_->it_);
    1013                 :        258 :     delete impl_;
    1014                 :        258 :     impl_ = newimpl;
    1015                 :            : }
    1016                 :            : 
    1017                 :            : template <typename T>
    1018                 :            : SectionIterator<T>&
    1019                 :       1706 : SectionIterator<T>::operator++() {
    1020                 :       1706 :     ++(impl_->it_);
    1021                 :       1706 :     return (*this);
    1022                 :            : }
    1023                 :            : 
    1024                 :            : template <typename T>
    1025                 :            : SectionIterator<T>
    1026                 :          0 : SectionIterator<T>::operator++(int) {
    1027                 :          0 :     SectionIterator<T> tmp(*this);
    1028   [ #  #  #  # ]:          0 :     ++(*this);
    1029                 :          0 :     return (tmp);
    1030                 :            : }
    1031                 :            : 
    1032                 :            : template <typename T>
    1033                 :            : const T&
    1034                 :       3182 : SectionIterator<T>::operator*() const {
    1035                 :       3182 :     return (*(impl_->it_));
    1036                 :            : }
    1037                 :            : 
    1038                 :            : template <typename T>
    1039                 :            : const T*
    1040                 :          0 : SectionIterator<T>::operator->() const {
    1041                 :          0 :     return (&(operator*()));
    1042                 :            : }
    1043                 :            : 
    1044                 :            : template <typename T>
    1045                 :            : bool
    1046                 :         79 : SectionIterator<T>::operator==(const SectionIterator<T>& other) const {
    1047                 :         79 :     return (impl_->it_ == other.impl_->it_);
    1048                 :            : }
    1049                 :            : 
    1050                 :            : template <typename T>
    1051                 :            : bool
    1052                 :       2763 : SectionIterator<T>::operator!=(const SectionIterator<T>& other) const {
    1053                 :       2763 :     return (impl_->it_ != other.impl_->it_);
    1054                 :            : }
    1055                 :            : 
    1056                 :            : ///
    1057                 :            : /// We need to explicitly instantiate these template classes because these
    1058                 :            : /// are public classes but defined in this implementation file.
    1059                 :            : ///
    1060                 :            : template class SectionIterator<QuestionPtr>;
    1061                 :            : template class SectionIterator<RRsetPtr>;
    1062                 :            : 
    1063                 :            : namespace {
    1064                 :            : typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
    1065                 :            : typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
    1066                 :            : }
    1067                 :            : 
    1068                 :            : ///
    1069                 :            : /// Question iterator
    1070                 :            : ///
    1071                 :            : const QuestionIterator
    1072                 :        624 : Message::beginQuestion() const {
    1073                 :        624 :     return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
    1074                 :            : }
    1075                 :            : 
    1076                 :            : const QuestionIterator
    1077                 :        310 : Message::endQuestion() const {
    1078                 :        310 :     return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
    1079                 :            : }
    1080                 :            : 
    1081                 :            : ///
    1082                 :            : /// RRsets iterators
    1083                 :            : ///
    1084                 :            : const SectionIterator<RRsetPtr>
    1085                 :        723 : Message::beginSection(const Section section) const {
    1086         [ +  + ]:        723 :     if (section >= MessageImpl::NUM_SECTIONS) {
    1087 [ +  - ][ +  - ]:          2 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
    1088                 :            :     }
    1089         [ +  + ]:        722 :     if (section == SECTION_QUESTION) {
    1090         [ +  - ]:          2 :         isc_throw(InvalidMessageSection,
    1091                 :            :                   "RRset iterator is requested for question");
    1092                 :            :     }
    1093                 :            : 
    1094                 :        721 :     return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
    1095                 :            : }
    1096                 :            : 
    1097                 :            : const SectionIterator<RRsetPtr>
    1098                 :        849 : Message::endSection(const Section section) const {
    1099         [ +  + ]:        849 :     if (section >= MessageImpl::NUM_SECTIONS) {
    1100 [ +  - ][ +  - ]:          2 :         isc_throw(OutOfRange, "Invalid message section: " << section);
                 [ +  - ]
    1101                 :            :     }
    1102         [ +  + ]:        848 :     if (section == SECTION_QUESTION) {
    1103         [ +  - ]:          2 :         isc_throw(InvalidMessageSection,
    1104                 :            :                   "RRset iterator is requested for question");
    1105                 :            :     }
    1106                 :            : 
    1107                 :        847 :     return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
    1108                 :            : }
    1109                 :            : 
    1110                 :            : ostream&
    1111                 :        420 : operator<<(ostream& os, const Message& message) {
    1112         [ +  - ]:        420 :     return (os << message.toText());
    1113                 :            : }
    1114                 :            : } // end of namespace dns
    1115                 :        137 : } // end of namespace isc

Generated by: LCOV version 1.9