face: NDNLP encoding change

FragIndex and FragCount fields are encoded as nonNegativeInteger.

refs #1283

Change-Id: I4654078c3bfd73c83ce06ce6a9cd97952a4f49f8
diff --git a/daemon/face/ndnlp-parse.cpp b/daemon/face/ndnlp-parse.cpp
index 1162f0e..5ce4fc5 100644
--- a/daemon/face/ndnlp-parse.cpp
+++ b/daemon/face/ndnlp-parse.cpp
@@ -20,7 +20,7 @@
   if (elements.size() < 2) {
     throw ParseError("NdnlpData element has incorrect number of children");
   }
-  
+
   const Block& sequenceElement = elements.front();
   if (sequenceElement.type() != tlv::NdnlpSequence) {
     throw ParseError("NdnlpSequence element is missing");
@@ -29,7 +29,7 @@
     throw ParseError("NdnlpSequence element has incorrect length");
   }
   m_seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
-  
+
   const Block& payloadElement = elements.back();
   if (payloadElement.type() != tlv::NdnlpPayload) {
     throw ParseError("NdnlpPayload element is missing");
@@ -44,24 +44,30 @@
   if (elements.size() != 4) {
     throw ParseError("NdnlpData element has incorrect number of children");
   }
-  
+
   const Block& fragIndexElement = elements.at(1);
   if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
     throw ParseError("NdnlpFragIndex element is missing");
   }
-  if (fragIndexElement.value_size() != sizeof(uint16_t)) {
-    throw ParseError("NdnlpFragIndex element has incorrect length");
+  uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
+  if (fragIndex > std::numeric_limits<uint16_t>::max()) {
+    throw ParseError("NdnlpFragIndex is too large");
   }
-  m_fragIndex = be16toh(*reinterpret_cast<const uint16_t*>(&*fragIndexElement.value_begin()));
-  
+  m_fragIndex = static_cast<uint16_t>(fragIndex);
+
   const Block& fragCountElement = elements.at(2);
   if (fragCountElement.type() != tlv::NdnlpFragCount) {
     throw ParseError("NdnlpFragCount element is missing");
   }
-  if (fragCountElement.value_size() != sizeof(uint16_t)) {
-    throw ParseError("NdnlpFragCount element has incorrect length");
+  uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
+  if (fragCount > std::numeric_limits<uint16_t>::max()) {
+    throw ParseError("NdnlpFragCount is too large");
   }
-  m_fragCount = be16toh(*reinterpret_cast<const uint16_t*>(&*fragCountElement.value_begin()));
+  m_fragCount = static_cast<uint16_t>(fragCount);
+
+  if (m_fragIndex >= m_fragCount) {
+    throw ParseError("NdnlpFragIndex must be less than NdnlpFragCount");
+  }
 }
 
 } // namespace ndnlp
diff --git a/daemon/face/ndnlp-parse.hpp b/daemon/face/ndnlp-parse.hpp
index 2790569..4215620 100644
--- a/daemon/face/ndnlp-parse.hpp
+++ b/daemon/face/ndnlp-parse.hpp
@@ -22,7 +22,7 @@
 };
 
 /** \brief represents a NdnlpData packet
- *  
+ *
  *  NdnlpData ::= NDNLP-DATA-TYPE TLV-LENGTH
  *                  NdnlpSequence
  *                  NdnlpFragIndex?
@@ -33,12 +33,12 @@
 {
 public:
   /** \brief parse a NdnlpData packet
-   *  
+   *
    *  \exception ParseError packet is malformated
    */
   void
   wireDecode(const Block& wire);
-  
+
 public:
   uint64_t m_seq;
   uint16_t m_fragIndex;
diff --git a/daemon/face/ndnlp-partial-message-store.cpp b/daemon/face/ndnlp-partial-message-store.cpp
index df8a285..74c109f 100644
--- a/daemon/face/ndnlp-partial-message-store.cpp
+++ b/daemon/face/ndnlp-partial-message-store.cpp
@@ -23,15 +23,15 @@
     m_fragCount = fragCount;
     m_payloads.resize(fragCount);
   }
-  
+
   if (m_fragCount != fragCount || fragIndex >= m_fragCount) {
     return false;
   }
