producer: Add error callback

Change-Id: I2cca1c8d06da2de20fdde09e1513d2fcb3f5df5f
Refs: #3355
diff --git a/src/producer.hpp b/src/producer.hpp
index c3cd14e..d87683c 100644
--- a/src/producer.hpp
+++ b/src/producer.hpp
@@ -17,12 +17,14 @@
  * ndn-group-encrypt, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
  * @author Prashanth Swaminathan <prashanthsw@gmail.com>
+ * @author Yingdi Yu <yuyingdi@gmail.com>
  */
 
 #ifndef NDN_GEP_PRODUCER_HPP
 #define NDN_GEP_PRODUCER_HPP
 
 #include "producer-db.hpp"
+#include "error-code.hpp"
 
 #include <ndn-cxx/security/key-chain.hpp>
 #include <ndn-cxx/face.hpp>
@@ -73,66 +75,120 @@
            Face& face, const std::string& dbPath, uint8_t repeatAttempts = 3);
 
   /**
-   * @brief Create content key
+   * @brief Create content key corresponding to @p timeslot
    *
    * This method will first check if the content key exists. For existing
    * content key, the method will return content key name directly.
    * If the key does not exist, the method will create one and encrypt
    * it using corresponding E-KEY. The encrypted content keys will be
-   * passed back through @p callback.
+   * passed back through @p callback. In case of any error, @p errorCallBack
+   * will be invoked.
    */
   Name
   createContentKey(const time::system_clock::TimePoint& timeslot,
-                   const ProducerEKeyCallback& callback);
+                   const ProducerEKeyCallback& callback,
+                   const ErrorCallBack& errorCallBack = Producer::defaultErrorCallBack);
 
   /**
-   * @brief Produce an data packet encrypted using corresponding content key
+   * @brief Produce an data packet encrypted using the content key corresponding @p timeslot
    *
-   * This method encrypts @p content with a content key covering
-   * @p timeslot, and set @p data with the encrypted content and
-   * appropriate data name.
+   * This method encrypts @p content of @p contentLen with a content key covering
+   * @p timeslot, and set @p data with the encrypted content and appropriate data name.
+   * In case of any error, @p errorCallBack will be invoked.
    */
   void
   produce(Data& data, const time::system_clock::TimePoint& timeslot,
-          const uint8_t* content, size_t contentLen);
+          const uint8_t* content, size_t contentLen,
+          const ErrorCallBack& errorCallBack = Producer::defaultErrorCallBack);
+
+public:
+  /**
+   * @brief Default error callback
+   *
+   * @param code The error code.
+   * @param msg The error msg.
+   */
+  static void
+  defaultErrorCallBack(const ErrorCode& code, const std::string& msg);
 
 private:
 
   /**
-   * @brief Sends interest through face with necessary callbacks
-   *        Uses @p exclude to limit interest if specified
+   * @brief Send interest for E-KEY
+   *
+   * This method simply construct DataCallback, NackCallback, TiemoutCallback using
+   * @p timeslot, @p callback, and @p errorCallBack, and express @p interest with
+   * the created callbacks.
    */
   void
-  sendKeyInterest(const Name& name, const time::system_clock::TimePoint& timeslot,
-                  KeyRequest& keyRequest, const ProducerEKeyCallback& callback,
-                  const Exclude& timeRange = Exclude());
+  sendKeyInterest(const Interest& interest,
+                  const time::system_clock::TimePoint& timeslot,
+                  const ProducerEKeyCallback& callback,
+                  const ErrorCallBack& errorCallBack = Producer::defaultErrorCallBack);
 
   /**
-   * @brief Updates state in @p keyRequest on timeout
+   * @brief Handle received E-KEY retrieved using @p interest.
+   *
+   * This method first checks if the E-key contained in @p data fits @p timeslot.
+   * If true, encrypt the C-KEY for @p timeslot using the E-KEY, if the retrieval for
+   * all E-KEYs for the C-KEY have been done, invoke @p callback. Otherwise, narrow down
+   * the search scope through revising exclude filter and re-express the interest. In case
+   * of any error, invoke @p errorCallBack.
+   */
+  void
+  handleCoveringKey(const Interest& interest, const Data& data,
+                    const time::system_clock::TimePoint& timeslot,
+                    const ProducerEKeyCallback& callback,
+                    const ErrorCallBack& errorCallBack = Producer::defaultErrorCallBack);
+
+  /**
+   * @brief Handle timeout.
+   *
+   * Re-express @p interest if the number of retrials is less than max limit.
+   * The DataCallback, NackCallback, TiemoutCallback are created using @p timeslot,
+   * @p callback, and @p errorCallBack,
    */
   void
   handleTimeout(const Interest& interest,
                 const time::system_clock::TimePoint& timeslot,
-                KeyRequest& keyRequest, const ProducerEKeyCallback& callback);
+                const ProducerEKeyCallback& callback,
+                const ErrorCallBack& errorCallBack = Producer::defaultErrorCallBack);
 
   /**
-   * @brief Checks that encryption key contained in @p data fits @p timeslot
-   *        Sends refined interest if required
+   * @brief Handle @p nack for the E-KEY requested through @p interest.
+   *
+   * This method will decrease the outstanding E-KEY interest count for the C-Key
+   * corresponding to @p timeCount.  When there is no outstanding interest, invoke
+   * @p callback.
    */
   void
-  handleCoveringKey(const Interest& interest, Data& data,
-                    const time::system_clock::TimePoint& timeslot,
-                    KeyRequest& keyRequest, const ProducerEKeyCallback& callback);
+  handleNack(const Interest& interest,
+             const lp::Nack& nack,
+             const time::system_clock::TimePoint& timeslot,
+             const ProducerEKeyCallback& callback);
 
   /**
-   * @brief Encrypts content key for @p timeslot with @p encryptionKey
-   *        Fires @p callback if no more interests to process
+   * @brief Decrease the count of outstanding E-KEY interests for C-KEY for @p timeCount
+   *
+   * If the count decrease to 0, invoke @p callback.
    */
   void
-  encryptContentKey(KeyRequest& keyRequest, const Buffer& encryptionKey,
-                    const Name& eKeyName,
+  updateKeyRequest(KeyRequest& keyRequest, uint64_t timeCount,
+                   const ProducerEKeyCallback& callback);
+
+  /**
+   * @brief Encrypts C-KEY for @p timeslot using @p encryptionKey of @p eKeyName
+   *
+   * Invoke @p callback if no more interests to process.
+   * invoke @p errorCallback in case of any error.
+   *
+   * @return true if encryption succeeds, otherwise false.
+   */
+  bool
+  encryptContentKey(const Buffer& encryptionKey, const Name& eKeyName,
                     const time::system_clock::TimePoint& timeslot,
-                    const ProducerEKeyCallback& callback);
+                    const ProducerEKeyCallback& callback,
+                    const ErrorCallBack& errorCallback = Producer::defaultErrorCallBack);
 
 private:
   Face& m_face;