-
Notifications
You must be signed in to change notification settings - Fork 588
/
Announce.h
427 lines (379 loc) · 16.5 KB
/
Announce.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/* 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 "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(struct Message* 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)pushTo->msgbytes % 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(struct Message* 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(struct Message* msg, void* last)
{
struct Announce_ItemHeader* ih = (struct Announce_ItemHeader*) last;
if (ih) {
Assert_true((uint8_t*)ih > &msg->msgbytes[-Message_getPadding(msg)]);
Assert_true((uint8_t*)ih < &msg->msgbytes[Message_getLength(msg)]);
ih = (struct Announce_ItemHeader*) ( &((uint8_t*) ih)[ih->length] );
} else {
ih = (struct Announce_ItemHeader*) &msg->msgbytes[Announce_Header_SIZE];
}
while ((uint8_t*)ih < &msg->msgbytes[Message_getLength(msg)]) {
if (!ih->length) { return NULL; } // invalid message
if (ih->length > 1) {
if ( &((uint8_t*) ih)[ih->length] > &msg->msgbytes[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(
struct Message* 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(struct Message* msg)
{
struct Announce_ItemHeader* ih = NULL;
for (;;) {
ih = Announce_ItemHeader_next(msg, ih);
if (!ih) { return false; }
if ((uint8_t*)ih == &msg->msgbytes[Message_getLength(msg) - ih->length]) { return true; }
}
}
static inline struct Announce_Peer* Announce_Peer_next(struct Message* 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