Buffer.hpp 12 KB

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