Trivial applications

Note

To successfully run the following examples, please make sure that NFD is properly configured and running. For more information about NFD, refer to NFD’s official homepage.

Trivial consumer

In the following trivial example, a consumer creates a Face with default transport (UnixTransport) and sends an Interest for /localhost/testApp/randomData. While expressing Interest, the app specifies three callbacks to be called when Data/Nack is retrieved or Interest times out.

  1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
  2/*
  3 * Copyright (c) 2013-2022 Regents of the University of California.
  4 *
  5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  6 *
  7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
  8 * terms of the GNU Lesser General Public License as published by the Free Software
  9 * Foundation, either version 3 of the License, or (at your option) any later version.
 10 *
 11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 13 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 14 *
 15 * You should have received copies of the GNU General Public License and GNU Lesser
 16 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 17 * <http://www.gnu.org/licenses/>.
 18 *
 19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 20 */
 21
 22#include <ndn-cxx/face.hpp>
 23#include <ndn-cxx/security/validator-config.hpp>
 24
 25#include <iostream>
 26
 27// Enclosing code in ndn simplifies coding (can also use `using namespace ndn`)
 28namespace ndn {
 29// Additional nested namespaces should be used to prevent/limit name conflicts
 30namespace examples {
 31
 32class Consumer
 33{
 34public:
 35  Consumer()
 36  {
 37    m_validator.load("trust-schema.conf");
 38  }
 39
 40  void
 41  run()
 42  {
 43    Name interestName("/example/testApp/randomData");
 44    interestName.appendVersion();
 45
 46    Interest interest(interestName);
 47    interest.setMustBeFresh(true);
 48    interest.setInterestLifetime(6_s); // The default is 4 seconds
 49
 50    std::cout << "Sending Interest " << interest << std::endl;
 51    m_face.expressInterest(interest,
 52                           std::bind(&Consumer::onData, this,  _1, _2),
 53                           std::bind(&Consumer::onNack, this, _1, _2),
 54                           std::bind(&Consumer::onTimeout, this, _1));
 55
 56    // processEvents will block until the requested data is received or a timeout occurs
 57    m_face.processEvents();
 58  }
 59
 60private:
 61  void
 62  onData(const Interest&, const Data& data)
 63  {
 64    std::cout << "Received Data " << data << std::endl;
 65
 66    m_validator.validate(data,
 67                         [] (const Data&) {
 68                           std::cout << "Data conforms to trust schema" << std::endl;
 69                         },
 70                         [] (const Data&, const security::ValidationError& error) {
 71                           std::cout << "Error authenticating data: " << error << std::endl;
 72                         });
 73  }
 74
 75  void
 76  onNack(const Interest&, const lp::Nack& nack) const
 77  {
 78    std::cout << "Received Nack with reason " << nack.getReason() << std::endl;
 79  }
 80
 81  void
 82  onTimeout(const Interest& interest) const
 83  {
 84    std::cout << "Timeout for " << interest << std::endl;
 85  }
 86
 87private:
 88  Face m_face;
 89  ValidatorConfig m_validator{m_face};
 90};
 91
 92} // namespace examples
 93} // namespace ndn
 94
 95int
 96main(int argc, char** argv)
 97{
 98  try {
 99    ndn::examples::Consumer consumer;
100    consumer.run();
101    return 0;
102  }
103  catch (const std::exception& e) {
104    std::cerr << "ERROR: " << e.what() << std::endl;
105    return 1;
106  }
107}

Trivial producer

The following example demonstrates how to write a simple producer application.

First, the application sets an Interest filter for /localhost/testApp to receive all Interests that have this prefix. The Face::setInterestFilter() call accepts two callbacks; the first will be called when an Interest is received and the second if prefix registration fails.

After an Interest is received, the producer creates a Data packet with the same name as the received Interest, adds content, and signs it with the system-default identity. It is also possible to specify a particular key to be used during the signing. For more information, refer to KeyChain API documentation.

