Utils.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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: 2024-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_UTILS_HPP
  14. #define ZT_UTILS_HPP
  15. #include "Constants.hpp"
  16. #ifdef ZT_ARCH_X64
  17. #include <xmmintrin.h>
  18. #include <emmintrin.h>
  19. #include <immintrin.h>
  20. #endif
  21. namespace ZeroTier {
  22. namespace Utils {
  23. #ifndef __WINDOWS__
  24. #include <sys/mman.h>
  25. #endif
  26. // Macros to convert endian-ness at compile time for constants.
  27. #if __BYTE_ORDER == __LITTLE_ENDIAN
  28. #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
  29. #define ZT_CONST_TO_BE_UINT64(x) ( \
  30. (((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \
  31. (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \
  32. (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \
  33. (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \
  34. (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \
  35. (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \
  36. (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \
  37. (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
  38. #else
  39. #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
  40. #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x))
  41. #endif
  42. #ifdef ZT_ARCH_X64
  43. struct CPUIDRegisters
  44. {
  45. uint32_t eax,ebx,ecx,edx;
  46. bool rdrand;
  47. bool aes;
  48. CPUIDRegisters();
  49. };
  50. extern const CPUIDRegisters CPUID;
  51. #endif
  52. /**
  53. * 256 zero bits / 32 zero bytes
  54. */
  55. extern const uint64_t ZERO256[4];
  56. /**
  57. * Hexadecimal characters 0-f
  58. */
  59. extern const char HEXCHARS[16];
  60. /**
  61. * Lock memory to prevent swapping out to secondary storage (if possible)
  62. *
  63. * This is used to attempt to prevent the swapping out of long-term stored secure
  64. * credentials like secret keys. It isn't supported on all platforms and may not
  65. * be absolutely guaranteed to work, but it's a countermeasure.
  66. *
  67. * @param p Memory to lock
  68. * @param l Size of memory
  69. */
  70. static ZT_INLINE void memoryLock(const void *const p,const unsigned int l) noexcept
  71. {
  72. #ifndef __WINDOWS__
  73. mlock(p,l);
  74. #endif
  75. }
  76. /**
  77. * Unlock memory locked with memoryLock()
  78. *
  79. * @param p Memory to unlock
  80. * @param l Size of memory
  81. */
  82. static ZT_INLINE void memoryUnlock(const void *const p,const unsigned int l) noexcept
  83. {
  84. #ifndef __WINDOWS__
  85. munlock(p,l);
  86. #endif
  87. }
  88. /**
  89. * Perform a time-invariant binary comparison
  90. *
  91. * @param a First binary string
  92. * @param b Second binary string
  93. * @param len Length of strings
  94. * @return True if strings are equal
  95. */
  96. bool secureEq(const void *a,const void *b,unsigned int len) noexcept;
  97. /**
  98. * Be absolutely sure to zero memory
  99. *
  100. * This uses some hacks to be totally sure the compiler does not optimize it out.
  101. *
  102. * @param ptr Memory to zero
  103. * @param len Length of memory in bytes
  104. */
  105. void burn(void *ptr,unsigned int len);
  106. /**
  107. * @param n Number to convert
  108. * @param s Buffer, at least 24 bytes in size
  109. * @return String containing 'n' in base 10 form
  110. */
  111. char *decimal(unsigned long n,char s[24]) noexcept;
  112. /**
  113. * Convert an unsigned integer into hex
  114. *
  115. * @param i Any unsigned integer
  116. * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
  117. * @return Pointer to s containing hex string with trailing zero byte
  118. */
  119. char *hex(uint8_t i,char s[3]) noexcept;
  120. /**
  121. * Convert an unsigned integer into hex
  122. *
  123. * @param i Any unsigned integer
  124. * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
  125. * @return Pointer to s containing hex string with trailing zero byte
  126. */
  127. char *hex(uint16_t i,char s[5]) noexcept;
  128. /**
  129. * Convert an unsigned integer into hex
  130. *
  131. * @param i Any unsigned integer
  132. * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
  133. * @return Pointer to s containing hex string with trailing zero byte
  134. */
  135. char *hex(uint32_t i,char s[9]) noexcept;
  136. /**
  137. * Convert an unsigned integer into hex
  138. *
  139. * @param i Any unsigned integer
  140. * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
  141. * @return Pointer to s containing hex string with trailing zero byte
  142. */
  143. char *hex(uint64_t i,char s[17]) noexcept;
  144. /**
  145. * Decode an unsigned integer in hex format
  146. *
  147. * @param s String to decode, non-hex chars are ignored
  148. * @return Unsigned integer
  149. */
  150. uint64_t unhex(const char *s) noexcept;
  151. /**
  152. * Convert a byte array into hex
  153. *
  154. * @param d Bytes
  155. * @param l Length of bytes
  156. * @param s String buffer, must be at least (l*2)+1 in size or overflow will occur
  157. * @return Pointer to filled string buffer
  158. */
  159. char *hex(const void *d,unsigned int l,char *s) noexcept;
  160. /**
  161. * Decode a hex string
  162. *
  163. * @param h Hex C-string (non hex chars are ignored)
  164. * @param hlen Maximum length of string (will stop at terminating zero)
  165. * @param buf Output buffer
  166. * @param buflen Length of output buffer
  167. * @return Number of written bytes
  168. */
  169. unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen) noexcept;
  170. /**
  171. * Generate secure random bytes
  172. *
  173. * This will try to use whatever OS sources of entropy are available. It's
  174. * guarded by an internal mutex so it's thread-safe.
  175. *
  176. * @param buf Buffer to fill
  177. * @param bytes Number of random bytes to generate
  178. */
  179. void getSecureRandom(void *buf,unsigned int bytes) noexcept;
  180. /**
  181. * @return Secure random 64-bit integer
  182. */
  183. uint64_t getSecureRandomU64() noexcept;
  184. /**
  185. * Encode string to base32
  186. *
  187. * @param data Binary data to encode
  188. * @param length Length of data in bytes
  189. * @param result Result buffer
  190. * @param bufSize Size of result buffer
  191. * @return Number of bytes written
  192. */
  193. int b32e(const uint8_t *data,int length,char *result,int bufSize) noexcept;
  194. /**
  195. * Decode base32 string
  196. *
  197. * @param encoded C-string in base32 format (non-base32 characters are ignored)
  198. * @param result Result buffer
  199. * @param bufSize Size of result buffer
  200. * @return Number of bytes written or -1 on error
  201. */
  202. int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept;
  203. /**
  204. * Get a non-cryptographic random integer
  205. */
  206. uint64_t random() noexcept;
  207. /**
  208. * Perform a safe C string copy, ALWAYS null-terminating the result
  209. *
  210. * This will never ever EVER result in dest[] not being null-terminated
  211. * regardless of any input parameter (other than len==0 which is invalid).
  212. *
  213. * @param dest Destination buffer (must not be NULL)
  214. * @param len Length of dest[] (if zero, false is returned and nothing happens)
  215. * @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
  216. * @return True on success, false on overflow (buffer will still be 0-terminated)
  217. */
  218. bool scopy(char *dest,unsigned int len,const char *src) noexcept;
  219. /**
  220. * Mix bits in a 64-bit integer (non-cryptographic)
  221. *
  222. * https://nullprogram.com/blog/2018/07/31/
  223. *
  224. * @param x Integer to mix
  225. * @return Hashed value
  226. */
  227. static ZT_INLINE uint64_t hash64(uint64_t x) noexcept
  228. {
  229. x ^= x >> 30U;
  230. x *= 0xbf58476d1ce4e5b9ULL;
  231. x ^= x >> 27U;
  232. x *= 0x94d049bb133111ebULL;
  233. x ^= x >> 31U;
  234. return x;
  235. }
  236. /**
  237. * Check if a buffer's contents are all zero
  238. */
  239. static ZT_INLINE bool allZero(const void *const b,unsigned int l) noexcept
  240. {
  241. for(unsigned int i=0;i<l;++i) {
  242. if (reinterpret_cast<const uint8_t *>(b)[i] != 0)
  243. return false;
  244. }
  245. return true;
  246. }
  247. /**
  248. * Wrapper around reentrant strtok functions, which differ in name by platform
  249. *
  250. * @param str String to tokenize or NULL for subsequent calls
  251. * @param delim Delimiter
  252. * @param saveptr Pointer to pointer where function can save state
  253. * @return Next token or NULL if none
  254. */
  255. static ZT_INLINE char *stok(char *str,const char *delim,char **saveptr) noexcept
  256. {
  257. #ifdef __WINDOWS__
  258. return strtok_s(str,delim,saveptr);
  259. #else
  260. return strtok_r(str,delim,saveptr);
  261. #endif
  262. }
  263. static ZT_INLINE unsigned int strToUInt(const char *s) noexcept
  264. {
  265. return (unsigned int)strtoul(s,nullptr,10);
  266. }
  267. static ZT_INLINE unsigned long long hexStrToU64(const char *s) noexcept
  268. {
  269. #ifdef __WINDOWS__
  270. return (unsigned long long)_strtoui64(s,nullptr,16);
  271. #else
  272. return strtoull(s,nullptr,16);
  273. #endif
  274. }
  275. /**
  276. * Compute 32-bit FNV-1a checksum
  277. *
  278. * See: http://www.isthe.com/chongo/tech/comp/fnv/
  279. *
  280. * @param data Data to checksum
  281. * @param len Length of data
  282. * @return FNV1a checksum
  283. */
  284. static ZT_INLINE uint32_t fnv1a32(const void *const data,const unsigned int len) noexcept
  285. {
  286. uint32_t h = 0x811c9dc5;
  287. const uint32_t p = 0x01000193;
  288. for(unsigned int i=0;i<len;++i)
  289. h = (h ^ (uint32_t)reinterpret_cast<const uint8_t *>(data)[i]) * p;
  290. return h;
  291. }
  292. #ifdef __GNUC__
  293. static ZT_INLINE unsigned int countBits(const uint8_t v) noexcept { return (unsigned int)__builtin_popcount((unsigned int)v); }
  294. static ZT_INLINE unsigned int countBits(const uint16_t v) noexcept { return (unsigned int)__builtin_popcount((unsigned int)v); }
  295. static ZT_INLINE unsigned int countBits(const uint32_t v) noexcept { return (unsigned int)__builtin_popcountl((unsigned long)v); }
  296. static ZT_INLINE unsigned int countBits(const uint64_t v) noexcept{ return (unsigned int)__builtin_popcountll((unsigned long long)v); }
  297. #else
  298. template<typename T>
  299. static ZT_INLINE unsigned int countBits(T v) noexcept
  300. {
  301. v = v - ((v >> 1) & (T)~(T)0/3);
  302. v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
  303. v = (v + (v >> 4)) & (T)~(T)0/255*15;
  304. return (unsigned int)((v * ((~((T)0))/((T)255))) >> ((sizeof(T) - 1) * 8));
  305. }
  306. #endif
  307. /**
  308. * Unconditionally swap bytes regardless of host byte order
  309. *
  310. * @param n Integer to swap
  311. * @return Integer with bytes reversed
  312. */
  313. static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept
  314. {
  315. #ifdef __GNUC__
  316. return __builtin_bswap64(n);
  317. #else
  318. #ifdef _MSC_VER
  319. return (uint64_t)_byteswap_uint64((unsigned __int64)n);
  320. #else
  321. return (
  322. ((n & 0x00000000000000ffULL) << 56) |
  323. ((n & 0x000000000000ff00ULL) << 40) |
  324. ((n & 0x0000000000ff0000ULL) << 24) |
  325. ((n & 0x00000000ff000000ULL) << 8) |
  326. ((n & 0x000000ff00000000ULL) >> 8) |
  327. ((n & 0x0000ff0000000000ULL) >> 24) |
  328. ((n & 0x00ff000000000000ULL) >> 40) |
  329. ((n & 0xff00000000000000ULL) >> 56)
  330. );
  331. #endif
  332. #endif
  333. }
  334. /**
  335. * Unconditionally swap bytes regardless of host byte order
  336. *
  337. * @param n Integer to swap
  338. * @return Integer with bytes reversed
  339. */
  340. static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept
  341. {
  342. #if defined(__GNUC__)
  343. return __builtin_bswap32(n);
  344. #else
  345. #ifdef _MSC_VER
  346. return (uint32_t)_byteswap_ulong((unsigned long)n);
  347. #else
  348. return htonl(n);
  349. #endif
  350. #endif
  351. }
  352. /**
  353. * Unconditionally swap bytes regardless of host byte order
  354. *
  355. * @param n Integer to swap
  356. * @return Integer with bytes reversed
  357. */
  358. static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept
  359. {
  360. #if defined(__GNUC__)
  361. return __builtin_bswap16(n);
  362. #else
  363. #ifdef _MSC_VER
  364. return (uint16_t)_byteswap_ushort((unsigned short)n);
  365. #else
  366. return htons(n);
  367. #endif
  368. #endif
  369. }
  370. // These are helper adapters to load and swap integer types special cased by size
  371. // to work with all typedef'd variants, signed/unsigned, etc.
  372. template<typename I,unsigned int S>
  373. class _swap_bytes_bysize;
  374. template<typename I>
  375. class _swap_bytes_bysize<I,1> { public: static ZT_INLINE I s(const I n) noexcept { return n; } };
  376. template<typename I>
  377. class _swap_bytes_bysize<I,2> { public: static ZT_INLINE I s(const I n) noexcept { return (I)swapBytes((uint16_t)n); } };
  378. template<typename I>
  379. class _swap_bytes_bysize<I,4> { public: static ZT_INLINE I s(const I n) noexcept { return (I)swapBytes((uint32_t)n); } };
  380. template<typename I>
  381. class _swap_bytes_bysize<I,8> { public: static ZT_INLINE I s(const I n) noexcept { return (I)swapBytes((uint64_t)n); } };
  382. template<typename I,unsigned int S>
  383. class _load_be_bysize;
  384. template<typename I>
  385. class _load_be_bysize<I,1> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return p[0]; }};
  386. template<typename I>
  387. class _load_be_bysize<I,2> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); }};
  388. template<typename I>
  389. class _load_be_bysize<I,4> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); }};
  390. template<typename I>
  391. class _load_be_bysize<I,8> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); }};
  392. template<typename I,unsigned int S>
  393. class _load_le_bysize;
  394. template<typename I>
  395. class _load_le_bysize<I,1> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return p[0]; }};
  396. template<typename I>
  397. class _load_le_bysize<I,2> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); }};
  398. template<typename I>
  399. class _load_le_bysize<I,4> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); }};
  400. template<typename I>
  401. class _load_le_bysize<I,8> { public: static ZT_INLINE I l(const uint8_t *const p) noexcept { return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); }};
  402. /**
  403. * Convert any signed or unsigned integer type to big-endian ("network") byte order
  404. *
  405. * @tparam I Integer type (usually inferred)
  406. * @param n Value to convert
  407. * @return Value in big-endian order
  408. */
  409. template<typename I>
  410. static ZT_INLINE I hton(const I n) noexcept
  411. {
  412. #if __BYTE_ORDER == __LITTLE_ENDIAN
  413. return _swap_bytes_bysize<I,sizeof(I)>::s(n);
  414. #else
  415. return n;
  416. #endif
  417. }
  418. /**
  419. * Convert any signed or unsigned integer type to host byte order from big-endian ("network") byte order
  420. *
  421. * @tparam I Integer type (usually inferred)
  422. * @param n Value to convert
  423. * @return Value in host byte order
  424. */
  425. template<typename I>
  426. static ZT_INLINE I ntoh(const I n) noexcept
  427. {
  428. #if __BYTE_ORDER == __LITTLE_ENDIAN
  429. return _swap_bytes_bysize<I,sizeof(I)>::s(n);
  430. #else
  431. return n;
  432. #endif
  433. }
  434. /**
  435. * Copy bits from memory into an integer type without modifying their order
  436. *
  437. * @tparam I Type to load
  438. * @param p Byte stream, must be at least sizeof(I) in size
  439. * @return Loaded raw integer
  440. */
  441. template<typename I>
  442. static ZT_INLINE I loadAsIsEndian(const void *const p) noexcept
  443. {
  444. #ifdef ZT_NO_UNALIGNED_ACCESS
  445. I tmp;
  446. for(int i=0;i<(int)sizeof(I);++i)
  447. reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i];
  448. return tmp;
  449. #else
  450. return *reinterpret_cast<const I *>(p);
  451. #endif
  452. }
  453. /**
  454. * Copy bits from memory into an integer type without modifying their order
  455. *
  456. * @tparam I Type to store
  457. * @param p Byte array (must be at least sizeof(I))
  458. * @param i Integer to store
  459. */
  460. template<typename I>
  461. static ZT_INLINE void storeAsIsEndian(void *const p,const I i) noexcept
  462. {
  463. #ifdef ZT_NO_UNALIGNED_ACCESS
  464. for(unsigned int k=0;k<sizeof(I);++k)
  465. reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k];
  466. #else
  467. *reinterpret_cast<I *>(p) = i;
  468. #endif
  469. }
  470. /**
  471. * Decode a big-endian value from a byte stream
  472. *
  473. * @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t)
  474. * @param p Byte stream, must be at least sizeof(I) in size
  475. * @return Decoded integer
  476. */
  477. template<typename I>
  478. static ZT_INLINE I loadBigEndian(const void *const p) noexcept
  479. {
  480. #ifdef ZT_NO_UNALIGNED_ACCESS
  481. return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
  482. #else
  483. return ntoh(*reinterpret_cast<const I *>(p));
  484. #endif
  485. }
  486. /**
  487. * Save an integer in big-endian format
  488. *
  489. * @tparam I Integer type to store (usually inferred)
  490. * @param p Byte stream to write (must be at least sizeof(I))
  491. * #param i Integer to write
  492. */
  493. template<typename I>
  494. static ZT_INLINE void storeBigEndian(void *const p,I i) noexcept
  495. {
  496. #ifdef ZT_NO_UNALIGNED_ACCESS
  497. storeAsIsEndian(p,hton(i));
  498. #else
  499. *reinterpret_cast<I *>(p) = hton(i);
  500. #endif
  501. }
  502. /**
  503. * Decode a little-endian value from a byte stream
  504. *
  505. * @tparam I Type to decode
  506. * @param p Byte stream, must be at least sizeof(I) in size
  507. * @return Decoded integer
  508. */
  509. template<typename I>
  510. static ZT_INLINE I loadLittleEndian(const void *const p) noexcept
  511. {
  512. #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
  513. return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
  514. #else
  515. return *reinterpret_cast<const I *>(p);
  516. #endif
  517. }
  518. /**
  519. * Save an integer in little-endian format
  520. *
  521. * @tparam I Integer type to store (usually inferred)
  522. * @param p Byte stream to write (must be at least sizeof(I))
  523. * #param i Integer to write
  524. */
  525. template<typename I>
  526. static ZT_INLINE void storeLittleEndian(void *const p,const I i) noexcept
  527. {
  528. #if __BYTE_ORDER == __BIG_ENDIAN
  529. storeAsIsEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i));
  530. #else
  531. #ifdef ZT_NO_UNALIGNED_ACCESS
  532. storeAsIsEndian(p,i);
  533. #else
  534. *reinterpret_cast<I *>(p) = i;
  535. #endif
  536. #endif
  537. }
  538. /**
  539. * Copy memory block whose size is known at compile time
  540. *
  541. * @tparam L Size of memory
  542. * @param dest Destination memory
  543. * @param src Source memory
  544. */
  545. template<unsigned int L>
  546. static ZT_INLINE void copy(void *const dest,const void *const src) noexcept
  547. {
  548. #ifdef ZT_NO_UNALIGNED_ACCESS
  549. if ((((uintptr_t)dest | (uintptr_t)src) & (sizeof(uintptr_t) - 1)) != 0) {
  550. memcpy(dest,src,L);
  551. return;
  552. }
  553. #endif
  554. uint8_t *d = reinterpret_cast<uint8_t *>(dest);
  555. const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
  556. #ifdef ZT_ARCH_X64
  557. for(unsigned int i=0;i<(L / 64U);++i) {
  558. __m128i x0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
  559. __m128i x1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s) + 1);
  560. __m128i x2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s) + 2);
  561. __m128i x3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s) + 3);
  562. _mm_storeu_si128(reinterpret_cast<__m128i *>(d),x0);
  563. _mm_storeu_si128(reinterpret_cast<__m128i *>(d) + 1,x1);
  564. _mm_storeu_si128(reinterpret_cast<__m128i *>(d) + 2,x2);
  565. _mm_storeu_si128(reinterpret_cast<__m128i *>(d) + 3,x3);
  566. d += 64;
  567. s += 64;
  568. }
  569. if ((L & 63U) >= 32U) {
  570. __m128i x0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
  571. __m128i x1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s) + 1);
  572. _mm_storeu_si128(reinterpret_cast<__m128i *>(d),x0);
  573. _mm_storeu_si128(reinterpret_cast<__m128i *>(d) + 1,x1);
  574. d += 32;
  575. s += 32;
  576. }
  577. if ((L & 31U) >= 16U) {
  578. __m128i x0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
  579. _mm_storeu_si128(reinterpret_cast<__m128i *>(d),x0);
  580. d += 16;
  581. s += 16;
  582. }
  583. if ((L & 15U) >= 8U) {
  584. *reinterpret_cast<uint64_t *>(d) = *reinterpret_cast<const uint64_t *>(s);
  585. d += 8;
  586. s += 8;
  587. }
  588. if ((L & 7U) >= 4U) {
  589. *reinterpret_cast<uint32_t *>(d) = *reinterpret_cast<const uint32_t *>(s);
  590. d += 4;
  591. s += 4;
  592. }
  593. if ((L & 3U) >= 2U) {
  594. *reinterpret_cast<uint16_t *>(d) = *reinterpret_cast<const uint16_t *>(s);
  595. d += 2;
  596. s += 2;
  597. }
  598. if ((L & 1U) != 0U) {
  599. *d = *s;
  600. }
  601. #else
  602. for(unsigned int i=0;i<(L / (sizeof(uintptr_t) * 4));++i) {
  603. uintptr_t x0 = reinterpret_cast<const uintptr_t *>(s)[0];
  604. uintptr_t x1 = reinterpret_cast<const uintptr_t *>(s)[1];
  605. uintptr_t x2 = reinterpret_cast<const uintptr_t *>(s)[2];
  606. uintptr_t x3 = reinterpret_cast<const uintptr_t *>(s)[3];
  607. reinterpret_cast<uintptr_t *>(d)[0] = x0;
  608. reinterpret_cast<uintptr_t *>(d)[1] = x1;
  609. reinterpret_cast<uintptr_t *>(d)[2] = x2;
  610. reinterpret_cast<uintptr_t *>(d)[3] = x3;
  611. s += (sizeof(uintptr_t) * 4);
  612. d += (sizeof(uintptr_t) * 4);
  613. }
  614. for(unsigned int i=0;i<(L & ((sizeof(uintptr_t) * 4) - 1));++i)
  615. d[i] = s[i];
  616. #endif
  617. }
  618. /**
  619. * Copy memory block whose size is known at run time
  620. *
  621. * @param dest Destination memory
  622. * @param src Source memory
  623. * @param len Bytes to copy
  624. */
  625. static ZT_INLINE void copy(void *const dest,const void *const src,unsigned int len) noexcept
  626. {
  627. memcpy(dest,src,len);
  628. }
  629. /**
  630. * Zero memory block whose size is known at compile time
  631. *
  632. * @tparam L Size in bytes
  633. * @param dest Memory to zero
  634. */
  635. template<unsigned int L>
  636. static ZT_INLINE void zero(void *const dest) noexcept
  637. {
  638. memset(dest,0,L);
  639. }
  640. /**
  641. * Zero memory block whose size is known at run time
  642. *
  643. * @param dest Memory to zero
  644. * @param len Size in bytes
  645. */
  646. static ZT_INLINE void zero(void *const dest,const unsigned int len) noexcept
  647. {
  648. memset(dest,0,len);
  649. }
  650. } // namespace Utils
  651. } // namespace ZeroTier
  652. #endif