interest: recognize Interest in Packet Format v0.3
Interest::wireDecode accepts both v0.2 and v0.3 formats,
but Interest::wireEncode only encodes into v0.2 format.
refs #4527
Change-Id: I784b6f1d5c0d93db33155efddc0180359d8cab74
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 8fbe92d..10961c5 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -156,7 +156,7 @@
* @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
* @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
*/
-inline bool
+constexpr bool
isCriticalType(uint32_t type)
{
return type <= 31 || (type & 0x01);
diff --git a/src/interest.cpp b/src/interest.cpp
index 40e78e4..f08eeb2 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -121,49 +121,193 @@
m_wire = wire;
m_wire.parse();
- if (m_wire.type() != tlv::Interest)
- BOOST_THROW_EXCEPTION(Error("Unexpected TLV number when decoding Interest"));
+ if (m_wire.type() != tlv::Interest) {
+ BOOST_THROW_EXCEPTION(Error("expecting Interest element, got " + to_string(m_wire.type())));
+ }
+
+ if (!decode02()) {
+ decode03();
+ if (!hasNonce()) {
+ setNonce(getNonce());
+ }
+ }
+}
+
+bool
+Interest::decode02()
+{
+ auto ele = m_wire.elements_begin();
// Name
- m_name.wireDecode(m_wire.get(tlv::Name));
-
- // Selectors
- Block::element_const_iterator val = m_wire.find(tlv::Selectors);
- if (val != m_wire.elements_end()) {
- m_selectors.wireDecode(*val);
+ if (ele != m_wire.elements_end() && ele->type() == tlv::Name) {
+ m_name.wireDecode(*ele);
+ ++ele;
}
- else
+ else {
+ return false;
+ }
+
+ // Selectors?
+ if (ele != m_wire.elements_end() && ele->type() == tlv::Selectors) {
+ m_selectors.wireDecode(*ele);
+ ++ele;
+ }
+ else {
m_selectors = Selectors();
+ }
// Nonce
- val = m_wire.find(tlv::Nonce);
- if (val == m_wire.elements_end()) {
- BOOST_THROW_EXCEPTION(Error("Nonce element is missing"));
+ if (ele != m_wire.elements_end() && ele->type() == tlv::Nonce) {
+ uint32_t nonce = 0;
+ if (ele->value_size() != sizeof(nonce)) {
+ BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
+ }
+ std::memcpy(&nonce, ele->value(), sizeof(nonce));
+ m_nonce = nonce;
+ ++ele;
}
- uint32_t nonce = 0;
- if (val->value_size() != sizeof(nonce)) {
- BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
+ else {
+ return false;
}
- std::memcpy(&nonce, val->value(), sizeof(nonce));
- m_nonce = nonce;
- // InterestLifetime
- val = m_wire.find(tlv::InterestLifetime);
- if (val != m_wire.elements_end()) {
- m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val));
+ // InterestLifetime?
+ if (ele != m_wire.elements_end() && ele->type() == tlv::InterestLifetime) {
+ m_interestLifetime = time::milliseconds(readNonNegativeInteger(*ele));
+ ++ele;
}
else {
m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
}
- // ForwardingHint
- val = m_wire.find(tlv::ForwardingHint);
- if (val != m_wire.elements_end()) {
- m_forwardingHint.wireDecode(*val, false);
+ // ForwardingHint?
+ if (ele != m_wire.elements_end() && ele->type() == tlv::ForwardingHint) {
+ m_forwardingHint.wireDecode(*ele, false);
+ ++ele;
}
else {
m_forwardingHint = DelegationList();
}
+
+ return ele == m_wire.elements_end();
+}
+
+void
+Interest::decode03()
+{
+ // Interest ::= INTEREST-TYPE TLV-LENGTH
+ // Name
+ // CanBePrefix?
+ // MustBeFresh?
+ // ForwardingHint?
+ // Nonce?
+ // InterestLifetime?
+ // HopLimit?
+ // Parameters?
+
+ bool hasName = false;
+ m_selectors = Selectors().setMaxSuffixComponents(1); // CanBePrefix=0
+ m_nonce.reset();
+ m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
+ m_forwardingHint = DelegationList();
+
+ int lastEle = 0; // last recognized element index, in spec order
+ for (const Block& ele : m_wire.elements()) {
+ switch (ele.type()) {
+ case tlv::Name: {
+ if (lastEle >= 1) {
+ BOOST_THROW_EXCEPTION(Error("Name element is out of order"));
+ }
+ hasName = true;
+ m_name.wireDecode(ele);
+ if (m_name.empty()) {
+ BOOST_THROW_EXCEPTION(Error("Name has zero name components"));
+ }
+ lastEle = 1;
+ break;
+ }
+ case tlv::CanBePrefix: {
+ if (lastEle >= 2) {
+ BOOST_THROW_EXCEPTION(Error("CanBePrefix element is out of order"));
+ }
+ if (ele.value_size() != 0) {
+ BOOST_THROW_EXCEPTION(Error("CanBePrefix element has non-zero TLV-LENGTH"));
+ }
+ m_selectors.setMaxSuffixComponents(-1);
+ lastEle = 2;
+ break;
+ }
+ case tlv::MustBeFresh: {
+ if (lastEle >= 3) {
+ BOOST_THROW_EXCEPTION(Error("MustBeFresh element is out of order"));
+ }
+ if (ele.value_size() != 0) {
+ BOOST_THROW_EXCEPTION(Error("MustBeFresh element has non-zero TLV-LENGTH"));
+ }
+ m_selectors.setMustBeFresh(true);
+ lastEle = 3;
+ break;
+ }
+ case tlv::ForwardingHint: {
+ if (lastEle >= 4) {
+ BOOST_THROW_EXCEPTION(Error("ForwardingHint element is out of order"));
+ }
+ m_forwardingHint.wireDecode(ele);
+ lastEle = 4;
+ break;
+ }
+ case tlv::Nonce: {
+ if (lastEle >= 5) {
+ BOOST_THROW_EXCEPTION(Error("Nonce element is out of order"));
+ }
+ uint32_t nonce = 0;
+ if (ele.value_size() != sizeof(nonce)) {
+ BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
+ }
+ std::memcpy(&nonce, ele.value(), sizeof(nonce));
+ m_nonce = nonce;
+ lastEle = 5;
+ break;
+ }
+ case tlv::InterestLifetime: {
+ if (lastEle >= 6) {
+ BOOST_THROW_EXCEPTION(Error("InterestLifetime element is out of order"));
+ }
+ m_interestLifetime = time::milliseconds(readNonNegativeInteger(ele));
+ lastEle = 6;
+ break;
+ }
+ case tlv::HopLimit: {
+ if (lastEle >= 7) {
+ break; // HopLimit is non-critical, ignore out-of-order appearance
+ }
+ if (ele.value_size() != 1) {
+ BOOST_THROW_EXCEPTION(Error("HopLimit element is malformed"));
+ }
+ // TLV-VALUE is ignored
+ lastEle = 7;
+ break;
+ }
+ case tlv::Parameters: {
+ if (lastEle >= 8) {
+ BOOST_THROW_EXCEPTION(Error("Parameters element is out of order"));
+ }
+ // TLV-VALUE is ignored
+ lastEle = 8;
+ break;
+ }
+ default: {
+ if (tlv::isCriticalType(ele.type())) {
+ BOOST_THROW_EXCEPTION(Error("unrecognized element of critical type " +
+ to_string(ele.type())));
+ }
+ break;
+ }
+ }
+ }
+
+ if (!hasName) {
+ BOOST_THROW_EXCEPTION(Error("Name element is missing"));
+ }
}
std::string
diff --git a/src/interest.hpp b/src/interest.hpp
index d547daa..5fc1c42 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -73,12 +73,16 @@
size_t
wireEncode(EncodingImpl<TAG>& encoder) const;
- /** @brief Encode to a @c Block in NDN Packet Format v0.2.
+ /** @brief Encode to a @c Block.
+ *
+ * Normally, this function encodes to NDN Packet Format v0.2. However, if this instance has
+ * cached wire encoding (@c hasWire() is true), the cached encoding is returned and it might
+ * be in v0.3 format.
*/
const Block&
wireEncode() const;
- /** @brief Decode from @p wire in NDN Packet Format v0.2.
+ /** @brief Decode from @p wire in NDN Packet Format v0.2 or v0.3.
*/
void
wireDecode(const Block& wire);
@@ -372,6 +376,21 @@
}
private:
+ /** @brief Decode @c m_wire as NDN Packet Format v0.2.
+ * @retval true decoding successful.
+ * @retval false decoding failed due to structural error.
+ * @throw tlv::Error decoding error within a sub-element.
+ */
+ bool
+ decode02();
+
+ /** @brief Decode @c m_wire as NDN Packet Format v0.3.
+ * @throw tlv::Error decoding error.
+ */
+ void
+ decode03();
+
+private:
Name m_name;
Selectors m_selectors;
mutable optional<uint32_t> m_nonce;