ndn-tlv-poke: simple producer to read payload from stdin and send it to local NDN forwarder as a single Data packet

refs: #1350

Change-Id: I5f5f86819beadfa6ecb4e62944d774417de8d6c0
diff --git a/tools/ndn-tlv-poke.cpp b/tools/ndn-tlv-poke.cpp
new file mode 100644
index 0000000..51a12d9
--- /dev/null
+++ b/tools/ndn-tlv-poke.cpp
@@ -0,0 +1,254 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 University of Arizona.
+ *
+ * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ */
+
+#include <boost/utility.hpp>
+ 
+#include <ndn-cpp-dev/face.hpp>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+
+namespace ndntlvpoke {
+
+class NdnTlvPoke : boost::noncopyable
+{
+
+public:
+
+  explicit
+  NdnTlvPoke(char* programName)
+    : m_programName(programName)
+    , m_isForceDataSet(false)
+    , m_isUseDigestSha256Set(false)
+    , m_isLastAsFinalBlockIdSet(false)
+    , m_freshnessPeriod(-1)
+    , m_timeout(-1)
+    , m_isDataSent(false)
+  {
+  }
+
+  void
+  usage()
+  {
+    std::cout << "\n Usage:\n " << m_programName << " "
+      "[-f] [-D] [-i identity] [-F] [-x freshness] [-w timeout] ndn:/name\n"
+      "   Reads payload from stdin and sends it to local NDN forwarder as a "
+      "single Data packet\n"
+      "   [-f]          - force, send Data without waiting for Interest\n"
+      "   [-D]          - use DigestSha256 signing method instead of "
+      "SignatureSha256WithRsa\n"
+      "   [-i identity] - set identity to be used for signing\n"
+      "   [-F]          - set FinalBlockId to the last component of Name\n"
+      "   [-x]          - set FreshnessPeriod in milliseconds\n"
+      "   [-w timeout]  - set Timeout in milliseconds\n"
+      "   [-h]          - print help and exit\n\n";
+    exit(1);
+  }
+
+  void
+  setForceData()
+  {
+    m_isForceDataSet = true;
+  }
+
+  void
+  setUseDigestSha256()
+  {
+    m_isUseDigestSha256Set = true;
+  }
+
+  void
+  setIdentityName(char* identityName)
+  {
+    m_identityName = ndn::make_shared<ndn::Name>(identityName);
+  }
+
+  void
+  setLastAsFinalBlockId()
+  {
+    m_isLastAsFinalBlockIdSet = true;
+  }
+
+  void
+  setFreshnessPeriod(int freshnessPeriod)
+  {
+    if (freshnessPeriod < 0)
+      usage();
+    m_freshnessPeriod = freshnessPeriod;
+  }
+
+  void
+  setTimeout(int timeout)
+  {
+    if (timeout < 0)
+      usage();
+    m_timeout = timeout;
+  }
+
+  void
+  setPrefixName(char* prefixName)
+  {
+    m_prefixName = ndn::Name(prefixName);
+  }
+
+  ndn::Milliseconds
+  getDefaultTimeout()
+  {
+    return 10000;
+  }
+
+  ndn::Data
+  createDataPacket()
+  {
+    ndn::Data dataPacket(m_prefixName);
+    std::stringstream payloadStream;
+    payloadStream << std::cin.rdbuf();
+    std::string payload = payloadStream.str();
+    dataPacket.setContent(reinterpret_cast<const uint8_t*>(payload.c_str()), payload.length());
+    if (m_freshnessPeriod >= 0)
+      dataPacket.setFreshnessPeriod(m_freshnessPeriod);
+    if (m_isLastAsFinalBlockIdSet)
+      {
+        if (!m_prefixName.empty())
+          dataPacket.setFinalBlockId(m_prefixName.get(-1));
+        else
+          {
+            std::cerr << "Name Provided Has 0 Components" << std::endl;
+            exit(1);
+          }
+      }
+    if (m_isUseDigestSha256Set)
+      m_keyChain.signWithSha256(dataPacket);
+    else
+      {
+        if (!static_cast<bool>(m_identityName))
+          m_keyChain.sign(dataPacket);
+        else
+          m_keyChain.signByIdentity(dataPacket, *m_identityName);
+      }
+    return dataPacket;
+  }
+
+  void
+  onInterest(const ndn::Name& name,
+             const ndn::Interest& interest,
+             const ndn::Data& dataPacket)
+  {
+    m_face.put(dataPacket);
+    m_isDataSent = true;
+    m_face.shutdown();
+  }
+
+  void
+  onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
+  {
+    std::cerr << "Prefix Registration Failure." << std::endl;
+    std::cerr << "Reason = " << reason << std::endl;
+  }
+
+  void
+  run()
+  {
+    try
+      {
+        ndn::Data dataPacket = createDataPacket();
+        if (m_isForceDataSet)
+          {
+            m_face.put(dataPacket);
+            m_isDataSent = true;
+          }
+        else
+          {
+            m_face.setInterestFilter(m_prefixName,
+                                     ndn::func_lib::bind(&NdnTlvPoke::onInterest,
+                                                         this, _1, _2, dataPacket),
+                                     ndn::func_lib::bind(&NdnTlvPoke::onRegisterFailed,
+                                                         this, _1, _2));
+          }
+        if (m_timeout < 0)
+          m_face.processEvents(getDefaultTimeout());
+        else
+          m_face.processEvents(m_timeout);
+      }
+    catch (std::exception& e)
+      {
+        std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
+        exit(1);
+      }
+  }
+
+  bool
+  isDataSent() const
+  {
+    return m_isDataSent;
+  }
+
+private:
+
+  ndn::KeyChain m_keyChain;
+  std::string m_programName;
+  bool m_isForceDataSet;
+  bool m_isUseDigestSha256Set;
+  ndn::shared_ptr<ndn::Name> m_identityName;
+  bool m_isLastAsFinalBlockIdSet;
+  ndn::Milliseconds m_freshnessPeriod;
+  ndn::Milliseconds m_timeout;
+  ndn::Name m_prefixName;
+  bool m_isDataSent;
+  ndn::Face m_face;
+
+};
+
+}
+
+int
+main(int argc, char* argv[])
+{
+  int option;
+  ndntlvpoke::NdnTlvPoke ndnTlvPoke(argv[0]);
+  while ((option = getopt(argc, argv, "hfDi:Fx:w:")) != -1)
+    {
+      switch (option) {
+        case 'h':
+          ndnTlvPoke.usage();
+          break;
+        case 'f':
+          ndnTlvPoke.setForceData();
+          break;
+        case 'D':
+          ndnTlvPoke.setUseDigestSha256();
+          break;
+        case 'i':
+          ndnTlvPoke.setIdentityName(optarg);
+          break;
+        case 'F':
+          ndnTlvPoke.setLastAsFinalBlockId();
+          break;
+        case 'x':
+          ndnTlvPoke.setFreshnessPeriod(atoi(optarg));
+          break;
+        case 'w':
+          ndnTlvPoke.setTimeout(atoi(optarg));
+          break;
+        default:
+          ndnTlvPoke.usage();
+          break;
+      }
+    }
+
+  argc -= optind;
+  argv += optind;
+
+  if (argv[0] == 0)
+    ndnTlvPoke.usage();
+
+  ndnTlvPoke.setPrefixName(argv[0]);
+  ndnTlvPoke.run();
+
+  if (ndnTlvPoke.isDataSent())
+    return 0;
+  else
+    return 1;
+}