Expect.hpp 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  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_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. * This must be a power of two. Memory consumed will be about this*4 bytes.
  21. */
  22. #define ZT_EXPECT_BUCKETS 32768
  23. /**
  24. * 1/2 the TTL for expected replies in milliseconds
  25. *
  26. * This must be a power of two.
  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() :
  37. m_packetIdSent()
  38. {}
  39. /**
  40. * Called by other code when something is sending a packet that could potentially receive an OK response
  41. *
  42. * @param packetId Packet ID of packet being sent (be sure it's post-armor())
  43. * @param now Current time
  44. */
  45. ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
  46. { m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] = (uint32_t)(now / ZT_EXPECT_TTL); }
  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 to filter OKs against replays or
  52. * responses to queries we did not send.
  53. *
  54. * @param inRePacketId In-re packet ID we're expecting
  55. * @param now Current time
  56. * @return True if we're expecting a reply (and a reset occurred)
  57. */
  58. ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept
  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. private:
  61. // Each bucket contains a timestamp in units of the max expect duration.
  62. std::atomic<uint32_t> m_packetIdSent[ZT_EXPECT_BUCKETS];
  63. };
  64. } // namespace ZeroTier
  65. #endif