util: Asynchronous data validation in SegmentFetcher

Change-Id: I407d3c1de49c86a6b4a0174baae6ed2e8be5c554
Refs: #2734
diff --git a/src/util/segment-fetcher.hpp b/src/util/segment-fetcher.hpp
index fb8f6d7..0c2e908 100644
--- a/src/util/segment-fetcher.hpp
+++ b/src/util/segment-fetcher.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2015 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,8 +22,10 @@
 #ifndef NDN_UTIL_SEGMENT_FETCHER_HPP
 #define NDN_UTIL_SEGMENT_FETCHER_HPP
 
+#include "scheduler.hpp"
 #include "../common.hpp"
 #include "../face.hpp"
+#include "../security/validator.hpp"
 
 namespace ndn {
 
@@ -32,19 +34,6 @@
 namespace util {
 
 /**
- * @brief Functor to skip validation of individual packets by SegmentFetcher
- */
-class DontVerifySegment
-{
-public:
-  bool
-  operator()(const Data& data) const
-  {
-    return true;
-  }
-};
-
-/**
  * @brief Utility class to fetch latest version of the segmented data
  *
  * SegmentFetcher assumes that the data is named `/<prefix>/<version>/<segment>`,
@@ -82,38 +71,42 @@
  * - `INTEREST_TIMEOUT`: if any of the Interests times out
  * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have segment
  *   as a last component of the name (not counting implicit digest)
- * - `SEGMENT_VERIFICATION_FAIL`: if any retrieved segment fails user-provided validation
+ * - `SEGMENT_VALIDATION_FAIL`: if any retrieved segment fails user-provided validation
  *
- * In order to validate individual segments, an VerifySegment callback needs to be specified.
- * If the callback returns false, fetching process is aborted with SEGMENT_VERIFICATION_FAIL.
- * If data validation is not required, provided DontVerifySegment() functor can be used.
+ * In order to validate individual segments, a Validator instance needs to be specified.
+ * If the segment validation is successful, afterValidationSuccess callback is fired, otherwise
+ * afterValidationFailure callback.
  *
  * Examples:
  *
  *     void
- *     onComplete(const ConstBufferPtr& data)
+ *     afterFetchComplete(const ConstBufferPtr& data)
  *     {
  *       ...
  *     }
  *
  *     void
- *     onError(uint32_t errorCode, const std::string& errorMsg)
+ *     afterFetchError(uint32_t errorCode, const std::string& errorMsg)
  *     {
  *       ...
  *     }
  *
  *     ...
  *     SegmentFetcher::fetch(face, Interest("/data/prefix", time::seconds(1000)),
- *                           DontVerifySegment(),
- *                           bind(&onComplete, this, _1),
- *                           bind(&onError, this, _1, _2));
+ *                           validator,
+ *                           bind(&afterFetchComplete, this, _1),
+ *                           bind(&afterFetchError, this, _1, _2));
  *
  */
 class SegmentFetcher : noncopyable
 {
 public:
+  /**
+   * @brief Maximum number of times an interest will be reexpressed incase of NackCallback
+   */
+  static const uint32_t MAX_INTEREST_REEXPRESS;
+
   typedef function<void (const ConstBufferPtr& data)> CompleteCallback;
-  typedef function<bool (const Data& data)> VerifySegment;
   typedef function<void (uint32_t code, const std::string& msg)> ErrorCallback;
 
   /**
@@ -122,7 +115,8 @@
   enum ErrorCode {
     INTEREST_TIMEOUT = 1,
     DATA_HAS_NO_SEGMENT = 2,
-    SEGMENT_VERIFICATION_FAIL = 3
+    SEGMENT_VALIDATION_FAIL = 3,
+    NACK_ERROR = 4
   };
 
   /**
@@ -132,12 +126,36 @@
    * @param baseInterest  An Interest for the initial segment of requested data.
    *                      This interest may include custom InterestLifetime and selectors that
    *                      will propagate to all subsequent Interests.  The only exception is that
+   *                      the initial Interest will be forced to include "ChildSelector=rightmost" and
+   *                      "MustBeFresh=true" selectors, which will be turned off in subsequent
+   *                      Interests.
+   * @param validator     Reference to the Validator that should be used to validate data. Caller
+   *                      must ensure validator is valid until either completeCallback or errorCallback
+   *                      is invoked.
+   *
+   * @param completeCallback    Callback to be fired when all segments are fetched
+   * @param errorCallback       Callback to be fired when an error occurs (@see Errors)
+   */
+  static
+  void
+  fetch(Face& face,
+        const Interest& baseInterest,
+        Validator& validator,
+        const CompleteCallback& completeCallback,
+        const ErrorCallback& errorCallback);
+
+  /**
+   * @brief Initiate segment fetching
+   *
+   * @param face          Reference to the Face that should be used to fetch data
+   * @param baseInterest  An Interest for the initial segment of requested data.
+   *                      This interest may include custom InterestLifetime and selectors that
+   *                      will propagate to all subsequent Interests.  The only exception is that
    *                      the initial Interest will be forced to include "ChildSelector=1" and
    *                      "MustBeFresh=true" selectors, which will be turned off in subsequent
    *                      Interests.
-   * @param verifySegment Functor to be called when Data segment is received.  If
-   *                      functor return false, fetching will be aborted with
-   *                      SEGMENT_VERIFICATION_FAIL error
+   * @param validator     A shared_ptr to the Validator that should be used to validate data.
+   *
    * @param completeCallback    Callback to be fired when all segments are fetched
    * @param errorCallback       Callback to be fired when an error occurs (@see Errors)
    */
@@ -145,38 +163,55 @@
   void
   fetch(Face& face,
         const Interest& baseInterest,
-        const VerifySegment& verifySegment,
+        shared_ptr<Validator> validator,
         const CompleteCallback& completeCallback,
         const ErrorCallback& errorCallback);
 
 private:
   SegmentFetcher(Face& face,
-                 const VerifySegment& verifySegment,
+                 shared_ptr<Validator> validator,
                  const CompleteCallback& completeCallback,
                  const ErrorCallback& errorCallback);
 
   void
-  fetchFirstSegment(const Interest& baseInterest, const shared_ptr<SegmentFetcher>& self);
+  fetchFirstSegment(const Interest& baseInterest, shared_ptr<SegmentFetcher> self);
 
   void
   fetchNextSegment(const Interest& origInterest, const Name& dataName, uint64_t segmentNo,
-                   const shared_ptr<SegmentFetcher>& self);
+                   shared_ptr<SegmentFetcher> self);
 
   void
-  onSegmentReceived(const Interest& origInterest,
-                    const Data& data, bool isSegmentZeroExpected,
-                    const shared_ptr<SegmentFetcher>& self);
+  afterSegmentReceived(const Interest& origInterest,
+                       const Data& data, bool isSegmentZeroExpected,
+                       shared_ptr<SegmentFetcher> self);
+  void
+  afterValidationSuccess(const shared_ptr<const Data> data,
+                         bool isSegmentZeroExpected,
+                         const Interest& origInterest,
+                         shared_ptr<SegmentFetcher> self);
+
+  void
+  afterValidationFailure(const shared_ptr<const Data> data);
+
+  void
+  afterNackReceived(const Interest& origInterest, const lp::Nack& nack,
+                    uint32_t reExpressCount, shared_ptr<SegmentFetcher> self);
+
+  void
+  reExpressInterest(Interest interest, uint32_t reExpressCount,
+                    shared_ptr<SegmentFetcher> self);
 
 private:
   Face& m_face;
-  VerifySegment m_verifySegment;
+  Scheduler m_scheduler;
+  shared_ptr<Validator> m_validator;
   CompleteCallback m_completeCallback;
   ErrorCallback m_errorCallback;
 
   shared_ptr<OBufferStream> m_buffer;
 };
 
-} // util
-} // ndn
+} // namespace util
+} // namespace ndn
 
 #endif // NDN_UTIL_SEGMENT_FETCHER_HPP