Expect.hpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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()
  37. {}
  38. /**
  39. * Called by other code when something is sending a packet that could potentially receive an OK response
  40. *
  41. * @param packetId Packet ID of packet being sent (be sure it's post-armor())
  42. * @param now Current time
  43. */
  44. ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
  45. {
  46. m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL));
  47. }
  48. /**
  49. * Check if an OK is expected and if so reset the corresponding bucket.
  50. *
  51. * This means this call mutates the state. If it returns true, it will
  52. * subsequently return false. This is for replay protection for OKs.
  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. {
  60. return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1);
  61. }
  62. private:
  63. // Each bucket contains a timestamp in units of the max expect duration.
  64. std::atomic<uint32_t> m_packetIdSent[ZT_EXPECT_BUCKETS];
  65. };
  66. } // namespace ZeroTier
  67. #endif