-  
+
   if (!m_payloads[fragIndex].empty()) { // duplicate
     return false;
   }
-  
+
   m_payloads[fragIndex] = payload;
   ++m_received;
   m_totalLength += payload.value_size();
@@ -48,7 +48,7 @@
 PartialMessage::reassemble()
 {
   BOOST_ASSERT(this->isComplete());
-  
+
   ndn::BufferPtr buffer = make_shared<ndn::Buffer>(m_totalLength);
   uint8_t* buf = buffer->get();
   for (std::vector<Block>::const_iterator it = m_payloads.begin();
@@ -57,7 +57,7 @@
     memcpy(buf, payload.value(), payload.value_size());
     buf += payload.value_size();
   }
-  
+
   return Block(buffer);
 }
 
@@ -80,14 +80,14 @@
     this->onReceive(parsed.m_payload.blockFromValue());
     return;
   }
-  
+
   uint64_t messageIdentifier = parsed.m_seq - parsed.m_fragIndex;
   shared_ptr<PartialMessage> pm = m_partialMessages[messageIdentifier];
   if (!static_cast<bool>(pm)) {
     m_partialMessages[messageIdentifier] = pm = make_shared<PartialMessage>();
   }
   this->scheduleCleanup(messageIdentifier, pm);
-  
+
   pm->add(parsed.m_fragIndex, parsed.m_fragCount, parsed.m_payload);
   if (pm->isComplete()) {
     this->onReceive(pm->reassemble());
@@ -111,7 +111,7 @@
   if (it == m_partialMessages.end()) {
     return;
   }
-  
+
   m_scheduler.cancelEvent(it->second->m_expiry);
   m_partialMessages.erase(it);
 }
