established_packet.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. #include "established_packet.h"
  2. #include <array>
  3. #include "../../encoding/bit_raw.h"
  4. #include "peer_container.h"
  5. namespace sunrise::middleware::gameplay::peer {
  6. namespace {
  7. namespace bits = encoding::bits;
  8. /** An established packet carries marker 0. */
  9. constexpr std::uint64_t kEstablishedMarker = 0;
  10. /** Width of the marker and of the fragmented flag. */
  11. constexpr std::uint8_t kFlagWidth = 1;
  12. /** The connection sequence guard is two bits. */
  13. constexpr std::uint8_t kSequenceGuardWidth = 2;
  14. /** The outbound packet head is published as ten low bits. */
  15. constexpr std::uint8_t kOutboundHeadWidth = 10;
  16. /** The distance from the head back to the event cursor is seven bits. */
  17. constexpr std::uint8_t kCursorWidth = 7;
  18. /** The acknowledged base is seven bits, matching the 128-entry ring. */
  19. constexpr std::uint8_t kAckBaseWidth = 7;
  20. /** Every status form is selected by a two-bit prefix, one of which extends to three. */
  21. constexpr std::uint8_t kStatusPrefixWidth = 2;
  22. /** The extending bit of the three-bit prefixes. */
  23. constexpr std::uint8_t kStatusExtensionWidth = 1;
  24. /** Prefix of the empty-ring form. */
  25. constexpr std::uint64_t kStatusEmpty = 0;
  26. /** Prefix of the single-difference form. */
  27. constexpr std::uint64_t kStatusSingle = 1;
  28. /** Prefix of the eight-entry explicit form. */
  29. constexpr std::uint64_t kStatusExplicit = 2;
  30. /** Prefix shared by the long-span and uninitialized forms. */
  31. constexpr std::uint64_t kStatusExtended = 3;
  32. /** Extension bit selecting the long-span form. */
  33. constexpr std::uint64_t kStatusLongSpan = 0;
  34. /** Width of the long-span count. */
  35. constexpr std::uint8_t kStatusCountWidth = 7;
  36. /** Width of the index in the single-difference form. */
  37. constexpr std::uint8_t kSingleIndexWidth = 3;
  38. /** The acknowledgement delay is ten bits. */
  39. constexpr std::uint8_t kDelayWidth = 10;
  40. /** Longest status run the long-span form can name. */
  41. constexpr std::uint64_t kMaximumStatusCount = 128;
  42. /** The message sequence selector is two bits. */
  43. constexpr std::uint8_t kSelectorWidth = 2;
  44. /** Selector ending the record list. */
  45. constexpr std::uint64_t kSelectorEnd = 0;
  46. /** Selector introducing an absolute low-13 sequence. */
  47. constexpr std::uint64_t kSelectorAbsolute = 1;
  48. /** Selector introducing a four-bit delta above the previous sequence. */
  49. constexpr std::uint64_t kSelectorDelta = 2;
  50. /** Width of an absolute message sequence. */
  51. constexpr std::uint8_t kAbsoluteSequenceWidth = 13;
  52. /** Message sequences unwrap modulo 8,192. */
  53. constexpr std::uint16_t kSequenceModulus = 8192;
  54. /** Width of the delta form. */
  55. constexpr std::uint8_t kDeltaWidth = 4;
  56. /** Width of the queue-specific short length for the 32-byte queue. */
  57. constexpr std::uint8_t kLargeShortLengthWidth = 8;
  58. /** Width of the queue-specific short length for the 6-byte queue. */
  59. constexpr std::uint8_t kSmallShortLengthWidth = 6;
  60. /** Bits in one byte. */
  61. constexpr std::uint16_t kByteBits = 8;
  62. /** The reassembled message begins with a 6-bit registry id. */
  63. constexpr std::uint8_t kMessageIdWidth = 6;
  64. /** The declared decoded size after it is 18 bits. */
  65. constexpr std::uint8_t kMessageSizeWidth = 18;
  66. /** The filler length is a 14-bit field. */
  67. constexpr std::uint8_t kFillerLengthWidth = 14;
  68. /** The recovered filler body limit is 9,920 bits. */
  69. constexpr std::uint64_t kMaximumFillerBits = 9920;
  70. /** Byte padding can carry at most seven bits. */
  71. constexpr std::size_t kMaximumPaddingBits = 7;
  72. /**
  73. * Reads one ternary packet status.
  74. * @param reader Open reader.
  75. * @param received Receives true for the two codes that mean received.
  76. * @return True when a complete code was present.
  77. */
  78. [[nodiscard]] bool read_status(bits::Reader& reader, bool& received) noexcept {
  79. std::uint64_t first = 0;
  80. if (!reader.read(kFlagWidth, first)) {
  81. return false;
  82. }
  83. if (first == 0) {
  84. // Code 0 is status 1, the ordinary received case.
  85. received = true;
  86. return true;
  87. }
  88. std::uint64_t second = 0;
  89. if (!reader.read(kFlagWidth, second)) {
  90. return false;
  91. }
  92. // Code 10 is status 0, unresolved. Code 11 is status 2, received out of order.
  93. received = second != 0;
  94. return true;
  95. }
  96. /** Writes one ternary packet status. @param received Selects status 1 or status 0. */
  97. [[nodiscard]] bool write_status(bits::Writer& writer, bool received) noexcept {
  98. if (received) {
  99. return writer.write(0, kFlagWidth);
  100. }
  101. return writer.write(1, kFlagWidth) && writer.write(0, kFlagWidth);
  102. }
  103. /**
  104. * Reads the acknowledgement handler payload.
  105. * @param reader Open reader positioned after the packet head.
  106. * @param output Receives the peer's acknowledgement state.
  107. * @return True when the selected status form was complete.
  108. */
  109. [[nodiscard]] bool read_ack(bits::Reader& reader, AckState& output) noexcept {
  110. std::uint64_t present = 0;
  111. std::uint64_t head = 0;
  112. std::uint64_t cursor = 0;
  113. if (!reader.read(kFlagWidth, present) || !reader.read(kOutboundHeadWidth, head)
  114. || !reader.read(kCursorWidth, cursor)) {
  115. return false;
  116. }
  117. output.outboundHeadPresent = present != 0;
  118. output.outboundHead = static_cast<std::uint16_t>(head);
  119. output.headMinusCursor = static_cast<std::uint8_t>(cursor);
  120. std::uint64_t base = 0;
  121. std::uint64_t prefix = 0;
  122. if (!reader.read(kAckBaseWidth, base) || !reader.read(kStatusPrefixWidth, prefix)) {
  123. return false;
  124. }
  125. output.receiveHead = static_cast<std::uint16_t>(base);
  126. output.received = {};
  127. output.reportedCount = 0;
  128. if (prefix == kStatusExtended) {
  129. std::uint64_t extension = 0;
  130. if (!reader.read(kStatusExtensionWidth, extension)) {
  131. return false;
  132. }
  133. if (extension != kStatusLongSpan) {
  134. // The uninitialized form ends the payload and carries no delay.
  135. output.ringInitialized = false;
  136. return true;
  137. }
  138. std::uint64_t count = 0;
  139. // The field is the number of statuses, not one less than it.
  140. if (!reader.read(kStatusCountWidth, count) || count > kMaximumStatusCount) {
  141. return false;
  142. }
  143. for (std::uint64_t index = 0; index < count; ++index) {
  144. bool received = false;
  145. if (!read_status(reader, received)) {
  146. return false;
  147. }
  148. if (index < output.received.size()) {
  149. output.received[index] = received;
  150. output.reportedCount = static_cast<std::uint8_t>(index + 1);
  151. }
  152. }
  153. } else if (prefix == kStatusExplicit) {
  154. for (bool& entry : output.received) {
  155. if (!read_status(reader, entry)) {
  156. return false;
  157. }
  158. }
  159. output.reportedCount = static_cast<std::uint8_t>(output.received.size());
  160. } else if (prefix == kStatusSingle) {
  161. std::uint64_t outOfOrder = 0;
  162. std::uint64_t index = 0;
  163. if (!reader.read(kFlagWidth, outOfOrder) || !reader.read(kSingleIndexWidth, index)) {
  164. return false;
  165. }
  166. // The named entry is the last one and the only one that is not an ordinary receive.
  167. output.received.fill(true);
  168. output.received[static_cast<std::size_t>(index)] = outOfOrder != 0;
  169. output.reportedCount = static_cast<std::uint8_t>(index + 1);
  170. } else {
  171. std::uint64_t ringState = 0;
  172. if (!reader.read(kFlagWidth, ringState)) {
  173. return false;
  174. }
  175. }
  176. std::uint64_t delay = 0;
  177. if (!reader.read(kDelayWidth, delay)) {
  178. return false;
  179. }
  180. output.delay = static_cast<std::uint16_t>(delay);
  181. output.ringInitialized = true;
  182. return true;
  183. }
  184. /**
  185. * Reads one reliable queue payload.
  186. * @param reader Open reader positioned at the queue payload.
  187. * @param fragmentBytes Fixed fragment size of this queue.
  188. * @param shortLengthWidth Width of this queue's short-fragment length field.
  189. * @param output Receives every record the packet carried.
  190. * @return True when the record list was well formed.
  191. */
  192. [[nodiscard]] bool read_queue(bits::Reader& reader,
  193. std::size_t fragmentBytes,
  194. std::uint8_t shortLengthWidth,
  195. QueueRecords& output) noexcept {
  196. output.count = 0;
  197. std::uint64_t recordsPresent = 0;
  198. if (!reader.read(kFlagWidth, recordsPresent)) {
  199. return false;
  200. }
  201. if (recordsPresent == 0) {
  202. return true;
  203. }
  204. std::uint16_t previous = 0;
  205. bool hasPrevious = false;
  206. for (;;) {
  207. std::uint64_t selector = 0;
  208. if (!reader.read(kSelectorWidth, selector)) {
  209. return false;
  210. }
  211. if (selector == kSelectorEnd) {
  212. return true;
  213. }
  214. if (output.count >= output.records.size()) {
  215. return false;
  216. }
  217. QueueRecord& record = output.records[output.count];
  218. record = {};
  219. if (selector == kSelectorAbsolute) {
  220. std::uint64_t sequence = 0;
  221. if (!reader.read(kAbsoluteSequenceWidth, sequence)) {
  222. return false;
  223. }
  224. record.sequence = static_cast<std::uint16_t>(sequence);
  225. } else if (selector == kSelectorDelta) {
  226. std::uint64_t delta = 0;
  227. if (!hasPrevious || !reader.read(kDeltaWidth, delta)) {
  228. return false;
  229. }
  230. record.sequence = static_cast<std::uint16_t>((previous + 1 + delta) % kSequenceModulus);
  231. } else {
  232. if (!hasPrevious) {
  233. return false;
  234. }
  235. record.sequence = static_cast<std::uint16_t>((previous + 1) % kSequenceModulus);
  236. }
  237. previous = record.sequence;
  238. hasPrevious = true;
  239. std::uint64_t isShort = 0;
  240. if (!reader.read(kFlagWidth, isShort)) {
  241. return false;
  242. }
  243. record.shortFragment = isShort != 0;
  244. if (record.shortFragment) {
  245. std::uint64_t secondary = 0;
  246. std::uint64_t lengthMinusOne = 0;
  247. if (!reader.read(kFlagWidth, secondary)
  248. || !reader.read(shortLengthWidth, lengthMinusOne)) {
  249. return false;
  250. }
  251. record.bitCount = static_cast<std::uint16_t>(lengthMinusOne + 1);
  252. } else {
  253. record.bitCount = static_cast<std::uint16_t>(fragmentBytes * kByteBits);
  254. }
  255. if (record.bitCount > record.bytes.size() * kByteBits) {
  256. return false;
  257. }
  258. // Fragment bits are read as whole bytes plus a remainder, so the tail keeps its padding.
  259. const std::size_t wholeBytes = record.bitCount / kByteBits;
  260. const std::uint8_t remainder = static_cast<std::uint8_t>(record.bitCount % kByteBits);
  261. if (!bits::read_raw(reader, std::span<std::byte>(record.bytes.data(), wholeBytes))) {
  262. return false;
  263. }
  264. if (remainder != 0) {
  265. std::uint64_t tail = 0;
  266. if (!reader.read(remainder, tail)) {
  267. return false;
  268. }
  269. record.bytes[wholeBytes] = static_cast<std::byte>(tail << (kByteBits - remainder));
  270. }
  271. ++output.count;
  272. }
  273. }
  274. } // namespace
  275. /** Decodes one established packet up to and including both reliable queues. */
  276. bool decode_established(std::span<const std::byte> payload,
  277. bool expectExternal,
  278. EstablishedPacket& output) noexcept {
  279. bits::Reader reader(payload);
  280. std::uint64_t marker = 0;
  281. std::uint64_t fragmented = 0;
  282. std::uint64_t guard = 0;
  283. if (!reader.read(kFlagWidth, marker) || marker != kEstablishedMarker
  284. || !reader.read(kFlagWidth, fragmented) || fragmented != 0
  285. || !reader.read(kSequenceGuardWidth, guard)) {
  286. return false;
  287. }
  288. output = {};
  289. output.connectionSequenceLow2 = static_cast<std::uint8_t>(guard);
  290. if (!read_ack(reader, output.ack)
  291. || !read_queue(reader, kLargeFragmentBytes, kLargeShortLengthWidth, output.large)
  292. || !read_queue(reader, kSmallFragmentBytes, kSmallShortLengthWidth, output.small)) {
  293. return false;
  294. }
  295. // The sentinel handler writes no bits, so the external body starts here when one exists.
  296. output.hasExternal = expectExternal;
  297. output.externalBitOffset = payload.size() * kByteBits - reader.remaining_bits();
  298. return true;
  299. }
  300. /** Reports whether one acknowledgement covers a packet this host sent. */
  301. bool acknowledgement_covers(const AckState& ack, std::uint16_t sentSequence) noexcept {
  302. if (!ack.ringInitialized) {
  303. return false;
  304. }
  305. const auto base = static_cast<std::uint16_t>(ack.receiveHead % kPacketRingSize);
  306. const auto sent = static_cast<std::uint16_t>(sentSequence % kPacketRingSize);
  307. const auto distance = static_cast<std::uint16_t>((base - sent) % kPacketRingSize);
  308. if (distance >= kPacketRingSize / 2) {
  309. // The base is behind the packet, so the peer has not reached it yet.
  310. return false;
  311. }
  312. if (distance == 0) {
  313. // The base is the newest packet the peer holds, and it carries no status entry.
  314. return true;
  315. }
  316. if (distance <= ack.reportedCount) {
  317. return ack.received[distance - 1U];
  318. }
  319. // Older than every entry the peer named, so it has left the peer's window.
  320. return true;
  321. }
  322. /** Writes the packet head and the acknowledgement handler payload. */
  323. bool write_head_and_ack(bits::Writer& writer,
  324. std::uint8_t connectionSequenceLow2,
  325. const AckState& ack) noexcept {
  326. if (!writer.write(kEstablishedMarker, kFlagWidth) || !writer.write(0, kFlagWidth)
  327. || !writer.write(connectionSequenceLow2, kSequenceGuardWidth)) {
  328. return false;
  329. }
  330. if (!writer.write(ack.outboundHeadPresent ? 1U : 0U, kFlagWidth)
  331. || !writer.write(ack.outboundHead, kOutboundHeadWidth)
  332. || !writer.write(ack.headMinusCursor, kCursorWidth)) {
  333. return false;
  334. }
  335. if (!ack.ringInitialized) {
  336. // Nothing has been received yet, so the uninitialized form ends the payload here.
  337. return writer.write(0, kAckBaseWidth) && writer.write(kStatusExtended, kStatusPrefixWidth)
  338. && writer.write(1, kStatusExtensionWidth);
  339. }
  340. if (!writer.write(ack.receiveHead, kAckBaseWidth)
  341. || !writer.write(kStatusExplicit, kStatusPrefixWidth)) {
  342. return false;
  343. }
  344. // Eight explicit statuses say exactly which packets arrived, without claiming any others.
  345. for (const bool received : ack.received) {
  346. if (!write_status(writer, received)) {
  347. return false;
  348. }
  349. }
  350. return writer.write(ack.delay, kDelayWidth);
  351. }
  352. /** Writes one reliable queue that carries no records. */
  353. bool write_empty_queue(bits::Writer& writer) noexcept {
  354. return writer.write(0, kFlagWidth);
  355. }
  356. /** Writes one reliable queue and every fragment it owes. */
  357. bool write_queue(bits::Writer& writer, const state::gameplay::OutboundQueue& queue) noexcept {
  358. if (queue.count == 0) {
  359. return write_empty_queue(writer);
  360. }
  361. if (!writer.write(1, kFlagWidth)) {
  362. return false;
  363. }
  364. for (std::size_t index = 0; index < queue.count; ++index) {
  365. const state::gameplay::OutboundFragment& fragment = queue.fragments[index];
  366. if (!writer.write(kSelectorAbsolute, kSelectorWidth)
  367. || !writer.write(fragment.sequence, kAbsoluteSequenceWidth)
  368. || !writer.write(fragment.shortFragment ? 1U : 0U, kFlagWidth)) {
  369. return false;
  370. }
  371. if (fragment.shortFragment) {
  372. // The secondary flag has no meaning for a fragment this host writes and stays clear.
  373. if (!writer.write(0, kFlagWidth)
  374. || !writer.write(fragment.bitCount - 1U, kLargeShortLengthWidth)) {
  375. return false;
  376. }
  377. }
  378. const std::size_t wholeBytes = fragment.bitCount / kByteBits;
  379. const auto remainder = static_cast<std::uint8_t>(fragment.bitCount % kByteBits);
  380. if (!bits::write_raw(writer, {fragment.bytes.data(), wholeBytes})) {
  381. return false;
  382. }
  383. if (remainder != 0) {
  384. const auto tail = std::to_integer<std::uint64_t>(fragment.bytes[wholeBytes]);
  385. if (!writer.write(tail >> (kByteBits - remainder), remainder)) {
  386. return false;
  387. }
  388. }
  389. }
  390. return writer.write(kSelectorEnd, kSelectorWidth);
  391. }
  392. /** Splits one reliable message into fragments and appends them to a send queue. */
  393. bool enqueue_message(state::gameplay::OutboundQueue& queue,
  394. std::uint8_t id,
  395. std::uint32_t declaredSize,
  396. std::span<const std::byte> body,
  397. std::size_t bodyBits) noexcept {
  398. if (id > kMaximumMessageId) {
  399. return false;
  400. }
  401. // The inner header precedes the body, so the message is staged once and then split.
  402. std::array<std::byte, state::gameplay::kReassemblyCapacity> staged{};
  403. bits::Writer writer(staged);
  404. if (!writer.write(id, kMessageIdWidth) || !writer.write(declaredSize, kMessageSizeWidth)) {
  405. return false;
  406. }
  407. bits::Reader reader(body);
  408. std::size_t remaining = bodyBits;
  409. while (remaining != 0) {
  410. const auto width = static_cast<std::uint8_t>(remaining < kByteBits ? remaining : kByteBits);
  411. std::uint64_t value = 0;
  412. if (!reader.read(width, value) || !writer.write(value, width)) {
  413. return false;
  414. }
  415. remaining -= width;
  416. }
  417. std::size_t stagedBytes = 0;
  418. if (!writer.finish(stagedBytes)) {
  419. return false;
  420. }
  421. const std::size_t totalBits = writer.bit_count();
  422. // Every fragment but the last carries the queue's whole fixed size.
  423. constexpr std::size_t kFragmentBits = kLargeFragmentBytes * kByteBits;
  424. std::size_t consumed = 0;
  425. bits::Reader source({staged.data(), stagedBytes});
  426. // A half-enqueued message can never be reassembled, so any failure below restores the queue.
  427. const std::size_t entryCount = queue.count;
  428. const std::uint16_t entrySequence = queue.nextSequence;
  429. const auto restore = [&queue, entryCount, entrySequence]() noexcept {
  430. for (std::size_t index = entryCount; index < queue.count; ++index) {
  431. queue.fragments[index] = {};
  432. }
  433. queue.count = entryCount;
  434. queue.nextSequence = entrySequence;
  435. };
  436. while (consumed < totalBits) {
  437. if (queue.count >= queue.fragments.size()) {
  438. restore();
  439. return false;
  440. }
  441. const std::size_t take =
  442. (totalBits - consumed) < kFragmentBits ? totalBits - consumed : kFragmentBits;
  443. // Only a short fragment closes a run. A full last fragment still needs one appended.
  444. const bool last = consumed + take >= totalBits;
  445. state::gameplay::OutboundFragment& fragment = queue.fragments[queue.count];
  446. fragment = {};
  447. bits::Writer chunk(fragment.bytes);
  448. std::size_t written = 0;
  449. std::size_t pending = take;
  450. while (pending != 0) {
  451. const auto width = static_cast<std::uint8_t>(pending < kByteBits ? pending : kByteBits);
  452. std::uint64_t value = 0;
  453. if (!source.read(width, value) || !chunk.write(value, width)) {
  454. restore();
  455. return false;
  456. }
  457. pending -= width;
  458. }
  459. if (!chunk.finish(written)) {
  460. restore();
  461. return false;
  462. }
  463. fragment.sequence = queue.nextSequence;
  464. fragment.bitCount = static_cast<std::uint16_t>(take);
  465. fragment.shortFragment = last && take < kFragmentBits;
  466. fragment.occupied = true;
  467. queue.nextSequence = static_cast<std::uint16_t>((queue.nextSequence + 1)
  468. % state::gameplay::kMessageSequenceModulus);
  469. ++queue.count;
  470. consumed += take;
  471. if (last && !fragment.shortFragment) {
  472. // An exact multiple of the fragment size still needs a closing short fragment.
  473. if (queue.count >= queue.fragments.size()) {
  474. restore();
  475. return false;
  476. }
  477. state::gameplay::OutboundFragment& terminator = queue.fragments[queue.count];
  478. terminator = {};
  479. terminator.sequence = queue.nextSequence;
  480. terminator.bitCount = 1;
  481. terminator.shortFragment = true;
  482. terminator.occupied = true;
  483. queue.nextSequence = static_cast<std::uint16_t>(
  484. (queue.nextSequence + 1) % state::gameplay::kMessageSequenceModulus);
  485. ++queue.count;
  486. }
  487. }
  488. return true;
  489. }
  490. /** Reads the bounded outer filler and requires exact zero byte padding. */
  491. bool read_filler_and_padding(bits::Reader& reader, FillerTrailer& output) noexcept {
  492. FillerTrailer candidate{};
  493. std::uint64_t present = 0;
  494. if (!reader.read(kFlagWidth, present)) {
  495. return false;
  496. }
  497. candidate.present = present != 0;
  498. if (candidate.present) {
  499. std::uint64_t bitCount = 0;
  500. if (!reader.read(kFillerLengthWidth, bitCount) || bitCount == 0
  501. || bitCount > kMaximumFillerBits || !reader.skip(static_cast<std::size_t>(bitCount))) {
  502. return false;
  503. }
  504. candidate.bitCount = static_cast<std::size_t>(bitCount);
  505. }
  506. const std::size_t paddingBits = reader.remaining_bits();
  507. std::uint64_t padding = 0;
  508. if (paddingBits > kMaximumPaddingBits
  509. || !reader.read(static_cast<std::uint8_t>(paddingBits), padding) || padding != 0) {
  510. return false;
  511. }
  512. output = candidate;
  513. return true;
  514. }
  515. /** Writes the filler trailer that ends every packet. */
  516. bool write_absent_filler(bits::Writer& writer) noexcept {
  517. // Two bits close a packet: the extended-presence bit, then the external-body present bit.
  518. // The reader consumes both, so both must be written even though both are zero.
  519. return writer.write(0, kFlagWidth) && writer.write(0, kFlagWidth);
  520. }
  521. } // namespace sunrise::middleware::gameplay::peer