esp8266ndn
NDN Arduino library for ESP8266 and more
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lp.hpp
Go to the documentation of this file.
1#ifndef NDNPH_PACKET_LP_HPP
2#define NDNPH_PACKET_LP_HPP
3
4#include "data.hpp"
5#include "interest.hpp"
6#include "nack.hpp"
7
8namespace ndnph {
9namespace lp {
10
13public:
15 using MaxSize = std::integral_constant<size_t, 1 + 1 + 8 + 1 + 1 + 1 + 1 + 1 + 1>;
16
17 uint64_t getSeqNumBase() const {
18 return seqNum - fragIndex;
19 }
20
21 void encodeTo(Encoder& encoder) const {
22 encoder.prepend(
23 [this](Encoder& encoder) { encoder.prependTlv(TT::LpSeqNum, tlv::NNI8(seqNum)); },
24 [this](Encoder& encoder) { encoder.prependTlv(TT::FragIndex, tlv::NNI(fragIndex)); },
25 [this](Encoder& encoder) { encoder.prependTlv(TT::FragCount, tlv::NNI(fragCount)); });
26 }
27
28public:
29 uint64_t seqNum = 0;
30 uint8_t fragIndex = 0;
31 uint8_t fragCount = 1;
32};
33
35class PitToken {
36public:
38 static PitToken from4(uint32_t n) {
39 uint8_t room[4];
40 tlv::NNI4::writeValue(room, n);
41 PitToken token;
42 token.set(4, room);
43 return token;
44 }
45
47 explicit operator bool() const {
48 return m_length > 0;
49 }
50
51 size_t length() const {
52 return m_length;
53 }
54
55 const uint8_t* value() const {
56 return m_value.begin();
57 }
58
60 uint32_t to4() const {
61 return m_length == 4 ? tlv::NNI4::readValue(m_value.begin()) : 0;
62 }
63
65 bool set(size_t length, const uint8_t* value) {
66 if (length > m_value.size()) {
67 return false;
68 }
69 m_length = length;
70 std::copy_n(value, length, m_value.begin());
71 return true;
72 }
73
74 void encodeTo(Encoder& encoder) const {
75 uint8_t* room = encoder.prependRoom(m_length);
76 if (room == nullptr) {
77 return;
78 }
79 std::copy_n(m_value.begin(), m_length, room);
80 encoder.prependTypeLength(TT::PitToken, m_length);
81 }
82
83 bool decodeFrom(const Decoder::Tlv& d) {
84 return set(d.length, d.value);
85 }
86
87 friend bool operator==(const PitToken& lhs, const PitToken& rhs) {
88 return lhs.m_length == rhs.m_length &&
89 std::equal(lhs.m_value.begin(), lhs.m_value.begin() + lhs.m_length, rhs.m_value.begin());
90 }
91
93
94private:
95 std::array<uint8_t, NDNPH_PITTOKEN_MAX> m_value;
96 uint8_t m_length = 0;
97
98 static_assert(NDNPH_PITTOKEN_MAX >= 4, "");
99 static_assert(NDNPH_PITTOKEN_MAX <= 32, "");
100};
101
104public:
106 using L3MaxSize =
107 std::integral_constant<size_t, 1 + 1 + NDNPH_PITTOKEN_MAX + NackHeader::MaxSize::value>;
108
109 void encodeL3Header(Encoder& encoder) const {
110 encoder.prepend(
111 [this](Encoder& encoder) {
112 if (pitToken) {
113 encoder.prepend(pitToken);
114 }
115 },
116 [this](Encoder& encoder) {
117 if (nack) {
118 encoder.prepend(nack);
119 }
120 });
121 }
122
124 pitToken = src.pitToken;
125 nack = src.nack;
126 }
127
128public:
132};
133
138template<typename Payload>
139class Encodable : public EncodableBase {
140public:
141 explicit Encodable(Payload payload)
142 : payload(std::move(payload)) {}
143
144 void encodeTo(Encoder& encoder) const {
146 Encoder l3h(l3hRegion);
147 encodeL3Header(l3h);
148 if (!l3h) {
149 encoder.setError();
150 return;
151 }
152
153 if (frag.fragCount <= 1 && l3h.size() == 0) {
154 encoder.prepend(payload);
155 return;
156 }
157 encoder.prependTlv(
158 TT::LpPacket,
159 [this](Encoder& encoder) {
160 if (frag.fragCount > 1) {
161 encoder.prepend(frag);
162 }
163 },
164 tlv::Value(l3h), [this](Encoder& encoder) { encoder.prependTlv(TT::LpPayload, payload); });
165 }
166
167public:
168 Payload payload;
169};
170
176template<typename L3, typename R = Encodable<L3>>
177R
178encode(L3 l3, PitToken pitToken = {}) {
179 R encodable(l3);
180 encodable.pitToken = pitToken;
181 return encodable;
182}
183
188inline Encodable<Interest>
189encode(Nack nack, PitToken pitToken = {}) {
190 auto encodable = encode(nack.getInterest(), pitToken);
191 encodable.nack = nack.getHeader();
192 return encodable;
193}
194
196class Fragmenter : public WithRegion {
197public:
199 class Fragment : public Encodable<tlv::Value> {
200 public:
201 using Encodable::Encodable;
202
203 public:
204 const Fragment* next = nullptr;
205 };
206
213 explicit Fragmenter(Region& region, uint16_t mtu)
214 : WithRegion(region)
215 , m_room(static_cast<int>(mtu) - FragmentOverhead) {
216 port::RandomSource::generate(reinterpret_cast<uint8_t*>(&m_nextSeqNum), sizeof(m_nextSeqNum));
217 }
218
230 template<typename L3>
232 region.reset();
233 size_t sizeofHeader = 0;
234 {
235 ScopedEncoder l3h(region);
236 packet.encodeL3Header(l3h);
237 if (!l3h) {
238 return nullptr;
239 }
240 sizeofHeader = l3h.size();
241 }
242
243 Encoder payload(region);
244 packet.payload.encodeTo(payload);
245 if (!payload) {
246 payload.discard();
247 return nullptr;
248 }
249 payload.trim();
250
251 return fragmentImpl(packet, sizeofHeader, tlv::Value(payload));
252 }
253
254private:
255 const Fragment* fragmentImpl(EncodableBase& input, size_t sizeofHeader, tlv::Value payload) {
256 int sizeofFirstFragment = m_room - sizeofHeader;
257 if (sizeofFirstFragment > static_cast<int>(payload.size())) {
258 auto frag = region.make<Fragment>(payload);
259 if (frag == nullptr) {
260 return nullptr;
261 }
262 frag->copyL3HeaderFrom(input);
263 return frag;
264 }
265 if (sizeofFirstFragment <= 0) {
266 return nullptr;
267 }
268
269 auto first = region.make<Fragment>(tlv::Value(payload.begin(), sizeofFirstFragment));
270 if (first == nullptr) {
271 return nullptr;
272 }
273 first->copyL3HeaderFrom(input);
274
275 auto prev = first;
276 uint8_t fragCount = 1;
277 for (size_t nextOffset, offset = sizeofFirstFragment; offset < payload.size();
278 offset = nextOffset) {
279 nextOffset = std::min(offset + m_room, payload.size());
280 auto frag =
281 region.make<Fragment>(tlv::Value(payload.begin() + offset, payload.begin() + nextOffset));
282 if (frag == nullptr) {
283 return nullptr;
284 }
285 prev->next = frag;
286 prev = frag;
287 ++fragCount;
288 }
289
290 auto frag = first;
291 for (uint8_t fragIndex = 0; fragIndex < fragCount; ++fragIndex) {
292 frag->frag.seqNum = m_nextSeqNum++;
293 frag->frag.fragIndex = fragIndex;
294 frag->frag.fragCount = fragCount;
295 frag = const_cast<Fragment*>(frag->next);
296 }
297 return first;
298 }
299
300private:
301 enum {
302 FragmentOverhead = 1 + 3 + // LpPacket TL
303 1 + 1 + 8 + // LpSeqNum
304 1 + 1 + 1 + // FragIndex
305 1 + 1 + 1 + // FragCount
306 1 + 3 // LpPayload TL
307 };
308
309 uint64_t m_nextSeqNum = 0;
310 int m_room = 0;
311};
312
314class L3Header {
315public:
316 std::tuple<bool, L3Header> clone(Region& region) const {
317 L3Header copy;
318 copy.pitToken = pitToken;
319 if (!nack) {
320 return std::make_tuple(true, copy);
321 }
322 copy.nack = nack.clone(region);
323 return std::make_tuple(!!copy.nack, copy);
324 }
325
326public:
329};
330
337
340public:
341 enum class Type : uint16_t {
342 None = 0,
343 Fragment = TT::FragIndex,
344 Interest = TT::Interest,
345 Data = TT::Data,
346 Nack = TT::Nack,
347 };
348
349 explicit PacketClassify() = default;
350
351 explicit PacketClassify(L3Header l3header, tlv::Value payload)
352 : m_l3header(l3header)
353 , m_payload(payload) {
354 m_type = classifyType();
355 }
356
357 bool decodeFrom(const Decoder::Tlv& input) {
358 m_type = Type::None;
359 m_l3header = L3Header();
360 m_frag = FragmentHeader();
361
362 switch (input.type) {
363 case TT::Interest:
364 case TT::Data:
365 m_payload = tlv::Value(input.tlv, input.size);
366 m_type = classifyType();
367 return m_type != Type::None;
368 case TT::LpPacket:
369 break;
370 default:
371 return false;
372 }
373
374 bool ok = EvDecoder::decodeEx(
375 input, {TT::LpPacket}, EvDecoder::DefaultUnknownCb(),
376 [](uint32_t type) { return type < 800 || type > 959 || (type & 0x03) != 0x00; },
377 EvDecoder::defNni<TT::LpSeqNum, tlv::NNI8>(&m_frag.seqNum),
378 EvDecoder::defNni<TT::FragIndex>(&m_frag.fragIndex),
379 EvDecoder::defNni<TT::FragCount>(&m_frag.fragCount),
380 EvDecoder::def<TT::PitToken>(&m_l3header.pitToken),
381 EvDecoder::def<TT::Nack>([this](const Decoder::Tlv& d) {
382 m_type = Type::Nack;
383 m_l3header.nack = tlv::Value(d.tlv, d.size);
384 }),
385 EvDecoder::def<TT::LpPayload>(&m_payload));
386 if (!ok) {
387 return false;
388 }
389
390 m_type = classifyType();
391 return m_type != Type::None;
392 }
393
395 Type getType() const {
396 return m_type;
397 }
398
400 const PitToken& getPitToken() const {
401 return m_l3header.pitToken;
402 }
403
409 Fragment frag;
410 static_cast<FragmentHeader&>(frag) = m_frag;
411 frag.l3header = m_l3header;
412 frag.payload = m_payload;
413 return frag;
414 }
415
420 bool decodeInterest(Interest interest) const {
421 return m_type == Type::Interest && m_payload.makeDecoder().decode(interest);
422 }
423
428 bool decodeData(Data data) const {
429 return m_type == Type::Data && m_payload.makeDecoder().decode(data);
430 }
431
436 bool decodeNack(Nack nack) const {
437 auto nackHeader = nack.getHeader();
438 auto interest = nack.getInterest();
439 return m_type == Type::Nack && m_l3header.nack.makeDecoder().decode(nackHeader) &&
440 m_payload.makeDecoder().decode(interest);
441 }
442
443private:
444 Type classifyType() const {
445 if (m_frag.fragCount > 1) {
446 return Type::Fragment;
447 }
448 for (auto l3 : m_payload.makeDecoder()) {
449 switch (l3.type) {
450 case TT::Interest:
451 return !!m_l3header.nack ? Type::Nack : Type::Interest;
452 case TT::Data:
453 return Type::Data;
454 default:
455 return Type::None;
456 }
457 }
458 return Type::None;
459 }
460
461private:
462 Type m_type = Type::None;
463 FragmentHeader m_frag;
464 L3Header m_l3header;
465 tlv::Value m_payload;
466};
467
471class Reassembler : public WithRegion {
472public:
478 explicit Reassembler(Region& region)
479 : WithRegion(region) {}
480
488 void discard() {
489 m_buffer = nullptr;
490 }
491
507 bool add(const Fragment& frag) {
508 if (frag.fragIndex == 0) {
509 return begin(frag);
510 }
511 return append(frag);
512 }
513
521 if (m_nextFragIndex != m_fragCount) {
522 return PacketClassify();
523 }
524 return PacketClassify(m_l3header, tlv::Value(m_buffer, m_size));
525 }
526
527private:
528 bool begin(const Fragment& frag) {
529 discard();
530 region.reset();
531
532 bool ok = false;
533 std::tie(ok, m_l3header) = frag.l3header.clone(region);
534 m_capacity = region.available();
535 m_buffer = region.alloc(m_capacity);
536 if (!ok || m_buffer == nullptr) {
537 return false;
538 }
539
540 m_size = 0;
541 m_seqNumBase = frag.getSeqNumBase();
542 m_nextFragIndex = 0;
543 m_fragCount = frag.fragCount;
544 return append(frag);
545 }
546
547 bool append(const Fragment& frag) {
548 if (m_buffer == nullptr || frag.getSeqNumBase() != m_seqNumBase ||
549 frag.fragIndex != m_nextFragIndex || frag.fragCount != m_fragCount ||
550 frag.payload.size() > m_capacity - m_size) {
551 return false;
552 }
553
554 std::copy(frag.payload.begin(), frag.payload.end(), &m_buffer[m_size]);
555 m_size += frag.payload.size();
556 ++m_nextFragIndex;
557 return true;
558 }
559
560private:
561 L3Header m_l3header;
562 uint8_t* m_buffer = nullptr;
563 size_t m_capacity = 0;
564 size_t m_size = 0;
565 uint64_t m_seqNumBase = 0;
566 uint8_t m_nextFragIndex = 0;
567 uint8_t m_fragCount = 0;
568};
569
570} // namespace lp
571} // namespace ndnph
572
573#endif // NDNPH_PACKET_LP_HPP
Data packet.
Definition data.hpp:136
Decoded TLV.
Definition decoder.hpp:13
const uint8_t * tlv
Definition decoder.hpp:42
size_t length
Definition decoder.hpp:39
size_t size
Definition decoder.hpp:43
const uint8_t * value
Definition decoder.hpp:40
TLV encoder that accepts items in reverse order.
Definition encoder.hpp:10
bool prepend(const First &first, const Arg &... arg)
Prepend a sequence of values.
Definition encoder.hpp:123
void trim() const
Release unused space to the Region.
Definition encoder.hpp:58
bool prependTypeLength(uint32_t type, size_t length)
Prepend TLV-TYPE and TLV-LENGTH.
Definition encoder.hpp:103
uint8_t * prependRoom(size_t size)
Make room to prepend an object.
Definition encoder.hpp:90
void discard()
Release all space to the Region.
Definition encoder.hpp:72
bool prependTlv(uint32_t type, OmitEmptyTag omitEmpty, const Arg &... arg)
Prepend TLV, measuring TLV-LENGTH automatically.
Definition encoder.hpp:143
void setError()
Indicate an error has occurred.
Definition encoder.hpp:166
size_t size() const
Get output size.
Definition encoder.hpp:44
Definition ev-decoder.hpp:95
Interest packet.
Definition interest.hpp:284
Nack header field.
Definition nack.hpp:22
Nack packet.
Definition nack.hpp:73
Interest getInterest() const
Access the Interest.
Definition nack.hpp:87
NackHeader getHeader() const
Access the Nack header.
Definition nack.hpp:78
Region-based memory allocator thats owns memory of NDNph objects.
Definition region.hpp:9
Encoder that auto-discards upon destruction.
Definition encoder.hpp:198
Region with statically allocated memory.
Definition region.hpp:143
Base class of an object associated with a Region.
Definition region.hpp:182
Common fields during encoding.
Definition lp.hpp:103
void encodeL3Header(Encoder &encoder) const
Definition lp.hpp:109
FragmentHeader frag
Definition lp.hpp:129
NackHeader nack
Definition lp.hpp:131
std::integral_constant< size_t, 1+1+NDNPH_PITTOKEN_MAX+NackHeader::MaxSize::value > L3MaxSize
Maximum encoded size of L3 headers.
Definition lp.hpp:107
PitToken pitToken
Definition lp.hpp:130
void copyL3HeaderFrom(const EncodableBase &src)
Definition lp.hpp:123
Encodable type of an LpPacket.
Definition lp.hpp:139
Encodable(Payload payload)
Definition lp.hpp:141
Payload payload
Definition lp.hpp:168
void encodeTo(Encoder &encoder) const
Definition lp.hpp:144
Fragment header fields.
Definition lp.hpp:12
void encodeTo(Encoder &encoder) const
Definition lp.hpp:21
std::integral_constant< size_t, 1+1+8+1+1+1+1+1+1 > MaxSize
Maximum encoded size.
Definition lp.hpp:15
uint64_t seqNum
Definition lp.hpp:29
uint64_t getSeqNumBase() const
Definition lp.hpp:17
uint8_t fragIndex
Definition lp.hpp:30
uint8_t fragCount
Definition lp.hpp:31
Decoded fragment.
Definition lp.hpp:332
tlv::Value payload
Definition lp.hpp:335
L3Header l3header
Definition lp.hpp:334
Singly linked list of encodable fragments.
Definition lp.hpp:199
NDNLPv2 fragmenter.
Definition lp.hpp:196
Fragmenter(Region &region, uint16_t mtu)
Constructor.
Definition lp.hpp:213
const Fragment * fragment(Encodable< L3 > packet)
Fragment an LP packet.
Definition lp.hpp:231
Decoded L3 header fields.
Definition lp.hpp:314
std::tuple< bool, L3Header > clone(Region &region) const
Definition lp.hpp:316
tlv::Value nack
Definition lp.hpp:328
PitToken pitToken
Definition lp.hpp:327
Decode NDNLPv2 packet for classification.
Definition lp.hpp:339
Type getType() const
Determine L3 packet type.
Definition lp.hpp:395
Fragment getFragment() const
Retrieve fragment.
Definition lp.hpp:408
bool decodeFrom(const Decoder::Tlv &input)
Definition lp.hpp:357
bool decodeNack(Nack nack) const
Decode Nack.
Definition lp.hpp:436
bool decodeData(Data data) const
Decode payload as Data.
Definition lp.hpp:428
Type
Definition lp.hpp:341
const PitToken & getPitToken() const
Retrieve PIT token.
Definition lp.hpp:400
PacketClassify(L3Header l3header, tlv::Value payload)
Definition lp.hpp:351
bool decodeInterest(Interest interest) const
Decode payload as Interest.
Definition lp.hpp:420
PIT token field.
Definition lp.hpp:35
bool decodeFrom(const Decoder::Tlv &d)
Definition lp.hpp:83
static PitToken from4(uint32_t n)
Construct 4-octet PIT token from uint32.
Definition lp.hpp:38
uint32_t to4() const
Interpret 4-octet PIT token as uint32.
Definition lp.hpp:60
bool set(size_t length, const uint8_t *value)
Assign PIT token length and value.
Definition lp.hpp:65
void encodeTo(Encoder &encoder) const
Definition lp.hpp:74
size_t length() const
Definition lp.hpp:51
friend bool operator==(const PitToken &lhs, const PitToken &rhs)
Definition lp.hpp:87
const uint8_t * value() const
Definition lp.hpp:55
NDNLPv2 fragmenter.
Definition lp.hpp:471
PacketClassify reassemble() const
Reassemble the packet if it's complete.
Definition lp.hpp:520
void discard()
Discard the reassembly buffer.
Definition lp.hpp:488
bool add(const Fragment &frag)
Add a fragment.
Definition lp.hpp:507
Reassembler(Region &region)
Constructor.
Definition lp.hpp:478
NonNegativeInteger encoding.
Definition nni.hpp:118
A sequence of bytes, usually TLV-VALUE.
Definition value.hpp:11
const uint8_t * begin() const
Definition value.hpp:38
size_t size() const
Definition value.hpp:46
Definition nni.hpp:12
static void writeValue(uint8_t *room, T n)
static T readValue(const uint8_t *input)
#define NDNPH_PITTOKEN_MAX
Maximum length of PIT token.
Definition common.hpp:45
@ LpSeqNum
Definition an.hpp:11
@ FragCount
Definition an.hpp:13
@ PitToken
Definition an.hpp:14
@ FragIndex
Definition an.hpp:12
R encode(L3 l3, PitToken pitToken={})
Encode Interest or Data as LpPacket, optionally with PIT token.
Definition lp.hpp:178
Definition fs.hpp:33
#define NDNPH_DECLARE_NE(T, specifier)
Declare operator!= in terms of operator==.
Definition operators.hpp:7