data.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2022 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
22 #include "ndn-cxx/data.hpp"
23 #include "ndn-cxx/util/sha256.hpp"
24 
25 namespace ndn {
26 
27 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
28 BOOST_CONCEPT_ASSERT((WireEncodable<Data>));
29 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Data>));
30 BOOST_CONCEPT_ASSERT((WireDecodable<Data>));
31 static_assert(std::is_base_of<tlv::Error, Data::Error>::value,
32  "Data::Error must inherit from tlv::Error");
33 
34 Data::Data(const Name& name)
35  : m_name(name)
36 {
37 }
38 
39 Data::Data(const Block& wire)
40 {
41  wireDecode(wire);
42 }
43 
44 template<encoding::Tag TAG>
45 size_t
46 Data::wireEncode(EncodingImpl<TAG>& encoder, bool wantUnsignedPortionOnly) const
47 {
48  // Data = DATA-TYPE TLV-LENGTH
49  // Name
50  // [MetaInfo]
51  // [Content]
52  // SignatureInfo
53  // SignatureValue
54  // (elements are encoded in reverse order)
55 
56  size_t totalLength = 0;
57 
58  // SignatureValue
59  if (!wantUnsignedPortionOnly) {
60  if (!m_signatureInfo) {
61  NDN_THROW(Error("Requested wire format, but Data has not been signed"));
62  }
63  totalLength += prependBlock(encoder, m_signatureValue);
64  }
65 
66  // SignatureInfo
67  totalLength += m_signatureInfo.wireEncode(encoder, SignatureInfo::Type::Data);
68 
69  // Content
70  if (hasContent()) {
71  totalLength += prependBlock(encoder, m_content);
72  }
73 
74  // MetaInfo
75  totalLength += m_metaInfo.wireEncode(encoder);
76 
77  // Name
78  totalLength += m_name.wireEncode(encoder);
79 
80  if (!wantUnsignedPortionOnly) {
81  totalLength += encoder.prependVarNumber(totalLength);
82  totalLength += encoder.prependVarNumber(tlv::Data);
83  }
84  return totalLength;
85 }
86 
87 template size_t
88 Data::wireEncode<encoding::EncoderTag>(EncodingBuffer&, bool) const;
89 
90 template size_t
91 Data::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, bool) const;
92 
93 const Block&
94 Data::wireEncode(EncodingBuffer& encoder, span<const uint8_t> signature) const
95 {
96  size_t totalLength = encoder.size();
97  totalLength += encoder.appendVarNumber(tlv::SignatureValue);
98  totalLength += encoder.appendVarNumber(signature.size());
99  totalLength += encoder.appendBytes(signature);
100 
101  encoder.prependVarNumber(totalLength);
102  encoder.prependVarNumber(tlv::Data);
103 
104  const_cast<Data*>(this)->wireDecode(encoder.block());
105  return m_wire;
106 }
107 
108 const Block&
110 {
111  if (m_wire.hasWire())
112  return m_wire;
113 
114  EncodingEstimator estimator;
115  size_t estimatedSize = wireEncode(estimator);
116 
117  EncodingBuffer buffer(estimatedSize, 0);
118  wireEncode(buffer);
119 
120  const_cast<Data*>(this)->wireDecode(buffer.block());
121  return m_wire;
122 }
123 
124 void
126 {
127  if (wire.type() != tlv::Data) {
128  NDN_THROW(Error("Data", wire.type()));
129  }
130  m_wire = wire;
131  m_wire.parse();
132 
133  // Data = DATA-TYPE TLV-LENGTH
134  // Name
135  // [MetaInfo]
136  // [Content]
137  // SignatureInfo
138  // SignatureValue
139 
140  auto element = m_wire.elements_begin();
141  if (element == m_wire.elements_end() || element->type() != tlv::Name) {
142  NDN_THROW(Error("Name element is missing or out of order"));
143  }
144  m_name.wireDecode(*element);
145 
146  m_metaInfo = {};
147  m_content = {};
148  m_signatureInfo = {};
149  m_signatureValue = {};
150  m_fullName.clear();
151 
152  int lastElement = 1; // last recognized element index, in spec order
153  for (++element; element != m_wire.elements_end(); ++element) {
154  switch (element->type()) {
155  case tlv::MetaInfo: {
156  if (lastElement >= 2) {
157  NDN_THROW(Error("MetaInfo element is out of order"));
158  }
159  m_metaInfo.wireDecode(*element);
160  lastElement = 2;
161  break;
162  }
163  case tlv::Content: {
164  if (lastElement >= 3) {
165  NDN_THROW(Error("Content element is out of order"));
166  }
167  m_content = *element;
168  lastElement = 3;
169  break;
170  }
171  case tlv::SignatureInfo: {
172  if (lastElement >= 4) {
173  NDN_THROW(Error("SignatureInfo element is out of order"));
174  }
175  m_signatureInfo.wireDecode(*element);
176  lastElement = 4;
177  break;
178  }
179  case tlv::SignatureValue: {
180  if (lastElement >= 5) {
181  NDN_THROW(Error("SignatureValue element is out of order"));
182  }
183  m_signatureValue = *element;
184  lastElement = 5;
185  break;
186  }
187  default: { // unrecognized element
188  // if the TLV-TYPE is critical, abort decoding
189  if (tlv::isCriticalType(element->type())) {
190  NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
191  }
192  // otherwise, ignore it
193  break;
194  }
195  }
196  }
197 
198  if (!m_signatureInfo) {
199  NDN_THROW(Error("SignatureInfo element is missing"));
200  }
201  if (!m_signatureValue.isValid()) {
202  NDN_THROW(Error("SignatureValue element is missing"));
203  }
204 }
205 
206 const Name&
208 {
209  if (m_fullName.empty()) {
210  if (!m_wire.hasWire()) {
211  NDN_THROW(Error("Cannot compute full name because Data has no wire encoding (not signed)"));
212  }
213  m_fullName = m_name;
215  }
216 
217  return m_fullName;
218 }
219 
220 void
222 {
223  m_wire.reset();
224  m_fullName.clear();
225 }
226 
227 Data&
228 Data::setName(const Name& name)
229 {
230  if (name != m_name) {
231  m_name = name;
232  resetWire();
233  }
234  return *this;
235 }
236 
237 Data&
238 Data::setMetaInfo(const MetaInfo& metaInfo)
239 {
240  m_metaInfo = metaInfo;
241  resetWire();
242  return *this;
243 }
244 
245 Data&
246 Data::setContent(const Block& block)
247 {
248  if (!block.isValid()) {
249  NDN_THROW(std::invalid_argument("Content block must be valid"));
250  }
251 
252  if (block.type() == tlv::Content) {
253  m_content = block;
254  }
255  else {
256  m_content = Block(tlv::Content, block);
257  }
258  m_content.encode();
259  resetWire();
260  return *this;
261 }
262 
263 Data&
264 Data::setContent(span<const uint8_t> value)
265 {
266  m_content = makeBinaryBlock(tlv::Content, value);
267  resetWire();
268  return *this;
269 }
270 
271 Data&
273 {
274  if (value == nullptr) {
275  NDN_THROW(std::invalid_argument("Content buffer cannot be nullptr"));
276  }
277 
278  m_content = Block(tlv::Content, std::move(value));
279  resetWire();
280  return *this;
281 }
282 
283 Data&
285 {
286  m_content = {};
287  resetWire();
288  return *this;
289 }
290 
291 Data&
293 {
294  m_signatureInfo = info;
295  resetWire();
296  return *this;
297 }
298 
299 Data&
300 Data::setSignatureValue(span<const uint8_t> value)
301 {
302  m_signatureValue = makeBinaryBlock(tlv::SignatureValue, value);
303  resetWire();
304  return *this;
305 }
306 
307 Data&
309 {
310  if (value == nullptr) {
311  NDN_THROW(std::invalid_argument("SignatureValue buffer cannot be nullptr"));
312  }
313 
314  m_signatureValue = Block(tlv::SignatureValue, std::move(value));
315  resetWire();
316  return *this;
317 }
318 
319 InputBuffers
321 {
322  InputBuffers bufs;
323  bufs.reserve(1); // One range containing data value up to, but not including, SignatureValue
324 
325  wireEncode();
326  auto lastSignedIt = std::prev(m_wire.find(tlv::SignatureValue));
327  // Note: we assume that both iterators point to the same underlying buffer
328  bufs.emplace_back(m_wire.value_begin(), lastSignedIt->end());
329 
330  return bufs;
331 }
332 
333 Data&
334 Data::setContentType(uint32_t type)
335 {
336  if (type != m_metaInfo.getType()) {
337  m_metaInfo.setType(type);
338  resetWire();
339  }
340  return *this;
341 }
342 
343 Data&
345 {
346  if (freshnessPeriod != m_metaInfo.getFreshnessPeriod()) {
347  m_metaInfo.setFreshnessPeriod(freshnessPeriod);
348  resetWire();
349  }
350  return *this;
351 }
352 
353 Data&
354 Data::setFinalBlock(optional<name::Component> finalBlockId)
355 {
356  if (finalBlockId != m_metaInfo.getFinalBlock()) {
357  m_metaInfo.setFinalBlock(std::move(finalBlockId));
358  resetWire();
359  }
360  return *this;
361 }
362 
363 bool
364 operator==(const Data& lhs, const Data& rhs)
365 {
366  return lhs.getName() == rhs.getName() &&
367  lhs.getMetaInfo().wireEncode() == rhs.getMetaInfo().wireEncode() &&
368  lhs.getContent() == rhs.getContent() &&
369  lhs.getSignatureInfo() == rhs.getSignatureInfo() &&
370  lhs.getSignatureValue() == rhs.getSignatureValue();
371 }
372 
373 std::ostream&
374 operator<<(std::ostream& os, const Data& data)
375 {
376  os << "Name: " << data.getName() << "\n"
377  << "MetaInfo: [" << data.getMetaInfo() << "]\n";
378 
379  if (data.hasContent()) {
380  os << "Content: [" << data.getContent().value_size() << " bytes]\n";
381  }
382 
383  os << "Signature: [type: " << static_cast<tlv::SignatureTypeValue>(data.getSignatureType())
384  << ", length: "<< data.getSignatureValue().value_size() << "]\n";
385 
386  return os;
387 }
388 
389 } // namespace ndn
Represents a TLV element of the NDN packet format.
Definition: block.hpp:45
element_const_iterator elements_begin() const noexcept
Equivalent to elements().begin().
Definition: block.hpp:435
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:424
size_t size() const
Return the size of the encoded wire, i.e., of the whole TLV.
Definition: block.cpp:294
element_const_iterator elements_end() const noexcept
Equivalent to elements().end().
Definition: block.hpp:444
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:221
bool isValid() const noexcept
Check if the Block is valid.
Definition: block.hpp:192
void encode()
Encode sub-elements into TLV-VALUE.
Definition: block.cpp:351
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition: block.hpp:277
void reset() noexcept
Reset the Block to a default-constructed state.
Definition: block.cpp:254
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:324
const_iterator value_begin() const noexcept
Get begin iterator of TLV-VALUE.
Definition: block.hpp:301
size_t value_size() const noexcept
Return the size of TLV-VALUE, i.e., the TLV-LENGTH.
Definition: block.hpp:321
Represents a Data packet.
Definition: data.hpp:39
int32_t getSignatureType() const noexcept
Get the SignatureType.
Definition: data.hpp:317
void wireDecode(const Block &wire)
Decode from wire.
Definition: data.cpp:125
InputBuffers extractSignedRanges() const
Extract ranges of Data covered by the signature.
Definition: data.cpp:320
Data & setContent(const Block &block)
Set Content from a Block.
Definition: data.cpp:246
Data(const Name &name=Name())
Construct an unsigned Data packet with given name and empty Content.
Definition: data.cpp:34
const MetaInfo & getMetaInfo() const noexcept
Get the MetaInfo element.
Definition: data.hpp:145
void resetWire()
Clear wire encoding and cached FullName.
Definition: data.cpp:221
Data & setFreshnessPeriod(time::milliseconds freshnessPeriod)
Definition: data.cpp:344
const Block & wireEncode() const
Encode into a Block.
Definition: data.cpp:109
const Name & getFullName() const
Get full name including implicit digest.
Definition: data.cpp:207
Data & setFinalBlock(optional< name::Component > finalBlockId)
Definition: data.cpp:354
bool hasContent() const noexcept
Return whether this Data has a Content element.
Definition: data.hpp:161
Data & setSignatureValue(span< const uint8_t > value)
Set SignatureValue by copying from a contiguous sequence of bytes.
Definition: data.cpp:300
const SignatureInfo & getSignatureInfo() const noexcept
Get the SignatureInfo element.
Definition: data.hpp:224
const Name & getName() const noexcept
Get the data name.
Definition: data.hpp:129
const Block & getSignatureValue() const noexcept
Get the SignatureValue element.
Definition: data.hpp:245
Data & setSignatureInfo(const SignatureInfo &info)
Set the SignatureInfo element.
Definition: data.cpp:292
Data & setName(const Name &name)
Set the data name.
Definition: data.cpp:228
const Block & getContent() const noexcept
Get the Content element.
Definition: data.hpp:180
Data & setContentType(uint32_t type)
Definition: data.cpp:334
Data & setMetaInfo(const MetaInfo &metaInfo)
Set the MetaInfo element.
Definition: data.cpp:238
Data & unsetContent()
Remove the Content element.
Definition: data.cpp:284
A MetaInfo holds the meta info which is signed inside the Data packet.
Definition: meta-info.hpp:62
void wireDecode(const Block &wire)
Definition: meta-info.cpp:181
const optional< name::Component > & getFinalBlock() const
Return the value of FinalBlockId.
Definition: meta-info.hpp:124
time::milliseconds getFreshnessPeriod() const
Return the value of FreshnessPeriod.
Definition: meta-info.hpp:110
MetaInfo & setType(uint32_t type)
Set ContentType.
Definition: meta-info.cpp:47
MetaInfo & setFinalBlock(optional< name::Component > finalBlockId)
Set FinalBlockId.
Definition: meta-info.cpp:66
MetaInfo & setFreshnessPeriod(time::milliseconds freshnessPeriod)
Set FreshnessPeriod.
Definition: meta-info.cpp:55
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Definition: meta-info.cpp:126
uint32_t getType() const
Return the value of ContentType.
Definition: meta-info.hpp:94
Represents an absolute name.
Definition: name.hpp:44
Name & appendImplicitSha256Digest(ConstBufferPtr digest)
Append an ImplicitSha256Digest component.
Definition: name.hpp:479
bool empty() const noexcept
Checks if the name is empty, i.e., has no components.
Definition: name.hpp:146
void clear()
Remove all components.
Definition: name.cpp:281
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:117
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition: name.cpp:150
Represents a SignatureInfo or InterestSignatureInfo TLV element.
size_t wireEncode(EncodingImpl< TAG > &encoder, Type type=Type::Data) const
Fast encoding or block size estimation.
void wireDecode(const Block &wire, Type type=Type::Data)
Decode from wire format.
A concept check for TLV abstraction with a wireDecode(Block) method and constructible from Block.
Definition: concepts.hpp:81
A concept check for TLV abstraction with a wireEncode(EncodingBuffer) method.
Definition: concepts.hpp:61
A concept check for TLV abstraction with a wireEncode() method.
Definition: concepts.hpp:45
ConstBufferPtr computeDigest()
Finalize and return the digest based on all previously supplied inputs.
Definition: sha256.cpp:64
#define NDN_THROW(e)
Definition: exception.hpp:61
EncodingImpl< EstimatorTag > EncodingEstimator
Block makeBinaryBlock(uint32_t type, span< const uint8_t > value)
Create a TLV block copying the TLV-VALUE from a byte range.
EncodingImpl< EncoderTag > EncodingBuffer
size_t prependBlock(EncodingImpl< TAG > &encoder, const Block &block)
Prepend a TLV element.
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
boost::chrono::milliseconds milliseconds
Definition: time.hpp:48
@ Name
Definition: tlv.hpp:71
@ SignatureInfo
Definition: tlv.hpp:94
@ Data
Definition: tlv.hpp:69
@ Content
Definition: tlv.hpp:93
@ MetaInfo
Definition: tlv.hpp:92
@ SignatureValue
Definition: tlv.hpp:95
constexpr bool isCriticalType(uint32_t type) noexcept
Determine whether a TLV-TYPE is "critical" for evolvability purpose.
Definition: tlv.hpp:162
SignatureTypeValue
SignatureType values.
Definition: tlv.hpp:127
Definition: data.cpp:25
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:139
bool operator==(const Data &lhs, const Data &rhs)
Definition: data.cpp:364
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:374
InputBuffers bufs
SignatureInfo info