ndnping: recognize and trace Nack

Change-Id: If47877892c75ae0849375f36430a66e02fb7a608
refs: #3335
diff --git a/tools/ping/client/ping.cpp b/tools/ping/client/ping.cpp
index b60be65..966d29e 100644
--- a/tools/ping/client/ping.cpp
+++ b/tools/ping/client/ping.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Arizona Board of Regents.
+ * Copyright (c) 2014-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -18,6 +18,7 @@
  *
  * @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
  * @author: Eric Newberry <enewberry@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #include "ping.hpp"
@@ -63,8 +64,10 @@
   interest.setMustBeFresh(!m_options.shouldAllowStaleData);
   interest.setInterestLifetime(m_options.timeout);
 
+  auto now = time::steady_clock::now();
   m_face.expressInterest(interest,
-                         bind(&Ping::onData, this, _1, _2, m_nextSeq, time::steady_clock::now()),
+                         bind(&Ping::onData, this, _1, _2, m_nextSeq, now),
+                         bind(&Ping::onNack, this, _1, _2, m_nextSeq, now),
                          bind(&Ping::onTimeout, this, _1, m_nextSeq));
 
   ++m_nSent;
@@ -80,11 +83,27 @@
 }
 
 void
-Ping::onData(const Interest& interest, Data& data, uint64_t seq, const time::steady_clock::TimePoint& sendTime)
+Ping::onData(const Interest& interest,
+             const Data& data,
+             uint64_t seq,
+             const time::steady_clock::TimePoint& sendTime)
 {
   time::nanoseconds rtt = time::steady_clock::now() - sendTime;
 
-  afterResponse(seq, rtt);
+  afterData(seq, rtt);
+
+  finish();
+}
+
+void
+Ping::onNack(const Interest& interest,
+             const lp::Nack& nack,
+             uint64_t seq,
+             const time::steady_clock::TimePoint& sendTime)
+{
+  time::nanoseconds rtt = time::steady_clock::now() - sendTime;
+
+  afterNack(seq, rtt, nack.getHeader());
 
   finish();
 }
diff --git a/tools/ping/client/ping.hpp b/tools/ping/client/ping.hpp
index 49ac492..ce4119d 100644
--- a/tools/ping/client/ping.hpp
+++ b/tools/ping/client/ping.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2015,  Arizona Board of Regents.
+ * Copyright (c) 2015-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -18,6 +18,7 @@
  *
  * @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
  * @author: Eric Newberry <enewberry@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #ifndef NDN_TOOLS_PING_CLIENT_PING_HPP
@@ -56,12 +57,21 @@
   Ping(Face& face, const Options& options);
 
   /**
-   * @brief Signals on the successful return of a packet
+   * @brief Signals on the successful return of a Data packet
    *
    * @param seq ping sequence number
    * @param rtt round trip time
    */
-  signal::Signal<Ping, uint64_t, Rtt> afterResponse;
+  signal::Signal<Ping, uint64_t, Rtt> afterData;
+
+  /**
+   * @brief Signals on the return of a Nack
+   *
+   * @param seq ping sequence number
+   * @param rtt round trip time
+   * @param header the received Network NACK header
+   */
+  signal::Signal<Ping, uint64_t, Rtt, lp::NackHeader> afterNack;
 
   /**
    * @brief Signals on timeout of a packet
@@ -109,7 +119,7 @@
   performPing();
 
   /**
-   * @brief Called when ping returned successfully
+   * @brief Called when a Data packet is received in response to a ping
    *
    * @param interest NDN interest
    * @param data returned data
@@ -117,7 +127,24 @@
    * @param sendTime time ping sent
    */
   void
