2
0

Buffer.hpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  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 <stdexcept>
  30. #include <string>
  31. #include <algorithm>
  32. #include <utility>
  33. #include <string.h>
  34. #include <stdint.h>
  35. #include "Utils.hpp"
  36. #ifdef __GNUC__
  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 unsigned char * const_pointer;
  65. typedef unsigned char & reference;
  66. typedef const unsigned char & const_reference;
  67. typedef unsigned char * iterator;
  68. typedef const unsigned 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. throw() :
  83. _l(0)
  84. {
  85. }
  86. Buffer(unsigned int l)
  87. throw(std::out_of_range)
  88. {
  89. if (l > C)
  90. throw std::out_of_range("Buffer: construct with size larger than capacity");
  91. _l = l;
  92. }
  93. template<unsigned int C2>
  94. Buffer(const Buffer<C2> &b)
  95. throw(std::out_of_range)
  96. {
  97. *this = b;
  98. }
  99. Buffer(const void *b,unsigned int l)
  100. throw(std::out_of_range)
  101. {
  102. copyFrom(b,l);
  103. }
  104. Buffer(const std::string &s)
  105. throw(std::out_of_range)
  106. {
  107. copyFrom(s.data(),s.length());
  108. }
  109. template<unsigned int C2>
  110. inline Buffer &operator=(const Buffer<C2> &b)
  111. throw(std::out_of_range)
  112. {
  113. if (b._l > C)
  114. throw std::out_of_range("Buffer: assignment from buffer larger than capacity");
  115. memcpy(this,&b,sizeof(_l) + b._l); // one memcpy for all fields
  116. return *this;
  117. }
  118. inline Buffer &operator=(const std::string &s)
  119. throw(std::out_of_range)
  120. {
  121. copyFrom(s.data(),s.length());
  122. return *this;
  123. }
  124. inline void copyFrom(const void *b,unsigned int l)
  125. throw(std::out_of_range)
  126. {
  127. if (l > C)
  128. throw std::out_of_range("Buffer: set from C array larger than capacity");
  129. _l = l;
  130. memcpy(_b,b,l);
  131. }
  132. unsigned char operator[](const unsigned int i) const
  133. throw(std::out_of_range)
  134. {
  135. if (i >= _l)
  136. throw std::out_of_range("Buffer: [] beyond end of data");
  137. return (unsigned char)_b[i];
  138. }
  139. unsigned char &operator[](const unsigned int i)
  140. throw(std::out_of_range)
  141. {
  142. if (i >= _l)
  143. throw std::out_of_range("Buffer: [] beyond end of data");
  144. return ((unsigned char *)_b)[i];
  145. }
  146. unsigned char *data() throw() { return (unsigned char *)_b; }
  147. const unsigned char *data() const throw() { return (const unsigned char *)_b; }
  148. /**
  149. * Safe way to get a pointer to a field from data() with bounds checking
  150. *
  151. * @param i Index of field in buffer
  152. * @param l Length of field in bytes
  153. * @return Pointer to field data
  154. * @throws std::out_of_range Field extends beyond data size
  155. */
  156. unsigned char *field(unsigned int i,unsigned int l)
  157. throw(std::out_of_range)
  158. {
  159. if ((i + l) > _l)
  160. throw std::out_of_range("Buffer: field() beyond end of data");
  161. return (unsigned char *)(_b + i);
  162. }
  163. const unsigned char *field(unsigned int i,unsigned int l) const
  164. throw(std::out_of_range)
  165. {
  166. if ((i + l) > _l)
  167. throw std::out_of_range("Buffer: field() beyond end of data");
  168. return (const unsigned char *)(_b + i);
  169. }
  170. /**
  171. * Place a primitive integer value at a given position
  172. *
  173. * @param i Index to place value
  174. * @param v Value
  175. * @tparam T Integer type (e.g. uint16_t, int64_t)
  176. */
  177. template<typename T>
  178. inline void setAt(unsigned int i,const T v)
  179. throw(std::out_of_range)
  180. {
  181. if ((i + sizeof(T)) > _l)
  182. throw std::out_of_range("Buffer: set() beyond end of data");
  183. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
  184. *p = Utils::hton(v);
  185. }
  186. /**
  187. * Get a primitive integer value at a given position
  188. *
  189. * This behaves like set() in reverse.
  190. *
  191. * @param i Index to get integer
  192. * @tparam T Integer type (e.g. uint16_t, int64_t)
  193. * @return Integer value
  194. */
  195. template<typename T>
  196. inline T at(unsigned int i) const
  197. throw(std::out_of_range)
  198. {
  199. if ((i + sizeof(T)) > _l)
  200. throw std::out_of_range("Buffer: at() beyond end of data");
  201. const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
  202. return Utils::ntoh(*p);
  203. }
  204. /**
  205. * Append an integer type to this buffer
  206. *
  207. * @param v Value to append
  208. * @tparam T Integer type (e.g. uint16_t, int64_t)
  209. * @throws std::out_of_range Attempt to append beyond capacity
  210. */
  211. template<typename T>
  212. inline void append(const T v)
  213. throw(std::out_of_range)
  214. {
  215. if ((_l + sizeof(T)) > C)
  216. throw std::out_of_range("Buffer: append beyond capacity");
  217. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
  218. *p = Utils::hton(v);
  219. _l += sizeof(T);
  220. }
  221. /**
  222. * Append a run of bytes
  223. *
  224. * @param c Character value to append
  225. * @param n Number of times to append
  226. * @throws std::out_of_range Attempt to append beyond capacity
  227. */
  228. inline void append(unsigned char c,unsigned int n)
  229. throw(std::out_of_range)
  230. {
  231. if ((_l + n) > C)
  232. throw std::out_of_range("Buffer: append beyond capacity");
  233. for(unsigned int i=0;i<n;++i)
  234. _b[_l++] = (char)c;
  235. }
  236. /**
  237. * Append a C-array of bytes
  238. *
  239. * @param b Data
  240. * @param l Length
  241. * @throws std::out_of_range Attempt to append beyond capacity
  242. */
  243. inline void append(const void *b,unsigned int l)
  244. throw(std::out_of_range)
  245. {
  246. if ((_l + l) > C)
  247. throw std::out_of_range("Buffer: append beyond capacity");
  248. memcpy(_b + _l,b,l);
  249. _l += l;
  250. }
  251. /**
  252. * Append a string
  253. *
  254. * @param s String to append
  255. * @throws std::out_of_range Attempt to append beyond capacity
  256. */
  257. inline void append(const std::string &s)
  258. throw(std::out_of_range)
  259. {
  260. append(s.data(),s.length());
  261. }
  262. /**
  263. * Append a buffer
  264. *
  265. * @param b Buffer to append
  266. * @tparam C2 Capacity of second buffer (typically inferred)
  267. * @throws std::out_of_range Attempt to append beyond capacity
  268. */
  269. template<unsigned int C2>
  270. inline void append(const Buffer<C2> &b)
  271. throw(std::out_of_range)
  272. {
  273. append(b._b,b._l);
  274. }
  275. /**
  276. * Increment size by a given number of bytes
  277. *
  278. * The contents of new space are undefined.
  279. *
  280. * @param i Bytes to increment
  281. * @throws std::out_of_range Capacity exceeded
  282. */
  283. inline void addSize(unsigned int i)
  284. throw(std::out_of_range)
  285. {
  286. if ((i + _l) > C)
  287. throw std::out_of_range("Buffer: setSize to larger than capacity");
  288. _l += i;
  289. }
  290. /**
  291. * Set size of data in buffer
  292. *
  293. * The contents of new space are undefined.
  294. *
  295. * @param i New size
  296. * @throws std::out_of_range Size larger than capacity
  297. */
  298. inline void setSize(const unsigned int i)
  299. throw(std::out_of_range)
  300. {
  301. if (i > C)
  302. throw std::out_of_range("Buffer: setSize to larger than capacity");
  303. _l = i;
  304. }
  305. /**
  306. * Set buffer data length to zero
  307. */
  308. inline void clear()
  309. throw()
  310. {
  311. _l = 0;
  312. }
  313. /**
  314. * Zero buffer up to size()
  315. */
  316. inline void zero()
  317. throw()
  318. {
  319. memset(_b,0,_l);
  320. }
  321. /**
  322. * Zero unused capacity area
  323. */
  324. inline void zeroUnused()
  325. throw()
  326. {
  327. memset(_b + _l,0,C - _l);
  328. }
  329. /**
  330. * @return Size of data in buffer
  331. */
  332. inline unsigned int size() const throw() { return _l; }
  333. /**
  334. * @return Capacity of buffer
  335. */
  336. inline unsigned int capacity() const throw() { return C; }
  337. template<unsigned int C2>
  338. inline bool operator==(const Buffer<C2> &b) const
  339. throw()
  340. {
  341. return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
  342. }
  343. template<unsigned int C2>
  344. inline bool operator!=(const Buffer<C2> &b) const
  345. throw()
  346. {
  347. return ((_l != b._l)||(memcmp(_b,b._b,_l)));
  348. }
  349. template<unsigned int C2>
  350. inline bool operator<(const Buffer<C2> &b) const
  351. throw()
  352. {
  353. return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
  354. }
  355. template<unsigned int C2>
  356. inline bool operator>(const Buffer<C2> &b) const
  357. throw()
  358. {
  359. return (b < *this);
  360. }
  361. template<unsigned int C2>
  362. inline bool operator<=(const Buffer<C2> &b) const
  363. throw()
  364. {
  365. return !(b < *this);
  366. }
  367. template<unsigned int C2>
  368. inline bool operator>=(const Buffer<C2> &b) const
  369. throw()
  370. {
  371. return !(*this < b);
  372. }
  373. private:
  374. unsigned int _l;
  375. char ZT_VAR_MAY_ALIAS _b[C];
  376. };
  377. } // namespace ZeroTier
  378. #endif