blob: 2ef008ce3abeac34319e5f97c1403ed68271ba07 [file] [log] [blame]
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 *
5 * BSD license, See the LICENSE file for more information
6 *
7 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
8 */
9
10#ifndef NDN_TLV_HPP
11#define NDN_TLV_HPP
12
Alexander Afanasyev54467af2014-01-06 15:45:32 -080013#include <stdexcept>
Yingdi Yu27158392014-01-20 13:04:20 -080014#include <iterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080015#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080016#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080017
18namespace ndn {
19
20/**
21 * @brief Namespace defining NDN-TLV related constants and procedures
22 */
23namespace Tlv {
24
25struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
26
27enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080028 Interest = 5,
29 Data = 6,
30 Name = 7,
31 NameComponent = 8,
32 Selectors = 9,
33 Nonce = 10,
34 Scope = 11,
35 InterestLifetime = 12,
36 MinSuffixComponents = 13,
37 MaxSuffixComponents = 14,
38 PublisherPublicKeyLocator = 15,
39 Exclude = 16,
40 ChildSelector = 17,
41 MustBeFresh = 18,
42 Any = 19,
43 MetaInfo = 20,
44 Content = 21,
45 SignatureInfo = 22,
46 SignatureValue = 23,
47 ContentType = 24,
48 FreshnessPeriod = 25,
49 FinalBlockId = 26,
50 SignatureType = 27,
51 KeyLocator = 28,
52 KeyLocatorDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080053
54 AppPrivateBlock1 = 128,
55 AppPrivateBlock2 = 32767
56};
57
58enum SignatureType {
59 DigestSha256 = 0,
60 SignatureSha256WithRsa = 1,
61};
62
63enum ConentType {
64 ContentType_Default = 0,
65 ContentType_Link = 1,
66 ContentType_Key = 2,
67};
68
69/**
70 * @brief Read VAR-NUMBER in NDN-TLV encoding
71 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -070072 * @param [in] begin Begin (pointer or iterator) of the buffer
73 * @param [in] end End (pointer or iterator) of the buffer
74 * @param [out] number Read number
75 *
76 * @throws This call never throws exception
77 *
78 * @return true if number successfully read from input, false otherwise
79 */
80template<class InputIterator>
81inline bool
82readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number);
83
84/**
85 * @brief Read TLV Type
86 *
87 * @param [in] begin Begin (pointer or iterator) of the buffer
88 * @param [in] end End (pointer or iterator) of the buffer
89 * @param [out] number Read type number
90 *
91 * @throws This call never throws exception
92 *
93 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
94 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
95 */
96template<class InputIterator>
97inline bool
98readType(InputIterator &begin, const InputIterator &end, uint32_t& type);
99
100
101/**
102 * @brief Read VAR-NUMBER in NDN-TLV encoding
103 *
104 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800105 *
106 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
107 */
108template<class InputIterator>
109inline uint64_t
110readVarNumber(InputIterator &begin, const InputIterator &end);
111
112/**
113 * @brief Read TLV Type
114 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700115 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
116 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
118 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
119 */
120template<class InputIterator>
121inline uint32_t
122readType(InputIterator &begin, const InputIterator &end);
123
124/**
125 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
126 */
127inline size_t
128sizeOfVarNumber(uint64_t varNumber);
129
130/**
131 * @brief Write VAR-NUMBER to the specified stream
132 */
133inline size_t
134writeVarNumber(std::ostream &os, uint64_t varNumber);
135
136/**
137 * @brief Read nonNegativeInteger in NDN-TLV encoding
138 *
139 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
140 *
141 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
142 *
143 * How many bytes will be read is directly controlled by the size parameter, which can be either
144 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
145 */
146template<class InputIterator>
147inline uint64_t
148readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end);
149
150/**
151 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
152 */
153inline size_t
154sizeOfNonNegativeInteger(uint64_t varNumber);
155
156/**
157 * @brief Write nonNegativeInteger to the specified stream
158 */
159inline size_t
160writeNonNegativeInteger(std::ostream &os, uint64_t varNumber);
161
162/////////////////////////////////////////////////////////////////////////////////
163/////////////////////////////////////////////////////////////////////////////////
164/////////////////////////////////////////////////////////////////////////////////
165
166// Inline implementations
167
168/////////////////////////////////////////////////////////////////////////////////
169/////////////////////////////////////////////////////////////////////////////////
170/////////////////////////////////////////////////////////////////////////////////
171
172template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173inline bool
174readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number)
175{
176 if (begin == end)
177 return false;
178
179 uint8_t value = *begin;
180 ++begin;
181 if (value < 253)
182 {
183 number = value;
184 }
185 else if (value == 253)
186 {
187 if (end - begin < 2)
188 return false;
189
190 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
191 begin += 2;
192 number = be16toh(value);
193 }
194 else if (value == 254)
195 {
196 if (end - begin < 4)
197 return false;
198
199 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
200 begin += 4;
201 number = be32toh(value);
202 }
203 else // if (value == 255)
204 {
205 if (end - begin < 8)
206 return false;
207
208 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
209 begin += 8;
210
211 number = be64toh(value);
212 }
213
214 return true;
215}
216
217template<class InputIterator>
218inline bool
219readType(InputIterator &begin, const InputIterator &end, uint32_t& type)
220{
221 uint64_t number;
222 bool ok = readVarNumber(begin, end, number);
223 if (number > std::numeric_limits<uint32_t>::max())
224 {
225 return false;
226 }
227
228 type = static_cast<uint64_t> (number);
229 return true;
230}
231
232template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800233inline uint64_t
234readVarNumber(InputIterator &begin, const InputIterator &end)
235{
236 if (begin == end)
237 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239 uint8_t value = *begin;
240 ++begin;
241 if (value < 253)
242 {
243 return value;
244 }
245 else if (value == 253)
246 {
247 if (end - begin < 2)
248 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700249
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800250 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
251 begin += 2;
252 return be16toh(value);
253 }
254 else if (value == 254)
255 {
256 if (end - begin < 4)
257 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
260 begin += 4;
261 return be32toh(value);
262 }
263 else // if (value == 255)
264 {
265 if (end - begin < 8)
266 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700267
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800268 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
269 begin += 8;
270
271 return be64toh(value);
272 }
273}
274
Yingdi Yu27158392014-01-20 13:04:20 -0800275template<>
276inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700277readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin,
Yingdi Yu27158392014-01-20 13:04:20 -0800278 const std::istream_iterator<uint8_t> &end)
279{
280 if (begin == end)
281 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700282
Yingdi Yu27158392014-01-20 13:04:20 -0800283 uint8_t value = *begin;
284 ++begin;
285 if (value < 253)
286 {
287 return value;
288 }
289 else if (value == 253)
290 {
291 uint8_t buffer[2];
292 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293
Yingdi Yu27158392014-01-20 13:04:20 -0800294 while(begin != end && count < 2){
295 buffer[count] = *begin;
296 begin++;
297 count++;
298 }
299
300 if (count < 2)
301 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700302
303 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
Yingdi Yu27158392014-01-20 13:04:20 -0800304 return be16toh(value);
305 }
306 else if (value == 254)
307 {
308 uint8_t buffer[4];
309 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
Yingdi Yu27158392014-01-20 13:04:20 -0800311 while(begin != end && count < 4){
312 buffer[count] = *begin;
313 begin++;
314 count++;
315 }
316
317 if (count < 4)
318 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700319
Yingdi Yu27158392014-01-20 13:04:20 -0800320 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
321 return be32toh(value);
322 }
323 else // if (value == 255)
324 {
325 uint8_t buffer[8];
326 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700327
Yingdi Yu27158392014-01-20 13:04:20 -0800328 while(begin != end && count < 8){
329 buffer[count] = *begin;
330 begin++;
331 count++;
332 }
333
334 if (count < 8)
335 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700336
Yingdi Yu27158392014-01-20 13:04:20 -0800337 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
338 return be64toh(value);
339 }
340}
341
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800342template<class InputIterator>
343inline uint32_t
344readType(InputIterator &begin, const InputIterator &end)
345{
346 uint64_t type = readVarNumber(begin, end);
347 if (type > std::numeric_limits<uint32_t>::max())
348 {
349 throw Error("TLV type code exceeds allowed maximum");
350 }
351
352 return static_cast<uint32_t> (type);
353}
354
355size_t
356sizeOfVarNumber(uint64_t varNumber)
357{
358 if (varNumber < 253) {
359 return 1;
360 }
361 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
362 return 3;
363 }
364 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
365 return 5;
366 }
367 else {
368 return 9;
369 }
370}
371
372inline size_t
373writeVarNumber(std::ostream &os, uint64_t varNumber)
374{
375 if (varNumber < 253) {
376 os.put(static_cast<uint8_t> (varNumber));
377 return 1;
378 }
379 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
380 os.put(253);
381 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
382 os.write(reinterpret_cast<const char*> (&value), 2);
383 return 3;
384 }
385 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
386 os.put(254);
387 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
388 os.write(reinterpret_cast<const char*> (&value), 4);
389 return 5;
390 }
391 else {
392 os.put(255);
393 uint64_t value = htobe64(varNumber);
394 os.write(reinterpret_cast<const char*> (&value), 8);
395 return 9;
396 }
397}
398
399template<class InputIterator>
400inline uint64_t
401readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end)
402{
403 switch (size) {
404 case 1:
405 {
406 if (end - begin < 1)
407 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700408
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 uint8_t value = *begin;
410 begin++;
411 return value;
412 }
413 case 2:
414 {
415 if (end - begin < 2)
416 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700417
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800418 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
419 begin += 2;
420 return be16toh(value);
421 }
422 case 4:
423 {
424 if (end - begin < 4)
425 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700426
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800427 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
428 begin += 4;
429 return be32toh(value);
430 }
431 case 8:
432 {
433 if (end - begin < 8)
434 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700435
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
437 begin += 8;
438 return be64toh(value);
439 }
440 }
441 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
442}
443
Yingdi Yu27158392014-01-20 13:04:20 -0800444template<>
445inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700446readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
447 std::istream_iterator<uint8_t> &begin,
Yingdi Yu27158392014-01-20 13:04:20 -0800448 const std::istream_iterator<uint8_t> &end)
449{
450 switch (size) {
451 case 1:
452 {
453 if(begin == end)
454 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700455
Yingdi Yu27158392014-01-20 13:04:20 -0800456 uint8_t value = *begin;
457 begin++;
458 return value;
459 }
460 case 2:
461 {
462 uint8_t buffer[2];
463 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700464
Yingdi Yu27158392014-01-20 13:04:20 -0800465 while(begin != end && count < 2){
466 buffer[count] = *begin;
467 begin++;
468 count++;
469 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700470
Yingdi Yu27158392014-01-20 13:04:20 -0800471 if (count < 2)
472 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700473
Yingdi Yu27158392014-01-20 13:04:20 -0800474 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
475 return be16toh(value);
476 }
477 case 4:
478 {
479 uint8_t buffer[4];
480 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700481
Yingdi Yu27158392014-01-20 13:04:20 -0800482 while(begin != end && count < 4){
483 buffer[count] = *begin;
484 begin++;
485 count++;
486 }
487
488 if (count < 4)
489 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700490
Yingdi Yu27158392014-01-20 13:04:20 -0800491 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
492 return be32toh(value);
493 }
494 case 8:
495 {
496 uint8_t buffer[8];
497 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700498
Yingdi Yu27158392014-01-20 13:04:20 -0800499 while(begin != end && count < 8){
500 buffer[count] = *begin;
501 begin++;
502 count++;
503 }
504
505 if (count < 8)
506 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700507
Yingdi Yu27158392014-01-20 13:04:20 -0800508 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
509 return be64toh(value);
510 }
511 }
512 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
513}
514
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800515inline size_t
516sizeOfNonNegativeInteger(uint64_t varNumber)
517{
518 if (varNumber < 253) {
519 return 1;
520 }
521 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
522 return 2;
523 }
524 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
525 return 4;
526 }
527 else {
528 return 8;
529 }
530}
531
532
533inline size_t
534writeNonNegativeInteger(std::ostream &os, uint64_t varNumber)
535{
536 if (varNumber < 253) {
537 os.put(static_cast<uint8_t> (varNumber));
538 return 1;
539 }
540 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
541 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
542 os.write(reinterpret_cast<const char*> (&value), 2);
543 return 2;
544 }
545 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
546 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
547 os.write(reinterpret_cast<const char*> (&value), 4);
548 return 4;
549 }
550 else {
551 uint64_t value = htobe64(varNumber);
552 os.write(reinterpret_cast<const char*> (&value), 8);
553 return 8;
554 }
555}
556
557
558} // namespace tlv
559} // namespace ndn
560
561#endif // NDN_TLV_HPP