LinkState.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #ifndef LinkState_H
  16. #define LinkState_H
  17. #include "util/VarInt.h"
  18. #include "wire/Message.h"
  19. #include "wire/Announce.h"
  20. #include <stdint.h>
  21. #include <stdbool.h>
  22. #define LinkState_SLOTS 18
  23. struct LinkState {
  24. uint16_t lagSlots[LinkState_SLOTS];
  25. uint16_t dropSlots[LinkState_SLOTS];
  26. uint32_t kbRecvSlots[LinkState_SLOTS];
  27. uint32_t samples;
  28. uint16_t nodeId;
  29. uint16_t _pad;
  30. };
  31. static inline int LinkState_encode(
  32. Message_t* msg,
  33. struct LinkState* ls,
  34. uint32_t lastSamples)
  35. {
  36. // Only encode the message if there is at least 255 bytes of headspace
  37. // We can then encode as many as possible and finally pop one which spills over the
  38. // size limit and then encode it again in the next message.
  39. if (Message_getPadding(msg) < 255) { return 1; }
  40. struct VarInt_Iter iter = {
  41. .ptr = Message_bytes(msg),
  42. .end = Message_bytes(msg),
  43. .start = &Message_bytes(msg)[-Message_getPadding(msg)]
  44. };
  45. // Take the newest X entries where X = MIN(ls->samples - lastSamples, LinkState_SLOTS)
  46. uint32_t i = ls->samples - 1;
  47. int count = 0;
  48. int err = 0;
  49. for (; i >= lastSamples && count < LinkState_SLOTS; i--, count++) {
  50. int idx = i % LinkState_SLOTS;
  51. err |= VarInt_push(&iter, ls->kbRecvSlots[idx]);
  52. err |= VarInt_push(&iter, ls->dropSlots[idx]);
  53. err |= VarInt_push(&iter, ls->lagSlots[idx]);
  54. }
  55. if (err) { return 1; }
  56. if (!count) { return 0; }
  57. // index of the first slot which should be updated when parsing
  58. Assert_true(!VarInt_push(&iter, (i + 1) % LinkState_SLOTS));
  59. Assert_true(!VarInt_push(&iter, ls->nodeId));
  60. int beginLength = Message_getLength(msg);
  61. Err_assert(Message_eshift(msg, (Message_bytes(msg) - iter.ptr)));
  62. Assert_true(Message_bytes(msg) == iter.ptr);
  63. int padCount = 0;
  64. while ((uintptr_t)(&Message_bytes(msg)[-3]) & 7) {
  65. Err_assert(Message_epush8(msg, 0));
  66. padCount++;
  67. }
  68. Err_assert(Message_epush8(msg, padCount));
  69. Err_assert(Message_epush8(msg, Announce_Type_LINK_STATE));
  70. int finalLength = Message_getLength(msg) - beginLength;
  71. Err_assert(Message_epush8(msg, finalLength + 1));
  72. Assert_true(!(((uintptr_t)Message_bytes(msg)) & 7));
  73. return 0;
  74. }
  75. static inline int LinkState_mkDecoder(Message_t* msg, struct VarInt_Iter* it)
  76. {
  77. if (!Message_getLength(msg)) { return 1; }
  78. uint8_t len = Message_bytes(msg)[0];
  79. if (Message_getLength(msg) < len) { return 1; }
  80. if (len < 3) { return 1; }
  81. it->ptr = &Message_bytes(msg)[1];
  82. it->start = it->ptr;
  83. it->end = &Message_bytes(msg)[len];
  84. // Ok to pop this using VarInt because it's supposed to be 3, which is less than 253
  85. uint64_t type = 0;
  86. if (VarInt_pop(it, &type)) { return 1; }
  87. if (type != Announce_Type_LINK_STATE) { return 1; }
  88. // Should be < 8
  89. uint64_t padCount = 0;
  90. if (VarInt_pop(it, &padCount)) { return 1; }
  91. for (unsigned int i = 0; i < padCount; i++) {
  92. if (VarInt_pop(it, NULL)) { return 1; }
  93. }
  94. return 0;
  95. }
  96. static inline int LinkState_getNodeId(const struct VarInt_Iter* iter, uint32_t* nodeId)
  97. {
  98. struct VarInt_Iter it;
  99. VarInt_clone(&it, iter);
  100. uint64_t id;
  101. if (VarInt_pop(&it, &id)) { return 1; }
  102. *nodeId = id;
  103. return 0;
  104. }
  105. #define LinkState_POP(it) (__extension__ ({ \
  106. uint64_t x; \
  107. if (VarInt_pop((it), &x)) { return 1; } \
  108. x; \
  109. }))
  110. static inline int LinkState_decode(const struct VarInt_Iter* iter, struct LinkState* ls)
  111. {
  112. struct VarInt_Iter it;
  113. VarInt_clone(&it, iter);
  114. ls->nodeId = LinkState_POP(&it);
  115. uint32_t i = LinkState_POP(&it);
  116. uint32_t count = 0;
  117. if (i >= LinkState_SLOTS) { return 1; }
  118. for (;;) {
  119. if (it.ptr == it.end) { break; }
  120. ls->lagSlots[i] = LinkState_POP(&it);
  121. ls->dropSlots[i] = LinkState_POP(&it);
  122. ls->kbRecvSlots[i] = LinkState_POP(&it);
  123. i = (i + 1) % LinkState_SLOTS;
  124. count++;
  125. }
  126. ls->samples += count;
  127. return 0;
  128. }
  129. #endif