Buffer.hpp 13 KB

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