buffer.h 18 KB

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