20.6 Changes required to add yr diffusion application to ns

Let's say you have an application (it might even be a certain filter, which also is by class hierarchy, a diffusion application and it would derive from class DiffApp) that runs on the test-bed version. Now you want to run diffusion on ns and so want to use yr application in the ns context. The few lines describe the changes/additions you need to make for yr diffusion application to work in ns environment.

We will consider onePhasePullFilter object (under diffusion3/filters/misc/log.*) as an example. As a first step you need to create a split object out of the application class object, presumably defined as a pure c++ object. A split object is one that is created by the user in the interpretor (in OTcl space) and which is also has a shadow object in the compiled hierarchy (in c++ space). In ns, a split object is derived from class TclClass as shown below:

#ifdef NS_DIFFUSION
static class LogFilterClass : public TclClass {
public:
  LogFilterClass() : TclClass("Application/DiffApp/LogFilter") {}
  TclObject * create(int argc, const char*const* argv) {
    return(new LogFilter());
  }
} class_log_filter;
#endif //DIFFUSION

Note that all filter objects specifically have a handle to the DiffAppAgent (the diffusion routing object) passed in the constructor call. Filter objects get created from function create-diffusionApp-agent diffFilters defined in ns-diffusion.tcl. Users need not specifically call the OTcl function create-diffusionApp-agent as it is called during node creation based on the node-configuration parameters. See how filters are defined in node-config under commands at a glance section. However application objects which are not filter objects (like ping_sender, push_receiver etc) are created by users directly from user scripts. And in that case the handle to DiffAppAgent is passed using $ns attach-diffapp $node $app where the application $app is attached to the node object $node.

So for the reasons explained above the constructors are different in non NS_DIFFUSION context as shown below.

#ifdef NS_DIFFUSION
LogFilter::LogFilter()
#else
LogFilter::LogFilter(int argc, char **argv)
#endif // NS_DIFFUSION
{
  // Create Diffusion Routing class
#ifndef NS_DIFFUSION
  parseCommandLine(argc, argv);
  dr_ = NR::createNR(diffusion_port_);
#endif // !NS_DIFFUSION

  filter_callback_ = new LogFilterReceive(this);

#ifndef NS_DIFFUSION
  // Set up the filter
  filter_handle_ = setupFilter();
  ...
  ...
#endif // !NS_DIFFUSION
}

Next you need to add the c++ function command(..) that allows execution of tcl commands through the compiled shadow object. For example the otcl command start is used to start a filter application as follows $app start. While commands publish and subscribe are used to start sender and receiver applications respectively. The command function is added, again with the NS_DIFFUSION scope using ifdef statements, as follows:

#ifdef NS_DIFFUSION
int LogFilter::command(int argc, const char*const* argv) {
  if (argc == 2) {
    if (strcmp(argv[1], "start") == 0) {
      run();
      return TCL_OK;
    }
  }
  return DiffApp::command(argc, argv);
}
#endif // NS_DIFFUSION

Note how the parent class command function is invoked incase the command string is not found. Look into lib/diffapp.* to see all otcl commands supported for the DiffApp class.

Once these changes made to your c++ code, you would also need to write a tcl script (see the section on test-suite for example tcl scripts) that uses your diffusion application using the right tcl APIs.

Tom Henderson 2011-11-05