-  onData(const Interest& interest, Data& data, uint64_t seq, const time::steady_clock::TimePoint& sendTime);
+  onData(const Interest& interest,
+         const Data& data,
+         uint64_t seq,
+         const time::steady_clock::TimePoint& sendTime);
+
+  /**
+   * @brief Called when a Nack is received in response to a ping
+   *
+   * @param interest NDN interest
+   * @param nack returned nack
+   * @param seq ping sequence number
+   * @param sendTime time ping sent
+   */
+  void
+  onNack(const Interest& interest,
+         const lp::Nack& nack,
+         uint64_t seq,
+         const time::steady_clock::TimePoint& sendTime);
 
   /**
    * @brief Called when ping timed out
diff --git a/tools/ping/client/statistics-collector.cpp b/tools/ping/client/statistics-collector.cpp
index bc1956e..0e7ad2a 100644
--- a/tools/ping/client/statistics-collector.cpp
+++ b/tools/ping/client/statistics-collector.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2015,  Arizona Board of Regents.
+ * Copyright (c) 2015-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -18,6 +18,7 @@
  *
  * @author: Eric Newberry <enewberry@email.arizona.edu>
  * @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #include "statistics-collector.hpp"
@@ -31,18 +32,20 @@
   , m_options(options)
   , m_nSent(0)
   , m_nReceived(0)
+  , m_nNacked(0)
   , m_pingStartTime(time::steady_clock::now())
   , m_minRtt(std::numeric_limits<double>::max())
   , m_maxRtt(0.0)
   , m_sumRtt(0.0)
   , m_sumRttSquared(0.0)
 {
-  m_ping.afterResponse.connect(bind(&StatisticsCollector::recordResponse, this, _2));
+  m_ping.afterData.connect(bind(&StatisticsCollector::recordData, this, _2));
+  m_ping.afterNack.connect(bind(&StatisticsCollector::recordNack, this));
   m_ping.afterTimeout.connect(bind(&StatisticsCollector::recordTimeout, this));
 }
 
 void
-StatisticsCollector::recordResponse(Rtt rtt)
+StatisticsCollector::recordData(Rtt rtt)
 {
   m_nSent++;
   m_nReceived++;
@@ -58,6 +61,13 @@
 }
 
 void
+StatisticsCollector::recordNack()
+{
+  m_nSent++;
+  m_nNacked++;
+}
+
+void
 StatisticsCollector::recordTimeout()
 {
   m_nSent++;
@@ -71,10 +81,12 @@
   statistics.prefix = m_options.prefix;
   statistics.nSent = m_nSent;
   statistics.nReceived = m_nReceived;
+  statistics.nNacked = m_nNacked;
   statistics.pingStartTime = m_pingStartTime;
   statistics.minRtt = m_minRtt;
   statistics.maxRtt = m_maxRtt;
-  statistics.packetLossRate = (double)(m_nSent - m_nReceived) / (double)m_nSent;
+  statistics.packetLossRate = static_cast<double>(m_nSent - m_nReceived - m_nNacked) / static_cast<double>(m_nSent);
+  statistics.packetNackedRate = static_cast<double>(m_nNacked) / static_cast<double>(m_nSent);
   statistics.sumRtt = m_sumRtt;
   statistics.avgRtt = m_sumRtt / m_nReceived;
   statistics.stdDevRtt = std::sqrt((m_sumRttSquared / m_nReceived) - (statistics.avgRtt * statistics.avgRtt));
@@ -99,7 +111,9 @@
   os << "--- " << statistics.prefix <<" ping statistics ---\n";
   os << statistics.nSent << " packets transmitted";
   os << ", " << statistics.nReceived << " received";
+  os << ", " << statistics.nNacked << " nacked";
   os << ", " << statistics.packetLossRate * 100.0 << "% packet loss";
+  os << ", " << statistics.packetNackedRate * 100.0 << "% nacked";
   os << ", time " << statistics.sumRtt << " ms";
   if (statistics.nReceived > 0) {
     os << "\n";
diff --git a/tools/ping/client/statistics-collector.hpp b/tools/ping/client/statistics-collector.hpp
index 2ced820..ee67f80 100644
--- a/tools/ping/client/statistics-collector.hpp
+++ b/tools/ping/client/statistics-collector.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2015,  Arizona Board of Regents.
+ * Copyright (c) 2015-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -18,6 +18,7 @@
  *
  * @author: Eric Newberry <enewberry@email.arizona.edu>
  * @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #ifndef NDN_TOOLS_PING_CLIENT_STATISTICS_COLLECTOR_HPP
@@ -39,10 +40,12 @@
   Name prefix;                                  //!< prefix pinged
   int nSent;                                    //!< number of pings sent
   int nReceived;                                //!< number of pings received
+  int nNacked;                                  //!< number of nacks received
   time::steady_clock::TimePoint pingStartTime;  //!< time pings started
   double minRtt;                                //!< minimum round trip time
   double maxRtt;                                //!< maximum round trip time
   double packetLossRate;                        //!< packet loss rate
+  double packetNackedRate;                      //!< packet nacked rate
   double sumRtt;                                //!< sum of round trip times
   double avgRtt;                                //!< average round trip time
   double stdDevRtt;                             //!< std dev of round trip time
@@ -71,12 +74,18 @@
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   /**
-   * @brief Called on ping response received
+   * @brief Called when a Data packet is received
    *
    * @param rtt round trip time
    */
   void
