123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /* vim: set expandtab ts=4 sw=4: */
- /*
- * You may redistribute this program and/or modify it under the terms of
- * the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #ifndef LinkState_H
- #define LinkState_H
- #include "benc/String.h"
- #include "util/VarInt.h"
- #include "wire/Message.h"
- #include "wire/Announce.h"
- #include <stdint.h>
- #include <stdbool.h>
- #define LinkState_SLOTS 18
- struct LinkState {
- uint16_t lagSlots[LinkState_SLOTS];
- uint16_t dropSlots[LinkState_SLOTS];
- uint32_t kbRecvSlots[LinkState_SLOTS];
- uint32_t samples;
- uint16_t nodeId;
- uint16_t _pad;
- };
- static inline int LinkState_encode(
- struct Message* msg,
- struct LinkState* ls,
- uint32_t lastSamples)
- {
- // Only encode the message if there is at least 255 bytes of headspace
- // We can then encode as many as possible and finally pop one which spills over the
- // size limit and then encode it again in the next message.
- if (msg->padding < 255) { return 1; }
- struct VarInt_Iter iter = {
- .ptr = msg->bytes,
- .end = msg->bytes,
- .start = &msg->bytes[-msg->padding]
- };
- // Take the newest X entries where X = MIN(ls->samples - lastSamples, LinkState_SLOTS)
- uint32_t i = ls->samples - 1;
- int count = 0;
- int err = 0;
- for (; i >= lastSamples && count < LinkState_SLOTS; i--, count++) {
- int idx = i % LinkState_SLOTS;
- err |= VarInt_push(&iter, ls->kbRecvSlots[idx]);
- err |= VarInt_push(&iter, ls->dropSlots[idx]);
- err |= VarInt_push(&iter, ls->lagSlots[idx]);
- }
- if (err) { return 1; }
- if (!count) { return 0; }
- // index of the first slot which should be updated when parsing
- Assert_true(!VarInt_push(&iter, (i + 1) % LinkState_SLOTS));
- Assert_true(!VarInt_push(&iter, ls->nodeId));
- int beginLength = msg->length;
- Er_assert(Message_eshift(msg, (msg->bytes - iter.ptr)));
- Assert_true(msg->bytes == iter.ptr);
- int padCount = 0;
- while ((uintptr_t)(&msg->bytes[-3]) & 7) {
- Er_assert(Message_epush8(msg, 0));
- padCount++;
- }
- Er_assert(Message_epush8(msg, padCount));
- Er_assert(Message_epush8(msg, Announce_Type_LINK_STATE));
- int finalLength = msg->length - beginLength;
- Er_assert(Message_epush8(msg, finalLength + 1));
- Assert_true(!(((uintptr_t)msg->bytes) & 7));
- return 0;
- }
- static inline int LinkState_mkDecoder(struct Message* msg, struct VarInt_Iter* it)
- {
- if (!msg->length) { return 1; }
- uint8_t len = msg->bytes[0];
- if (msg->length < len) { return 1; }
- if (len < 3) { return 1; }
- it->ptr = &msg->bytes[1];
- it->start = it->ptr;
- it->end = &msg->bytes[len];
- // Ok to pop this using VarInt because it's supposed to be 3, which is less than 253
- uint64_t type = 0;
- if (VarInt_pop(it, &type)) { return 1; }
- if (type != Announce_Type_LINK_STATE) { return 1; }
- // Should be < 8
- uint64_t padCount = 0;
- if (VarInt_pop(it, &padCount)) { return 1; }
- for (unsigned int i = 0; i < padCount; i++) {
- if (VarInt_pop(it, NULL)) { return 1; }
- }
- return 0;
- }
- static inline int LinkState_getNodeId(const struct VarInt_Iter* iter, uint32_t* nodeId)
- {
- struct VarInt_Iter it;
- VarInt_clone(&it, iter);
- uint64_t id;
- if (VarInt_pop(&it, &id)) { return 1; }
- *nodeId = id;
- return 0;
- }
- #define LinkState_POP(it) (__extension__ ({ \
- uint64_t x; \
- if (VarInt_pop((it), &x)) { return 1; } \
- x; \
- }))
- static inline int LinkState_decode(const struct VarInt_Iter* iter, struct LinkState* ls)
- {
- struct VarInt_Iter it;
- VarInt_clone(&it, iter);
- ls->nodeId = LinkState_POP(&it);
- uint32_t i = LinkState_POP(&it);
- uint32_t count = 0;
- if (i >= LinkState_SLOTS) { return 1; }
- for (;;) {
- if (it.ptr == it.end) { break; }
- ls->lagSlots[i] = LinkState_POP(&it);
- ls->dropSlots[i] = LinkState_POP(&it);
- ls->kbRecvSlots[i] = LinkState_POP(&it);
- i = (i + 1) % LinkState_SLOTS;
- count++;
- }
- ls->samples += count;
- return 0;
- }
- #endif
|