face: no exceptions in NDNLP PartialMessageStore
refs #2261
Change-Id: I711502be23bb4b3691eb44fc63332ffd0bfb8d34
diff --git a/daemon/face/ethernet-face.cpp b/daemon/face/ethernet-face.cpp
index d2cd9a1..a2b10e3 100644
--- a/daemon/face/ethernet-face.cpp
+++ b/daemon/face/ethernet-face.cpp
@@ -360,11 +360,10 @@
EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
{
size_t length = header->caplen;
- if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN)
- {
- NFD_LOG_FACE_WARN("Received frame is too short (" << length << " bytes)");
- return;
- }
+ if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN) {
+ NFD_LOG_FACE_WARN("Received frame is too short (" << length << " bytes)");
+ return;
+ }
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
const ethernet::Address sourceAddress(eh->ether_shost);
@@ -382,31 +381,30 @@
/// \todo Reserve space in front and at the back of the underlying buffer
bool isOk = false;
- Block fragment;
- std::tie(isOk, fragment) = Block::fromBuffer(packet, length);
- if (!isOk)
- {
- NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
- << " is invalid or too large to process");
- return;
- }
+ Block fragmentBlock;
+ std::tie(isOk, fragmentBlock) = Block::fromBuffer(packet, length);
+ if (!isOk) {
+ NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
+ << " is invalid or too large to process");
+ return;
+ }
- NFD_LOG_FACE_TRACE("Received: " << fragment.size() << " bytes from " << sourceAddress.toString());
- this->getMutableCounters().getNInBytes() += fragment.size();
+ NFD_LOG_FACE_TRACE("Received: " << fragmentBlock.size() << " bytes from "
+ << sourceAddress.toString());
+ this->getMutableCounters().getNInBytes() += fragmentBlock.size();
Reassembler& reassembler = m_reassemblers[sourceAddress];
- if (!reassembler.pms)
- {
- // new sender, setup a PartialMessageStore for it
- reassembler.pms.reset(new ndnlp::PartialMessageStore);
- reassembler.pms->onReceive.connect(
- [this, sourceAddress] (const Block& block) {
- NFD_LOG_FACE_TRACE("All fragments received from " << sourceAddress.toString());
- if (!decodeAndDispatchInput(block))
- NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << block.type()
- << " from " << sourceAddress.toString());
- });
- }
+ if (!reassembler.pms) {
+ // new sender, setup a PartialMessageStore for it
+ reassembler.pms.reset(new ndnlp::PartialMessageStore);
+ reassembler.pms->onReceive.connect(
+ [this, sourceAddress] (const Block& block) {
+ NFD_LOG_FACE_TRACE("All fragments received from " << sourceAddress.toString());
+ if (!decodeAndDispatchInput(block))
+ NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << block.type()
+ << " from " << sourceAddress.toString());
+ });
+ }
scheduler::cancel(reassembler.expireEvent);
reassembler.expireEvent = scheduler::schedule(REASSEMBLER_LIFETIME,
@@ -414,13 +412,15 @@
BOOST_VERIFY(m_reassemblers.erase(sourceAddress) == 1);
});
- try {
- reassembler.pms->receiveNdnlpData(fragment);
- }
- catch (const ndnlp::ParseError& e) {
+ ndnlp::NdnlpData fragment;
+ std::tie(isOk, fragment) = ndnlp::NdnlpData::fromBlock(fragmentBlock);
+ if (!isOk) {
NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from "
- << sourceAddress.toString() << " : " << e.what());
+ << sourceAddress.toString());
+ return;
}
+
+ reassembler.pms->receive(fragment);
}
void
diff --git a/daemon/face/ndnlp-data.cpp b/daemon/face/ndnlp-data.cpp
new file mode 100644
index 0000000..7cfacac
--- /dev/null
+++ b/daemon/face/ndnlp-data.cpp
@@ -0,0 +1,108 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ndnlp-data.hpp"
+
+namespace nfd {
+namespace ndnlp {
+
+std::tuple<bool, NdnlpData>
+NdnlpData::fromBlock(const Block& wire)
+{
+ if (wire.type() != tlv::NdnlpData) {
+ // top element is not NdnlpData
+ return std::make_tuple(false, NdnlpData());
+ }
+ wire.parse();
+ const Block::element_container& elements = wire.elements();
+ if (elements.size() < 2) {
+ // NdnlpData element has incorrect number of children
+ return std::make_tuple(false, NdnlpData());
+ }
+
+ NdnlpData parsed;
+
+ const Block& sequenceElement = elements.front();
+ if (sequenceElement.type() != tlv::NdnlpSequence) {
+ // NdnlpSequence element is missing
+ return std::make_tuple(false, NdnlpData());
+ }
+ if (sequenceElement.value_size() != sizeof(uint64_t)) {
+ // NdnlpSequence element has incorrect length
+ return std::make_tuple(false, NdnlpData());
+ }
+ parsed.seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
+
+ const Block& payloadElement = elements.back();
+ if (payloadElement.type() != tlv::NdnlpPayload) {
+ // NdnlpPayload element is missing
+ return std::make_tuple(false, NdnlpData());
+ }
+ parsed.payload = payloadElement;
+
+ if (elements.size() == 2) { // single wire packet
+ parsed.fragIndex = 0;
+ parsed.fragCount = 1;
+ return std::make_tuple(true, parsed);
+ }
+ if (elements.size() != 4) {
+ // NdnlpData element has incorrect number of children
+ return std::make_tuple(false, NdnlpData());
+ }
+
+ const Block& fragIndexElement = elements.at(1);
+ if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
+ // NdnlpFragIndex element is missing
+ return std::make_tuple(false, NdnlpData());
+ }
+ uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
+ if (fragIndex > std::numeric_limits<uint16_t>::max()) {
+ // NdnlpFragIndex is too large
+ return std::make_tuple(false, NdnlpData());
+ }
+ parsed.fragIndex = static_cast<uint16_t>(fragIndex);
+
+ const Block& fragCountElement = elements.at(2);
+ if (fragCountElement.type() != tlv::NdnlpFragCount) {
+ // NdnlpFragCount element is missing
+ return std::make_tuple(false, NdnlpData());
+ }
+ uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
+ if (fragCount > std::numeric_limits<uint16_t>::max()) {
+ // NdnlpFragCount is too large
+ return std::make_tuple(false, NdnlpData());
+ }
+ parsed.fragCount = static_cast<uint16_t>(fragCount);
+
+ if (parsed.fragIndex >= parsed.fragCount) {
+ // NdnlpFragIndex must be less than NdnlpFragCount
+ return std::make_tuple(false, NdnlpData());
+ }
+
+ return std::make_tuple(true, parsed);
+}
+
+} // namespace ndnlp
+} // namespace nfd
diff --git a/daemon/face/ndnlp-parse.hpp b/daemon/face/ndnlp-data.hpp
similarity index 67%
rename from daemon/face/ndnlp-parse.hpp
rename to daemon/face/ndnlp-data.hpp
index f40c910..fd921e2 100644
--- a/daemon/face/ndnlp-parse.hpp
+++ b/daemon/face/ndnlp-data.hpp
@@ -1,11 +1,12 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014 Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,7 +21,7 @@
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- **/
+ */
#ifndef NFD_DAEMON_FACE_NDNLP_PARSE_HPP
#define NFD_DAEMON_FACE_NDNLP_PARSE_HPP
@@ -31,14 +32,6 @@
namespace nfd {
namespace ndnlp {
-struct ParseError : public std::runtime_error
-{
- ParseError(const std::string& what)
- : std::runtime_error(what)
- {
- }
-};
-
/** \brief represents a NdnlpData packet
*
* NdnlpData ::= NDNLP-DATA-TYPE TLV-LENGTH
@@ -51,17 +44,16 @@
{
public:
/** \brief parse a NdnlpData packet
- *
- * \exception ParseError packet is malformated
+ * \return whether \p wire has a valid NdnlpData packet, and the parsed packet
*/
- void
- wireDecode(const Block& wire);
+ static std::tuple<bool, NdnlpData>
+ fromBlock(const Block& wire);
public:
- uint64_t m_seq;
- uint16_t m_fragIndex;
- uint16_t m_fragCount;
- Block m_payload;
+ uint64_t seq;
+ uint16_t fragIndex;
+ uint16_t fragCount;
+ Block payload;
};
} // namespace ndnlp
diff --git a/daemon/face/ndnlp-parse.cpp b/daemon/face/ndnlp-parse.cpp
deleted file mode 100644
index 21d959f..0000000
--- a/daemon/face/ndnlp-parse.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014 Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "ndnlp-parse.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-void
-NdnlpData::wireDecode(const Block& wire)
-{
- if (wire.type() != tlv::NdnlpData) {
- throw ParseError("top element is not NdnlpData");
- }
- wire.parse();
- const Block::element_container& elements = wire.elements();
- 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");
- }
- if (sequenceElement.value_size() != sizeof(uint64_t)) {
- 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");
- }
- m_payload = payloadElement;
-
- if (elements.size() == 2) { // single wire packet
- m_fragIndex = 0;
- m_fragCount = 1;
- return;
- }
- 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");
- }
- uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
- if (fragIndex > std::numeric_limits<uint16_t>::max()) {
- throw ParseError("NdnlpFragIndex is too large");
- }
- m_fragIndex = static_cast<uint16_t>(fragIndex);
-
- const Block& fragCountElement = elements.at(2);
- if (fragCountElement.type() != tlv::NdnlpFragCount) {
- throw ParseError("NdnlpFragCount element is missing");
- }
- uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
- if (fragCount > std::numeric_limits<uint16_t>::max()) {
- throw ParseError("NdnlpFragCount is too large");
- }
- m_fragCount = static_cast<uint16_t>(fragCount);
-
- if (m_fragIndex >= m_fragCount) {
- throw ParseError("NdnlpFragIndex must be less than NdnlpFragCount");
- }
-}
-
-} // namespace ndnlp
-} // namespace nfd
diff --git a/daemon/face/ndnlp-partial-message-store.cpp b/daemon/face/ndnlp-partial-message-store.cpp
index fafeaf0..082f678 100644
--- a/daemon/face/ndnlp-partial-message-store.cpp
+++ b/daemon/face/ndnlp-partial-message-store.cpp
@@ -24,10 +24,13 @@
*/
#include "ndnlp-partial-message-store.hpp"
+#include "core/logger.hpp"
namespace nfd {
namespace ndnlp {
+NFD_LOG_INIT("NdnlpPartialMessageStore");
+
PartialMessage::PartialMessage()
: m_fragCount(0)
, m_received(0)
@@ -63,21 +66,32 @@
return m_received == m_fragCount;
}
-Block
+std::tuple<bool, Block>
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();
- it != m_payloads.end(); ++it) {
- const Block& payload = *it;
- memcpy(buf, payload.value(), payload.value_size());
- buf += payload.value_size();
+ ndn::Buffer::iterator buf = buffer->begin();
+ for (const Block& payload : m_payloads) {
+ buf = std::copy(payload.value_begin(), payload.value_end(), buf);
}
+ BOOST_ASSERT(buf == buffer->end());
- return Block(buffer);
+ Block reassembled;
+ bool isBlockOk = Block::fromBuffer(buffer, 0, reassembled);
+ return std::make_tuple(isBlockOk, reassembled);
+}
+
+std::tuple<bool, Block>
+PartialMessage::reassembleSingle(const NdnlpData& fragment)
+{
+ BOOST_ASSERT(fragment.fragCount == 1);
+
+ Block reassembled;
+ bool isBlockOk = Block::fromBuffer(fragment.payload.value(), fragment.payload.value_size(),
+ reassembled);
+ return std::make_tuple(isBlockOk, reassembled);
}
PartialMessageStore::PartialMessageStore(const time::nanoseconds& idleDuration)
@@ -85,28 +99,38 @@
{
}
-PartialMessageStore::~PartialMessageStore()
-{
-}
-
void
-PartialMessageStore::receiveNdnlpData(const Block& pkt)
+PartialMessageStore::receive(const NdnlpData& pkt)
{
- NdnlpData parsed;
- parsed.wireDecode(pkt);
- if (parsed.m_fragCount == 1) { // single fragment
- this->onReceive(parsed.m_payload.blockFromValue());
+ bool isReassembled = false;
+ Block reassembled;
+ if (pkt.fragCount == 1) { // single fragment
+ std::tie(isReassembled, reassembled) = PartialMessage::reassembleSingle(pkt);
+ if (!isReassembled) {
+ NFD_LOG_TRACE(pkt.seq << " reassemble error");
+ return;
+ }
+
+ NFD_LOG_TRACE(pkt.seq << " deliver");
+ this->onReceive(reassembled);
return;
}
- uint64_t messageIdentifier = parsed.m_seq - parsed.m_fragIndex;
+ uint64_t messageIdentifier = pkt.seq - pkt.fragIndex;
PartialMessage& pm = m_partialMessages[messageIdentifier];
this->scheduleCleanup(messageIdentifier, pm);
- pm.add(parsed.m_fragIndex, parsed.m_fragCount, parsed.m_payload);
+ pm.add(pkt.fragIndex, pkt.fragCount, pkt.payload);
if (pm.isComplete()) {
- this->onReceive(pm.reassemble());
- this->cleanup(messageIdentifier);
+ std::tie(isReassembled, reassembled) = pm.reassemble();
+ if (!isReassembled) {
+ NFD_LOG_TRACE(messageIdentifier << " reassemble error");
+ return;
+ }
+
+ NFD_LOG_TRACE(messageIdentifier << " deliver");
+ this->onReceive(reassembled);
+ m_partialMessages.erase(messageIdentifier);
}
}
@@ -121,6 +145,7 @@
void
PartialMessageStore::cleanup(uint64_t messageIdentifier)
{
+ NFD_LOG_TRACE(messageIdentifier << " cleanup");
m_partialMessages.erase(messageIdentifier);
}
diff --git a/daemon/face/ndnlp-partial-message-store.hpp b/daemon/face/ndnlp-partial-message-store.hpp
index 6fbf0f7..25afcd8 100644
--- a/daemon/face/ndnlp-partial-message-store.hpp
+++ b/daemon/face/ndnlp-partial-message-store.hpp
@@ -26,7 +26,7 @@
#ifndef NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
#define NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
-#include "ndnlp-parse.hpp"
+#include "ndnlp-data.hpp"
#include "core/scheduler.hpp"
namespace nfd {
@@ -56,15 +56,19 @@
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
+ * \pre isComplete() == true
+ * \return whether success, network layer packet
*/
- Block
+ std::tuple<bool, Block>
reassemble();
+ /** \brief reassemble network layer packet from a single fragment
+ * \pre fragment.fragCount == 1
+ * \return whether success, network layer packet
+ */
+ static std::tuple<bool, Block>
+ reassembleSingle(const NdnlpData& fragment);
+
public:
scheduler::ScopedEventId expiry;
@@ -83,16 +87,12 @@
explicit
PartialMessageStore(const time::nanoseconds& 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
+ * Reassembly errors will be ignored.
*/
void
- receiveNdnlpData(const Block& pkt);
+ receive(const NdnlpData& pkt);
/** \brief fires when network layer packet is received
*/