packet_fragments.h 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. namespace sunrise::middleware::gameplay::peer::packet_fragments {
  7. /** Direct IPv4 transport admits 1,228 bytes per datagram. */
  8. inline constexpr std::size_t kDefaultDatagramLimit = 1228;
  9. /** The native transport's largest datagram buffer holds 1,240 bytes. */
  10. inline constexpr std::size_t kMaximumDatagramLimit = 1240;
  11. /** Fragment headers contain two bytes before their payload. */
  12. inline constexpr std::size_t kFragmentHeaderBytes = 2;
  13. /** Three-bit fragment indices and counts admit eight pieces per packet. */
  14. inline constexpr std::size_t kMaximumFragments = 8;
  15. /** The native receive ring retains eight fragment groups. */
  16. inline constexpr std::size_t kMaximumGroups = 8;
  17. /** One group stores eight maximum-sized fragment bodies. */
  18. inline constexpr std::size_t kMaximumPacketBytes =
  19. kMaximumFragments * (kMaximumDatagramLimit - kFragmentHeaderBytes);
  20. /** A matching sequence starts a new group only after more than 2,000 milliseconds. */
  21. inline constexpr std::uint64_t kExpiryMilliseconds = 2000;
  22. enum class Result : std::uint8_t { refused, incomplete, duplicate, complete };
  23. /** Each caller-owned store belongs to one authenticated peer channel and needs about 80 KiB. */
  24. class Store final {
  25. public:
  26. /**
  27. * Returns a complete original packet without altering its inner header.
  28. * @param datagram One decrypted transport datagram.
  29. * @param expectedGuard The admitted connection sequence modulo four.
  30. * @param nowMs Unwrapped monotonic arrival time in milliseconds.
  31. * @param output Receives the packet only on complete; must not overlap this store.
  32. * @param written Cleared, then receives the complete packet's byte count.
  33. * @param datagramLimit This channel's maximum datagram size, including the fragment header.
  34. * @return Complete only once for a retained group; all other results leave output unchanged.
  35. */
  36. [[nodiscard]] Result accept(std::span<const std::byte> datagram,
  37. std::uint8_t expectedGuard,
  38. std::uint64_t nowMs,
  39. std::span<std::byte> output,
  40. std::size_t& written,
  41. std::size_t datagramLimit = kDefaultDatagramLimit) noexcept;
  42. /** Reset on channel replacement; payload storage needs no clearing before reuse. */
  43. void reset() noexcept;
  44. private:
  45. struct Group final {
  46. std::array<std::byte, kMaximumPacketBytes> bytes{};
  47. std::uint64_t startedMs{};
  48. std::size_t bodyLimit{}, finalBytes{};
  49. std::uint8_t sequence{}, guard{}, count{}, present{};
  50. bool active{};
  51. };
  52. std::array<Group, kMaximumGroups> groups_{};
  53. std::size_t nextGroup_{};
  54. };
  55. } // namespace sunrise::middleware::gameplay::peer::packet_fragments