Finally, after Data packet has been created and signed, it is returned to the requester using Face::put() method.

  1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
  2/*
  3 * Copyright (c) 2013-2023 Regents of the University of California.
  4 *
  5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  6 *
  7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
  8 * terms of the GNU Lesser General Public License as published by the Free Software
  9 * Foundation, either version 3 of the License, or (at your option) any later version.
 10 *
 11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 13 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 14 *
 15 * You should have received copies of the GNU General Public License and GNU Lesser
 16 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 17 * <http://www.gnu.org/licenses/>.
 18 *
 19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 20 */
 21
 22#include <ndn-cxx/face.hpp>
 23#include <ndn-cxx/security/key-chain.hpp>
 24#include <ndn-cxx/security/signing-helpers.hpp>
 25
 26#include <iostream>
 27
 28// Enclosing code in ndn simplifies coding (can also use `using namespace ndn`)
 29namespace ndn {
 30// Additional nested namespaces should be used to prevent/limit name conflicts
 31namespace examples {
 32
 33class Producer
 34{
 35public:
 36  void
 37  run()
 38  {
 39    m_face.setInterestFilter("/example/testApp/randomData",
 40                             std::bind(&Producer::onInterest, this, _2),
 41                             nullptr, // RegisterPrefixSuccessCallback is optional
 42                             std::bind(&Producer::onRegisterFailed, this, _1, _2));
 43
 44    auto cert = m_keyChain.getPib().getDefaultIdentity().getDefaultKey().getDefaultCertificate();
 45    m_certServeHandle = m_face.setInterestFilter(security::extractIdentityFromCertName(cert.getName()),
 46                                                 [this, cert] (auto&&...) {
 47                                                   m_face.put(cert);
 48                                                 },
 49                                                 std::bind(&Producer::onRegisterFailed, this, _1, _2));
 50    m_face.processEvents();
 51  }
 52
 53private:
 54  void
 55  onInterest(const Interest& interest)
 56  {
 57    std::cout << ">> I: " << interest << std::endl;
 58
 59    // Create Data packet
 60    auto data = std::make_shared<Data>();
 61    data->setName(interest.getName());
 62    data->setFreshnessPeriod(10_s);
 63    data->setContent("Hello, world!");
 64
 65    // In order for the consumer application to be able to validate the packet, you need to setup
 66    // the following keys:
 67    // 1. Generate example trust anchor
 68    //
 69    //         ndnsec key-gen /example
 70    //         ndnsec cert-dump -i /example > example-trust-anchor.cert
 71    //
 72    // 2. Create a key for the producer and sign it with the example trust anchor
 73    //
 74    //         ndnsec key-gen /example/testApp
 75    //         ndnsec sign-req /example/testApp | ndnsec cert-gen -s /example -i example | ndnsec cert-install -
 76
 77    // Sign Data packet with default identity
 78    m_keyChain.sign(*data);
 79    // m_keyChain.sign(*data, signingByIdentity(<identityName>));
 80    // m_keyChain.sign(*data, signingByKey(<keyName>));
 81    // m_keyChain.sign(*data, signingByCertificate(<certName>));
 82    // m_keyChain.sign(*data, signingWithSha256());
 83
 84    // Return Data packet to the requester
 85    std::cout << "<< D: " << *data << std::endl;
 86    m_face.put(*data);
 87  }
 88
 89  void
 90  onRegisterFailed(const Name& prefix, const std::string& reason)
 91  {
 92    std::cerr << "ERROR: Failed to register prefix '" << prefix
 93              << "' with the local forwarder (" << reason << ")\n";
 94    m_face.shutdown();
 95  }
 96
 97private:
 98  Face m_face;
 99  KeyChain m_keyChain;
100  ScopedRegisteredPrefixHandle m_certServeHandle;
101};
102
103} // namespace examples
104} // namespace ndn
105
106int
107main(int argc, char** argv)
108{
109  try {
110    ndn::examples::Producer producer;
111    producer.run();
112    return 0;
113  }
114  catch (const std::exception& e) {
115    std::cerr << "ERROR: " << e.what() << std::endl;
116    return 1;
117  }
118}

Consumer that uses Scheduler

The following example demonstrates how to use Scheduler to schedule arbitrary events for execution at specific points of time.

The library internally uses boost::asio::io_context to implement fully asynchronous NDN operations (i.e., sending and receiving Interests and Data). In addition to network-related operations, boost::asio::io_context can be used to execute any arbitrary callback within the processing thread (run either explicitly via io_context::run() or implicitly via Face::processEvents() as in previous examples). Scheduler is just a wrapper on top of io_context, providing a simple interface to schedule tasks at specific times.

