blob: 511d0f6802851747ec36260c58461a9a2101b0df [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 Afanasyev636e9f12014-01-07 12:01:03 -080028 Interest = 1,
29 Data = 2,
30 Name = 3,
31 NameComponent = 4,
32 Selectors = 5,
33 Nonce = 6,
34 Scope = 7,
35 InterestLifetime = 8,
36 MinSuffixComponents = 9,
37 MaxSuffixComponents = 10,
38 PublisherPublicKeyLocator = 11,
39 Exclude = 12,
40 ChildSelector = 13,
41 MustBeFresh = 14,
42 Any = 15,
43 MetaInfo = 16,
44 Content = 17,
45 SignatureInfo = 18,
46 SignatureValue = 19,
47 ContentType = 20,
48 FreshnessPeriod = 21,
49 SignatureType = 22,
50 KeyLocator = 23,
51 KeyLocatorDigest = 24,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080052
53 AppPrivateBlock1 = 128,
54 AppPrivateBlock2 = 32767
55};
56
57enum SignatureType {
58 DigestSha256 = 0,
59 SignatureSha256WithRsa = 1,
60};
61
62enum ConentType {
63 ContentType_Default = 0,
64 ContentType_Link = 1,
65 ContentType_Key = 2,
66};
67
68/**
69 * @brief Read VAR-NUMBER in NDN-TLV encoding
70 *
71 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
72 *
73 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
74 */
75template<class InputIterator>
76inline uint64_t
77readVarNumber(InputIterator &begin, const InputIterator &end);
78
79/**
80 * @brief Read TLV Type
81 *
82 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
83 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
84 */
85template<class InputIterator>
86inline uint32_t
87readType(InputIterator &begin, const InputIterator &end);
88
89/**
90 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
91 */
92inline size_t
93sizeOfVarNumber(uint64_t varNumber);
94
95/**
96 * @brief Write VAR-NUMBER to the specified stream
97 */
98inline size_t
99writeVarNumber(std::ostream &os, uint64_t varNumber);
100
101/**
102 * @brief Read nonNegativeInteger in NDN-TLV encoding
103 *
104 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
105 *
106 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
107 *
108 * How many bytes will be read is directly controlled by the size parameter, which can be either
109 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
110 */
111template<class InputIterator>
112inline uint64_t
113readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end);
114
115/**
116 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
117 */
118inline size_t
119sizeOfNonNegativeInteger(uint64_t varNumber);
120
121/**
122 * @brief Write nonNegativeInteger to the specified stream
123 */
124inline size_t
125writeNonNegativeInteger(std::ostream &os, uint64_t varNumber);
126
127/////////////////////////////////////////////////////////////////////////////////
128/////////////////////////////////////////////////////////////////////////////////
129/////////////////////////////////////////////////////////////////////////////////
130
131// Inline implementations
132
133/////////////////////////////////////////////////////////////////////////////////
134/////////////////////////////////////////////////////////////////////////////////
135/////////////////////////////////////////////////////////////////////////////////
136
137template<class InputIterator>
138inline uint64_t
139readVarNumber(InputIterator &begin, const InputIterator &end)
140{
141 if (begin == end)
142 throw Error("Empty buffer during TLV processing");
143
144 uint8_t value = *begin;
145 ++begin;
146 if (value < 253)
147 {
148 return value;
149 }
150 else if (value == 253)
151 {
152 if (end - begin < 2)
153 throw Error("Insufficient data during TLV processing");
154
155 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
156 begin += 2;
157 return be16toh(value);
158 }
159 else if (value == 254)
160 {
161 if (end - begin < 4)
162 throw Error("Insufficient data during TLV processing");
163
164 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
165 begin += 4;
166 return be32toh(value);
167 }
168 else // if (value == 255)
169 {
170 if (end - begin < 8)
171 throw Error("Insufficient data during TLV processing");
172
173 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
174 begin += 8;
175
176 return be64toh(value);
177 }
178}
179
Yingdi Yu27158392014-01-20 13:04:20 -0800180template<>
181inline uint64_t
182readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin,
183 const std::istream_iterator<uint8_t> &end)
184{
185 if (begin == end)
186 throw Error("Empty buffer during TLV processing");
187
188 uint8_t value = *begin;
189 ++begin;
190 if (value < 253)
191 {
192 return value;
193 }
194 else if (value == 253)
195 {
196 uint8_t buffer[2];
197 int count = 0;
198
199 while(begin != end && count < 2){
200 buffer[count] = *begin;
201 begin++;
202 count++;
203 }
204
205 if (count < 2)
206 throw Error("Insufficient data during TLV processing");
207
208 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
209 return be16toh(value);
210 }
211 else if (value == 254)
212 {
213 uint8_t buffer[4];
214 int count = 0;
215
216 while(begin != end && count < 4){
217 buffer[count] = *begin;
218 begin++;
219 count++;
220 }
221
222 if (count < 4)
223 throw Error("Insufficient data during TLV processing");
224
225 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
226 return be32toh(value);
227 }
228 else // if (value == 255)
229 {
230 uint8_t buffer[8];
231 int count = 0;
232
233 while(begin != end && count < 8){
234 buffer[count] = *begin;
235 begin++;
236 count++;
237 }
238
239 if (count < 8)
240 throw Error("Insufficient data during TLV processing");
241
242 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
243 return be64toh(value);
244 }
245}
246
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800247template<class InputIterator>
248inline uint32_t
249readType(InputIterator &begin, const InputIterator &end)
250{
251 uint64_t type = readVarNumber(begin, end);
252 if (type > std::numeric_limits<uint32_t>::max())
253 {
254 throw Error("TLV type code exceeds allowed maximum");
255 }
256
257 return static_cast<uint32_t> (type);
258}
259
260size_t
261sizeOfVarNumber(uint64_t varNumber)
262{
263 if (varNumber < 253) {
264 return 1;
265 }
266 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
267 return 3;
268 }
269 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
270 return 5;
271 }
272 else {
273 return 9;
274 }
275}
276
277inline size_t
278writeVarNumber(std::ostream &os, uint64_t varNumber)
279{
280 if (varNumber < 253) {
281 os.put(static_cast<uint8_t> (varNumber));
282 return 1;
283 }
284 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
285 os.put(253);
286 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
287 os.write(reinterpret_cast<const char*> (&value), 2);
288 return 3;
289 }
290 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
291 os.put(254);
292 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
293 os.write(reinterpret_cast<const char*> (&value), 4);
294 return 5;
295 }
296 else {
297 os.put(255);
298 uint64_t value = htobe64(varNumber);
299 os.write(reinterpret_cast<const char*> (&value), 8);
300 return 9;
301 }
302}
303
304template<class InputIterator>
305inline uint64_t
306readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end)
307{
308 switch (size) {
309 case 1:
310 {
311 if (end - begin < 1)
312 throw Error("Insufficient data during TLV processing");
313
314 uint8_t value = *begin;
315 begin++;
316 return value;
317 }
318 case 2:
319 {
320 if (end - begin < 2)
321 throw Error("Insufficient data during TLV processing");
322
323 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
324 begin += 2;
325 return be16toh(value);
326 }
327 case 4:
328 {
329 if (end - begin < 4)
330 throw Error("Insufficient data during TLV processing");
331
332 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
333 begin += 4;
334 return be32toh(value);
335 }
336 case 8:
337 {
338 if (end - begin < 8)
339 throw Error("Insufficient data during TLV processing");
340
341 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
342 begin += 8;
343 return be64toh(value);
344 }
345 }
346 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
347}
348
Yingdi Yu27158392014-01-20 13:04:20 -0800349template<>
350inline uint64_t
351readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
352 std::istream_iterator<uint8_t> &begin,
353 const std::istream_iterator<uint8_t> &end)
354{
355 switch (size) {
356 case 1:
357 {
358 if(begin == end)
359 throw Error("Insufficient data during TLV processing");
360
361 uint8_t value = *begin;
362 begin++;
363 return value;
364 }
365 case 2:
366 {
367 uint8_t buffer[2];
368 int count = 0;
369
370 while(begin != end && count < 2){
371 buffer[count] = *begin;
372 begin++;
373 count++;
374 }
375
376 if (count < 2)
377 throw Error("Insufficient data during TLV processing");
378
379 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
380 return be16toh(value);
381 }
382 case 4:
383 {
384 uint8_t buffer[4];
385 int count = 0;
386
387 while(begin != end && count < 4){
388 buffer[count] = *begin;
389 begin++;
390 count++;
391 }
392
393 if (count < 4)
394 throw Error("Insufficient data during TLV processing");
395
396 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
397 return be32toh(value);
398 }
399 case 8:
400 {
401 uint8_t buffer[8];
402 int count = 0;
403
404 while(begin != end && count < 8){
405 buffer[count] = *begin;
406 begin++;
407 count++;
408 }
409
410 if (count < 8)
411 throw Error("Insufficient data during TLV processing");
412
413 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
414 return be64toh(value);
415 }
416 }
417 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
418}
419
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800420inline size_t
421sizeOfNonNegativeInteger(uint64_t varNumber)
422{
423 if (varNumber < 253) {
424 return 1;
425 }
426 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
427 return 2;
428 }
429 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
430 return 4;
431 }
432 else {
433 return 8;
434 }
435}
436
437
438inline size_t
439writeNonNegativeInteger(std::ostream &os, uint64_t varNumber)
440{
441 if (varNumber < 253) {
442 os.put(static_cast<uint8_t> (varNumber));
443 return 1;
444 }
445 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
446 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
447 os.write(reinterpret_cast<const char*> (&value), 2);
448 return 2;
449 }
450 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
451 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
452 os.write(reinterpret_cast<const char*> (&value), 4);
453 return 4;
454 }
455 else {
456 uint64_t value = htobe64(varNumber);
457 os.write(reinterpret_cast<const char*> (&value), 8);
458 return 8;
459 }
460}
461
462
463} // namespace tlv
464} // namespace ndn
465
466#endif // NDN_TLV_HPP