face: GenericLinkService encoding/decoding
refs #3104
Change-Id: I26e83cd1dd5dc87ebdc040105ab1bad4afdba5f7
diff --git a/daemon/face/generic-link-service.cpp b/daemon/face/generic-link-service.cpp
index 79010e6..4fa4c1c 100644
--- a/daemon/face/generic-link-service.cpp
+++ b/daemon/face/generic-link-service.cpp
@@ -30,10 +30,23 @@
NFD_LOG_INIT("GenericLinkService");
+GenericLinkService::Options::Options()
+ : allowLocalFields(false)
+{
+}
+
+GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
+ : m_options(options)
+{
+}
+
void
GenericLinkService::doSendInterest(const Interest& interest)
{
lp::Packet lpPacket(interest.wireEncode());
+ if (m_options.allowLocalFields) {
+ encodeLocalFields(interest, lpPacket);
+ }
Transport::Packet packet;
packet.packet = lpPacket.wireEncode();
sendPacket(std::move(packet));
@@ -43,6 +56,9 @@
GenericLinkService::doSendData(const Data& data)
{
lp::Packet lpPacket(data.wireEncode());
+ if (m_options.allowLocalFields) {
+ encodeLocalFields(data, lpPacket);
+ }
Transport::Packet packet;
packet.packet = lpPacket.wireEncode();
sendPacket(std::move(packet));
@@ -53,40 +69,188 @@
{
lp::Packet lpPacket(nack.getInterest().wireEncode());
lpPacket.add<lp::NackField>(nack.getHeader());
+ if (m_options.allowLocalFields) {
+ encodeLocalFields(nack.getInterest(), lpPacket);
+ }
Transport::Packet packet;
packet.packet = lpPacket.wireEncode();
sendPacket(std::move(packet));
}
+bool
+GenericLinkService::encodeLocalFields(const Interest& interest, lp::Packet& lpPacket)
+{
+ if (interest.getLocalControlHeader().hasIncomingFaceId()) {
+ lpPacket.add<lp::IncomingFaceIdField>(interest.getIncomingFaceId());
+ }
+
+ if (interest.getLocalControlHeader().hasCachingPolicy()) {
+ // Packet must be dropped
+ return false;
+ }
+
+ return true;
+}
+
+bool
+GenericLinkService::encodeLocalFields(const Data& data, lp::Packet& lpPacket)
+{
+ if (data.getLocalControlHeader().hasIncomingFaceId()) {
+ lpPacket.add<lp::IncomingFaceIdField>(data.getIncomingFaceId());
+ }
+
+ if (data.getLocalControlHeader().hasCachingPolicy()) {
+ switch (data.getCachingPolicy()) {
+ case ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE: {
+ lp::CachePolicy cachePolicy;
+ cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
+ lpPacket.add<lp::CachePolicyField>(cachePolicy);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
void
GenericLinkService::doReceivePacket(Transport::Packet&& packet)
{
- lp::Packet lpPacket(packet.packet);
- ndn::Buffer::const_iterator fragBegin, fragEnd;
- std::tie(fragBegin, fragEnd) = lpPacket.get<lp::FragmentField>();
- Block netPacket(&*fragBegin, std::distance(fragBegin, fragEnd));
+ lp::Packet pkt(packet.packet);
- // Forwarding expects Interest and Data to be created with make_shared,
- // but has no such requirement on Nack.
- switch (netPacket.type()) {
- case tlv::Interest: {
- auto interest = make_shared<Interest>(netPacket);
- if (lpPacket.has<lp::NackField>()) {
- lp::Nack nack(std::move(*interest));
- nack.setHeader(lpPacket.get<lp::NackField>());
- receiveNack(nack);
- }
- else {
- receiveInterest(*interest);
- }
- break;
- }
- case tlv::Data: {
- auto data = make_shared<Data>(netPacket);
- receiveData(*data);
- break;
+ if (pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) {
+ NFD_LOG_FACE_WARN("received fragment, but reassembly not implemented: DROP");
+ return;
+ }
+
+ try {
+ ndn::Buffer::const_iterator fragBegin, fragEnd;
+ std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
+ Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
+
+ switch (netPkt.type()) {
+ case tlv::Interest:
+ if (pkt.has<lp::NackField>()) {
+ this->decodeNack(netPkt, pkt);
+ }
+ else {
+ this->decodeInterest(netPkt, pkt);
+ }
+ break;
+ case tlv::Data:
+ this->decodeData(netPkt, pkt);
+ break;
+ default:
+ NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
+ return;
}
}
+ catch (const tlv::Error& e) {
+ NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
+ }
+}
+
+
+void
+GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
+{
+ BOOST_ASSERT(netPkt.type() == tlv::Interest);
+ BOOST_ASSERT(!firstPkt.has<lp::NackField>());
+
+ // forwarding expects Interest to be created with make_shared
+ auto interest = make_shared<Interest>(netPkt);
+
+ if (firstPkt.has<lp::NextHopFaceIdField>()) {
+ if (m_options.allowLocalFields) {
+ interest->setNextHopFaceId(firstPkt.get<lp::NextHopFaceIdField>());
+ }
+ else {
+ NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
+ return;
+ }
+ }
+
+ if (firstPkt.has<lp::CachePolicyField>()) {
+ NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
+ return;
+ }
+
+ if (firstPkt.has<lp::IncomingFaceIdField>()) {
+ NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
+ }
+
+ this->receiveInterest(*interest);
+}
+
+void
+GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
+{
+ BOOST_ASSERT(netPkt.type() == tlv::Data);
+
+ // forwarding expects Data to be created with make_shared
+ auto data = make_shared<Data>(netPkt);
+
+ if (firstPkt.has<lp::NackField>()) {
+ NFD_LOG_FACE_WARN("received Nack with Data: DROP");
+ return;
+ }
+
+ if (firstPkt.has<lp::NextHopFaceIdField>()) {
+ NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
+ return;
+ }
+
+ if (firstPkt.has<lp::CachePolicyField>()) {
+ if (m_options.allowLocalFields) {
+ lp::CachePolicyType policy = firstPkt.get<lp::CachePolicyField>().getPolicy();
+ switch (policy) {
+ case lp::CachePolicyType::NO_CACHE:
+ data->setCachingPolicy(ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE);
+ break;
+ default:
+ NFD_LOG_FACE_WARN("unrecognized CachePolicyType " << policy << ": DROP");
+ return;
+ }
+ }
+ else {
+ NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
+ }
+ }
+
+ if (firstPkt.has<lp::IncomingFaceIdField>()) {
+ NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
+ }
+
+ this->receiveData(*data);
+}
+
+void
+GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
+{
+ BOOST_ASSERT(netPkt.type() == tlv::Interest);
+ BOOST_ASSERT(firstPkt.has<lp::NackField>());
+
+ lp::Nack nack((Interest(netPkt)));
+ nack.setHeader(firstPkt.get<lp::NackField>());
+
+ if (firstPkt.has<lp::NextHopFaceIdField>()) {
+ NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
+ return;
+ }
+
+ if (firstPkt.has<lp::CachePolicyField>()) {
+ NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
+ return;
+ }
+
+ if (firstPkt.has<lp::IncomingFaceIdField>()) {
+ NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
+ }
+
+ this->receiveNack(nack);
}
} // namespace face
diff --git a/daemon/face/generic-link-service.hpp b/daemon/face/generic-link-service.hpp
index 8d91f88..ae3328f 100644
--- a/daemon/face/generic-link-service.hpp
+++ b/daemon/face/generic-link-service.hpp
@@ -36,10 +36,40 @@
namespace nfd {
namespace face {
-/** \brief generic LinkService
+/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
+ * \sa http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class GenericLinkService : public LinkService
{
+public:
+ /** \brief Options that control the behavior of GenericLinkService
+ */
+ class Options
+ {
+ public:
+ Options();
+
+ public:
+ // TODO #3171: fragmentation and reassembly options
+
+ /** \brief enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy
+ */
+ bool allowLocalFields;
+ };
+
+ explicit
+ GenericLinkService(const Options& options = Options());
+
+ /** \brief get Options used by GenericLinkService
+ */
+ const Options&
+ getOptions() const;
+
+ /** \brief sets Options used by GenericLinkService
+ */
+ void
+ setOptions(const Options& options);
+
private: // send path entrypoint
/** \brief sends Interest
*/
@@ -62,9 +92,71 @@
*/
void
doReceivePacket(Transport::Packet&& packet) DECL_OVERRIDE;
+
+private: // encoding and decoding
+ /** \brief encode IncomingFaceId into LpPacket and verify local fields
+ */
+ static bool
+ encodeLocalFields(const Interest& interest, lp::Packet& lpPacket);
+
+ /** \brief encode CachingPolicy and IncomingFaceId into LpPacket and verify local fields
+ */
+ static bool
+ encodeLocalFields(const Data& data, lp::Packet& lpPacket);
+
+ /** \brief decode incoming Interest
+ * \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
+ * \param firstPkt LpPacket of first fragment; must not have Nack field
+ *
+ * If decoding is successful, receiveInterest signal is emitted;
+ * otherwise, a warning is logged.
+ *
+ * \throw tlv::Error parse error in an LpHeader field
+ */
+ void
+ decodeInterest(const Block& netPkt, const lp::Packet& firstPkt);
+
+ /** \brief decode incoming Interest
+ * \param netPkt reassembled network-layer packet; TLV-TYPE must be Data
+ * \param firstPkt LpPacket of first fragment
+ *
+ * If decoding is successful, receiveData signal is emitted;
+ * otherwise, a warning is logged.
+ *
+ * \throw tlv::Error parse error in an LpHeader field
+ */
+ void
+ decodeData(const Block& netPkt, const lp::Packet& firstPkt);
+
+ /** \brief decode incoming Interest
+ * \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
+ * \param firstPkt LpPacket of first fragment; must have Nack field
+ *
+ * If decoding is successful, receiveNack signal is emitted;
+ * otherwise, a warning is logged.
+ *
+ * \throw tlv::Error parse error in an LpHeader field
+ */
+ void
+ decodeNack(const Block& netPkt, const lp::Packet& firstPkt);
+
+private:
+ Options m_options;
};
+inline const GenericLinkService::Options&
+GenericLinkService::getOptions() const
+{
+ return m_options;
+}
+
+inline void
+GenericLinkService::setOptions(const GenericLinkService::Options& options)
+{
+ m_options = options;
+}
+
} // namespace face
} // namespace nfd
-#endif // NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
\ No newline at end of file
+#endif // NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP