management: Making LocalControlHeader encoding independent of Interest/Data wire
Boost.Asio support multi-buffer send operation, which is enabled in this
commit for prepending (potentially different) LocalControlHeader's to
Interest/Data wire.
Change-Id: I39b979f89f196d3e47d6466fb71f6d440bce74d4
refs: #1265
diff --git a/src/management/nfd-local-control-header.hpp b/src/management/nfd-local-control-header.hpp
index e931f57..5ddc14b 100644
--- a/src/management/nfd-local-control-header.hpp
+++ b/src/management/nfd-local-control-header.hpp
@@ -14,11 +14,12 @@
namespace nfd {
const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
-const size_t ESTIMATED_LOCAL_HEADER_RESERVE = 10;
class LocalControlHeader
{
public:
+ struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
+
LocalControlHeader()
: m_incomingFaceId(INVALID_FACE_ID)
, m_nextHopFaceId(INVALID_FACE_ID)
@@ -28,17 +29,26 @@
/**
* @brief Create wire encoding with options LocalControlHeader and the supplied item
*
- * This method will return wire encoding of the item if none of the LocalControlHeader
- * fields are set, otherwise it will encapsulate the item inside LocalControlHeader
+ * The caller is responsible of checking whether LocalControlHeader contains
+ * any information.
*
- * Note that this method will use default maximum packet size (8800 bytes) during the
- * encoding process.
+ * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
+ * set, or neither of them is enabled.
+ *
+ * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
+ *
+ * @returns Block, containing LocalControlHeader. Top-level length field of the
+ * returned LocalControlHeader includes payload length, but the memory
+ * block is independent of the payload's wire buffer. It is expected
+ * that both LocalControlHeader's and payload's wire will be send out
+ * together within a single send call.
*
* @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
*/
template<class U>
- inline const Block&
- wireEncode(const U& item) const;
+ inline Block
+ wireEncode(const U& payload,
+ bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
/**
* @brief Decode from the wire format and set LocalControlHeader on the supplied item
@@ -55,12 +65,13 @@
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
- // Gettest/setters
+ // Getters/setters
bool
- empty() const
+ empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
{
- return (!hasIncomingFaceId() && !hasNextHopFaceId());
+ return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
+ (encodeNextHopFaceId && hasNextHopFaceId()));
}
//
@@ -81,7 +92,6 @@
setIncomingFaceId(uint64_t incomingFaceId)
{
m_incomingFaceId = incomingFaceId;
- m_wire.reset();
}
//
@@ -102,38 +112,37 @@
setNextHopFaceId(uint64_t nextHopFaceId)
{
m_nextHopFaceId = nextHopFaceId;
- m_wire.reset();
}
private:
- template<bool T, class U>
+ template<bool T>
inline size_t
- wireEncode(EncodingImpl<T>& block, const U& item) const;
+ wireEncode(EncodingImpl<T>& block, size_t payloadSize,
+ bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
private:
uint64_t m_incomingFaceId;
uint64_t m_nextHopFaceId;
-
- mutable Block m_wire;
};
/**
* @brief Fast encoding or block size estimation
*/
-template<bool T, class U>
+template<bool T>
inline size_t
-LocalControlHeader::wireEncode(EncodingImpl<T>& block, const U& item) const
+LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
+ bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
{
- size_t total_len = item.wireEncode().size();
+ size_t total_len = payloadSize;
- if (hasIncomingFaceId())
+ if (encodeIncomingFaceId && hasIncomingFaceId())
{
total_len += prependNonNegativeIntegerBlock(block,
tlv::nfd::IncomingFaceId, getIncomingFaceId());
}
- if (hasNextHopFaceId())
+ if (encodeNextHopFaceId && hasNextHopFaceId())
{
total_len += prependNonNegativeIntegerBlock(block,
tlv::nfd::NextHopFaceId, getNextHopFaceId());
@@ -145,58 +154,36 @@
}
template<class U>
-inline const Block&
-LocalControlHeader::wireEncode(const U& item) const
+inline Block
+LocalControlHeader::wireEncode(const U& payload,
+ bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
{
- if (item.hasWire() && m_wire.hasWire())
- return m_wire;
+ /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
+ if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
+ throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
- if (empty())
- {
- if (item.hasWire())
- return item.wireEncode();
- else
- {
- EncodingBuffer buffer; // use default (maximum) packet size here
- item.wireEncode(buffer);
- item.m_wire = buffer.block();
- m_wire = buffer.block();
- }
- }
- else
- {
- if (item.hasWire())
- {
- // extend the existing buffer
- EncodingBuffer buffer(item.wireEncode());
- wireEncode(buffer, item);
- m_wire = buffer.block();
- }
- else
- {
- EncodingBuffer buffer;
- item.wireEncode(buffer);
- item.m_wire = buffer.block();
+ EncodingEstimator estimator;
+ size_t length = wireEncode(estimator, payload.wireEncode().size(),
+ encodeIncomingFaceId, encodeNextHopFaceId);
+
+ EncodingBuffer buffer(length);
+ wireEncode(buffer, payload.wireEncode().size(),
+ encodeIncomingFaceId, encodeNextHopFaceId);
- wireEncode(buffer, item);
- m_wire = buffer.block();
- }
- }
- return m_wire;
+ return buffer.block(false);
}
inline void
LocalControlHeader::wireDecode(const Block& wire)
{
BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
- m_wire = wire;
- m_wire.parse();
+ wire.parse();
m_incomingFaceId = INVALID_FACE_ID;
m_nextHopFaceId = INVALID_FACE_ID;
- for (Block::element_const_iterator i = m_wire.elements_begin();
- i != m_wire.elements_end();
+ for (Block::element_const_iterator i = wire.elements_begin();
+ i != wire.elements_end();
++i)
{
switch(i->type())