buffer.h 21 KB

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