encoding: Optimized Data packet encoding, preparation for memory-efficient signing operation
Change-Id: I6eb1f8acef917970790d1f228ade6212c45181fa
refs: #1172
diff --git a/src/common.cpp b/src/common.cpp
deleted file mode 100644
index 7665dc8..0000000
--- a/src/common.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/**
- * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
- * See COPYING for copyright and distribution information.
- */
-
-#include "common.hpp"
-
-#include "util/time.hpp"
-
-using namespace std;
-
-namespace ndn {
-
-string
-toHex(const vector<uint8_t>& array)
-{
- if (!&array)
- return "";
-
- ostringstream result;
- result.flags(ios::hex | ios::uppercase);
- for (size_t i = 0; i < array.size(); ++i) {
- uint8_t x = array[i];
- if (x < 16)
- result << '0';
- result << (unsigned int)x;
- }
-
- return result.str();
-}
-
-MillisecondsSince1970
-getNow()
-{
- return getNowMilliseconds();
-}
-
-
-}
-
diff --git a/src/common.hpp b/src/common.hpp
index 8d26a14..281da0b 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -98,27 +98,8 @@
using boost::noncopyable;
-/**
- * A time interval represented as the number of milliseconds.
- */
-typedef int64_t Milliseconds;
-
-/**
- * The calendar time represented as the number of milliseconds since 1/1/1970.
- */
-typedef int64_t MillisecondsSince1970;
-
-/**
- * Return the hex representation of the bytes in array.
- * @param array The array of bytes.
- * @return Hex string.
- */
-std::string
-toHex(const std::vector<uint8_t>& array);
-
-MillisecondsSince1970
-getNow();
-
}
+#include "util/time.hpp"
+
#endif
diff --git a/src/data.cpp b/src/data.cpp
deleted file mode 100644
index 00a915c..0000000
--- a/src/data.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/**
- * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
- * See COPYING for copyright and distribution information.
- */
-
-#include "common.hpp"
-
-#include "data.hpp"
-
-using namespace std;
-
-namespace ndn {
-
-const Block&
-Data::wireEncode() const
-{
- if (wire_.hasWire())
- return wire_;
-
- // Data ::= DATA-TLV TLV-LENGTH
- // Name
- // MetaInfo
- // Content
- // Signature
-
- wire_ = Block(Tlv::Data);
-
- // Name
- wire_.push_back(getName().wireEncode());
-
- // MetaInfo
- wire_.push_back(getMetaInfo().wireEncode());
-
- // Content
- wire_.push_back(getContent());
-
- if (!signature_) {
- throw Error("Requested wire format, but data packet has not been signed yet");
- }
-
- ///////////////
- // Signature //
- ///////////////
-
- // SignatureInfo
- wire_.push_back(signature_.getInfo());
-
- // SignatureValue
- wire_.push_back(signature_.getValue());
-
- wire_.encode();
- return wire_;
-}
-
-/**
- * Decode the input using a particular wire format and update this Data.
- * @param input The input byte array to be decoded.
- */
-void
-Data::wireDecode(const Block &wire)
-{
- wire_ = wire;
- wire_.parse();
-
- // Data ::= DATA-TLV TLV-LENGTH
- // Name
- // MetaInfo
- // Content
- // Signature
-
- // Name
- name_.wireDecode(wire_.get(Tlv::Name));
-
- // MetaInfo
- metaInfo_.wireDecode(wire_.get(Tlv::MetaInfo));
-
- // Content
- content_ = wire_.get(Tlv::Content);
-
- ///////////////
- // Signature //
- ///////////////
-
- // SignatureInfo
- signature_.setInfo(wire_.get(Tlv::SignatureInfo));
-
- // SignatureValue
- signature_.setValue(wire_.get(Tlv::SignatureValue));
-}
-
-std::ostream&
-operator << (std::ostream &os, const Data &data)
-{
- os << "Name: " << data.getName() << "\n";
- os << "MetaInfo: " << data.getMetaInfo() << "\n";
- os << "Content: (size: " << data.getContent().value_size() << ")\n";
- os << "Signature: (type: " << data.getSignature().getType() <<
- ", value_length: "<< data.getSignature().getValue().value_size() << ")";
- os << std::endl;
-
- return os;
-}
-
-
-}
diff --git a/src/data.hpp b/src/data.hpp
index f1b64a3..4c09811 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -37,25 +37,32 @@
Data(const Name& name);
/**
- * @brief The virtual destructor.
+ * @brief The destructor
*/
- inline virtual
+ inline
~Data();
/**
- * @brief Encode this Data for a wire format.
- * @return The encoded byte array.
+ * @brief Fast encoding or block size estimation
*/
- const Block&
- wireEncode() const;
+ template<bool T>
+ inline size_t
+ wireEncode(EncodingImpl<T> &block, bool unsignedPortion = false) const;
/**
- * @brief Decode the input using a particular wire format and update this Data.
- * @param input The input byte array to be decoded.
+ * @brief Encode to a wire format
*/
- void
+ inline const Block&
+ wireEncode() const;
+
+ /**
+ * @brief Decode from the wire format
+ */
+ inline void
wireDecode(const Block &wire);
+ ////////////////////////////////////////////////////////////////////
+
inline const Name&
getName() const;
@@ -68,6 +75,8 @@
inline void
setName(const Name& name);
+ //
+
inline const MetaInfo&
getMetaInfo() const;
@@ -79,13 +88,20 @@
inline void
setMetaInfo(const MetaInfo& metaInfo);
+ //
+
+ ///////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// MetaInfo proxy methods
+
inline uint32_t
getContentType() const;
inline void
setContentType(uint32_t type);
+
+ //
inline Milliseconds
getFreshnessPeriod() const;
@@ -93,11 +109,18 @@
inline void
setFreshnessPeriod(Milliseconds freshnessPeriod);
+ //
+
inline const name::Component&
getFinalBlockId() const;
inline void
setFinalBlockId(const name::Component& finalBlockId);
+
+ //
+ ///////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////
/**
* @brief Get content Block
@@ -121,6 +144,8 @@
inline void
setContent(const ConstBufferPtr &contentValue);
+
+ //
inline const Signature&
getSignature() const;
@@ -131,10 +156,12 @@
*/
inline void
setSignature(const Signature& signature);
-
+
inline void
setSignatureValue(const Block &value);
+ ///////////////////////////////////////////////////////////////
+
inline uint64_t
getIncomingFaceId() const;
@@ -149,25 +176,25 @@
onChanged();
private:
- Name name_;
- MetaInfo metaInfo_;
- mutable Block content_;
- Signature signature_;
+ Name m_name;
+ MetaInfo m_metaInfo;
+ mutable Block m_content;
+ Signature m_signature;
- mutable Block wire_;
+ mutable Block m_wire;
uint64_t m_incomingFaceId;
};
inline
Data::Data()
- : content_(Tlv::Content) // empty content
+ : m_content(Tlv::Content) // empty content
{
}
inline
Data::Data(const Name& name)
- : name_(name)
+ : m_name(name)
{
}
@@ -176,80 +203,179 @@
{
}
+template<bool T>
+inline size_t
+Data::wireEncode(EncodingImpl<T> &block, bool unsignedPortion/* = false*/) const
+{
+ size_t total_len = 0;
+
+ // Data ::= DATA-TLV TLV-LENGTH
+ // Name
+ // MetaInfo
+ // Content
+ // Signature
+
+ // (reverse encoding)
+
+ if (!unsignedPortion && !m_signature)
+ {
+ throw Error("Requested wire format, but data packet has not been signed yet");
+ }
+
+ if (!unsignedPortion)
+ {
+ // SignatureValue
+ total_len += prependBlock(block, m_signature.getValue());
+ }
+
+ // SignatureInfo
+ total_len += prependBlock(block, m_signature.getInfo());
+
+ // Content
+ total_len += prependBlock(block, getContent());
+
+ // MetaInfo
+ total_len += getMetaInfo().wireEncode(block);
+
+ // Name
+ total_len += getName().wireEncode(block);
+
+ if (!unsignedPortion)
+ {
+ total_len += block.prependVarNumber (total_len);
+ total_len += block.prependVarNumber (Tlv::Data);
+ }
+ return total_len;
+}
+
+inline const Block &
+Data::wireEncode() const
+{
+ if (m_wire.hasWire())
+ return m_wire;
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = wireEncode(estimator);
+
+ EncodingBuffer buffer(estimatedSize, 0);
+ wireEncode(buffer);
+
+ const_cast<Data*>(this)->wireDecode(buffer.block());
+ return m_wire;
+}
+
+/**
+ * Decode the input using a particular wire format and update this Data.
+ * @param input The input byte array to be decoded.
+ */
+void
+Data::wireDecode(const Block &wire)
+{
+ m_wire = wire;
+ m_wire.parse();
+
+ // Data ::= DATA-TLV TLV-LENGTH
+ // Name
+ // MetaInfo
+ // Content
+ // Signature
+
+ // Name
+ m_name.wireDecode(m_wire.get(Tlv::Name));
+
+ // MetaInfo
+ m_metaInfo.wireDecode(m_wire.get(Tlv::MetaInfo));
+
+ // Content
+ m_content = m_wire.get(Tlv::Content);
+
+ ///////////////
+ // Signature //
+ ///////////////
+
+ // SignatureInfo
+ m_signature.setInfo(m_wire.get(Tlv::SignatureInfo));
+
+ // SignatureValue
+ Block::element_const_iterator val = m_wire.find(Tlv::SignatureValue);
+ if (val != m_wire.elements_end())
+ m_signature.setValue(*val);
+}
+
inline const Name&
Data::getName() const
{
- return name_;
+ return m_name;
}
inline void
Data::setName(const Name& name)
{
onChanged();
- name_ = name;
+ m_name = name;
}
inline const MetaInfo&
Data::getMetaInfo() const
{
- return metaInfo_;
+ return m_metaInfo;
}
inline void
Data::setMetaInfo(const MetaInfo& metaInfo)
{
onChanged();
- metaInfo_ = metaInfo;
+ m_metaInfo = metaInfo;
}
inline uint32_t
Data::getContentType() const
{
- return metaInfo_.getType();
+ return m_metaInfo.getType();
}
inline void
Data::setContentType(uint32_t type)
{
onChanged();
- metaInfo_.setType(type);
+ m_metaInfo.setType(type);
}
inline Milliseconds
Data::getFreshnessPeriod() const
{
- return metaInfo_.getFreshnessPeriod();
+ return m_metaInfo.getFreshnessPeriod();
}
inline void
Data::setFreshnessPeriod(Milliseconds freshnessPeriod)
{
onChanged();
- metaInfo_.setFreshnessPeriod(freshnessPeriod);
+ m_metaInfo.setFreshnessPeriod(freshnessPeriod);
}
inline const name::Component&
Data::getFinalBlockId() const
{
- return metaInfo_.getFinalBlockId();
+ return m_metaInfo.getFinalBlockId();
}
inline void
Data::setFinalBlockId(const name::Component& finalBlockId)
{
onChanged();
- metaInfo_.setFinalBlockId(finalBlockId);
+ m_metaInfo.setFinalBlockId(finalBlockId);
}
inline const Block&
Data::getContent() const
{
- if (content_.empty())
- content_ = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
+ if (m_content.empty())
+ m_content = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
- if (!content_.hasWire())
- content_.encode();
- return content_;
+ if (!m_content.hasWire())
+ m_content.encode();
+ return m_content;
}
inline void
@@ -257,7 +383,7 @@
{
onChanged();
- content_ = dataBlock(Tlv::Content, content, contentLength);
+ m_content = dataBlock(Tlv::Content, content, contentLength);
}
inline void
@@ -265,7 +391,7 @@
{
onChanged();
- content_ = Block(Tlv::Content, contentValue); // not real a wire encoding yet
+ m_content = Block(Tlv::Content, contentValue); // not real a wire encoding yet
}
inline void
@@ -274,30 +400,30 @@
onChanged();
if (content.type() == Tlv::Content)
- content_ = content;
+ m_content = content;
else {
- content_ = Block(Tlv::Content, content);
+ m_content = Block(Tlv::Content, content);
}
}
inline const Signature&
Data::getSignature() const
{
- return signature_;
+ return m_signature;
}
inline void
Data::setSignature(const Signature& signature)
{
onChanged();
- signature_ = signature;
+ m_signature = signature;
}
inline void
Data::setSignatureValue(const Block &value)
{
onChanged();
- signature_.setValue(value);
+ m_signature.setValue(value);
}
inline uint64_t
@@ -320,11 +446,21 @@
// !!!Note!!! Signature is not invalidated and it is responsibility of
// the application to do proper re-signing if necessary
- wire_.reset();
+ m_wire.reset();
}
-std::ostream&
-operator << (std::ostream &os, const Data &data);
+inline std::ostream&
+operator << (std::ostream &os, const Data &data)
+{
+ os << "Name: " << data.getName() << "\n";
+ os << "MetaInfo: " << data.getMetaInfo() << "\n";
+ os << "Content: (size: " << data.getContent().value_size() << ")\n";
+ os << "Signature: (type: " << data.getSignature().getType() <<
+ ", value_length: "<< data.getSignature().getValue().value_size() << ")";
+ os << std::endl;
+
+ return os;
+}
} // namespace ndn
diff --git a/src/encoding/encoding-buffer.hpp b/src/encoding/encoding-buffer.hpp
index 7385c65..c9abd31 100644
--- a/src/encoding/encoding-buffer.hpp
+++ b/src/encoding/encoding-buffer.hpp
@@ -523,7 +523,7 @@
template<bool P, class U>
inline size_t
-prependNestedBlock(EncodingImpl<P>& blk, uint32_t type, U& nestedBlock)
+prependNestedBlock(EncodingImpl<P>& blk, uint32_t type, const U& nestedBlock)
{
size_t var_len = nestedBlock.wireEncode(blk);
size_t total_len = var_len;
@@ -533,6 +533,13 @@
return total_len;
}
+template<bool P>
+inline size_t
+prependBlock(EncodingImpl<P>& blk, const Block& block)
+{
+ return blk.prependByteArray(block.wire(), block.size());
+}
+
} // ndn
diff --git a/src/key-locator.hpp b/src/key-locator.hpp
index 54c9725..65a966b 100644
--- a/src/key-locator.hpp
+++ b/src/key-locator.hpp
@@ -26,27 +26,35 @@
inline
KeyLocator()
- : type_(KeyLocator_None)
+ : m_type(KeyLocator_None)
{
}
inline
KeyLocator(const Name &name);
- inline const Block&
- wireEncode() const;
+ ///////////////////////////////////////////////////////////////////////////////
+
+ template<bool T>
+ size_t
+ wireEncode(EncodingImpl<T> &block) const;
- inline void
- wireDecode(const Block &value);
+ const Block&
+ wireEncode() const;
+
+ void
+ wireDecode(const Block &wire);
+
+ ///////////////////////////////////////////////////////////////////////////////
inline bool
empty() const
{
- return type_ == KeyLocator_None;
+ return m_type == KeyLocator_None;
}
uint32_t
- getType() const { return type_; }
+ getType() const { return m_type; }
////////////////////////////////////////////////////////
// Helper methods for different types of key locators
@@ -60,10 +68,10 @@
setName(const Name &name);
private:
- uint32_t type_;
- Name name_;
+ uint32_t m_type;
+ Name m_name;
- mutable Block wire_;
+ mutable Block m_wire;
};
inline
@@ -72,61 +80,85 @@
setName(name);
}
-inline const Block&
-KeyLocator::wireEncode() const
+template<bool T>
+inline size_t
+KeyLocator::wireEncode(EncodingImpl<T>& block) const
{
- if (wire_.hasWire())
- return wire_;
+ // KeyLocator ::= KEY-LOCATOR-TYPE TLV-LENGTH KeyLocatorValue
- // KeyLocator
+ // KeyLocatorValue ::= Name |
+ // KeyLocatorDigest | (not supported yet)
+ // ...
- switch (type_) {
+ // KeyLocatorDigest ::= KEY-LOCATOR-DIGEST-TYPE TLV-LENGTH BYTE+
+
+ size_t total_len = 0;
+
+ switch (m_type) {
case KeyLocator_None:
- wire_ = dataBlock(Tlv::KeyLocator, reinterpret_cast<const uint8_t*>(0), 0);
break;
case KeyLocator_Name:
- wire_ = Block(Tlv::KeyLocator);
- wire_.push_back(name_.wireEncode());
- wire_.encode();
+ total_len += m_name.wireEncode(block);
break;
default:
throw Error("Unsupported KeyLocator type");
}
+
+ total_len += block.prependVarNumber (total_len);
+ total_len += block.prependVarNumber (Tlv::KeyLocator);
+ return total_len;
+}
+
+inline const Block&
+KeyLocator::wireEncode() const
+{
+ if (m_wire.hasWire ())
+ return m_wire;
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = wireEncode(estimator);
- return wire_;
+ EncodingBuffer buffer(estimatedSize, 0);
+ wireEncode(buffer);
+
+ m_wire = buffer.block();
+ return m_wire;
}
inline void
KeyLocator::wireDecode(const Block &value)
{
- wire_ = value;
- wire_.parse();
+ if (value.type() != Tlv::KeyLocator)
+ throw Error("Unexpected TLV type during KeyLocator decoding");
+
+ m_wire = value;
+ m_wire.parse();
- if (!wire_.elements().empty() && wire_.elements_begin()->type() == Tlv::Name)
+ if (!m_wire.elements().empty() && m_wire.elements_begin()->type() == Tlv::Name)
{
- type_ = KeyLocator_Name;
- name_.wireDecode(*wire_.elements_begin());
+ m_type = KeyLocator_Name;
+ m_name.wireDecode(*m_wire.elements_begin());
}
else
{
- type_ = KeyLocator_Unknown;
+ m_type = KeyLocator_Unknown;
}
}
inline const Name&
KeyLocator::getName() const
{
- if (type_ != KeyLocator_Name)
+ if (m_type != KeyLocator_Name)
throw Error("Requested Name, but KeyLocator is not of the Name type");
- return name_;
+ return m_name;
}
inline void
KeyLocator::setName(const Name &name)
{
- type_ = KeyLocator_Name;
- name_ = name;
+ m_type = KeyLocator_Name;
+ m_name = name;
}
diff --git a/src/util/string-helper.hpp b/src/util/string-helper.hpp
index de0c41f..14f499e 100644
--- a/src/util/string-helper.hpp
+++ b/src/util/string-helper.hpp
@@ -16,6 +16,29 @@
static const char *WHITESPACE_CHARS = " \n\r\t";
/**
+ * Return the hex representation of the bytes in array.
+ * @param array The array of bytes.
+ * @return Hex string.
+ */
+inline std::string
+toHex(const uint8_t* array, size_t arraySize)
+{
+ if (!&array)
+ return "";
+
+ std::ostringstream result;
+ result.flags(std::ios::hex | std::ios::uppercase);
+ for (size_t i = 0; i < arraySize; ++i) {
+ uint8_t x = array[i];
+ if (x < 16)
+ result << '0';
+ result << (unsigned int)x;
+ }
+
+ return result.str();
+}
+
+/**
* Modify str in place to erase whitespace on the left.
* @param str
*/
diff --git a/src/util/time.hpp b/src/util/time.hpp
index 5d729d9..e0b3727 100644
--- a/src/util/time.hpp
+++ b/src/util/time.hpp
@@ -12,6 +12,17 @@
namespace ndn {
+/**
+ * A time interval represented as the number of milliseconds.
+ */
+typedef int64_t Milliseconds;
+
+/**
+ * The calendar time represented as the number of milliseconds since 1/1/1970.
+ */
+typedef int64_t MillisecondsSince1970;
+
+
const boost::posix_time::ptime UNIX_EPOCH_TIME =
boost::posix_time::ptime (boost::gregorian::date (1970, boost::gregorian::Jan, 1));
@@ -30,6 +41,11 @@
return getNowMilliseconds();
}
+inline MillisecondsSince1970
+getNow()
+{
+ return getNowMilliseconds();
+}
/**
* Convert to the ISO string representation of the time.
diff --git a/tests/test-interest.cpp b/tests/test-interest.cpp
index df0cdf3..4ddc3b9 100644
--- a/tests/test-interest.cpp
+++ b/tests/test-interest.cpp
@@ -97,6 +97,7 @@
i.setNonce(1);
const Block &wire = i.wireEncode();
+
BOOST_REQUIRE_EQUAL_COLLECTIONS(Interest1, Interest1+sizeof(Interest1),
wire.begin(), wire.end());
}