LinkState.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 "benc/String.h"
  18. #include "util/VarInt.h"
  19. #include "wire/Message.h"
  20. #include "wire/Announce.h"
  21. #include <stdint.h>
  22. #include <stdbool.h>
  23. #define LinkState_SLOTS 18
  24. struct LinkState {
  25. uint16_t lagSlots[LinkState_SLOTS];
  26. uint16_t dropSlots[LinkState_SLOTS];
  27. uint32_t kbRecvSlots[LinkState_SLOTS];
  28. uint32_t samples;
  29. uint16_t nodeId;
  30. uint16_t _pad;
  31. };
  32. static inline int LinkState_encode(
  33. struct Message* msg,
  34. struct LinkState* ls,
  35. uint32_t lastSamples)
  36. {
  37. // Only encode the message if there is at least 255 bytes of headspace
  38. // We can then encode as many as possible and finally pop one which spills over the
  39. // size limit and then encode it again in the next message.
  40. if (Message_getPadding(msg) < 255) { return 1; }
  41. struct VarInt_Iter iter = {
  42. .ptr = msg->msgbytes,
  43. .end = msg->msgbytes,
  44. .start = &msg->msgbytes[-Message_getPadding(msg)]
  45. };
  46. // Take the newest X entries where X = MIN(ls->samples - lastSamples, LinkState_SLOTS)
  47. uint32_t i = ls->samples - 1;
  48. int count = 0;
  49. int err = 0;
  50. for (; i >= lastSamples && count < LinkState_SLOTS; i--, count++) {
  51. int idx = i % LinkState_SLOTS;
  52. err |= VarInt_push(&iter, ls->kbRecvSlots[idx]);
  53. err |= VarInt_push(&iter, ls->dropSlots[idx]);
  54. err |= VarInt_push(&iter, ls->lagSlots[idx]);
  55. }
  56. if (err) { return 1; }
  57. if (!count) { return 0; }
  58. // index of the first slot which should be updated when parsing
  59. Assert_true(!VarInt_push(&iter, (i + 1) % LinkState_SLOTS));
  60. Assert_true(!VarInt_push(&iter, ls->nodeId));
  61. int beginLength = Message_getLength(msg);
  62. Er_assert(Message_eshift(msg, (msg->msgbytes - iter.ptr)));
  63. Assert_true(msg->msgbytes == iter.ptr);
  64. int padCount = 0;
  65. while ((uintptr_t)(&msg->msgbytes[-3]) & 7) {
  66. Er_assert(Message_epush8(msg, 0));
  67. padCount++;
  68. }
  69. Er_assert(Message_epush8(msg, padCount));
  70. Er_assert(Message_epush8(msg, Announce_Type_LINK_STATE));
  71. int finalLength = Message_getLength(msg) - beginLength;
  72. Er_assert(Message_epush8(msg, finalLength + 1));
  73. Assert_true(!(((uintptr_t)msg->msgbytes) & 7));
  74. return 0;
  75. }
  76. static inline int LinkState_mkDecoder(struct Message* msg, struct VarInt_Iter* it)
  77. {
  78. if (!Message_getLength(msg)) { return 1; }
  79. uint8_t len = msg->msgbytes[0];
  80. if (Message_getLength(msg) < len) { return 1; }
  81. if (len < 3) { return 1; }
  82. it->ptr = &msg->msgbytes[1];
  83. it->start = it->ptr;
  84. it->end = &msg->msgbytes[len];
  85. // Ok to pop this using VarInt because it's supposed to be 3, which is less than 253
  86. uint64_t type = 0;
  87. if (VarInt_pop(it, &type)) { return 1; }
  88. if (type != Announce_Type_LINK_STATE) { return 1; }
  89. // Should be < 8
  90. uint64_t padCount = 0;
  91. if (VarInt_pop(it, &padCount)) { return 1; }
  92. for (unsigned int i = 0; i < padCount; i++) {
  93. if (VarInt_pop(it, NULL)) { return 1; }
  94. }
  95. return 0;
  96. }
  97. static inline int LinkState_getNodeId(const struct VarInt_Iter* iter, uint32_t* nodeId)
  98. {
  99. struct VarInt_Iter it;
  100. VarInt_clone(&it, iter);
  101. uint64_t id;
  102. if (VarInt_pop(&it, &id)) { return 1; }
  103. *nodeId = id;
  104. return 0;
  105. }
  106. #define LinkState_POP(it) (__extension__ ({ \
  107. uint64_t x; \
  108. if (VarInt_pop((it), &x)) { return 1; } \
  109. x; \
  110. }))
  111. static inline int LinkState_decode(const struct VarInt_Iter* iter, struct LinkState* ls)
  112. {
  113. struct VarInt_Iter it;
  114. VarInt_clone(&it, iter);
  115. ls->nodeId = LinkState_POP(&it);
  116. uint32_t i = LinkState_POP(&it);
  117. uint32_t count = 0;
  118. if (i >= LinkState_SLOTS) { return 1; }
  119. for (;;) {
  120. if (it.ptr == it.end) { break; }
  121. ls->lagSlots[i] = LinkState_POP(&it);
  122. ls->dropSlots[i] = LinkState_POP(&it);
  123. ls->kbRecvSlots[i] = LinkState_POP(&it);
  124. i = (i + 1) % LinkState_SLOTS;
  125. count++;
  126. }
  127. ls->samples += count;
  128. return 0;
  129. }
  130. #endif