blob: 0edf94ad3387910a441f40a9d5c2c7333d44a2d2 [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
13#include "buffer.hpp"
14#include "endian.h"
15
16namespace ndn {
17
18/**
19 * @brief Namespace defining NDN-TLV related constants and procedures
20 */
21namespace Tlv {
22
23struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
24
25enum {
26 Interest = 0,
27 Data = 1,
28 Name = 2,
29 NameComponent = 3,
30 Selectors = 4,
31 Nonce = 5,
32 Scope = 6,
33 InterestLifetime = 7,
34 MinSuffixComponents = 8,
35 MaxSuffixComponents = 9,
36 PublisherPublicKeyLocator = 10,
37 Exclude = 11,
38 ChildSelector = 12,
39 MustBeFresh = 13,
40 Any = 14,
41 MetaInfo = 15,
42 Content = 16,
43 SignatureInfo = 17,
44 SignatureValue = 18,
45 ContentType = 19,
46 FreshnessPeriod = 20,
47 SignatureType = 21,
48 KeyLocator = 22,
49 KeyLocatorDigest = 23,
50
51 AppPrivateBlock1 = 128,
52 AppPrivateBlock2 = 32767
53};
54
55enum SignatureType {
56 DigestSha256 = 0,
57 SignatureSha256WithRsa = 1,
58};
59
60enum ConentType {
61 ContentType_Default = 0,
62 ContentType_Link = 1,
63 ContentType_Key = 2,
64};
65
66/**
67 * @brief Read VAR-NUMBER in NDN-TLV encoding
68 *
69 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
70 *
71 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
72 */
73template<class InputIterator>
74inline uint64_t
75readVarNumber(InputIterator &begin, const InputIterator &end);
76
77/**
78 * @brief Read TLV Type
79 *
80 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
81 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
82 */
83template<class InputIterator>
84inline uint32_t
85readType(InputIterator &begin, const InputIterator &end);
86
87/**
88 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
89 */
90inline size_t
91sizeOfVarNumber(uint64_t varNumber);
92
93/**
94 * @brief Write VAR-NUMBER to the specified stream
95 */
96inline size_t
97writeVarNumber(std::ostream &os, uint64_t varNumber);
98
99/**
100 * @brief Read nonNegativeInteger in NDN-TLV encoding
101 *
102 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
103 *
104 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
105 *
106 * How many bytes will be read is directly controlled by the size parameter, which can be either
107 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
108 */
109template<class InputIterator>
110inline uint64_t
111readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end);
112
113/**
114 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
115 */
116inline size_t
117sizeOfNonNegativeInteger(uint64_t varNumber);
118
119/**
120 * @brief Write nonNegativeInteger to the specified stream
121 */
122inline size_t
123writeNonNegativeInteger(std::ostream &os, uint64_t varNumber);
124
125/////////////////////////////////////////////////////////////////////////////////
126/////////////////////////////////////////////////////////////////////////////////
127/////////////////////////////////////////////////////////////////////////////////
128
129// Inline implementations
130
131/////////////////////////////////////////////////////////////////////////////////
132/////////////////////////////////////////////////////////////////////////////////
133/////////////////////////////////////////////////////////////////////////////////
134
135template<class InputIterator>
136inline uint64_t
137readVarNumber(InputIterator &begin, const InputIterator &end)
138{
139 if (begin == end)
140 throw Error("Empty buffer during TLV processing");
141
142 uint8_t value = *begin;
143 ++begin;
144 if (value < 253)
145 {
146 return value;
147 }
148 else if (value == 253)
149 {
150 if (end - begin < 2)
151 throw Error("Insufficient data during TLV processing");
152
153 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
154 begin += 2;
155 return be16toh(value);
156 }
157 else if (value == 254)
158 {
159 if (end - begin < 4)
160 throw Error("Insufficient data during TLV processing");
161
162 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
163 begin += 4;
164 return be32toh(value);
165 }
166 else // if (value == 255)
167 {
168 if (end - begin < 8)
169 throw Error("Insufficient data during TLV processing");
170
171 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
172 begin += 8;
173
174 return be64toh(value);
175 }
176}
177
178template<class InputIterator>
179inline uint32_t
180readType(InputIterator &begin, const InputIterator &end)
181{
182 uint64_t type = readVarNumber(begin, end);
183 if (type > std::numeric_limits<uint32_t>::max())
184 {
185 throw Error("TLV type code exceeds allowed maximum");
186 }
187
188 return static_cast<uint32_t> (type);
189}
190
191size_t
192sizeOfVarNumber(uint64_t varNumber)
193{
194 if (varNumber < 253) {
195 return 1;
196 }
197 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
198 return 3;
199 }
200 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
201 return 5;
202 }
203 else {
204 return 9;
205 }
206}
207
208inline size_t
209writeVarNumber(std::ostream &os, uint64_t varNumber)
210{
211 if (varNumber < 253) {
212 os.put(static_cast<uint8_t> (varNumber));
213 return 1;
214 }
215 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
216 os.put(253);
217 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
218 os.write(reinterpret_cast<const char*> (&value), 2);
219 return 3;
220 }
221 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
222 os.put(254);
223 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
224 os.write(reinterpret_cast<const char*> (&value), 4);
225 return 5;
226 }
227 else {
228 os.put(255);
229 uint64_t value = htobe64(varNumber);
230 os.write(reinterpret_cast<const char*> (&value), 8);
231 return 9;
232 }
233}
234
235template<class InputIterator>
236inline uint64_t
237readNonNegativeInteger(size_t size, InputIterator &begin, const InputIterator &end)
238{
239 switch (size) {
240 case 1:
241 {
242 if (end - begin < 1)
243 throw Error("Insufficient data during TLV processing");
244
245 uint8_t value = *begin;
246 begin++;
247 return value;
248 }
249 case 2:
250 {
251 if (end - begin < 2)
252 throw Error("Insufficient data during TLV processing");
253
254 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
255 begin += 2;
256 return be16toh(value);
257 }
258 case 4:
259 {
260 if (end - begin < 4)
261 throw Error("Insufficient data during TLV processing");
262
263 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
264 begin += 4;
265 return be32toh(value);
266 }
267 case 8:
268 {
269 if (end - begin < 8)
270 throw Error("Insufficient data during TLV processing");
271
272 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
273 begin += 8;
274 return be64toh(value);
275 }
276 }
277 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
278}
279
280inline size_t
281sizeOfNonNegativeInteger(uint64_t varNumber)
282{
283 if (varNumber < 253) {
284 return 1;
285 }
286 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
287 return 2;
288 }
289 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
290 return 4;
291 }
292 else {
293 return 8;
294 }
295}
296
297
298inline size_t
299writeNonNegativeInteger(std::ostream &os, uint64_t varNumber)
300{
301 if (varNumber < 253) {
302 os.put(static_cast<uint8_t> (varNumber));
303 return 1;
304 }
305 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
306 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
307 os.write(reinterpret_cast<const char*> (&value), 2);
308 return 2;
309 }
310 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
311 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
312 os.write(reinterpret_cast<const char*> (&value), 4);
313 return 4;
314 }
315 else {
316 uint64_t value = htobe64(varNumber);
317 os.write(reinterpret_cast<const char*> (&value), 8);
318 return 8;
319 }
320}
321
322
323} // namespace tlv
324} // namespace ndn
325
326#endif // NDN_TLV_HPP