-  recordResponse(Rtt rtt);
+  recordData(Rtt rtt);
+
+  /**
+   * @brief Called when a Nack is received
+   */
+  void
+  recordNack();
 
   /**
    * @brief Called on ping timeout
@@ -89,6 +98,7 @@
   const Options& m_options;
   int m_nSent;
   int m_nReceived;
+  int m_nNacked;
   time::steady_clock::TimePoint m_pingStartTime;
   double m_minRtt;
   double m_maxRtt;
diff --git a/tools/ping/client/tracer.cpp b/tools/ping/client/tracer.cpp
index c521b20..9510af8 100644
--- a/tools/ping/client/tracer.cpp
+++ b/tools/ping/client/tracer.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2015,  Arizona Board of Regents.
+ * Copyright (c) 2015-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -17,6 +17,7 @@
  * ndn-tools, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
  * @author: Eric Newberry <enewberry@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #include "tracer.hpp"
@@ -28,12 +29,13 @@
 Tracer::Tracer(Ping& ping, const Options& options)
   : m_options(options)
 {
-  ping.afterResponse.connect(bind(&Tracer::onResponse, this, _1, _2));
+  ping.afterData.connect(bind(&Tracer::onData, this, _1, _2));
+  ping.afterNack.connect(bind(&Tracer::onNack, this, _1, _2, _3));
   ping.afterTimeout.connect(bind(&Tracer::onTimeout, this, _1));
 }
 
 void
-Tracer::onResponse(uint64_t seq, Rtt rtt)
+Tracer::onData(uint64_t seq, Rtt rtt)
 {
   if (m_options.shouldPrintTimestamp) {
     std::cout << time::toIsoString(time::system_clock::now()) << " - ";
@@ -44,6 +46,17 @@
 }
 
 void
+Tracer::onNack(uint64_t seq, Rtt rtt, const lp::NackHeader& header)
+{
+  if (m_options.shouldPrintTimestamp) {
+    std::cout << time::toIsoString(time::system_clock::now()) << " - ";
+  }
+
+  std::cout << "nack from " << m_options.prefix << ": seq=" << seq << " time="
+            << rtt.count() << " ms" << " reason=" << header.getReason() << std::endl;
+}
+
+void
 Tracer::onTimeout(uint64_t seq)
 {
   if (m_options.shouldPrintTimestamp) {
diff --git a/tools/ping/client/tracer.hpp b/tools/ping/client/tracer.hpp
index f62b9b8..ca75fb5 100644
--- a/tools/ping/client/tracer.hpp
+++ b/tools/ping/client/tracer.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2015,  Arizona Board of Regents.
+ * Copyright (c) 2015-2016,  Arizona Board of Regents.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -17,6 +17,7 @@
  * ndn-tools, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
  * @author: Eric Newberry <enewberry@email.arizona.edu>
+ * @author: Teng Liang <philoliang@email.arizona.edu>
  */
 
 #ifndef NDN_TOOLS_PING_CLIENT_TRACER_HPP
@@ -43,13 +44,23 @@
   Tracer(Ping& ping, const Options& options);
 
   /**
-   * @brief Prints ping results when response received
+   * @brief Prints ping results when a Data packet is received
    *
    * @param seq ping sequence number
    * @param rtt round trip time
    */
   void
-  onResponse(uint64_t seq, Rtt rtt);
+  onData(uint64_t seq, Rtt rtt);
+
+  /**
+   * @brief Prints NackReason when a Nack is received
+   *
+   * @param seq ping sequence number
+   * @param rtt round trip time
+   * @param header the header of Nack
+   */
+  void
+  onNack(uint64_t seq, Rtt rtt, const lp::NackHeader& header);
 
   /**
    * @brief Prints ping results when timed out