The highlighted lines in the example demonstrate all that is needed to express a second Interest approximately 3 seconds after the first one.

  1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
  2/*
  3 * Copyright (c) 2013-2023 Regents of the University of California.
  4 *
  5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  6 *
  7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
  8 * terms of the GNU Lesser General Public License as published by the Free Software
  9 * Foundation, either version 3 of the License, or (at your option) any later version.
 10 *
 11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 13 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 14 *
 15 * You should have received copies of the GNU General Public License and GNU Lesser
 16 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 17 * <http://www.gnu.org/licenses/>.
 18 *
 19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 20 */
 21
 22#include <ndn-cxx/face.hpp>
 23#include <ndn-cxx/util/scheduler.hpp>
 24
 25#include <boost/asio/io_context.hpp>
 26#include <iostream>
 27
 28// Enclosing code in ndn simplifies coding (can also use `using namespace ndn`)
 29namespace ndn {
 30// Additional nested namespaces should be used to prevent/limit name conflicts
 31namespace examples {
 32
 33class ConsumerWithTimer
 34{
 35public:
 36  void
 37  run()
 38  {
 39    Name interestName("/example/testApp/randomData");
 40    interestName.appendVersion();
 41
 42    Interest interest(interestName);
 43    interest.setMustBeFresh(true);
 44    interest.setInterestLifetime(2_s);
 45
 46    std::cout << "Sending Interest " << interest << std::endl;
 47    m_face.expressInterest(interest,
 48                           std::bind(&ConsumerWithTimer::onData, this, _1, _2),
 49                           std::bind(&ConsumerWithTimer::onNack, this, _1, _2),
 50                           std::bind(&ConsumerWithTimer::onTimeout, this, _1));
 51
 52    // Schedule a new event
 53    m_scheduler.schedule(3_s, [this] { delayedInterest(); });
 54
 55    // m_ioCtx.run() will block until all events finished or m_ioCtx.stop() is called
 56    m_ioCtx.run();
 57
 58    // Alternatively, m_face.processEvents() can also be called.
 59    // processEvents will block until the requested data received or timeout occurs.
 60    // m_face.processEvents();
 61  }
 62
 63private:
 64  void
 65  onData(const Interest&, const Data& data) const
 66  {
 67    std::cout << "Received Data " << data << std::endl;
 68  }
 69
 70  void
 71  onNack(const Interest& interest, const lp::Nack& nack) const
 72  {
 73    std::cout << "Received Nack with reason " << nack.getReason()
 74              << " for " << interest << std::endl;
 75  }
 76
 77  void
 78  onTimeout(const Interest& interest) const
 79  {
 80    std::cout << "Timeout for " << interest << std::endl;
 81  }
 82
 83  void
 84  delayedInterest()
 85  {
 86    std::cout << "One more Interest, delayed by the scheduler" << std::endl;
 87
 88    Name interestName("/example/testApp/randomData");
 89    interestName.appendVersion();
 90
 91    Interest interest(interestName);
 92    interest.setMustBeFresh(true);
 93    interest.setInterestLifetime(2_s);
 94
 95    std::cout << "Sending Interest " << interest << std::endl;
 96    m_face.expressInterest(interest,
 97                           std::bind(&ConsumerWithTimer::onData, this, _1, _2),
 98                           std::bind(&ConsumerWithTimer::onNack, this, _1, _2),
 99                           std::bind(&ConsumerWithTimer::onTimeout, this, _1));
100  }
101
102private:
103  // Explicitly create io_context object, which will be shared between Face and Scheduler
104  boost::asio::io_context m_ioCtx;
105  Face m_face{m_ioCtx};
106  Scheduler m_scheduler{m_ioCtx};
107};
108
109} // namespace examples
110} // namespace ndn
111
112int
113main(int argc, char** argv)
114{
115  try {
116    ndn::examples::ConsumerWithTimer consumer;
117    consumer.run();
118    return 0;
119  }
120  catch (const std::exception& e) {
121    std::cerr << "ERROR: " << e.what() << std::endl;
122    return 1;
123  }
124}