Buf.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2025-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_BUF_HPP
  14. #define ZT_BUF_HPP
  15. #include "Constants.hpp"
  16. #include "Utils.hpp"
  17. #include "SharedPtr.hpp"
  18. #include "Mutex.hpp"
  19. #include "TriviallyCopyable.hpp"
  20. #include "FCV.hpp"
  21. #include <stdexcept>
  22. #include <utility>
  23. #include <algorithm>
  24. #include <new>
  25. // Buffers are 16384 bytes in size because this is the smallest size that can hold any packet
  26. // and is a power of two. It needs to be a power of two because masking is significantly faster
  27. // than integer division modulus.
  28. #define ZT_BUF_MEM_SIZE 0x00004000
  29. #define ZT_BUF_MEM_MASK 0x00003fffU
  30. // Sanity limit on maximum buffer pool size
  31. #define ZT_BUF_MAX_POOL_SIZE 1024
  32. namespace ZeroTier {
  33. /**
  34. * Buffer and methods for branch-free bounds-checked data assembly and parsing
  35. *
  36. * This implements an extremely fast buffer for packet assembly and parsing that avoids
  37. * branching whenever possible. To be safe it must be used correctly!
  38. *
  39. * The read methods are prefixed by 'r', and write methods with 'w'. All methods take
  40. * an iterator, which is just an int that should be initialized to 0 (or whatever starting
  41. * position is desired). All read methods will advance the iterator regardless of outcome.
  42. *
  43. * Read and write methods fail silently in the event of overflow. They do not corrupt or
  44. * access memory outside the bounds of Buf, but will otherwise produce undefined results.
  45. *
  46. * IT IS THE RESPONSIBILITY OF THE USER of this class to use the readOverflow() and
  47. * writeOverflow() static methods to check the iterator for overflow after each series
  48. * of reads and writes and BEFORE ANY PARSING or other decisions are made on the basis
  49. * of the data obtained from a buffer. Failure to do so can result in bugs due
  50. * to parsing and branching on undefined or corrupt data.
  51. *
  52. * ^^ THIS IS VERY IMPORTANT ^^
  53. *
  54. * A typical packet assembly consists of repeated calls to the write methods followed by
  55. * a check to writeOverflow() before final packet armoring and transport. A typical packet
  56. * disassembly and parsing consists of a series of read calls to obtain the packet's
  57. * fields followed by a call to readOverflow() to check that these fields are valid. The
  58. * packet is discarded if readOverflow() returns true. Some packet parsers may make
  59. * additional reads and in this case readOverflow() must be checked after each set of
  60. * reads to ensure that overflow did not occur.
  61. *
  62. * Buf uses a lock-free pool for extremely fast allocation and deallocation.
  63. *
  64. * Buf can optionally take a template parameter that will be placed in the 'data'
  65. * union as 'fields.' This must be a basic plain data type and must be no larger than
  66. * ZT_BUF_MEM_SIZE. It's typically a packed struct.
  67. *
  68. * Buf instances with different template parameters can freely be cast to one another
  69. * as there is no actual difference in size or layout.
  70. *
  71. * @tparam U Type to overlap with data bytes in data union (can't be larger than ZT_BUF_MEM_SIZE)
  72. */
  73. class Buf
  74. {
  75. friend class SharedPtr< Buf >;
  76. public:
  77. // New and delete operators that allocate Buf instances from a shared lock-free memory pool.
  78. static void *operator new(std::size_t sz);
  79. static void operator delete(void *ptr);
  80. /**
  81. * Raw data held in buffer
  82. *
  83. * The additional eight bytes should not be used and should be considered undefined.
  84. * They exist to allow reads and writes of integer types to silently overflow if a
  85. * read or write is performed at the end of the buffer.
  86. */
  87. uint8_t unsafeData[ZT_BUF_MEM_SIZE + 8];
  88. /**
  89. * Free all instances of Buf in shared pool.
  90. *
  91. * New buffers will be created and the pool repopulated if get() is called
  92. * and outstanding buffers will still be returned to the pool. This just
  93. * frees buffers currently held in reserve.
  94. */
  95. static void freePool() noexcept;
  96. /**
  97. * @return Number of Buf objects currently allocated via pool mechanism
  98. */
  99. static long poolAllocated() noexcept;
  100. /**
  101. * Slice is almost exactly like the built-in slice data structure in Go
  102. */
  103. struct Slice : TriviallyCopyable
  104. {
  105. ZT_INLINE Slice(const SharedPtr< Buf > &b_, const unsigned int s_, const unsigned int e_) noexcept: b(b_), s(s_), e(e_)
  106. {}
  107. ZT_INLINE Slice() noexcept: b(), s(0), e(0)
  108. {}
  109. ZT_INLINE operator bool() const noexcept
  110. { return (b); }
  111. ZT_INLINE unsigned int size() const noexcept
  112. { return (e - s); }
  113. ZT_INLINE void zero() noexcept
  114. {
  115. b.zero();
  116. s = 0;
  117. e = 0;
  118. }
  119. /**
  120. * Buffer holding slice data
  121. */
  122. SharedPtr< Buf > b;
  123. /**
  124. * Index of start of data in slice
  125. */
  126. unsigned int s;
  127. /**
  128. * Index of end of data in slice (make sure it's greater than or equal to 's'!)
  129. */
  130. unsigned int e;
  131. };
  132. /**
  133. * A vector of slices making up a packet that might span more than one buffer.
  134. */
  135. class PacketVector : public ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS >
  136. {
  137. public:
  138. ZT_INLINE PacketVector() : ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS >()
  139. {}
  140. ZT_INLINE unsigned int totalSize() const noexcept
  141. {
  142. unsigned int size = 0;
  143. for (PacketVector::const_iterator s(begin()); s != end(); ++s)
  144. size += s->e - s->s;
  145. return size;
  146. }
  147. /**
  148. * Merge this packet vector into a single destination buffer
  149. *
  150. * @param b Destination buffer
  151. * @return Size of data in destination or -1 on error
  152. */
  153. ZT_INLINE int mergeCopy(Buf &b) const noexcept
  154. {
  155. unsigned int size = 0;
  156. for (PacketVector::const_iterator s(begin()); s != end(); ++s) {
  157. const unsigned int start = s->s;
  158. const unsigned int rem = s->e - start;
  159. if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) {
  160. Utils::copy(b.unsafeData + size, s->b->unsafeData + start, rem);
  161. size += rem;
  162. } else {
  163. return -1;
  164. }
  165. }
  166. return (int)size;
  167. }
  168. /**
  169. * Merge this packet vector into a single destination buffer with an arbitrary copy function
  170. *
  171. * This can be used to e.g. simultaneously merge and decrypt a packet.
  172. *
  173. * @param b Destination buffer
  174. * @param simpleCopyBefore Don't start using copyFunction until this index (0 to always use)
  175. * @param copyFunction Function to invoke with memcpy-like arguments: (dest, source, size)
  176. * @tparam F Type of copyFunction (typically inferred)
  177. * @return Size of data in destination or -1 on error
  178. */
  179. template< typename F >
  180. ZT_INLINE int mergeMap(Buf &b, const unsigned int simpleCopyBefore, F copyFunction) const noexcept
  181. {
  182. unsigned int size = 0;
  183. for (PacketVector::const_iterator s(begin()); s != end(); ++s) {
  184. unsigned int start = s->s;
  185. unsigned int rem = s->e - start;
  186. if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) {
  187. if (size < simpleCopyBefore) {
  188. unsigned int sc = simpleCopyBefore - size;
  189. if (unlikely(sc > rem))
  190. sc = rem;
  191. Utils::copy(b.unsafeData + size, s->b->unsafeData + start, sc);
  192. start += sc;
  193. rem -= sc;
  194. }
  195. if (likely(rem > 0)) {
  196. copyFunction(b.unsafeData + size, s->b->unsafeData + start, rem);
  197. size += rem;
  198. }
  199. } else {
  200. return -1;
  201. }
  202. }
  203. return (int)size;
  204. }
  205. };
  206. /**
  207. * Create a new uninitialized buffer with undefined contents (use clear() to zero if needed)
  208. */
  209. ZT_INLINE Buf() noexcept: __nextInPool(0), __refCount(0)
  210. {}
  211. /**
  212. * Create a new buffer and copy data into it
  213. */
  214. ZT_INLINE Buf(const void *const data, const unsigned int len) noexcept:
  215. __refCount(0)
  216. {
  217. Utils::copy(unsafeData, data, len);
  218. }
  219. ZT_INLINE Buf(const Buf &b2) noexcept:
  220. __nextInPool(0),
  221. __refCount(0)
  222. {
  223. Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData);
  224. }
  225. ZT_INLINE Buf &operator=(const Buf &b2) noexcept
  226. {
  227. if (this != &b2)
  228. Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData);
  229. return *this;
  230. }
  231. /**
  232. * Check for overflow beyond the size of the buffer
  233. *
  234. * This is used to check for overflow when writing. It returns true if the iterator
  235. * has passed beyond the capacity of the buffer.
  236. *
  237. * @param ii Iterator to check
  238. * @return True if iterator has read past the size of the buffer
  239. */
  240. static ZT_INLINE bool writeOverflow(const int &ii) noexcept
  241. { return ((ii - ZT_BUF_MEM_SIZE) > 0); }
  242. /**
  243. * Check for overflow beyond the size of the data that should be in the buffer
  244. *
  245. * This is used to check for overflow when reading, with the second argument being the
  246. * size of the meaningful data actually present in the buffer.
  247. *
  248. * @param ii Iterator to check
  249. * @param size Size of data that should be in buffer
  250. * @return True if iterator has read past the size of the data
  251. */
  252. static ZT_INLINE bool readOverflow(const int &ii, const unsigned int size) noexcept
  253. { return ((ii - (int)size) > 0); }
  254. /**
  255. * Set all memory to zero
  256. */
  257. ZT_INLINE void clear() noexcept
  258. {
  259. Utils::zero< ZT_BUF_MEM_SIZE >(unsafeData);
  260. }
  261. /**
  262. * Read a byte
  263. *
  264. * @param ii Index value-result parameter (incremented by 1)
  265. * @return Byte (undefined on overflow)
  266. */
  267. ZT_INLINE uint8_t rI8(int &ii) const noexcept
  268. {
  269. const int s = ii++;
  270. return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK];
  271. }
  272. /**
  273. * Read a 16-bit integer
  274. *
  275. * @param ii Index value-result parameter (incremented by 2)
  276. * @return Integer (undefined on overflow)
  277. */
  278. ZT_INLINE uint16_t rI16(int &ii) const noexcept
  279. {
  280. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  281. ii += 2;
  282. #ifdef ZT_NO_UNALIGNED_ACCESS
  283. return (
  284. ((uint16_t)unsafeData[s] << 8U) |
  285. (uint16_t)unsafeData[s + 1]);
  286. #else
  287. return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s));
  288. #endif
  289. }
  290. /**
  291. * Read a 32-bit integer
  292. *
  293. * @param ii Index value-result parameter (incremented by 4)
  294. * @return Integer (undefined on overflow)
  295. */
  296. ZT_INLINE uint32_t rI32(int &ii) const noexcept
  297. {
  298. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  299. ii += 4;
  300. #ifdef ZT_NO_UNALIGNED_ACCESS
  301. return (
  302. ((uint32_t)unsafeData[s] << 24U) |
  303. ((uint32_t)unsafeData[s + 1] << 16U) |
  304. ((uint32_t)unsafeData[s + 2] << 8U) |
  305. (uint32_t)unsafeData[s + 3]);
  306. #else
  307. return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s));
  308. #endif
  309. }
  310. /**
  311. * Read a 64-bit integer
  312. *
  313. * @param ii Index value-result parameter (incremented by 8)
  314. * @return Integer (undefined on overflow)
  315. */
  316. ZT_INLINE uint64_t rI64(int &ii) const noexcept
  317. {
  318. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  319. ii += 8;
  320. #ifdef ZT_NO_UNALIGNED_ACCESS
  321. return (
  322. ((uint64_t)unsafeData[s] << 56U) |
  323. ((uint64_t)unsafeData[s + 1] << 48U) |
  324. ((uint64_t)unsafeData[s + 2] << 40U) |
  325. ((uint64_t)unsafeData[s + 3] << 32U) |
  326. ((uint64_t)unsafeData[s + 4] << 24U) |
  327. ((uint64_t)unsafeData[s + 5] << 16U) |
  328. ((uint64_t)unsafeData[s + 6] << 8U) |
  329. (uint64_t)unsafeData[s + 7]);
  330. #else
  331. return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s));
  332. #endif
  333. }
  334. /**
  335. * Read an object supporting the marshal/unmarshal interface
  336. *
  337. * If the return value is negative the object's state is undefined. A return value of
  338. * zero typically also indicates a problem, though this may depend on the object type.
  339. *
  340. * Since objects may be invalid even if there is no overflow, it's important to check
  341. * the return value of this function in all cases and discard invalid packets as it
  342. * indicates.
  343. *
  344. * @tparam T Object type
  345. * @param ii Index value-result parameter (incremented by object's size in bytes)
  346. * @param obj Object to read
  347. * @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
  348. */
  349. template< typename T >
  350. ZT_INLINE int rO(int &ii, T &obj) const noexcept
  351. {
  352. if (likely(ii < ZT_BUF_MEM_SIZE)) {
  353. int ms = obj.unmarshal(unsafeData + ii, ZT_BUF_MEM_SIZE - ii);
  354. if (ms > 0)
  355. ii += ms;
  356. return ms;
  357. }
  358. return -1;
  359. }
  360. /**
  361. * Read a C-style string from the buffer, making a copy and advancing the iterator
  362. *
  363. * Use this if the buffer's memory may get changed between reading and processing
  364. * what is read.
  365. *
  366. * @param ii Index value-result parameter (incremented by length of string)
  367. * @param buf Buffer to receive string
  368. * @param bufSize Capacity of buffer in bytes
  369. * @return Pointer to buf or NULL on overflow or error
  370. */
  371. ZT_INLINE char *rS(int &ii, char *const buf, const unsigned int bufSize) const noexcept
  372. {
  373. const char *const s = (const char *)(unsafeData + ii);
  374. const int sii = ii;
  375. while (ii < ZT_BUF_MEM_SIZE) {
  376. if (unsafeData[ii++] == 0) {
  377. const int l = ii - sii;
  378. if (unlikely((unsigned int)l > bufSize))
  379. return nullptr;
  380. Utils::copy(buf, s, l);
  381. return buf;
  382. }
  383. }
  384. return nullptr;
  385. }
  386. /**
  387. * Obtain a pointer to a C-style string in the buffer without copying and advance the iterator
  388. *
  389. * The iterator is advanced even if this fails and returns NULL so that readOverflow()
  390. * will indicate that an overflow occurred. As with other reads the string's contents are
  391. * undefined if readOverflow() returns true.
  392. *
  393. * This version avoids a copy and so is faster if the buffer won't be modified between
  394. * reading and processing.
  395. *
  396. * @param ii Index value-result parameter (incremented by length of string)
  397. * @return Pointer to null-terminated C-style string or NULL on overflow or error
  398. */
  399. ZT_INLINE const char *rSnc(int &ii) const noexcept
  400. {
  401. const char *const s = (const char *)(unsafeData + ii);
  402. while (ii < ZT_BUF_MEM_SIZE) {
  403. if (unsafeData[ii++] == 0)
  404. return s;
  405. }
  406. return nullptr;
  407. }
  408. /**
  409. * Read a byte array from the buffer, making a copy and advancing the iterator
  410. *
  411. * Use this if the buffer's memory may get changed between reading and processing
  412. * what is read.
  413. *
  414. * @param ii Index value-result parameter (incremented by len)
  415. * @param bytes Buffer to contain data to read
  416. * @param len Length of buffer
  417. * @return Pointer to data or NULL on overflow or error
  418. */
  419. ZT_INLINE uint8_t *rB(int &ii, void *const bytes, const unsigned int len) const noexcept
  420. {
  421. if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) {
  422. Utils::copy(bytes, unsafeData + ii, len);
  423. return reinterpret_cast<uint8_t *>(bytes);
  424. }
  425. return nullptr;
  426. }
  427. /**
  428. * Obtain a pointer to a field in the buffer without copying and advance the iterator
  429. *
  430. * The iterator is advanced even if this fails and returns NULL so that readOverflow()
  431. * will indicate that an overflow occurred.
  432. *
  433. * This version avoids a copy and so is faster if the buffer won't be modified between
  434. * reading and processing.
  435. *
  436. * @param ii Index value-result parameter (incremented by len)
  437. * @param len Length of data field to obtain a pointer to
  438. * @return Pointer to field or NULL on overflow
  439. */
  440. ZT_INLINE const uint8_t *rBnc(int &ii, unsigned int len) const noexcept
  441. {
  442. const uint8_t *const b = unsafeData + ii;
  443. return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
  444. }
  445. /**
  446. * Load a value at an index that is compile time checked against the maximum buffer size
  447. *
  448. * @tparam I Static index
  449. * @return Value
  450. */
  451. template< unsigned int I >
  452. ZT_INLINE uint8_t lI8() const noexcept
  453. {
  454. static_assert(I < ZT_BUF_MEM_SIZE, "overflow");
  455. return unsafeData[I];
  456. }
  457. /**
  458. * Load a value at an index that is compile time checked against the maximum buffer size
  459. *
  460. * @tparam I Static index
  461. * @return Value
  462. */
  463. template< unsigned int I >
  464. ZT_INLINE uint8_t lI16() const noexcept
  465. {
  466. static_assert((I + 1) < ZT_BUF_MEM_SIZE, "overflow");
  467. #ifdef ZT_NO_UNALIGNED_ACCESS
  468. return (
  469. ((uint16_t)unsafeData[I] << 8U) |
  470. (uint16_t)unsafeData[I + 1]);
  471. #else
  472. return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + I));
  473. #endif
  474. }
  475. /**
  476. * Load a value at an index that is compile time checked against the maximum buffer size
  477. *
  478. * @tparam I Static index
  479. * @return Value
  480. */
  481. template< unsigned int I >
  482. ZT_INLINE uint8_t lI32() const noexcept
  483. {
  484. static_assert((I + 3) < ZT_BUF_MEM_SIZE, "overflow");
  485. #ifdef ZT_NO_UNALIGNED_ACCESS
  486. return (
  487. ((uint32_t)unsafeData[I] << 24U) |
  488. ((uint32_t)unsafeData[I + 1] << 16U) |
  489. ((uint32_t)unsafeData[I + 2] << 8U) |
  490. (uint32_t)unsafeData[I + 3]);
  491. #else
  492. return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + I));
  493. #endif
  494. }
  495. /**
  496. * Load a value at an index that is compile time checked against the maximum buffer size
  497. *
  498. * @tparam I Static index
  499. * @return Value
  500. */
  501. template< unsigned int I >
  502. ZT_INLINE uint8_t lI64() const noexcept
  503. {
  504. static_assert((I + 7) < ZT_BUF_MEM_SIZE, "overflow");
  505. #ifdef ZT_NO_UNALIGNED_ACCESS
  506. return (
  507. ((uint64_t)unsafeData[I] << 56U) |
  508. ((uint64_t)unsafeData[I + 1] << 48U) |
  509. ((uint64_t)unsafeData[I + 2] << 40U) |
  510. ((uint64_t)unsafeData[I + 3] << 32U) |
  511. ((uint64_t)unsafeData[I + 4] << 24U) |
  512. ((uint64_t)unsafeData[I + 5] << 16U) |
  513. ((uint64_t)unsafeData[I + 6] << 8U) |
  514. (uint64_t)unsafeData[I + 7]);
  515. #else
  516. return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + I));
  517. #endif
  518. }
  519. /**
  520. * Load a value at an index without advancing the index
  521. *
  522. * Note that unlike the rI??() methods this does not increment ii and therefore
  523. * will not necessarily result in a 'true' return from readOverflow(). It does
  524. * however subject 'ii' to soft bounds masking like the gI??() methods.
  525. */
  526. ZT_INLINE uint8_t lI8(const int ii) const noexcept
  527. {
  528. return unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK];
  529. }
  530. /**
  531. * Load a value at an index without advancing the index
  532. *
  533. * Note that unlike the rI??() methods this does not increment ii and therefore
  534. * will not necessarily result in a 'true' return from readOverflow(). It does
  535. * however subject 'ii' to soft bounds masking like the gI??() methods.
  536. */
  537. ZT_INLINE uint16_t lI16(const int ii) const noexcept
  538. {
  539. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  540. #ifdef ZT_NO_UNALIGNED_ACCESS
  541. return (
  542. ((uint16_t)unsafeData[s] << 8U) |
  543. (uint16_t)unsafeData[s + 1]);
  544. #else
  545. return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s));
  546. #endif
  547. }
  548. /**
  549. * Load a value at an index without advancing the index
  550. *
  551. * Note that unlike the rI??() methods this does not increment ii and therefore
  552. * will not necessarily result in a 'true' return from readOverflow(). It does
  553. * however subject 'ii' to soft bounds masking like the gI??() methods.
  554. */
  555. ZT_INLINE uint32_t lI32(const int ii) const noexcept
  556. {
  557. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  558. #ifdef ZT_NO_UNALIGNED_ACCESS
  559. return (
  560. ((uint32_t)unsafeData[s] << 24U) |
  561. ((uint32_t)unsafeData[s + 1] << 16U) |
  562. ((uint32_t)unsafeData[s + 2] << 8U) |
  563. (uint32_t)unsafeData[s + 3]);
  564. #else
  565. return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s));
  566. #endif
  567. }
  568. /**
  569. * Load a value at an index without advancing the index
  570. *
  571. * Note that unlike the rI??() methods this does not increment ii and therefore
  572. * will not necessarily result in a 'true' return from readOverflow(). It does
  573. * however subject 'ii' to soft bounds masking like the gI??() methods.
  574. */
  575. ZT_INLINE uint8_t lI64(const int ii) const noexcept
  576. {
  577. const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
  578. #ifdef ZT_NO_UNALIGNED_ACCESS
  579. return (
  580. ((uint64_t)unsafeData[s] << 56U) |
  581. ((uint64_t)unsafeData[s + 1] << 48U) |
  582. ((uint64_t)unsafeData[s + 2] << 40U) |
  583. ((uint64_t)unsafeData[s + 3] << 32U) |
  584. ((uint64_t)unsafeData[s + 4] << 24U) |
  585. ((uint64_t)unsafeData[s + 5] << 16U) |
  586. ((uint64_t)unsafeData[s + 6] << 8U) |
  587. (uint64_t)unsafeData[s + 7]);
  588. #else
  589. return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s));
  590. #endif
  591. }
  592. /**
  593. * Write a byte
  594. *
  595. * @param ii Index value-result parameter (incremented by 1)
  596. * @param n Byte
  597. */
  598. ZT_INLINE void wI8(int &ii, const uint8_t n) noexcept
  599. {
  600. const int s = ii++;
  601. unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n;
  602. }
  603. /**
  604. * Write a 16-bit integer in big-endian byte order
  605. *
  606. * @param ii Index value-result parameter (incremented by 2)
  607. * @param n Integer
  608. */
  609. ZT_INLINE void wI16(int &ii, const uint16_t n) noexcept
  610. {
  611. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  612. ii += 2;
  613. #ifdef ZT_NO_UNALIGNED_ACCESS
  614. unsafeData[s] = (uint8_t)(n >> 8U);
  615. unsafeData[s + 1] = (uint8_t)n;
  616. #else
  617. *reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n);
  618. #endif
  619. }
  620. /**
  621. * Write a 32-bit integer in big-endian byte order
  622. *
  623. * @param ii Index value-result parameter (incremented by 4)
  624. * @param n Integer
  625. */
  626. ZT_INLINE void wI32(int &ii, const uint32_t n) noexcept
  627. {
  628. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  629. ii += 4;
  630. #ifdef ZT_NO_UNALIGNED_ACCESS
  631. unsafeData[s] = (uint8_t)(n >> 24U);
  632. unsafeData[s + 1] = (uint8_t)(n >> 16U);
  633. unsafeData[s + 2] = (uint8_t)(n >> 8U);
  634. unsafeData[s + 3] = (uint8_t)n;
  635. #else
  636. *reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n);
  637. #endif
  638. }
  639. /**
  640. * Write a 64-bit integer in big-endian byte order
  641. *
  642. * @param ii Index value-result parameter (incremented by 8)
  643. * @param n Integer
  644. */
  645. ZT_INLINE void wI64(int &ii, const uint64_t n) noexcept
  646. {
  647. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  648. ii += 8;
  649. #ifdef ZT_NO_UNALIGNED_ACCESS
  650. unsafeData[s] = (uint8_t)(n >> 56U);
  651. unsafeData[s + 1] = (uint8_t)(n >> 48U);
  652. unsafeData[s + 2] = (uint8_t)(n >> 40U);
  653. unsafeData[s + 3] = (uint8_t)(n >> 32U);
  654. unsafeData[s + 4] = (uint8_t)(n >> 24U);
  655. unsafeData[s + 5] = (uint8_t)(n >> 16U);
  656. unsafeData[s + 6] = (uint8_t)(n >> 8U);
  657. unsafeData[s + 7] = (uint8_t)n;
  658. #else
  659. *reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n);
  660. #endif
  661. }
  662. /**
  663. * Write an object implementing the marshal interface
  664. *
  665. * @tparam T Object type
  666. * @param ii Index value-result parameter (incremented by size of object)
  667. * @param t Object to write
  668. */
  669. template< typename T >
  670. ZT_INLINE void wO(int &ii, T &t) noexcept
  671. {
  672. const int s = ii;
  673. if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) {
  674. int ms = t.marshal(unsafeData + s);
  675. if (ms > 0)
  676. ii += ms;
  677. } else {
  678. ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything
  679. }
  680. }
  681. /**
  682. * Write a C-style null-terminated string (including the trailing zero)
  683. *
  684. * @param ii Index value-result parameter (incremented by length of string)
  685. * @param s String to write (writes an empty string if this is NULL)
  686. */
  687. ZT_INLINE void wS(int &ii, const char *s) noexcept
  688. {
  689. if (s) {
  690. char c;
  691. do {
  692. c = *(s++);
  693. wI8(ii, (uint8_t)c);
  694. } while (c);
  695. } else {
  696. wI8(ii, 0);
  697. }
  698. }
  699. /**
  700. * Write a byte array
  701. *
  702. * @param ii Index value-result parameter (incremented by len)
  703. * @param bytes Bytes to write
  704. * @param len Size of data in bytes
  705. */
  706. ZT_INLINE void wB(int &ii, const void *const bytes, const unsigned int len) noexcept
  707. {
  708. const int s = ii;
  709. if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
  710. Utils::copy(unsafeData + s, bytes, len);
  711. }
  712. /**
  713. * Write zeroes
  714. *
  715. * @param ii Index value-result parameter (incremented by len)
  716. * @param len Number of zero bytes to write
  717. */
  718. ZT_INLINE void wZ(int &ii, const unsigned int len) noexcept
  719. {
  720. const int s = ii;
  721. if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
  722. Utils::zero(unsafeData + s, len);
  723. }
  724. /**
  725. * Write secure random bytes
  726. *
  727. * @param ii Index value-result parameter (incremented by len)
  728. * @param len Number of random bytes to write
  729. */
  730. ZT_INLINE void wR(int &ii, const unsigned int len) noexcept
  731. {
  732. const int s = ii;
  733. if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
  734. Utils::getSecureRandom(unsafeData + s, len);
  735. }
  736. /**
  737. * Store a byte without advancing the index
  738. */
  739. ZT_INLINE void sI8(const int ii, const uint8_t n) noexcept
  740. {
  741. unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK] = n;
  742. }
  743. /**
  744. * Store an integer without advancing the index
  745. */
  746. ZT_INLINE void sI16(const int ii, const uint16_t n) noexcept
  747. {
  748. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  749. #ifdef ZT_NO_UNALIGNED_ACCESS
  750. unsafeData[s] = (uint8_t)(n >> 8U);
  751. unsafeData[s + 1] = (uint8_t)n;
  752. #else
  753. *reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n);
  754. #endif
  755. }
  756. /**
  757. * Store an integer without advancing the index
  758. */
  759. ZT_INLINE void sI32(const int ii, const uint32_t n) noexcept
  760. {
  761. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  762. #ifdef ZT_NO_UNALIGNED_ACCESS
  763. unsafeData[s] = (uint8_t)(n >> 24U);
  764. unsafeData[s + 1] = (uint8_t)(n >> 16U);
  765. unsafeData[s + 2] = (uint8_t)(n >> 8U);
  766. unsafeData[s + 3] = (uint8_t)n;
  767. #else
  768. *reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n);
  769. #endif
  770. }
  771. /**
  772. * Store an integer without advancing the index
  773. */
  774. ZT_INLINE void sI64(const int ii, const uint64_t n) noexcept
  775. {
  776. const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
  777. #ifdef ZT_NO_UNALIGNED_ACCESS
  778. unsafeData[s] = (uint8_t)(n >> 56U);
  779. unsafeData[s + 1] = (uint8_t)(n >> 48U);
  780. unsafeData[s + 2] = (uint8_t)(n >> 40U);
  781. unsafeData[s + 3] = (uint8_t)(n >> 32U);
  782. unsafeData[s + 4] = (uint8_t)(n >> 24U);
  783. unsafeData[s + 5] = (uint8_t)(n >> 16U);
  784. unsafeData[s + 6] = (uint8_t)(n >> 8U);
  785. unsafeData[s + 7] = (uint8_t)n;
  786. #else
  787. *reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n);
  788. #endif
  789. }
  790. /**
  791. * @return Capacity of this buffer (usable size of data.bytes)
  792. */
  793. static constexpr unsigned int capacity() noexcept
  794. { return ZT_BUF_MEM_SIZE; }
  795. private:
  796. // Next item in free buffer pool linked list if Buf is placed in pool, undefined and unused otherwise
  797. std::atomic< uintptr_t > __nextInPool;
  798. // Reference counter for SharedPtr<>
  799. std::atomic< int > __refCount;
  800. };
  801. } // namespace ZeroTier
  802. #endif