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