diff --git a/daemon/face/ndnlp-partial-message-store.hpp b/daemon/face/ndnlp-partial-message-store.hpp
index 954b79a..e5de5b1 100644
--- a/daemon/face/ndnlp-partial-message-store.hpp
+++ b/daemon/face/ndnlp-partial-message-store.hpp
@@ -20,26 +20,26 @@
 {
 public:
   PartialMessage();
-  
+
   bool
   add(uint16_t fragIndex, uint16_t fragCount, const Block& payload);
-  
+
   bool
   isComplete() const;
-  
+
   /** \brief reassemble network layer packet
-   *  
+   *
    *  isComplete() must be true before calling this method
-   *  
+   *
    *  \exception ndn::Block::Error packet is malformated
    *  \return network layer packet
    */
   Block
   reassemble();
-  
+
 public:
   EventId m_expiry;
-  
+
 private:
   size_t m_fragCount;
   size_t m_received;
@@ -54,28 +54,28 @@
 public:
   PartialMessageStore(Scheduler& scheduler,
     time::Duration idleDuration = time::milliseconds(100));
-  
+
   virtual
   ~PartialMessageStore();
-  
+
   /** \brief receive a NdnlpData packet
-   *  
+   *
    *  \exception ParseError NDNLP packet is malformated
    *  \exception ndn::Block::Error network layer packet is malformated
    */
   void
   receiveNdnlpData(const Block& pkt);
-  
+
   /// fires when network layer packet is received
   EventEmitter<Block> onReceive;
-  
+
 private:
   void
   scheduleCleanup(uint64_t messageIdentifier, shared_ptr<PartialMessage> partialMessage);
-  
+
   void
   cleanup(uint64_t messageIdentifier);
-  
+
 private:
   std::map<uint64_t, shared_ptr<PartialMessage> > m_partialMessages;
 
diff --git a/daemon/face/ndnlp-sequence-generator.hpp b/daemon/face/ndnlp-sequence-generator.hpp
index f067552..537cac2 100644
--- a/daemon/face/ndnlp-sequence-generator.hpp
+++ b/daemon/face/ndnlp-sequence-generator.hpp
@@ -18,15 +18,15 @@
 {
 public:
   SequenceBlock(uint64_t start, size_t count);
-  
+
   /** \return{ the pos-th sequence number }
    */
   uint64_t
   operator[](size_t pos) const;
-  
+
   size_t
   count() const;
-  
+
 private:
   uint64_t m_start;
   size_t m_count;
@@ -53,7 +53,7 @@
 {
 public:
   SequenceGenerator();
-  
+
   /** \brief generates a block of consecutive sequence numbers
    *
    *  This block must not overlap with a recent block.
diff --git a/daemon/face/ndnlp-slicer.cpp b/daemon/face/ndnlp-slicer.cpp
index 074a4f7..1cc64a4 100644
--- a/daemon/face/ndnlp-slicer.cpp
+++ b/daemon/face/ndnlp-slicer.cpp
@@ -28,32 +28,28 @@
                       const uint8_t* payload, size_t payloadSize)
 {
   size_t totalLength = 0;
-  
+
   // NdnlpPayload
   size_t payloadLength = blk.prependByteArray(payload, payloadSize);
   totalLength += payloadLength;
   totalLength += blk.prependVarNumber(payloadLength);
   totalLength += blk.prependVarNumber(tlv::NdnlpPayload);
-  
+
   bool needFragIndexAndCount = fragCount > 1;
   if (needFragIndexAndCount) {
     // NdnlpFragCount
-    uint16_t fragCountBE = htobe16(fragCount);
-    size_t fragCountLength = blk.prependByteArray(
-      reinterpret_cast<uint8_t*>(&fragCountBE), sizeof(fragCountBE));
+    size_t fragCountLength = blk.prependNonNegativeInteger(fragCount);
     totalLength += fragCountLength;
     totalLength += blk.prependVarNumber(fragCountLength);
     totalLength += blk.prependVarNumber(tlv::NdnlpFragCount);
-    
+
     // NdnlpFragIndex
-    uint16_t fragIndexBE = htobe16(fragIndex);
-    size_t fragIndexLength = blk.prependByteArray(
-      reinterpret_cast<uint8_t*>(&fragIndexBE), sizeof(fragIndexBE));
+    size_t fragIndexLength = blk.prependNonNegativeInteger(fragIndex);
     totalLength += fragIndexLength;
     totalLength += blk.prependVarNumber(fragIndexLength);
     totalLength += blk.prependVarNumber(tlv::NdnlpFragIndex);
   }
-  
+
   // NdnlpSequence
   uint64_t sequenceBE = htobe64(seq);
   size_t sequenceLength = blk.prependByteArray(
@@ -61,10 +57,11 @@
   totalLength += sequenceLength;
   totalLength += blk.prependVarNumber(sequenceLength);
   totalLength += blk.prependVarNumber(tlv::NdnlpSequence);
-  
+
+  // NdnlpData
   totalLength += blk.prependVarNumber(totalLength);
   totalLength += blk.prependVarNumber(tlv::NdnlpData);
-  
+
   return totalLength;
 }
 
@@ -74,7 +71,7 @@
   ndn::EncodingEstimator estimator;
   size_t estimatedSize = Slicer_encodeFragment(estimator,
                          0, 0, 2, 0, m_mtu);
-  
+
   size_t overhead = estimatedSize - m_mtu;
   m_maxPayload = m_mtu - overhead;
 }
@@ -85,7 +82,7 @@
   BOOST_ASSERT(block.hasWire());
   const uint8_t* networkPacket = block.wire();
   size_t networkPacketSize = block.size();
-  
+
   uint16_t fragCount = static_cast<uint16_t>(
                          (networkPacketSize / m_maxPayload) +
                          (networkPacketSize % m_maxPayload == 0 ? 0 : 1)
@@ -93,21 +90,21 @@
   PacketArray pa = make_shared<std::vector<Block> >();
   pa->reserve(fragCount);
   SequenceBlock seqBlock = m_seqgen.nextBlock(fragCount);
-  
+
   for (uint16_t fragIndex = 0; fragIndex < fragCount; ++fragIndex) {
     size_t payloadOffset = fragIndex * m_maxPayload;
     const uint8_t* payload = networkPacket + payloadOffset;
     size_t payloadSize = std::min(m_maxPayload, networkPacketSize - payloadOffset);
-    
+
     ndn::EncodingBuffer buffer(m_mtu, 0);
     size_t pktSize = Slicer_encodeFragment(buffer,
       seqBlock[fragIndex], fragIndex, fragCount, payload, payloadSize);
-    
+
     BOOST_ASSERT(pktSize <= m_mtu);
-    
+
     pa->push_back(buffer.block());
   }
-  
+
   return pa;
 }
 
diff --git a/daemon/face/ndnlp-slicer.hpp b/daemon/face/ndnlp-slicer.hpp
index ba04e3c..716cddc 100644
--- a/daemon/face/ndnlp-slicer.hpp
+++ b/daemon/face/ndnlp-slicer.hpp
@@ -22,10 +22,10 @@
 public:
   explicit
   Slicer(size_t mtu);
-  
+
   virtual
   ~Slicer();
-  
+
   PacketArray
   slice(const Block& block);
 
@@ -33,13 +33,13 @@
   /// estimate the size of NDNLP header and maximum payload size per packet
   void
   estimateOverhead();
-  
+
 private:
   SequenceGenerator m_seqgen;
-  
+
   /// maximum packet size
   size_t m_mtu;
-  
+
   /// maximum payload size
   size_t m_maxPayload;
 };
diff --git a/daemon/face/ndnlp-tlv.hpp b/daemon/face/ndnlp-tlv.hpp
index fe15e6a..ed97dae 100644
--- a/daemon/face/ndnlp-tlv.hpp
+++ b/daemon/face/ndnlp-tlv.hpp
@@ -10,7 +10,8 @@
 namespace nfd {
 namespace tlv {
 
-enum {
+enum
+{
   NdnlpData      = 80,
   NdnlpSequence  = 81,
   NdnlpFragIndex = 82,
diff --git a/tests/face/ndnlp.cpp b/tests/face/ndnlp.cpp
index 589af94..77e99e2 100644
--- a/tests/face/ndnlp.cpp
+++ b/tests/face/ndnlp.cpp
@@ -35,7 +35,7 @@
 BOOST_AUTO_TEST_CASE(SequenceGenerator)
 {
   ndnlp::SequenceGenerator seqgen;
-  
+
   ndnlp::SequenceBlock sb1 = seqgen.nextBlock(2);
   BOOST_CHECK_EQUAL(sb1.count(), 2);
 
@@ -50,28 +50,28 @@
   uint8_t blockValue[60];
   memset(blockValue, 0xcc, sizeof(blockValue));
   Block block = ndn::dataBlock(0x01, blockValue, sizeof(blockValue));
-  
+
   ndnlp::Slicer slicer(9000);
   ndnlp::PacketArray pa = slicer.slice(block);
-  
+
   BOOST_REQUIRE_EQUAL(pa->size(), 1);
-  
+
   const Block& pkt = pa->at(0);
   BOOST_CHECK_EQUAL(pkt.type(), static_cast<uint32_t>(tlv::NdnlpData));
   pkt.parse();
-  
+
   const Block::element_container& elements = pkt.elements();
   BOOST_REQUIRE_EQUAL(elements.size(), 2);
-  
+
   const Block& sequenceElement = elements[0];
   BOOST_CHECK_EQUAL(sequenceElement.type(), static_cast<uint32_t>(tlv::NdnlpSequence));
   BOOST_REQUIRE_EQUAL(sequenceElement.value_size(), sizeof(uint64_t));
-  
+
   const Block& payloadElement = elements[1];
   BOOST_CHECK_EQUAL(payloadElement.type(), static_cast<uint32_t>(tlv::NdnlpPayload));
   size_t payloadSize = payloadElement.value_size();
   BOOST_CHECK_EQUAL(payloadSize, block.size());
-  
+
   BOOST_CHECK_EQUAL_COLLECTIONS(payloadElement.value_begin(), payloadElement.value_end(),
                                 block.begin(),                block.end());
 }
@@ -82,24 +82,24 @@
   uint8_t blockValue[5050];
   memset(blockValue, 0xcc, sizeof(blockValue));
   Block block = ndn::dataBlock(0x01, blockValue, sizeof(blockValue));
-  
+
   ndnlp::Slicer slicer(1500);
   ndnlp::PacketArray pa = slicer.slice(block);
-  
+
   BOOST_REQUIRE_EQUAL(pa->size(), 4);
-  
+
   uint64_t seq0 = 0xdddd;
-  
+
   size_t totalPayloadSize = 0;
-  
+
   for (size_t i = 0; i < 4; ++i) {
     const Block& pkt = pa->at(i);
     BOOST_CHECK_EQUAL(pkt.type(), static_cast<uint32_t>(tlv::NdnlpData));
     pkt.parse();
-    
+
     const Block::element_container& elements = pkt.elements();
     BOOST_REQUIRE_EQUAL(elements.size(), 4);
-    
+
     const Block& sequenceElement = elements[0];
     BOOST_CHECK_EQUAL(sequenceElement.type(), static_cast<uint32_t>(tlv::NdnlpSequence));
     BOOST_REQUIRE_EQUAL(sequenceElement.value_size(), sizeof(uint64_t));
@@ -109,27 +109,23 @@
       seq0 = seq;
     }
     BOOST_CHECK_EQUAL(seq, seq0 + i);
-    
+
     const Block& fragIndexElement = elements[1];
     BOOST_CHECK_EQUAL(fragIndexElement.type(), static_cast<uint32_t>(tlv::NdnlpFragIndex));
-    BOOST_REQUIRE_EQUAL(fragIndexElement.value_size(), sizeof(uint16_t));
-    uint16_t fragIndex = be16toh(*reinterpret_cast<const uint16_t*>(
-                                   &*fragIndexElement.value_begin()));
+    uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
     BOOST_CHECK_EQUAL(fragIndex, i);
-    
+
     const Block& fragCountElement = elements[2];
     BOOST_CHECK_EQUAL(fragCountElement.type(), static_cast<uint32_t>(tlv::NdnlpFragCount));
-    BOOST_REQUIRE_EQUAL(fragCountElement.value_size(), sizeof(uint16_t));
-    uint16_t fragCount = be16toh(*reinterpret_cast<const uint16_t*>(
-                                   &*fragCountElement.value_begin()));
+    uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
     BOOST_CHECK_EQUAL(fragCount, 4);
-    
+
     const Block& payloadElement = elements[3];
     BOOST_CHECK_EQUAL(payloadElement.type(), static_cast<uint32_t>(tlv::NdnlpPayload));
     size_t payloadSize = payloadElement.value_size();
     totalPayloadSize += payloadSize;
   }
-  
+
   BOOST_CHECK_EQUAL(totalPayloadSize, block.size());
 }
 
@@ -152,11 +148,11 @@
     memset(blockValue, 0xcc, sizeof(blockValue));
     return ndn::dataBlock(0x01, blockValue, sizeof(blockValue));
   }
-  
+
 protected:
   boost::asio::io_service m_io;
   Scheduler m_scheduler;
-  
+
   ndnlp::Slicer m_slicer;
   ndnlp::PartialMessageStore m_partialMessageStore;
 
@@ -170,10 +166,10 @@
   Block block = makeBlock(60);
   ndnlp::PacketArray pa = m_slicer.slice(block);
   BOOST_REQUIRE_EQUAL(pa->size(), 1);
-  
+
   BOOST_CHECK_EQUAL(m_received.size(), 0);
   m_partialMessageStore.receiveNdnlpData(pa->at(0));
-  
+
   BOOST_REQUIRE_EQUAL(m_received.size(), 1);
   BOOST_CHECK_EQUAL_COLLECTIONS(m_received.at(0).begin(), m_received.at(0).end(),
                                 block.begin(),            block.end());
@@ -185,11 +181,11 @@
   Block block = makeBlock(5050);
   ndnlp::PacketArray pa = m_slicer.slice(block);
   BOOST_REQUIRE_EQUAL(pa->size(), 4);
-  
+
   Block block2 = makeBlock(2000);
   ndnlp::PacketArray pa2 = m_slicer.slice(block2);
   BOOST_REQUIRE_EQUAL(pa2->size(), 2);
-  
+
   BOOST_CHECK_EQUAL(m_received.size(), 0);
   m_partialMessageStore.receiveNdnlpData(pa->at(0));
   BOOST_CHECK_EQUAL(m_received.size(), 0);
@@ -204,7 +200,7 @@
   m_partialMessageStore.receiveNdnlpData(pa->at(3));
   BOOST_CHECK_EQUAL(m_received.size(), 1);
   m_partialMessageStore.receiveNdnlpData(pa->at(2));
-  
+
   BOOST_REQUIRE_EQUAL(m_received.size(), 2);
   BOOST_CHECK_EQUAL_COLLECTIONS(m_received.at(1).begin(), m_received.at(1).end(),
                                 block.begin(),            block.end());