Buffer.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2015 ZeroTier, Inc.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #ifndef ZT_BUFFER_HPP
  28. #define ZT_BUFFER_HPP
  29. #include <string.h>
  30. #include <stdint.h>
  31. #include <stdexcept>
  32. #include <string>
  33. #include <algorithm>
  34. #include <utility>
  35. #include "Constants.hpp"
  36. #include "Utils.hpp"
  37. #if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING))
  38. #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
  39. #else
  40. #define ZT_VAR_MAY_ALIAS
  41. #endif
  42. namespace ZeroTier {
  43. /**
  44. * A variable length but statically allocated buffer
  45. *
  46. * Bounds-checking is done everywhere, since this is used in security
  47. * critical code. This supports construction and assignment from buffers
  48. * of differing capacities, provided the data actually in them fits.
  49. * It throws std::out_of_range on any boundary violation.
  50. *
  51. * The at(), append(), etc. methods encode integers larger than 8-bit in
  52. * big-endian (network) byte order.
  53. *
  54. * @tparam C Total capacity
  55. */
  56. template<unsigned int C>
  57. class Buffer
  58. {
  59. // I love me!
  60. template <unsigned int C2> friend class Buffer;
  61. public:
  62. // STL container idioms
  63. typedef unsigned char value_type;
  64. typedef unsigned char * pointer;
  65. typedef const unsigned char * const_pointer;
  66. typedef unsigned char & reference;
  67. typedef const unsigned char & const_reference;
  68. typedef unsigned char * iterator;
  69. typedef const unsigned char * const_iterator;
  70. typedef unsigned int size_type;
  71. typedef int difference_type;
  72. typedef std::reverse_iterator<iterator> reverse_iterator;
  73. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  74. inline iterator begin() { return _b; }
  75. inline iterator end() { return (_b + _l); }
  76. inline const_iterator begin() const { return _b; }
  77. inline const_iterator end() const { return (_b + _l); }
  78. inline reverse_iterator rbegin() { return reverse_iterator(begin()); }
  79. inline reverse_iterator rend() { return reverse_iterator(end()); }
  80. inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
  81. inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
  82. Buffer()
  83. throw() :
  84. _l(0)
  85. {
  86. }
  87. Buffer(unsigned int l)
  88. throw(std::out_of_range)
  89. {
  90. if (l > C)
  91. throw std::out_of_range("Buffer: construct with size larger than capacity");
  92. _l = l;
  93. }
  94. template<unsigned int C2>
  95. Buffer(const Buffer<C2> &b)
  96. throw(std::out_of_range)
  97. {
  98. *this = b;
  99. }
  100. Buffer(const void *b,unsigned int l)
  101. throw(std::out_of_range)
  102. {
  103. copyFrom(b,l);
  104. }
  105. Buffer(const std::string &s)
  106. throw(std::out_of_range)
  107. {
  108. copyFrom(s.data(),s.length());
  109. }
  110. template<unsigned int C2>
  111. inline Buffer &operator=(const Buffer<C2> &b)
  112. throw(std::out_of_range)
  113. {
  114. if (b._l > C)
  115. throw std::out_of_range("Buffer: assignment from buffer larger than capacity");
  116. memcpy(_b,b._b,_l = b._l);
  117. return *this;
  118. }
  119. inline Buffer &operator=(const std::string &s)
  120. throw(std::out_of_range)
  121. {
  122. copyFrom(s.data(),s.length());
  123. return *this;
  124. }
  125. inline void copyFrom(const void *b,unsigned int l)
  126. throw(std::out_of_range)
  127. {
  128. if (l > C)
  129. throw std::out_of_range("Buffer: set from C array larger than capacity");
  130. _l = l;
  131. memcpy(_b,b,l);
  132. }
  133. unsigned char operator[](const unsigned int i) const
  134. throw(std::out_of_range)
  135. {
  136. if (i >= _l)
  137. throw std::out_of_range("Buffer: [] beyond end of data");
  138. return (unsigned char)_b[i];
  139. }
  140. unsigned char &operator[](const unsigned int i)
  141. throw(std::out_of_range)
  142. {
  143. if (i >= _l)
  144. throw std::out_of_range("Buffer: [] beyond end of data");
  145. return ((unsigned char *)_b)[i];
  146. }
  147. /**
  148. * Get a raw pointer to a field with bounds checking
  149. *
  150. * This isn't perfectly safe in that the caller could still overflow
  151. * the pointer, but its use provides both a sanity check and
  152. * documentation / reminder to the calling code to treat the returned
  153. * pointer as being of size [l].
  154. *
  155. * @param i Index of field in buffer
  156. * @param l Length of field in bytes
  157. * @return Pointer to field data
  158. * @throws std::out_of_range Field extends beyond data size
  159. */
  160. unsigned char *field(unsigned int i,unsigned int l)
  161. throw(std::out_of_range)
  162. {
  163. if ((i + l) > _l)
  164. throw std::out_of_range("Buffer: field() beyond end of data");
  165. return (unsigned char *)(_b + i);
  166. }
  167. const unsigned char *field(unsigned int i,unsigned int l) const
  168. throw(std::out_of_range)
  169. {
  170. if ((i + l) > _l)
  171. throw std::out_of_range("Buffer: field() beyond end of data");
  172. return (const unsigned char *)(_b + i);
  173. }
  174. /**
  175. * Place a primitive integer value at a given position
  176. *
  177. * @param i Index to place value
  178. * @param v Value
  179. * @tparam T Integer type (e.g. uint16_t, int64_t)
  180. */
  181. template<typename T>
  182. inline void setAt(unsigned int i,const T v)
  183. throw(std::out_of_range)
  184. {
  185. if ((i + sizeof(T)) > _l)
  186. throw std::out_of_range("Buffer: setAt() beyond end of data");
  187. #ifdef ZT_NO_TYPE_PUNNING
  188. uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
  189. for(unsigned int x=1;x<=sizeof(T);++x)
  190. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  191. #else
  192. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
  193. *p = Utils::hton(v);
  194. #endif
  195. }
  196. /**
  197. * Get a primitive integer value at a given position
  198. *
  199. * @param i Index to get integer
  200. * @tparam T Integer type (e.g. uint16_t, int64_t)
  201. * @return Integer value
  202. */
  203. template<typename T>
  204. inline T at(unsigned int i) const
  205. throw(std::out_of_range)
  206. {
  207. if ((i + sizeof(T)) > _l)
  208. throw std::out_of_range("Buffer: at() beyond end of data");
  209. #ifdef ZT_NO_TYPE_PUNNING
  210. T v = 0;
  211. const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
  212. for(unsigned int x=0;x<sizeof(T);++x) {
  213. v <<= 8;
  214. v |= (T)*(p++);
  215. }
  216. return v;
  217. #else
  218. const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
  219. return Utils::ntoh(*p);
  220. #endif
  221. }
  222. /**
  223. * Append an integer type to this buffer
  224. *
  225. * @param v Value to append
  226. * @tparam T Integer type (e.g. uint16_t, int64_t)
  227. * @throws std::out_of_range Attempt to append beyond capacity
  228. */
  229. template<typename T>
  230. inline void append(const T v)
  231. throw(std::out_of_range)
  232. {
  233. if ((_l + sizeof(T)) > C)
  234. throw std::out_of_range("Buffer: append beyond capacity");
  235. #ifdef ZT_NO_TYPE_PUNNING
  236. uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
  237. for(unsigned int x=1;x<=sizeof(T);++x)
  238. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  239. #else
  240. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
  241. *p = Utils::hton(v);
  242. #endif
  243. _l += sizeof(T);
  244. }
  245. /**
  246. * Append a run of bytes
  247. *
  248. * @param c Character value to append
  249. * @param n Number of times to append
  250. * @throws std::out_of_range Attempt to append beyond capacity
  251. */
  252. inline void append(unsigned char c,unsigned int n)
  253. throw(std::out_of_range)
  254. {
  255. if ((_l + n) > C)
  256. throw std::out_of_range("Buffer: append beyond capacity");
  257. for(unsigned int i=0;i<n;++i)
  258. _b[_l++] = (char)c;
  259. }
  260. /**
  261. * Append a C-array of bytes
  262. *
  263. * @param b Data
  264. * @param l Length
  265. * @throws std::out_of_range Attempt to append beyond capacity
  266. */
  267. inline void append(const void *b,unsigned int l)
  268. throw(std::out_of_range)
  269. {
  270. if ((_l + l) > C)
  271. throw std::out_of_range("Buffer: append beyond capacity");
  272. memcpy(_b + _l,b,l);
  273. _l += l;
  274. }
  275. /**
  276. * Append a string
  277. *
  278. * @param s String to append
  279. * @throws std::out_of_range Attempt to append beyond capacity
  280. */
  281. inline void append(const std::string &s)
  282. throw(std::out_of_range)
  283. {
  284. append(s.data(),(unsigned int)s.length());
  285. }
  286. /**
  287. * Append a buffer
  288. *
  289. * @param b Buffer to append
  290. * @tparam C2 Capacity of second buffer (typically inferred)
  291. * @throws std::out_of_range Attempt to append beyond capacity
  292. */
  293. template<unsigned int C2>
  294. inline void append(const Buffer<C2> &b)
  295. throw(std::out_of_range)
  296. {
  297. append(b._b,b._l);
  298. }
  299. /**
  300. * Increment size and return pointer to field of specified size
  301. *
  302. * Nothing is actually written to the memory. This is a shortcut
  303. * for addSize() followed by field() to reference the previous
  304. * position and the new size.
  305. *
  306. * @param l Length of field to append
  307. * @return Pointer to beginning of appended field of length 'l'
  308. */
  309. inline char *appendField(unsigned int l)
  310. throw(std::out_of_range)
  311. {
  312. if ((_l + l) > C)
  313. throw std::out_of_range("Buffer: append beyond capacity");
  314. char *r = _b + _l;
  315. _l += l;
  316. return r;
  317. }
  318. /**
  319. * Increment size by a given number of bytes
  320. *
  321. * The contents of new space are undefined.
  322. *
  323. * @param i Bytes to increment
  324. * @throws std::out_of_range Capacity exceeded
  325. */
  326. inline void addSize(unsigned int i)
  327. throw(std::out_of_range)
  328. {
  329. if ((i + _l) > C)
  330. throw std::out_of_range("Buffer: setSize to larger than capacity");
  331. _l += i;
  332. }
  333. /**
  334. * Set size of data in buffer
  335. *
  336. * The contents of new space are undefined.
  337. *
  338. * @param i New size
  339. * @throws std::out_of_range Size larger than capacity
  340. */
  341. inline void setSize(const unsigned int i)
  342. throw(std::out_of_range)
  343. {
  344. if (i > C)
  345. throw std::out_of_range("Buffer: setSize to larger than capacity");
  346. _l = i;
  347. }
  348. /**
  349. * Move everything after 'at' to the buffer's front and truncate
  350. *
  351. * @param at Truncate before this position
  352. * @throw std::out_of_range Position is beyond size of buffer
  353. */
  354. inline void behead(const unsigned int at)
  355. throw(std::out_of_range)
  356. {
  357. if (!at)
  358. return;
  359. if (at > _l)
  360. throw std::out_of_range("Buffer: behead() beyond capacity");
  361. ::memmove(_b,_b + at,_l -= at);
  362. }
  363. /**
  364. * Set buffer data length to zero
  365. */
  366. inline void clear()
  367. throw()
  368. {
  369. _l = 0;
  370. }
  371. /**
  372. * Zero buffer up to size()
  373. */
  374. inline void zero()
  375. throw()
  376. {
  377. memset(_b,0,_l);
  378. }
  379. /**
  380. * Zero unused capacity area
  381. */
  382. inline void zeroUnused()
  383. throw()
  384. {
  385. memset(_b + _l,0,C - _l);
  386. }
  387. /**
  388. * Unconditionally and securely zero buffer's underlying memory
  389. */
  390. inline void burn()
  391. throw()
  392. {
  393. Utils::burn(_b,sizeof(_b));
  394. }
  395. /**
  396. * @return Constant pointer to data in buffer
  397. */
  398. inline const void *data() const throw() { return _b; }
  399. /**
  400. * @return Size of data in buffer
  401. */
  402. inline unsigned int size() const throw() { return _l; }
  403. /**
  404. * @return Capacity of buffer
  405. */
  406. inline unsigned int capacity() const throw() { return C; }
  407. template<unsigned int C2>
  408. inline bool operator==(const Buffer<C2> &b) const
  409. throw()
  410. {
  411. return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
  412. }
  413. template<unsigned int C2>
  414. inline bool operator!=(const Buffer<C2> &b) const
  415. throw()
  416. {
  417. return ((_l != b._l)||(memcmp(_b,b._b,_l)));
  418. }
  419. template<unsigned int C2>
  420. inline bool operator<(const Buffer<C2> &b) const
  421. throw()
  422. {
  423. return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
  424. }
  425. template<unsigned int C2>
  426. inline bool operator>(const Buffer<C2> &b) const
  427. throw()
  428. {
  429. return (b < *this);
  430. }
  431. template<unsigned int C2>
  432. inline bool operator<=(const Buffer<C2> &b) const
  433. throw()
  434. {
  435. return !(b < *this);
  436. }
  437. template<unsigned int C2>
  438. inline bool operator>=(const Buffer<C2> &b) const
  439. throw()
  440. {
  441. return !(*this < b);
  442. }
  443. private:
  444. unsigned int _l;
  445. char ZT_VAR_MAY_ALIAS _b[C];
  446. };
  447. } // namespace ZeroTier
  448. #endif