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