123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- /* 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 Announce_H
- #define Announce_H
- #include "benc/String.h"
- #include "wire/Message.h"
- #include "util/version/Version.h"
- #include "util/Assert.h"
- #include "util/Endian.h"
- #include "util/Bits.h"
- #include "util/Gcc.h"
- // NOTE: Length of 0 in a Announce message is invalid.
- // Length of 1 is by definition a pad byte.
- // Length field allows parsers to skip over entries which they do not understand.
- enum Announce_Type {
- Announce_Type_ENCODING_SCHEME,
- Announce_Type_PEER,
- Announce_Type_VERSION,
- Announce_Type_LINK_STATE
- };
- /**
- * 1 2 3
- * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 0 | length | type | version |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- struct Announce_Version
- {
- // Announce_Version_SIZE
- uint8_t length;
- // Announce_Type_VERSION
- uint8_t type;
- uint16_t version_be;
- };
- #define Announce_Version_SIZE 4
- Assert_compileTime(sizeof(struct Announce_Version) == Announce_Version_SIZE);
- static inline void Announce_Version_init(struct Announce_Version* v)
- {
- v->length = Announce_Version_SIZE;
- v->type = Announce_Type_VERSION;
- v->version_be = Endian_hostToBigEndian16(Version_CURRENT_PROTOCOL);
- }
- struct Announce_EncodingScheme
- {
- // Length of `scheme` + 2
- uint8_t length;
- // Announce_Type_ENCODING_SCHEME
- uint8_t type;
- // real length is `length` - 2
- uint8_t scheme[2];
- };
- static inline void Announce_EncodingScheme_push(Message_t* pushTo, String* compressedScheme)
- {
- Assert_true(compressedScheme->len + 2 < 256);
- Er_assert(Message_epush(pushTo, compressedScheme->bytes, compressedScheme->len));
- Er_assert(Message_epush8(pushTo, Announce_Type_ENCODING_SCHEME));
- Er_assert(Message_epush8(pushTo, compressedScheme->len + 2));
- while ((uintptr_t)Message_bytes(pushTo) % 4) {
- Er_assert(Message_epush8(pushTo, 1));
- }
- }
- /**
- * 1 2 3
- * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 0 | length | type | encodingForm | flags |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 4 | MTU (8 byte units) | peer number |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 8 | Unused |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 12 | |
- * + +
- * 16 | |
- * + Peer IPv6 +
- * 20 | |
- * + +
- * 24 | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 28 | label |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- struct Announce_Peer
- {
- // Announce_Peer_SIZE
- uint8_t length;
- // Announce_Type_PEER
- uint8_t type;
- // The number of the encoding form needed for getting to this node via the peer.
- uint8_t encodingFormNum;
- // no flags yet but maybe in the future...
- uint8_t flags;
- // MTU of the link in 8 byte units.
- // 0 is unknown
- // 0xffff = MTU of 542280 bytes
- uint16_t mtu8_be;
- // Number of the peer in the list, used for referencing in LinkState
- // 0xffff is unknown
- uint16_t peerNum_be;
- // 0xffffffff
- uint32_t unused;
- // Ipv6 of a node from which this node is reachable
- uint8_t peerIpv6[16];
- // Label for getting to this node from the given node
- // 0 means withdraw the link.
- uint32_t label_be;
- };
- #define Announce_Peer_SIZE 32
- Assert_compileTime(sizeof(struct Announce_Peer) == Announce_Peer_SIZE);
- static inline void Announce_Peer_init(struct Announce_Peer* peer)
- {
- Bits_memset(peer, 0, Announce_Peer_SIZE);
- peer->length = Announce_Peer_SIZE;
- peer->type = Announce_Type_PEER;
- peer->unused = 0xffffffff;
- peer->peerNum_be = 0xffff;
- }
- /**
- * 1 2 3
- * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 0 | length | type | padding | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
- * 4 | Compressed Link State..... |
- * + +
- */
- struct Announce_LinkState
- {
- // Length of linkState + 3
- uint8_t length;
- // Announce_Type_LINK_STATE
- uint8_t type;
- // number of zero bytes before beginning of packed numbers
- uint8_t padding;
- // linkState
- uint8_t linkState[1];
- };
- static inline void Announce_LinkState_applyHeader(Message_t* pushTo)
- {
- Assert_failure("todo implement");
- }
- struct Announce_ItemHeader
- {
- uint8_t length;
- uint8_t type;
- };
- /**
- * 1 2 3
- * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 0 | |
- * + +
- * 4 | |
- * + +
- * 8 | |
- * + +
- * 12 | |
- * + +
- * 16 | |
- * + +
- * 20 | |
- * + +
- * 24 | |
- * + +
- * 28 | |
- * + Signature +
- * 32 | |
- * + +
- * 36 | |
- * + +
- * 40 | |
- * + +
- * 44 | |
- * + +
- * 48 | |
- * + +
- * 52 | |
- * + +
- * 56 | |
- * + +
- * 60 | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 64 | |
- * + +
- * 68 | |
- * + +
- * 72 | |
- * + +
- * 76 | |
- * + Public Signing Key +
- * 80 | |
- * + +
- * 84 | |
- * + +
- * 88 | |
- * + +
- * 92 | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 96 | |
- * + +
- * 100 | |
- * + SuperNode IP +
- * 104 | |
- * + +
- * 108 | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 112 | |
- * + Timestamp +-+-+-+-+
- * 116 | |R| ver |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- struct Announce_Header
- {
- // Signature of the header concatinated with the SHA-512 of the set of
- uint8_t signature[64];
- // Public signing key (can be derived to crypto key, see Sign.h)
- uint8_t pubSigningKey[32];
- // This is the IPv6 of the supernode which we are announcing to.
- // Including this allows supernodes to replicate only messages which:
- // 1. Indicate that a subnode has changed its supernode
- // 2. Update a link state which affects best paths between clusters of nodes that
- // are controlled by a given supernode.
- uint8_t snodeIp[16];
- // Milliseconds since the epoch when this message was crafted and reset flag
- uint8_t timeStampVersionFlags_be[8];
- };
- #define Announce_Header_SIZE 120
- Assert_compileTime(sizeof(struct Announce_Header) == Announce_Header_SIZE);
- static inline int64_t Announce_Header_getTimestamp(struct Announce_Header* hdr)
- {
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- return Endian_bigEndianToHost64(ts_be) >> 4;
- }
- static inline void Announce_Header_setTimestamp(struct Announce_Header* hdr,
- int64_t timestamp)
- {
- uint64_t uTime = (uint64_t) timestamp;
- // This will fail on January 1, 20892770.
- // It will also fail for negative timestamps.
- Assert_true(!(uTime >> 60));
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- ts_be = (ts_be & Endian_hostToBigEndian64(0x0f)) | Endian_hostToBigEndian64(uTime << 4);
- Bits_memcpy(hdr->timeStampVersionFlags_be, &ts_be, sizeof(uint64_t));
- }
- static inline bool Announce_Header_isReset(struct Announce_Header* hdr)
- {
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- return (Endian_bigEndianToHost64(ts_be) >> 3) & 1;
- }
- static inline void Announce_Header_setReset(struct Announce_Header* hdr, bool isReset)
- {
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- if (isReset) {
- ts_be |= Endian_hostToBigEndian64(1<<3);
- } else {
- ts_be &= ~Endian_hostToBigEndian64(1<<3);
- }
- Bits_memcpy(hdr->timeStampVersionFlags_be, &ts_be, sizeof(uint64_t));
- }
- static inline int Announce_Header_getVersion(struct Announce_Header* hdr)
- {
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- return Endian_bigEndianToHost64(ts_be) & 0x07;
- }
- #define Announce_Header_CURRENT_VERSION 1
- static inline void Announce_Header_setVersion(struct Announce_Header* hdr, int version)
- {
- uint64_t ts_be;
- Bits_memcpy(&ts_be, hdr->timeStampVersionFlags_be, sizeof(uint64_t));
- ts_be = (ts_be & ~Endian_hostToBigEndian64(0x07)) | Endian_hostToBigEndian64(version & 0x07);
- Bits_memcpy(hdr->timeStampVersionFlags_be, &ts_be, sizeof(uint64_t));
- }
- static inline struct Announce_ItemHeader* Announce_ItemHeader_next(Message_t* msg, void* last)
- {
- struct Announce_ItemHeader* ih = (struct Announce_ItemHeader*) last;
- if (ih) {
- Assert_true((uint8_t*)ih > &Message_bytes(msg)[-Message_getPadding(msg)]);
- Assert_true((uint8_t*)ih < &Message_bytes(msg)[Message_getLength(msg)]);
- ih = (struct Announce_ItemHeader*) ( &((uint8_t*) ih)[ih->length] );
- } else {
- ih = (struct Announce_ItemHeader*) &Message_bytes(msg)[Announce_Header_SIZE];
- }
- while ((uint8_t*)ih < &Message_bytes(msg)[Message_getLength(msg)]) {
- if (!ih->length) { return NULL; } // invalid message
- if (ih->length > 1) {
- if ( &((uint8_t*) ih)[ih->length] > &Message_bytes(msg)[Message_getLength(msg)] ) {
- // invalid message, overflow...
- return NULL;
- }
- return ih;
- }
- ih = (struct Announce_ItemHeader*) ( &((uint8_t*) ih)[ih->length] );
- }
- return NULL;
- }
- static inline bool Announce_ItemHeader_isEphimeral(struct Announce_ItemHeader* h)
- {
- switch (h->type) {
- case Announce_Type_VERSION:
- case Announce_Type_PEER:
- case Announce_Type_ENCODING_SCHEME: return false;
- default: return true;
- }
- }
- static inline bool Announce_ItemHeader_equals(
- struct Announce_ItemHeader* h0,
- struct Announce_ItemHeader* h1)
- {
- if (h0->type != h1->type || h0->length != h1->length) {
- return false;
- }
- return !Bits_memcmp(h0, h1, h0->length);
- }
- // Check if one item is a replacement for another
- static inline bool Announce_ItemHeader_doesReplace(
- struct Announce_ItemHeader* h0,
- struct Announce_ItemHeader* h1)
- {
- if (h0->type != h1->type) { return false; }
- switch (h0->type) {
- case Announce_Type_ENCODING_SCHEME:
- case Announce_Type_VERSION: {
- // only one version or encoding scheme is allowed at a time
- return true;
- }
- case Announce_Type_PEER: {
- // peers are identified by their peernum
- struct Announce_Peer* p0 = (struct Announce_Peer*) h0;
- struct Announce_Peer* p1 = (struct Announce_Peer*) h1;
- return p0->peerNum_be == p1->peerNum_be;
- }
- // Ephimeral entities never replace one another
- default: return false;
- }
- }
- static inline struct Announce_ItemHeader* Announce_itemInMessage(
- Message_t* msg,
- struct Announce_ItemHeader* ref)
- {
- struct Announce_ItemHeader* ih = NULL;
- do {
- ih = Announce_ItemHeader_next(msg, ih);
- } while (ih && !Announce_ItemHeader_doesReplace(ref, ih));
- return ih;
- }
- static inline bool Announce_isValid(Message_t* msg)
- {
- struct Announce_ItemHeader* ih = NULL;
- for (;;) {
- ih = Announce_ItemHeader_next(msg, ih);
- if (!ih) { return false; }
- if ((uint8_t*)ih == &Message_bytes(msg)[Message_getLength(msg) - ih->length]) { return true; }
- }
- }
- static inline struct Announce_Peer* Announce_Peer_next(Message_t* msg, void* last)
- {
- struct Announce_ItemHeader* ih = (struct Announce_ItemHeader*) last;
- do {
- ih = Announce_ItemHeader_next(msg, ih);
- } while (ih && ih->type != Announce_Type_PEER);
- return (struct Announce_Peer*) ih;
- }
- #endif
|