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