matchmaking_nested_selection.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <array>
  2. #include <limits>
  3. #include "field_selection.h"
  4. #include "internal.h"
  5. namespace sunrise::middleware::bap::matchmaking::request {
  6. namespace {
  7. using protobuf::WireType;
  8. /** Fields inside the kind-4 activity message. Both are 32-bit hashes. */
  9. enum class ActivityField : std::uint32_t {
  10. definitionHash = 1,
  11. typeHash = 2,
  12. };
  13. /** A hash field is one 32-bit value carried as a varint. */
  14. constexpr std::uint64_t kMaximumHash = (std::numeric_limits<std::uint32_t>::max)();
  15. /** Fields inside the root advertisement message. */
  16. enum class AdvertisementField : std::uint32_t {
  17. /** Optional existing advertisement id. */
  18. existingId = 1,
  19. /** Advertisement record with the stable key and descriptor. */
  20. record = 2,
  21. };
  22. /** Fields inside the advertisement record. */
  23. enum class RecordField : std::uint32_t {
  24. /** Descriptor wrapper. It carries the whole opaque join descriptor. */
  25. descriptor = 2,
  26. /** Stable advertisement variant key. */
  27. variantKey = 4,
  28. };
  29. /** The descriptor wrapper carries its opaque bytes in field one. */
  30. constexpr std::uint32_t kDescriptorBytesField = 1;
  31. /** Index of each pick in the advertisement selection array. */
  32. constexpr std::size_t kExistingIdPick = 0;
  33. constexpr std::size_t kRecordPick = 1;
  34. constexpr std::size_t kAdvertisementPickCount = 2;
  35. /** Index of each pick in the record selection array. */
  36. constexpr std::size_t kDescriptorPick = 0;
  37. constexpr std::size_t kVariantKeyPick = 1;
  38. constexpr std::size_t kRecordPickCount = 2;
  39. /** The descriptor wrapper has a single pick. */
  40. constexpr std::size_t kDescriptorBytesPick = 0;
  41. constexpr std::size_t kDescriptorPickCount = 1;
  42. /** Index of each pick in the activity selection array. */
  43. constexpr std::size_t kDefinitionHashPick = 0;
  44. constexpr std::size_t kTypeHashPick = 1;
  45. constexpr std::size_t kActivityPickCount = 2;
  46. } // namespace
  47. /** Parses the kind-2 path into borrowed request fields. */
  48. bool parse_update(std::span<const std::byte> input, AdvertisementUpdate& update) noexcept {
  49. update = {};
  50. std::array<FieldPick, kAdvertisementPickCount> advertisement{
  51. FieldPick{static_cast<std::uint32_t>(AdvertisementField::existingId), WireType::varint},
  52. FieldPick{static_cast<std::uint32_t>(AdvertisementField::record),
  53. WireType::lengthDelimited},
  54. };
  55. if (!select_first_fields(input, advertisement)) {
  56. return false;
  57. }
  58. update.hasExistingId = advertisement[kExistingIdPick].has;
  59. update.existingId = advertisement[kExistingIdPick].value;
  60. if (!advertisement[kRecordPick].has) {
  61. return true;
  62. }
  63. // Only the submessages we pick are read further. Other byte fields stay opaque.
  64. std::array<FieldPick, kRecordPickCount> record{
  65. FieldPick{static_cast<std::uint32_t>(RecordField::descriptor), WireType::lengthDelimited},
  66. FieldPick{static_cast<std::uint32_t>(RecordField::variantKey), WireType::varint},
  67. };
  68. if (!select_first_fields(advertisement[kRecordPick].bytes, record)) {
  69. return false;
  70. }
  71. if (record[kVariantKeyPick].has) {
  72. update.variantKey = record[kVariantKeyPick].value;
  73. }
  74. if (!record[kDescriptorPick].has) {
  75. return true;
  76. }
  77. std::array<FieldPick, kDescriptorPickCount> descriptor{
  78. FieldPick{kDescriptorBytesField, WireType::lengthDelimited},
  79. };
  80. if (!select_first_fields(record[kDescriptorPick].bytes, descriptor)) {
  81. return false;
  82. }
  83. // A wrapper that carried bytes must carry the whole fixed-width descriptor.
  84. if (descriptor[kDescriptorBytesPick].has
  85. && descriptor[kDescriptorBytesPick].bytes.size() != kJoinDescriptorSize) {
  86. return false;
  87. }
  88. update.hasDescriptor = descriptor[kDescriptorBytesPick].has;
  89. update.descriptor = descriptor[kDescriptorBytesPick].bytes;
  90. return true;
  91. }
  92. /** Parses the kind-4 activity submessage into its two hashes. */
  93. bool parse_activity(std::span<const std::byte> input, ConfigurationActivity& activity) noexcept {
  94. activity = {};
  95. std::array<FieldPick, kActivityPickCount> picks{
  96. FieldPick{static_cast<std::uint32_t>(ActivityField::definitionHash), WireType::varint},
  97. FieldPick{static_cast<std::uint32_t>(ActivityField::typeHash), WireType::varint},
  98. };
  99. if (!select_first_fields(input, picks)) {
  100. return false;
  101. }
  102. if (picks[kDefinitionHashPick].has && picks[kDefinitionHashPick].value <= kMaximumHash) {
  103. activity.hasDefinitionHash = true;
  104. activity.definitionHash = static_cast<std::uint32_t>(picks[kDefinitionHashPick].value);
  105. }
  106. if (picks[kTypeHashPick].has && picks[kTypeHashPick].value <= kMaximumHash) {
  107. activity.hasTypeHash = true;
  108. activity.typeHash = static_cast<std::uint32_t>(picks[kTypeHashPick].value);
  109. }
  110. return true;
  111. }
  112. } // namespace sunrise::middleware::bap::matchmaking::request