docs: Add guide on how to simulate real apps in ndnSIM
Change-Id: I3694a8791b9540fc1b926a83ff55421b47e0f2a2
diff --git a/docs/Doxyfile b/docs/Doxyfile
index dfe0463..b8d1823 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -764,7 +764,7 @@
doxygen.hpp
# For example:
-# ../../../build/utils/ns3-dev-print-introspected-doxygen-debug --log --group Ndn > introspected-doxygen.hpp
+# ../../../build/utils/ns3-dev-print-introspected-doxygen-debug --group=Ndn > introspected-doxygen.hpp
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/docs/log-sources.hpp b/docs/log-sources.hpp
deleted file mode 100644
index e69de29..0000000
--- a/docs/log-sources.hpp
+++ /dev/null
diff --git a/docs/source/guide-to-simulate-real-apps.rst b/docs/source/guide-to-simulate-real-apps.rst
index ab73f8d..5d7b8ac 100644
--- a/docs/source/guide-to-simulate-real-apps.rst
+++ b/docs/source/guide-to-simulate-real-apps.rst
@@ -1,4 +1,216 @@
-Simulating real applications
-============================
+Simulating real NDN applications
+================================
-TODO
+The version of `ndn-cxx library <http://named-data.net/doc/ndn-cxx/>`__ bundled with ndnSIM includes
+a modified version of :ndnsim:`ndn::Face` to directly send and receive Interest and Data packets to
+and from the simulated instances of NFD. With this modification, ndnSIM enables support to simulate
+real NDN applications written against the ndn-cxx, if they satisfy requirements listed in this guide
+or can be modified to satisfy these requirements.
+
+
+Requirements
+++++++++++++
+
+#. **Source code of the application must be available**
+
+ The application (parts of the application) needs to be compiled against the ndnSIM version of
+ ndn-cxx library.
+
+#. **Source code should separate** ``main`` **function from the functional components of the
+ application that will be simulated**
+
+ The entry point to the application (its functional component) will be NS-3 application class,
+ which should be able to create and destroy an instance of the simulated component when scheduled
+ by the scenario.
+
+#. **The application should not use global variables, if they define a state for the application
+ instance**
+
+ ndnSIM should be able to create multiple different instances of the application, e.g., for each
+ simulated node.
+
+ Exception to this requirement is :ndnsim:`ndn::Scheduler <ndn::util::scheduler::Scheduler>`: its
+ implementation has been rewired to use NS-3's scheduling routines.
+
+#. **The application MUST NOT contain any GUI or command-line terminal interactions**
+
+#. **The application SHOULD NOT use disk operations, unless application instances access unique
+ parts of the file system**
+
+ In the simulated environment, all application instances will be accessing the same local file
+ system, which can result in undefined behavior if not properly handled.
+
+#. **The application MUST use a subset of** :ndnsim:`ndn::Face` **API:**
+
+ - If the application create :ndnsim:`ndn::Face`, it MUST BE created either with a default
+ constructor or constructor that accepts a single ``boost::asio::io_service`` parameter.
+
+ .. code-block:: c++
+
+ // Supported
+ ndn::Face face1();
+ ndn::Face face2(ioService);
+
+ // Not supported in ndnSIM
+ ndn::Face face4(host_name, port_number)
+ ndn::Face face3(transport);
+ // and others
+
+ - :ndnsim:`ndn::Face::getIoService()` should be used only to obtain a reference to
+ ``boost::asio::io_service``. **Application MUST NOT use any methods of**
+ ``boost::asio::io_service``, **otherwise the simulation will crash.**
+
+ .. code-block:: c++
+
+ ndn::Face face;
+ ...
+ // Supported (the rewired Scheduler implementation does not access io_service methods)
+ Scheduler scheduler(face.getIoService());
+
+ // Not supported in ndnSIM and will result in crash
+ face.getIoService().stop();
+
+
+ - Application should avoid use of :ndnsim:`Face::processEvents` or use it with caution
+
+ In real applications, processEvents blocks until some data is received or the timeout callback
+ is called. In this case, any variables created before calling this method will still exist
+ after the method returns. However, in ndnSIM, such an assumption cannot be made, since the
+ scope of a variable is local.
+
+ .. code-block:: c++
+
+ void
+ foo
+ {
+ ndn::Face face;
+ face.expressInterest(...);
+ face.setInterestFilter(...);
+
+ // ndnSIM version of processEvents will not block!
+ face.processEvents();
+ }
+ // after existing foo scope, face variable is deallocated and all scheduled operations
+ // will be canceled
+
+#. **Application (simulated component) MUST NOT create instances of** ``boost::asio::io_service``
+ **and use their methods**
+
+ ``boost::asio::io_service`` is inherently incompatible with NS-3, as both are providing mechanisms
+ for asynchronous event processing.
+
+#. We also recommend that functional part of the application accepts reference to the
+ :ndnsim:`KeyChain` instance, instead of creating instance itself.
+
+ When simulating non-security aspects of the application, in simulation scenario it will be
+ possible to use a dummy implementation of the :ndnsim:`KeyChain` that does not perform crypto
+ operations, but signs Data and Interests with fake signatures.
+
+ For example, this can be achieved by enabling the constructor of the real application to accept a reference
+ to the :ndnsim:`KeyChain`:
+
+ .. code-block:: c++
+
+ // Real applications should accept a reference to the KeyChain instance
+ RealApp::RealApp(KeyChain& keyChain)
+ : m_keyChain(keyChain)
+ {
+ }
+
+
+How to simulate real applications using ndnSIM
+++++++++++++++++++++++++++++++++++++++++++++++
+
+To simulate a real application, the simulation scenario should contain a class derived from
+``ns3::Application``. This class needs to create an instance of the :ndnsim:`ndn::Face` and/or real
+application in the overloaded ``StartApplication`` method. This class also need to ensure that the
+created instance is not deallocated until ``StopApplication`` method is called.
+
+For example, if the functional class of the real application looks like:
+
+.. literalinclude:: ../../examples/ndn-cxx-simple/real-app.hpp
+ :language: c++
+ :linenos:
+ :lines: 23-75
+
+
+The corresponding NS-3 "entry point" application class can be like this:
+
+.. literalinclude:: ../../examples/ndn-cxx-simple/real-app-starter.hpp
+ :language: c++
+ :linenos:
+ :lines: 25-65
+
+.. note::
+ There is a requirement that :ndnsim:`ndn::Face` MUST BE created within the context of a specific
+ ``ns3::Node``. In simple words this means that :ndnsim:`ndn::Face` constructor must be called
+ somewhere within the overloaded ``StartApplication`` method.
+
+ Attempt to create a :ndnsim:`ndn::Face` outside ``ns3::Node`` (e.g., if the example included
+ member variable ``Face m_face`` in ``RealAppStarter`` class) will result in simulation crash.
+
+The final step is to actually write a simulation scenario that defines network topology, routing
+information between nodes, on which nodes the application should be installed and when it should be
+started and stopped.
+
+For the trivial example, let us assume that we have only one simulation node and we want to start
+the application at time moment 6.5 seconds. This scenario can look like:
+
+.. literalinclude:: ../../examples/ndn-cxx-simple.cpp
+ :language: c++
+ :linenos:
+ :lines: 20-
+
+
+Example of a real application simulation
+++++++++++++++++++++++++++++++++++++++++
+
+To demonstrate functionality of ndnSIM in a more complex and realistic case, we will use the NDN
+ping application included as part of `NDN Essential Tools`_.
+
+For this example, we used a `scenario template repository`_ as a base to write simulation-specific
+extensions and define scenarios, and the `final version of the scenario is available in GitHub
+<https://github.com/named-data-ndnSIM/scenario-ndn-ping>`__.
+
+The following lists steps we did to simulate `ndnping` and `ndnpingserver` apps on a simple
+three-node topology:
+
+- forked `scenario template repository`_
+
+- imported the latest version of `NDN Essential Tools`_ source code as a git submodule
+
+- updated the build script (``wscript``) to compile the source code of ``ndnping`` and
+ ``ndnpingserver`` (with the exception of compilation units that contain ``main`` function) against
+ ndnSIM
+
+ `View changes <https://github.com/named-data-ndnSIM/scenario-ndn-ping/commit/74269dc4de6afe2b6e13a0bcc8c0faac350d8fa3>`__
+
+- defined ``PingClient`` and ``PingServer`` classes to hold state of application instances
+
+ `View changes <https://github.com/named-data-ndnSIM/scenario-ndn-ping/commit/4f087a16e3171af38c05b53c6cfd9e752e7cda72>`__
+
+- defined ``PingClientApp`` and ``PingServerApp`` NS-3 applications, that create and destroy
+ instances of ``PingClient`` and ``PingServer`` per NS-3 logic.
+
+ `View changes <https://github.com/named-data-ndnSIM/scenario-ndn-ping/commit/2b317860f55b71b34ffdccac31444246d9b804fe>`__
+
+- defined a simple scenario that creates a three node topology, installs NDN stacks, and installs
+ ``PingClientApp`` and ``PingServerApp`` applications on different simulation nodes.
+
+ `View changes <https://github.com/named-data-ndnSIM/scenario-ndn-ping/commit/2b317860f55b71b34ffdccac31444246d9b804fe>`__
+
+After all these steps, the repository is ready to run the simulation (see `README.md
+<https://github.com/named-data-ndnSIM/scenario-ndn-ping/blob/master/README.md>`__ for more details).
+
+
+.. note::
+ The listed steps did not include any modification of `NDN Essential Tools`_ source code.
+ However, this was not the case when we initially attempted to run the simulation, as the source
+ code was violating a few requirements of this guide. `The changes that we made
+ <https://github.com/named-data/ndn-tools/commit/1e7a7b20c93014e86639e3d07f357c95b48b34ac>`__ are
+ an example of how to adapt the source code to be compatible with ndnSIM simulations.
+
+
+.. _NDN Essential Tools: http://github.com/named-data/ndn-tools
+
+.. _scenario template repository: https://github.com/named-data-ndnSIM/scenario-template
diff --git a/examples/ndn-cxx-simple.cpp b/examples/ndn-cxx-simple.cpp
new file mode 100644
index 0000000..22497e0
--- /dev/null
+++ b/examples/ndn-cxx-simple.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2015 Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM 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.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "ndn-cxx-simple/real-app.hpp"
+#include "ndn-cxx-simple/real-app-starter.hpp"
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/ndnSIM-module.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(RealAppStarter);
+
+int
+main(int argc, char* argv[])
+{
+ CommandLine cmd;
+ cmd.Parse(argc, argv);
+
+ Ptr<Node> node = CreateObject<Node>();
+
+ ndn::StackHelper ndnHelper;
+ ndnHelper.Install(node);
+
+ ndn::AppHelper appHelper("RealAppStarter");
+ appHelper.Install(node)
+ .Start(Seconds(6.5));
+
+ Simulator::Stop(Seconds(20.0));
+
+ Simulator::Run();
+ Simulator::Destroy();
+
+ return 0;
+}
+
+} // namespace ns3
+
+int
+main(int argc, char* argv[])
+{
+ return ns3::main(argc, argv);
+}
diff --git a/examples/ndn-cxx-simple/real-app-starter.hpp b/examples/ndn-cxx-simple/real-app-starter.hpp
new file mode 100644
index 0000000..00119e5
--- /dev/null
+++ b/examples/ndn-cxx-simple/real-app-starter.hpp
@@ -0,0 +1,67 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2015 Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM 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.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_STARTER_HPP
+#define NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_STARTER_HPP
+
+#include "real-app.hpp"
+
+#include "ns3/ndnSIM/helper/ndn-stack-helper.hpp"
+#include "ns3/application.h"
+
+namespace ns3 {
+
+// Class inheriting from ns3::Application
+class RealAppStarter : public Application
+{
+public:
+ static TypeId
+ GetTypeId()
+ {
+ static TypeId tid = TypeId("RealAppStarter")
+ .SetParent<Application>()
+ .AddConstructor<RealAppStarter>();
+
+ return tid;
+ }
+
+protected:
+ // inherited from Application base class.
+ virtual void
+ StartApplication()
+ {
+ // Create an instance of the app, and passing the dummy version of KeyChain (no real signing)
+ m_instance.reset(new app::RealApp(ndn::StackHelper::getKeyChain()));
+ m_instance->run(); // can be omitted
+ }
+
+ virtual void
+ StopApplication()
+ {
+ // Stop and destroy the instance of the app
+ m_instance.reset();
+ }
+
+private:
+ std::unique_ptr<app::RealApp> m_instance;
+};
+
+} // namespace ns3
+
+#endif // NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_STARTER_HPP
diff --git a/examples/ndn-cxx-simple/real-app.hpp b/examples/ndn-cxx-simple/real-app.hpp
new file mode 100644
index 0000000..0aa2f38
--- /dev/null
+++ b/examples/ndn-cxx-simple/real-app.hpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2015 Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM 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.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_HPP
+#define NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_HPP
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/interest.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/util/scheduler.hpp>
+
+#include <iostream>
+
+namespace app {
+
+class RealApp
+{
+public:
+ RealApp(ndn::KeyChain& keyChain)
+ : m_keyChain(keyChain)
+ , m_faceProducer(m_faceConsumer.getIoService())
+ , m_scheduler(m_faceConsumer.getIoService())
+ {
+ // register prefix and set interest filter on producer face
+ m_faceProducer.setInterestFilter("/hello", std::bind(&RealApp::respondToAnyInterest, this, _2),
+ std::bind([]{}), std::bind([]{}));
+
+ // use scheduler to send interest later on consumer face
+ m_scheduler.scheduleEvent(ndn::time::seconds(2), [this] {
+ m_faceConsumer.expressInterest(ndn::Interest("/hello/world"),
+ std::bind([] { std::cout << "Hello!" << std::endl; }),
+ std::bind([] { std::cout << "Bye!.." << std::endl; }));
+ });
+ }
+
+ void
+ run()
+ {
+ m_faceConsumer.processEvents(); // ok (will not block and do nothing)
+ // m_faceConsumer.getIoService().run(); // will crash
+ }
+
+private:
+ void
+ respondToAnyInterest(const ndn::Interest& interest)
+ {
+ auto data = std::make_shared<ndn::Data>(interest.getName());
+ m_keyChain.sign(*data);
+ m_faceProducer.put(*data);
+ }
+
+private:
+ ndn::KeyChain& m_keyChain;
+ ndn::Face m_faceConsumer;
+ ndn::Face m_faceProducer;
+ ndn::Scheduler m_scheduler;
+};
+
+} // namespace app
+
+#endif // NDNSIM_EXAMPLES_NDN_CXX_SIMPLE_REAL_APP_HPP