Expect.hpp 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  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_EXPECT_HPP
  14. #define ZT_EXPECT_HPP
  15. #include "Constants.hpp"
  16. #include "Utils.hpp"
  17. /**
  18. * Number of buckets to use to maintain a list of expected replies.
  19. *
  20. * Making this a power of two improves efficiency a little by allowing bit shift division.
  21. */
  22. #define ZT_EXPECT_BUCKETS 32768
  23. /**
  24. * 1/2 the TTL for expected replies in milliseconds
  25. *
  26. * Making this a power of two improves efficiency a little by allowing bit shift division.
  27. */
  28. #define ZT_EXPECT_TTL 4096LL
  29. namespace ZeroTier {
  30. /**
  31. * Tracker for expected OK replies to packet IDs of sent packets
  32. */
  33. class Expect
  34. {
  35. public:
  36. ZT_INLINE Expect() {} // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init,hicpp-use-equals-default,modernize-use-equals-default)
  37. /**
  38. * Called by other code when something is sending a packet that could potentially receive an OK response
  39. *
  40. * @param packetId Packet ID of packet being sent (be sure it's post-armor())
  41. * @param now Current time
  42. */
  43. ZT_INLINE void sending(const uint64_t packetId,const int64_t now) noexcept
  44. {
  45. m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL));
  46. }
  47. /**
  48. * Check if an OK is expected and if so reset the corresponding bucket.
  49. *
  50. * This means this call mutates the state. If it returns true, it will
  51. * subsequently return false. This is for replay protection for OKs.
  52. *
  53. * @param inRePacketId In-re packet ID we're expecting
  54. * @param now Current time
  55. * @return True if we're expecting a reply (and a reset occurred)
  56. */
  57. ZT_INLINE bool expecting(const uint64_t inRePacketId,const int64_t now) noexcept
  58. {
  59. return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1);
  60. }
  61. private:
  62. // Each bucket contains a timestamp in units of the max expect duration.
  63. std::atomic<uint32_t> m_packetIdSent[ZT_EXPECT_BUCKETS];
  64. };
  65. } // namespace ZeroTier
  66. #endif