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