fw: Nack in multicast strategy

refs: #3176

Change-Id: I1ef43c277a6a251170b652bf77d5516912a5d630
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index cbf409c..d053482 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,14 +25,18 @@
 
 #include "multicast-strategy.hpp"
 #include "algorithm.hpp"
+#include "core/logger.hpp"
 
 namespace nfd {
 namespace fw {
 
 NFD_REGISTER_STRATEGY(MulticastStrategy);
 
+NFD_LOG_INIT("MulticastStrategy");
+
 MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
   : Strategy(forwarder)
+  , ProcessNackTraits(this)
 {
   ParsedInstanceName parsed = parseInstanceName(name);
   if (!parsed.parameters.empty()) {
@@ -56,21 +60,44 @@
 MulticastStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
                                         const shared_ptr<pit::Entry>& pitEntry)
 {
+  if (hasPendingOutRecords(*pitEntry)) {
+    // not a new Interest, don't forward
+    return;
+  }
+
   const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
   const fib::NextHopList& nexthops = fibEntry.getNextHops();
 
-  for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
-    Face& outFace = it->getFace();
-    if (!wouldViolateScope(inFace, interest, outFace) &&
-        canForwardToLegacy(*pitEntry, outFace)) {
+  int nEligibleNextHops = 0;
+
+  for (const auto& nexthop : nexthops) {
+    Face& outFace = nexthop.getFace();
+
+    if (&outFace != &inFace && !wouldViolateScope(inFace, interest, outFace)) {
       this->sendInterest(pitEntry, outFace, interest);
+      NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
+                             << " pitEntry-to=" << outFace.getId());
+      ++nEligibleNextHops;
     }
   }
 
-  if (!hasPendingOutRecords(*pitEntry)) {
-    this->rejectPendingInterest(pitEntry);
+  if (nEligibleNextHops == 0) {
+      NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
+
+      lp::NackHeader nackHeader;
+      nackHeader.setReason(lp::NackReason::NO_ROUTE);
+      this->sendNack(pitEntry, inFace, nackHeader);
+
+      this->rejectPendingInterest(pitEntry);
   }
 }
 
+void
+MulticastStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
+                                    const shared_ptr<pit::Entry>& pitEntry)
+{
+  this->processNack(inFace, nack, pitEntry);
+}
+
 } // namespace fw
 } // namespace nfd
diff --git a/daemon/fw/multicast-strategy.hpp b/daemon/fw/multicast-strategy.hpp
index e656e45..7e77d72 100644
--- a/daemon/fw/multicast-strategy.hpp
+++ b/daemon/fw/multicast-strategy.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,7 @@
 #define NFD_DAEMON_FW_MULTICAST_STRATEGY_HPP
 
 #include "strategy.hpp"
+#include "process-nack-traits.hpp"
 
 namespace nfd {
 namespace fw {
@@ -34,16 +35,25 @@
 /** \brief a forwarding strategy that forwards Interest to all FIB nexthops
  */
 class MulticastStrategy : public Strategy
+                        , public ProcessNackTraits<MulticastStrategy>
 {
 public:
+  explicit
   MulticastStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
 
   static const Name&
   getStrategyName();
 
-  virtual void
+  void
   afterReceiveInterest(const Face& inFace, const Interest& interest,
                        const shared_ptr<pit::Entry>& pitEntry) override;
+
+  void
+  afterReceiveNack(const Face& inFace, const lp::Nack& nack,
+                   const shared_ptr<pit::Entry>& pitEntry) override;
+
+private:
+  friend ProcessNackTraits<MulticastStrategy>;
 };
 
 } // namespace fw