fw: Adaptive SRTT-based Forwarding strategy

refs: #3566

Change-Id: Idae198bb0c2ae25e25aeceec0552b1c11be89c14
diff --git a/daemon/fw/asf-measurements.hpp b/daemon/fw/asf-measurements.hpp
new file mode 100644
index 0000000..8339d97
--- /dev/null
+++ b/daemon/fw/asf-measurements.hpp
@@ -0,0 +1,311 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
+#define NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
+
+#include "fw/rtt-estimator.hpp"
+#include "fw/strategy-info.hpp"
+#include "table/measurements-accessor.hpp"
+
+namespace nfd {
+namespace fw {
+namespace asf {
+
+class RttStats
+{
+public:
+  typedef time::duration<double, boost::micro> Rtt;
+
+  RttStats();
+
+  void
+  addRttMeasurement(RttEstimator::Duration& durationRtt);
+
+  void
+  recordTimeout()
+  {
+    m_rtt = RTT_TIMEOUT;
+  }
+
+  Rtt
+  getRtt() const
+  {
+    return m_rtt;
+  }
+
+  Rtt
+  getSrtt() const
+  {
+    return m_srtt;
+  }
+
+  RttEstimator::Duration
+  computeRto() const
+  {
+    return m_rttEstimator.computeRto();
+  }
+
+private:
+  static Rtt
+  computeSrtt(Rtt previousSrtt, Rtt currentRtt);
+
+public:
+  static const Rtt RTT_TIMEOUT;
+  static const Rtt RTT_NO_MEASUREMENT;
+
+private:
+  Rtt m_srtt;
+  Rtt m_rtt;
+  RttEstimator m_rttEstimator;
+
+  static const double ALPHA;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/** \brief Strategy information for each face in a namespace
+*/
+class FaceInfo
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  FaceInfo();
+
+  ~FaceInfo();
+
+  void
+  setTimeoutEvent(const scheduler::EventId& id, const ndn::Name& interestName);
+
+  void
+  setMeasurementExpirationEventId(const scheduler::EventId& id)
+  {
+    m_measurementExpirationId = id;
+  }
+
+  const scheduler::EventId&
+  getMeasurementExpirationEventId()
+  {
+    return m_measurementExpirationId;
+  }
+
+  void
+  cancelTimeoutEvent(const ndn::Name& prefix);
+
+  bool
+  isTimeoutScheduled() const
+  {
+    return m_isTimeoutScheduled;
+  }
+
+  void
+  recordRtt(const shared_ptr<pit::Entry> pitEntry, const Face& inFace);
+
+  void
+  recordTimeout(const ndn::Name& interestName);
+
+  bool
+  isTimeout() const
+  {
+    return getRtt() == RttStats::RTT_TIMEOUT;
+  }
+
+  RttEstimator::Duration
+  computeRto() const
+  {
+    return m_rttStats.computeRto();
+  }
+
+  RttStats::Rtt
+  getRtt() const
+  {
+    return m_rttStats.getRtt();
+  }
+
+  RttStats::Rtt
+  getSrtt() const
+  {
+    return m_rttStats.getSrtt();
+  }
+
+  bool
+  hasSrttMeasurement() const
+  {
+    return getSrtt() != RttStats::RTT_NO_MEASUREMENT;
+  }
+
+private:
+  void
+  cancelTimeoutEvent();
+
+  bool
+  doesNameMatchLastInterest(const ndn::Name& name);
+
+private:
+  RttStats m_rttStats;
+  ndn::Name m_lastInterestName;
+
+  // Timeout associated with measurement
+  scheduler::EventId m_measurementExpirationId;
+
+  // RTO associated with Interest
+  scheduler::EventId m_timeoutEventId;
+  bool m_isTimeoutScheduled;
+};
+
+typedef std::unordered_map<face::FaceId, FaceInfo> FaceInfoTable;
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/** \brief stores stategy information about each face in this namespace
+ */
+class NamespaceInfo : public StrategyInfo
+{
+public:
+  NamespaceInfo();
+
+  static constexpr int
+  getTypeId()
+  {
+    return 1030;
+  }
+
+  FaceInfo&
+  getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face);
+
+  FaceInfo*
+  getFaceInfo(const fib::Entry& fibEntry, const Face& face);
+
+  void
+  expireFaceInfo(nfd::face::FaceId faceId);
+
+  void
+  extendFaceInfoLifetime(FaceInfo& info, const Face& face);
+
+  FaceInfo&
+  get(nfd::face::FaceId faceId)
+  {
+    return m_fit.at(faceId);
+  }
+
+  FaceInfoTable::iterator
+  find(nfd::face::FaceId faceId)
+  {
+    return m_fit.find(faceId);
+  }
+
+  FaceInfoTable::iterator
+  end()
+  {
+    return m_fit.end();
+  }
+
+  const FaceInfoTable::iterator
+  insert(nfd::face::FaceId faceId)
+  {
+    const auto& pair = m_fit.insert(std::make_pair(faceId, FaceInfo()));
+    return pair.first;
+  }
+
+  bool
+  isProbingDue() const
+  {
+    return m_isProbingDue;
+  }
+
+  void
+  setIsProbingDue(bool isProbingDue)
+  {
+    m_isProbingDue = isProbingDue;
+  }
+
+  bool
+  isFirstProbeScheduled() const
+  {
+    return m_hasFirstProbeBeenScheduled;
+  }
+
+  void
+  setHasFirstProbeBeenScheduled(bool hasBeenScheduled)
+  {
+    m_hasFirstProbeBeenScheduled = hasBeenScheduled;
+  }
+
+private:
+  FaceInfoTable m_fit;
+
+  bool m_isProbingDue;
+  bool m_hasFirstProbeBeenScheduled;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/** \brief Helper class to retrieve and create strategy measurements
+ */
+class AsfMeasurements : noncopyable
+{
+public:
+  explicit
+  AsfMeasurements(MeasurementsAccessor& measurements);
+
+  FaceInfo*
+  getFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face);
+
+  FaceInfo&
+  getOrCreateFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face);
+
+  shared_ptr<NamespaceInfo>
+  getNamespaceInfo(const ndn::Name& prefix);
+
+  NamespaceInfo&
+  getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest);
+
+  void
+  extendLifetime(shared_ptr<measurements::Entry> me);
+
+public:
+  static constexpr time::microseconds MEASUREMENTS_LIFETIME = time::seconds(300);
+
+private:
+  MeasurementsAccessor& m_measurements;
+};
+
+} // namespace asf
+} // namespace fw
+} // namespace nfd
+
+#endif // NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP