LCOV - code coverage report
Current view: top level - util - buffer.h (source / functions) Hit Total Coverage
Test: report.info Lines: 118 131 90.1 %
Date: 2012-05-15 Functions: 32 44 72.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 60 110 54.5 %

           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                 :            : #ifndef __BUFFER_H
      16                 :            : #define __BUFFER_H 1
      17                 :            : 
      18                 :            : #include <stdlib.h>
      19                 :            : #include <cstring>
      20                 :            : #include <vector>
      21                 :            : 
      22                 :            : #include <stdint.h>
      23                 :            : 
      24                 :            : #include <exceptions/exceptions.h>
      25                 :            : 
      26                 :            : #include <boost/shared_ptr.hpp>
      27                 :            : 
      28                 :            : namespace isc {
      29                 :            : namespace util {
      30                 :            : 
      31                 :            : ///
      32                 :            : /// \brief A standard DNS module exception that is thrown if an out-of-range
      33                 :            : /// buffer operation is being performed.
      34                 :            : ///
      35                 :         66 : class InvalidBufferPosition : public Exception {
      36                 :            : public:
      37                 :         12 :     InvalidBufferPosition(const char* file, size_t line, const char* what) :
      38 [ +  - ][ +  - ]:         66 :         isc::Exception(file, line, what) {}
      39                 :            : };
      40                 :            : 
      41                 :            : ///\brief The \c InputBuffer class is a buffer abstraction for manipulating
      42                 :            : /// read-only data.
      43                 :            : ///
      44                 :            : /// The main purpose of this class is to provide a safe placeholder for
      45                 :            : /// examining wire-format data received from a network.
      46                 :            : ///
      47                 :            : /// Applications normally use this class only in a limited situation: as an
      48                 :            : /// interface between legacy I/O operation (such as receiving data from a BSD
      49                 :            : /// socket) and the rest of the BIND10 DNS library.  One common usage of this
      50                 :            : /// class for an application would therefore be something like this:
      51                 :            : ///
      52                 :            : /// \code unsigned char buf[1024];
      53                 :            : /// struct sockaddr addr;
      54                 :            : /// socklen_t addrlen = sizeof(addr);
      55                 :            : /// int cc = recvfrom(s, buf, sizeof(buf), 0, &addr, &addrlen);
      56                 :            : /// InputBuffer buffer(buf, cc);
      57                 :            : /// // pass the buffer to a DNS message object to parse the message \endcode
      58                 :            : ///
      59                 :            : /// Other BIND10 DNS classes will then use methods of this class to get access
      60                 :            : /// to the data, but the application normally doesn't have to care about the
      61                 :            : /// details.
      62                 :            : ///
      63                 :            : /// An \c InputBuffer object internally holds a reference to the given data,
      64                 :            : /// rather than make a local copy of the data.  Also, it does not have an
      65                 :            : /// ownership of the given data.  It is application's responsibility to ensure
      66                 :            : /// the data remains valid throughout the lifetime of the \c InputBuffer
      67                 :            : /// object.  Likewise, this object generally assumes the data isn't modified
      68                 :            : /// throughout its lifetime; if the application modifies the data while this
      69                 :            : /// object retains a reference to it, the result is undefined.  The application
      70                 :            : /// will also be responsible for releasing the data when it's not needed if it
      71                 :            : /// was dynamically acquired.
      72                 :            : ///
      73                 :            : /// This is a deliberate design choice: although it's safer to make a local
      74                 :            : /// copy of the given data on construction, it would cause unacceptable
      75                 :            : /// performance overhead, especially considering that a DNS message can be
      76                 :            : /// as large as a few KB.  Alternatively, we could allow the object to allocate
      77                 :            : /// memory internally and expose it to the application to store network data
      78                 :            : /// in it.  This is also a bad design, however, in that we would effectively
      79                 :            : /// break the abstraction employed in the class, and do so by publishing
      80                 :            : /// "read-only" stuff as a writable memory region.  Since there doesn't seem to
      81                 :            : /// be a perfect solution, we have adopted what we thought a "least bad" one.
      82                 :            : ///
      83                 :            : /// Methods for reading data from the buffer generally work like an input
      84                 :            : /// stream: it begins with the head of the data, and once some length of data
      85                 :            : /// is read from the buffer, the next read operation will take place from the
      86                 :            : /// head of the unread data.  An object of this class internally holds (a
      87                 :            : /// notion of) where the next read operation should start.  We call it the
      88                 :            : /// <em>read position</em> in this document.
      89                 :            : class InputBuffer {
      90                 :            : public:
      91                 :            :     ///
      92                 :            :     /// \name Constructors and Destructor
      93                 :            :     //@{
      94                 :            :     /// \brief Constructor from variable length of data.
      95                 :            :     ///
      96                 :            :     /// It is caller's responsibility to ensure that the data is valid as long
      97                 :            :     /// as the buffer exists.
      98                 :            :     /// \param data A pointer to the data stored in the buffer.
      99                 :            :     /// \param len The length of the data in bytes.
     100                 :            :     InputBuffer(const void* data, size_t len) :
     101                 :      11407 :         position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
     102                 :            :     //@}
     103                 :            : 
     104                 :            :     ///
     105                 :            :     /// \name Getter Methods
     106                 :            :     //@{
     107                 :            :     /// \brief Return the length of the data stored in the buffer.
     108                 :          0 :     size_t getLength() const { return (len_); }
     109                 :            :     /// \brief Return the current read position.
     110                 :          0 :     size_t getPosition() const { return (position_); }
     111                 :            :     //@}
     112                 :            : 
     113                 :            :     ///
     114                 :            :     /// \name Setter Methods
     115                 :            :     ///
     116                 :            :     //@{
     117                 :            :     /// \brief Set the read position of the buffer to the given value.
     118                 :            :     ///
     119                 :            :     /// The new position must be in the valid range of the buffer; otherwise
     120                 :            :     /// an exception of class \c isc::dns::InvalidBufferPosition will be thrown.
     121                 :            :     /// \param position The new position (offset from the beginning of the
     122                 :            :     /// buffer).
     123                 :          0 :     void setPosition(size_t position) {
     124 [ +  + ][ -  + ]:       6419 :         if (position > len_) {
         [ -  + ][ -  + ]
           [ -  +  -  + ]
                 [ #  # ]
     125                 :          2 :             throwError("position is too large");
     126                 :            :         }
     127                 :     270831 :         position_ = position;
     128                 :          0 :     }
     129                 :            :     //@}
     130                 :            : 
     131                 :            :     ///
     132                 :            :     /// \name Methods for reading data from the buffer.
     133                 :            :     //@{
     134                 :            :     /// \brief Read an unsigned 8-bit integer from the buffer and return it.
     135                 :            :     ///
     136                 :            :     /// If the remaining length of the buffer is smaller than 8-bit, an
     137                 :            :     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
     138                 :      28197 :     uint8_t readUint8() {
     139         [ +  + ]:      88360 :         if (position_ + sizeof(uint8_t) > len_) {
     140                 :          8 :             throwError("read beyond end of buffer");
     141                 :            :         }
     142                 :            : 
     143                 :      88352 :         return (data_[position_++]);
     144                 :            :     }
     145                 :            :     /// \brief Read an unsigned 16-bit integer in network byte order from the
     146                 :            :     /// buffer, convert it to host byte order, and return it.
     147                 :            :     ///
     148                 :            :     /// If the remaining length of the buffer is smaller than 16-bit, an
     149                 :            :     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
     150                 :       9729 :     uint16_t readUint16() {
     151                 :            :         uint16_t data;
     152                 :            :         const uint8_t* cp;
     153                 :            : 
     154 [ +  + ][ +  + ]:     272193 :         if (position_ + sizeof(data) > len_) {
     155                 :          5 :             throwError("read beyond end of buffer");
     156                 :            :         }
     157                 :            : 
     158                 :     272188 :         cp = &data_[position_];
     159                 :     272188 :         data = ((unsigned int)(cp[0])) << 8;
     160                 :     272188 :         data |= ((unsigned int)(cp[1]));
     161                 :     272100 :         position_ += sizeof(data);
     162                 :            : 
     163                 :       9728 :         return (data);
     164                 :            :     }
     165                 :            :     /// \brief Read an unsigned 32-bit integer in network byte order from the
     166                 :            :     /// buffer, convert it to host byte order, and return it.
     167                 :            :     ///
     168                 :            :     /// If the remaining length of the buffer is smaller than 32-bit, an
     169                 :            :     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
     170                 :      16121 :     uint32_t readUint32() {
     171                 :            :         uint32_t data;
     172                 :            :         const uint8_t* cp;
     173                 :            : 
     174         [ +  + ]:      17064 :         if (position_ + sizeof(data) > len_) {
     175                 :          2 :             throwError("read beyond end of buffer");
     176                 :            :         }
     177                 :            : 
     178                 :      17062 :         cp = &data_[position_];
     179                 :      17062 :         data = ((unsigned int)(cp[0])) << 24;
     180                 :      17062 :         data |= ((unsigned int)(cp[1])) << 16;
     181                 :      17062 :         data |= ((unsigned int)(cp[2])) << 8;
     182                 :      17062 :         data |= ((unsigned int)(cp[3]));
     183                 :      17062 :         position_ += sizeof(data);
     184                 :            : 
     185                 :      16119 :         return (data);
     186                 :            :     }
     187                 :            :     /// \brief Read data of the specified length from the buffer and copy it to
     188                 :            :     /// the caller supplied buffer.
     189                 :            :     ///
     190                 :            :     /// The data is copied as stored in the buffer; no conversion is performed.
     191                 :            :     /// If the remaining length of the buffer is smaller than the specified
     192                 :            :     /// length, an exception of class \c isc::dns::InvalidBufferPosition will
     193                 :            :     /// be thrown.
     194                 :       1617 :     void readData(void* data, size_t len) {
     195         [ +  + ]:       1694 :         if (position_ + len > len_) {
     196                 :         43 :             throwError("read beyond end of buffer");
     197                 :            :         }
     198                 :            : 
     199                 :       1651 :         std::memcpy(data, &data_[position_], len);
     200                 :       1651 :         position_ += len;
     201                 :       1583 :     }
     202                 :            :     //@}
     203                 :            : 
     204                 :            :     /// @brief Read specified number of bytes as a vector.
     205                 :            :     ///
     206                 :            :     /// If specified buffer is too short, it will be expanded
     207                 :            :     /// using vector::resize() method.
     208                 :            :     ///
     209                 :            :     /// @param Reference to a buffer (data will be stored there).
     210                 :            :     /// @param Size specified number of bytes to read in a vector.
     211                 :            :     ///
     212                 :          4 :     void readVector(std::vector<uint8_t>& data, size_t len) {
     213         [ +  + ]:          4 :         if (position_ + len > len_) {
     214                 :          1 :             throwError("read beyond end of buffer");
     215                 :            :         }
     216                 :            : 
     217                 :            :         data.resize(len);
     218                 :          3 :         readData(&data[0], len);
     219                 :          3 :     }
     220                 :            : 
     221                 :            : private:
     222                 :            :     /// \brief A common helper to throw an exception on invalid operation.
     223                 :            :     ///
     224                 :            :     /// Experiments showed that throwing from each method makes the buffer
     225                 :            :     /// operation slower, so we consolidate it here, and let the methods
     226                 :            :     /// call this.
     227                 :         61 :     static void throwError(const char* msg) {
     228 [ +  - ][ +  - ]:        122 :         isc_throw(InvalidBufferPosition, msg);
     229                 :            :     }
     230                 :            : 
     231                 :            :     size_t position_;
     232                 :            : 
     233                 :            :     // XXX: The following must be private, but for a short term workaround with
     234                 :            :     // Boost.Python binding, we changed it to protected.  We should soon
     235                 :            :     // revisit it.
     236                 :            : protected:
     237                 :            :     const uint8_t* data_;
     238                 :            :     size_t len_;
     239                 :            : };
     240                 :            : 
     241                 :            : ///
     242                 :            : ///\brief The \c OutputBuffer class is a buffer abstraction for manipulating
     243                 :            : /// mutable data.
     244                 :            : ///
     245                 :            : /// The main purpose of this class is to provide a safe workplace for
     246                 :            : /// constructing wire-format data to be sent out to a network.  Here,
     247                 :            : /// <em>safe</em> means that it automatically allocates necessary memory and
     248                 :            : /// avoid buffer overrun.
     249                 :            : ///
     250                 :            : /// Like for the \c InputBuffer class, applications normally use this class only
     251                 :            : /// in a limited situation.  One common usage of this class for an application
     252                 :            : /// would be something like this:
     253                 :            : ///
     254                 :            : /// \code OutputBuffer buffer(4096); // give a sufficiently large initial size
     255                 :            : /// // pass the buffer to a DNS message object to construct a wire-format
     256                 :            : /// // DNS message.
     257                 :            : /// struct sockaddr to;
     258                 :            : /// sendto(s, buffer.getData(), buffer.getLength(), 0, &to, sizeof(to));
     259                 :            : /// \endcode
     260                 :            : ///
     261                 :            : /// where the \c getData() method gives a reference to the internal memory
     262                 :            : /// region stored in the \c buffer object.  This is a suboptimal design in that
     263                 :            : /// it exposes an encapsulated "handle" of an object to its user.
     264                 :            : /// Unfortunately, there is no easy way to avoid this without involving
     265                 :            : /// expensive data copy if we want to use this object with a legacy API such as
     266                 :            : /// a BSD socket interface.  And, indeed, this is one major purpose for this
     267                 :            : /// object.  Applications should use this method only under such a special
     268                 :            : /// circumstance.  It should also be noted that the memory region returned by
     269                 :            : /// \c getData() may be invalidated after a subsequent write operation.
     270                 :            : ///
     271                 :            : /// An \c OutputBuffer class object automatically extends its memory region when
     272                 :            : /// data is written beyond the end of the current buffer.  However, it will
     273                 :            : /// involve performance overhead such as reallocating more memory and copying
     274                 :            : /// data.  It is therefore recommended to construct the buffer object with a
     275                 :            : /// sufficiently large initial size.
     276                 :            : /// The \c getCapacity() method provides the current maximum size of data
     277                 :            : /// (including the portion already written) that can be written into the buffer
     278                 :            : /// without causing memory reallocation.
     279                 :            : ///
     280                 :            : /// Methods for writing data into the buffer generally work like an output
     281                 :            : /// stream: it begins with the head of the buffer, and once some length of data
     282                 :            : /// is written into the buffer, the next write operation will take place from
     283                 :            : /// the end of the buffer.  Other methods to emulate "random access" are also
     284                 :            : /// provided (e.g., \c writeUint16At()).  The normal write operations are
     285                 :            : /// normally exception-free as this class automatically extends the buffer
     286                 :            : /// when necessary.  However, in extreme cases such as an attempt of writing
     287                 :            : /// multi-GB data, a separate exception (e.g., \c std::bad_alloc) may be thrown
     288                 :            : /// by the system.  This also applies to the constructor with a very large
     289                 :            : /// initial size.
     290                 :            : ///
     291                 :            : /// Note to developers: it may make more sense to introduce an abstract base
     292                 :            : /// class for the \c OutputBuffer and define the simple implementation as a
     293                 :            : /// a concrete derived class.  That way we can provide flexibility for future
     294                 :            : /// extension such as more efficient buffer implementation or allowing users
     295                 :            : /// to have their own customized version without modifying the source code.
     296                 :            : /// We in fact considered that option, but at the moment chose the simpler
     297                 :            : /// approach with a single concrete class because it may make the
     298                 :            : /// implementation unnecessarily complicated while we were still not certain
     299                 :            : /// if we really want that flexibility.  We may revisit the class design as
     300                 :            : /// we see more applications of the class.  The same considerations apply to
     301                 :            : /// the \c InputBuffer and \c MessageRenderer classes.
     302                 :            : class OutputBuffer {
     303                 :            : public:
     304                 :            :     ///
     305                 :            :     /// \name Constructors and Destructor
     306                 :            :     ///
     307                 :            :     //@{
     308                 :            :     /// \brief Constructor from the initial size of the buffer.
     309                 :            :     ///
     310                 :            :     /// \param len The initial length of the buffer in bytes.
     311                 :       4546 :     OutputBuffer(size_t len) :
     312                 :            :         buffer_(NULL),
     313                 :            :         size_(0),
     314                 :       6450 :         allocated_(len)
     315                 :            :     {
     316                 :            :         // We use malloc and free instead of C++ new[] and delete[].
     317                 :            :         // This way we can use realloc, which may in fact do it without a copy.
     318                 :       6450 :         buffer_ = static_cast<uint8_t*>(malloc(allocated_));
     319         [ +  + ]:       4728 :         if (buffer_ == NULL && len != 0) {
     320                 :          0 :             throw std::bad_alloc();
     321                 :            :         }
     322                 :       4546 :     }
     323                 :            : 
     324                 :            :     /// \brief Copy constructor
     325                 :          2 :     OutputBuffer(const OutputBuffer& other) :
     326                 :            :         buffer_(NULL),
     327                 :            :         size_(other.size_),
     328                 :          2 :         allocated_(other.allocated_)
     329                 :            :     {
     330                 :          2 :         buffer_ = static_cast<uint8_t*>(malloc(allocated_));
     331 [ -  + ][ #  # ]:          2 :         if (buffer_ == NULL && allocated_ != 0) {
     332                 :          0 :             throw std::bad_alloc();
     333                 :            :         }
     334                 :          2 :         std::memcpy(buffer_, other.buffer_, size_);
     335                 :          2 :     }
     336                 :            : 
     337                 :            :     /// \brief Destructor
     338                 :          0 :     ~ OutputBuffer() {
     339                 :       6205 :         free(buffer_);
     340                 :          0 :     }
     341                 :            :     //@}
     342                 :            : 
     343                 :            :     /// \brief Assignment operator
     344                 :          2 :     OutputBuffer& operator =(const OutputBuffer& other) {
     345                 :         20 :         uint8_t* newbuff(static_cast<uint8_t*>(malloc(other.allocated_)));
     346 [ -  + ][ #  # ]:         20 :         if (newbuff == NULL && other.allocated_ != 0) {
     347                 :          0 :             throw std::bad_alloc();
     348                 :            :         }
     349                 :         20 :         free(buffer_);
     350                 :         20 :         buffer_ = newbuff;
     351                 :         20 :         size_ = other.size_;
     352                 :         20 :         allocated_ = other.allocated_;
     353                 :         20 :         std::memcpy(buffer_, other.buffer_, size_);
     354                 :          2 :         return (*this);
     355                 :            :     }
     356                 :            : 
     357                 :            :     ///
     358                 :            :     /// \name Getter Methods
     359                 :            :     ///
     360                 :            :     //@{
     361                 :            :     /// \brief Return the current capacity of the buffer.
     362                 :          0 :     size_t getCapacity() const { return (allocated_); }
     363                 :            :     /// \brief Return a pointer to the head of the data stored in the buffer.
     364                 :            :     ///
     365                 :            :     /// The caller can assume that the subsequent \c getLength() bytes are
     366                 :            :     /// identical to the stored data of the buffer.
     367                 :            :     ///
     368                 :            :     /// Note: The pointer returned by this method may be invalidated after a
     369                 :            :     /// subsequent write operation.
     370                 :          0 :     const void* getData() const { return (buffer_); }
     371                 :            :     /// \brief Return the length of data written in the buffer.
     372                 :          0 :     size_t getLength() const { return (size_); }
     373                 :            :     /// \brief Return the value of the buffer at the specified position.
     374                 :            :     ///
     375                 :            :     /// \c pos must specify the valid position of the buffer; otherwise an
     376                 :            :     /// exception class of \c InvalidBufferPosition will be thrown.
     377                 :            :     ///
     378                 :            :     /// \param pos The position in the buffer to be returned.
     379                 :      45224 :     uint8_t operator[](size_t pos) const
     380                 :            :     {
     381 [ -  + ][ -  + ]:      45296 :         assert (pos < size_);
                 [ #  # ]
     382                 :      45224 :         return (buffer_[pos]);
     383                 :            :     }
     384                 :            :     //@}
     385                 :            : 
     386                 :            :     ///
     387                 :            :     /// \name Methods for writing data into the buffer.
     388                 :            :     ///
     389                 :            :     //@{
     390                 :            :     /// \brief Insert a specified length of gap at the end of the buffer.
     391                 :            :     ///
     392                 :            :     /// The caller should not assume any particular value to be inserted.
     393                 :            :     /// This method is provided as a shortcut to make a hole in the buffer
     394                 :            :     /// that is to be filled in later, e.g, by \ref writeUint16At().
     395                 :            :     /// \param len The length of the gap to be inserted in bytes.
     396                 :        710 :     void skip(size_t len) {
     397                 :       1662 :         ensureAllocated(size_ + len);
     398                 :       1662 :         size_ += len;
     399                 :        710 :     }
     400                 :            : 
     401                 :            :     /// \brief Trim the specified length of data from the end of the buffer.
     402                 :            :     ///
     403                 :            :     /// The specified length must not exceed the current data size of the
     404                 :            :     /// buffer; otherwise an exception of class \c isc::OutOfRange will
     405                 :            :     /// be thrown.
     406                 :            :     ///
     407                 :            :     /// \param len The length of data that should be trimmed.
     408                 :         25 :     void trim(size_t len)
     409                 :            :     {
     410         [ +  + ]:         25 :         if (len > size_) {
     411 [ +  - ][ #  # ]:          2 :             isc_throw(OutOfRange, "trimming too large from output buffer");
     412                 :            :         }
     413                 :         24 :         size_ -= len;
     414                 :         24 :     }
     415                 :            :     /// \brief Clear buffer content.
     416                 :            :     ///
     417                 :            :     /// This method can be used to re-initialize and reuse the buffer without
     418                 :            :     /// constructing a new one.
     419                 :         35 :     void clear() { size_ = 0; }
     420                 :            :     /// \brief Write an unsigned 8-bit integer into the buffer.
     421                 :            :     ///
     422                 :            :     /// \param data The 8-bit integer to be written into the buffer.
     423                 :         80 :     void writeUint8(uint8_t data) {
     424         [ +  - ]:         81 :         ensureAllocated(size_ + 1);
     425                 :         81 :         buffer_[size_ ++] = data;
     426                 :         80 :     }
     427                 :            : 
     428                 :            :     /// \brief Write an unsigned 8-bit integer into the buffer.
     429                 :            :     ///
     430                 :            :     /// The position must be lower than the size of the buffer,
     431                 :            :     /// otherwise an exception of class \c isc::dns::InvalidBufferPosition
     432                 :            :     /// will be thrown.
     433                 :            :     ///
     434                 :            :     /// \param data The 8-bit integer to be written into the buffer.
     435                 :            :     /// \param pos The position in the buffer to write the data.
     436                 :        110 :     void writeUint8At(uint8_t data, size_t pos) {
     437         [ +  + ]:        110 :         if (pos + sizeof(data) > size_) {
     438 [ +  - ][ +  - ]:          4 :             isc_throw(InvalidBufferPosition, "write at invalid position");
     439                 :            :         }
     440                 :        108 :         buffer_[pos] = data;
     441                 :        108 :     }
     442                 :            : 
     443                 :            :     /// \brief Write an unsigned 16-bit integer in host byte order into the
     444                 :            :     /// buffer in network byte order.
     445                 :            :     ///
     446                 :            :     /// \param data The 16-bit integer to be written into the buffer.
     447                 :       6216 :     void writeUint16(uint16_t data)
     448                 :            :     {
     449 [ +  - ][ +  - ]:     139448 :         ensureAllocated(size_ + sizeof(data));
     450                 :     139448 :         buffer_[size_ ++] = static_cast<uint8_t>((data & 0xff00U) >> 8);
     451                 :     139448 :         buffer_[size_ ++] = static_cast<uint8_t>(data & 0x00ffU);
     452                 :       6216 :     }
     453                 :            :     /// \brief Write an unsigned 16-bit integer in host byte order at the
     454                 :            :     /// specified position of the buffer in network byte order.
     455                 :            :     ///
     456                 :            :     /// The buffer must have a sufficient room to store the given data at the
     457                 :            :     /// given position, that is, <code>pos + 2 < getLength()</code>;
     458                 :            :     /// otherwise an exception of class \c isc::dns::InvalidBufferPosition will
     459                 :            :     /// be thrown.
     460                 :            :     /// Note also that this method never extends the buffer.
     461                 :            :     ///
     462                 :            :     /// \param data The 16-bit integer to be written into the buffer.
     463                 :            :     /// \param pos The beginning position in the buffer to write the data.
     464                 :       6367 :     void writeUint16At(uint16_t data, size_t pos)
     465                 :            :     {
     466         [ +  + ]:       6367 :         if (pos + sizeof(data) > size_) {
     467 [ +  - ][ +  - ]:          6 :             isc_throw(InvalidBufferPosition, "write at invalid position");
     468                 :            :         }
     469                 :            : 
     470                 :       6364 :         buffer_[pos] = static_cast<uint8_t>((data & 0xff00U) >> 8);
     471                 :       6364 :         buffer_[pos + 1] = static_cast<uint8_t>(data & 0x00ffU);
     472                 :       6364 :     }
     473                 :            :     /// \brief Write an unsigned 32-bit integer in host byte order
     474                 :            :     /// into the buffer in network byte order.
     475                 :            :     ///
     476                 :            :     /// \param data The 32-bit integer to be written into the buffer.
     477                 :      16693 :     void writeUint32(uint32_t data)
     478                 :            :     {
     479                 :      16696 :         ensureAllocated(size_ + sizeof(data));
     480                 :      16696 :         buffer_[size_ ++] = static_cast<uint8_t>((data & 0xff000000) >> 24);
     481                 :      16696 :         buffer_[size_ ++] = static_cast<uint8_t>((data & 0x00ff0000) >> 16);
     482                 :      16696 :         buffer_[size_ ++] = static_cast<uint8_t>((data & 0x0000ff00) >> 8);
     483                 :      16696 :         buffer_[size_ ++] = static_cast<uint8_t>(data & 0x000000ff);
     484                 :      16693 :     }
     485                 :            :     /// \brief Copy an arbitrary length of data into the buffer.
     486                 :            :     ///
     487                 :            :     /// No conversion on the copied data is performed.
     488                 :            :     ///
     489                 :            :     /// \param data A pointer to the data to be copied into the buffer.
     490                 :            :     /// \param len The length of the data in bytes.
     491                 :       1992 :     void writeData(const void *data, size_t len)
     492                 :            :     {
     493         [ +  - ]:     136413 :         ensureAllocated(size_ + len);
     494                 :     136413 :         std::memcpy(buffer_ + size_, data, len);
     495                 :     136413 :         size_ += len;
     496                 :       1992 :     }
     497                 :            :     //@}
     498                 :            : 
     499                 :            : private:
     500                 :            :     // The actual data
     501                 :            :     uint8_t* buffer_;
     502                 :            :     // How many bytes are used
     503                 :            :     size_t size_;
     504                 :            :     // How many bytes do we have preallocated (eg. the capacity)
     505                 :            :     size_t allocated_;
     506                 :            :     // Make sure at last needed_size bytes are allocated in the buffer
     507                 :      25348 :     void ensureAllocated(size_t needed_size) {
     508 [ +  + ][ +  + ]:     294300 :         if (allocated_ < needed_size) {
         [ +  + ][ #  # ]
                 [ #  # ]
     509                 :            :             // Guess some bigger size
     510 [ +  + ][ #  # ]:       1187 :             size_t new_size = (allocated_ == 0) ? 1024 : allocated_;
         [ #  # ][ +  + ]
     511 [ +  + ][ +  + ]:       1492 :             while (new_size < needed_size) {
         [ #  # ][ #  # ]
                 [ #  # ]
     512                 :        305 :                 new_size *= 2;
     513                 :            :             }
     514                 :            :             // Allocate bigger space
     515                 :            :             uint8_t* new_buffer_(static_cast<uint8_t*>(realloc(buffer_,
     516                 :       1187 :                 new_size)));
     517 [ -  + ][ -  + ]:       1187 :             if (new_buffer_ == NULL) {
                 [ #  # ]
     518                 :            :                 // If it fails, the original block is left intact by it
     519                 :          0 :                 throw std::bad_alloc();
     520                 :            :             }
     521                 :       1187 :             buffer_ = new_buffer_;
     522                 :       1187 :             allocated_ = new_size;
     523                 :            :         }
     524                 :      25348 :     }
     525                 :            : };
     526                 :            : 
     527                 :            : /// \brief Pointer-like types pointing to \c InputBuffer or \c OutputBuffer
     528                 :            : ///
     529                 :            : /// These types are expected to be used as an argument in asynchronous
     530                 :            : /// callback functions.  The internal reference-counting will ensure that
     531                 :            : /// that ongoing state information will not be lost if the object
     532                 :            : /// that originated the asynchronous call falls out of scope.
     533                 :            : typedef boost::shared_ptr<InputBuffer> InputBufferPtr;
     534                 :            : typedef boost::shared_ptr<OutputBuffer> OutputBufferPtr;
     535                 :            : 
     536                 :            : } // namespace util
     537                 :            : } // namespace isc
     538                 :            : #endif  // __BUFFER_H
     539                 :            : 
     540                 :            : // Local Variables:
     541                 :            : // mode: c++
     542                 :            : // End:

Generated by: LCOV version 1.9