OTcl and C++ Linkages
In this post
- The
linkages between OTcl and C++ is covered.
- The functions of various TclCL classes were explored.
Network simulator 2 (ns) deals with two different languages OTcl and
C++. The OTcl is mainly for beginners that act as a frontend to test, analyze
the components of networks. But C++ on the other hand runs in the background
and usually deals with implementation of Queues, protocols, packets, agents,
applications, etc. However when C++ modules are introduced, it is necessary to
see how it is linking with the OTcl objects. This chapter deals this.
3.1 NS-2 Architecture
Network Simulator
2 (NS-2) deals with two different languages C++ and OTcl. Mainly OTcl is interpreted language and C++
is Compiled language.
The advantage of both the languages in NS2 is not compromised as both the languages have their own pros and cons.
OTcl
·
Preferable for beginners (to
start simulation even without knowing much about ns2)
·
Runs in the front end. (Since
interpreter is slow in execution, OTcl preferred in the front end)
·
Interpretation is fast and
execution is slow (Since it accepts changes fast, the source code can be
modified easily to verify the network performance)
C++
·
Mainly deals with
implementation of network terminologies like queues, packets, agents,
applications, routing algorithms, etc.
·
Preferable for medium and
advanced users
·
Its execution is fast and
compilation is slow. (Compilers usually are slow in compilation and hence they
are running in the background to make the execution faster)
With these above, we can conclude that OTcl and C++ both need to be in their places for faster execution.
3.2 Code Overview
Consider the example:
set
tcp1 [new Agent/TCP]
set
sink1 [new Agent/TCPSink]
set udp1 [new Agent/UDP]
The above code is a Tcl code that calls TcpAgent, TCPSink Agent and FTP Application. All three are C++ modules that are executing in the backend.
These three Tcl Objects links with the C++ Objects as given in the Table
OTcl Object |
C++ Class |
Location of C++ file |
Agent/TCP |
TcpClass |
~ns-2.35/tcp/tcp.cc |
Agent/TCPSink |
TcpSinkClass |
~ns-2.35/tcp/tcp-sink.cc |
Agent/UDP |
UdpAgentClass |
~ns-2.35/apps/udp.cc |
As shown in the table, there should be a link between the OTcl and C++. NS-2 defines a interface called TclCL (~tclcl/) that contains some classes that makes the mapping between OTcl and C++.
There are some
lists of classes and this chapter will be focusing on four main classes with
their member functions. These classes are defined in ~tclcl-xx/Tcl.h. The
following table lists the purpose of each class with their class names
Tcl |
Contains method
to access the interpreter |
TclObject |
This is the base
class of all Simulated object libraries |
TclClass |
Provides the
mapping between the classes of interpreted hierarchy and compiled hierarchy |
TclCommand |
Used to define
the global interpreter command |
EmbeddedTcl |
Contains method
to load the C++ commands for easier configuration |
InstVar |
Contains methods
to access C++ member variables as OTcl instance variables. |
The location of these classes are found in the ~tclcl/Tcl.[h, .cc], ~tclcl/Tcl2.cc, ~tclcl/tcl-object.tcl, etc. These classes are used in building ns.
Class Tcl
The class Tcl that
contains methods to access the interpreted hierarchy. The methods can be used
by the programmer to develop the C++ code.
Class Tcl provides
the following operations
·
Obtain a reference to Tcl instance
o Tcl& tcl = Tcl::instance();
o tcl is the reference and all the methods can be accessed using
tcl.eval(), tcl.evalf(), etc.
·
Invoke Tcl procedures
o Four methods are there to invoke the command through the instance
tcl.
o tcl.eval() -
o tcl.eval(char* a) – executes ‘a’ through the interpreter.
o tcl.evalf(const char* a…..)- this is similar like a printf()
statement where the format specifiers are used.
o tcl.evalc(const char* a)- it preserves the argument string ‘a’ as a
constant.
Example:
tcl.evalf(“%d is the packet id”,
packet_id);
tcl.evalc(“put this to the screen”);
·
Passing Results to/from the Interpreter
o Two functions are used to pass results to/from the interpreter.
o tcl.result(const char* a) – pass the string a to the interpreter
back.
o tcl.resultf(const char* fmt, ...)
o the following script will help you on this
if
(strcmp(argv[1], "HELLO") == 0)
{
tcl.resultf("%d",
seq_no);
return
TCL_OK;
}
tcl.result("Invalid
operation specified");
return
TCL_ERROR;
·
Error Reporting and Exit
o Errors are often reported to the interpreter using the function
error().
o tcl.error(const char* a) performs the following functions:
§ write a to stdout;
§ write tcl_->result to stdout;
§ exit with error code 1.
·
There are other operations and hash Functions within the
Interpreter, they are
o tcl.enter(TclObject* o) – to insert an object in the hash table
while creating the TclObject
o tcl.lookup(char* a) will retrieve the TclObject with the name a.
o tcl.remove(TclObject* o) will delete references to the TclObject.
o These functions are used internally by the class TclObject and class
TclClass.
Class TclClass and Class TclObject
TclClass is a pure
virtual class. Classes derived from this base class provide two functions:
·
It does the mapping between the
classes of interpreted hierarchy and compiled hierarchy;
·
This class provides methods to
create instance for TclObject.
// ~ns-2.35/tcp/tcp.cc
static class TcpClass :
public TclClass {
public:
TcpClass()
: TclClass("Agent/TCP") {}
TclObject*
create(int , const char*const*) {
return
(new TcpAgent());
}
}
class_tcp;
As an example, consider the code segment above which shows the syntax of the TcpClass. It is derived from class TclClass, and is associated with the class TcpAgent. This will will create the instance of TcpAgent and thus create new objects in the class TcpAgent. The compiled class hierarchy for TcpAgent is that it derives from Agent, that in turn derives from TclObject.
Here is the
observation from this definition:
·
This TclClass defines only the constructor and it shows the compiled
hierarchy.
·
ns will execute the TcpClass constructor for the static
variable class_tcp, when it is first
started.
·
The constructor specifies the
interpreted class explicitly as Agent/TCP.
This also specifies the interpreted hierarchy.
·
The convention in ns
is to use the character slash (’/’) is a separator. For any given class
A/B/C/D, the class A/B/C/D is a sub-class of A/B/C that is itself a sub-class
of A/B, that, in turn, is a sub-class of A. and A is the sub class of
TclObject. In our case above, the TclClass
constructor creates two classes, Agent/TCP
sub-class of Agent sub- class of TclObject.
·
The TcpClass::create method returns TclObject in the class TcpAgent.
· When the user specifies new Agent/TCP in the tcl file, the class TcpClass::create is invoked and thus a shadow object is created.
Consider the Example shown called as the Amplifier Agent that amplifies the given value in to multiples times
/* A Simple agent that does the amplification of a given value to 3 fold and more. The name of the agent is represented as TSPAgent as The SPecial Agent that does the amplification */
//Header file declaration
#include
<stdio.h>
#include
<string.h>
#include "agent.h"
class TSPAgent :
public Agent {
public:
TSPAgent();
protected:
int command(int argc, const char*const*
argv);
private:
int
amp1, amp2, amp3;
void
APrivateFunc(void);
};
static class
TSPAgentClass : public TclClass {
public:
TSPAgentClass() :
TclClass("Agent/AMPLIFY") {}
TclObject* create(int, const char*const*)
{
return(new
TSPAgent());
}
}
class_tsp_agent;
TSPAgent::TSPAgent()
: Agent(PT_UDP) {
bind("Ampli1", &1);
bind("Ampli2", &2);
bind("Ampli3", &3);
}
int
TSPAgent::command(int argc, const char*const* argv) {
if(argc == 2) {
if(strcmp(argv[1],
"call-the-private-function") == 0) {
APrivateFunc();
return(TCL_OK);
}
}
return(Agent::command(argc, argv));
}
void
TSPAgent::APrivateFunc(void) {
Tcl& tcl = Tcl::instance();
tcl.eval("puts \"Message From
the Private Function\"");
tcl.evalf("puts \" The Amplified Value is %d and the factor is 2
\"", amp1*amp1);
tcl.evalf("puts \" The Amplified Value is %d and the factor is 3
\"", amp2*amp2*amp2);
tcl.evalf("puts \" The Amplified Value is %d and the factor is 4
\"", amp3*amp3*amp3*amp3);
}
In the above
example, the Line 1 to 3, includes the header files, the Agent class is
available in the agent.h file.
Line 5 to 13,
declares a class with three integer variables and two functions command() and
APrivateFunc().
Line 14 to 19,
includes a static class that does the mapping between the OTCL and C++ and also
contains the code that instantiates the TclObject. The name of the Agent here
is Agent/AMPLIFY which indicates it is a interpreted hierarchy and the static
class TSPAgentClass is the compiled hierarchy class. Clearly, the TclClass does
the mapping between the Interpreted hierarchy and Compiled hierarchy.
Line 20 to 24,
declares the constructor and all the agents should act on a Packet, so this
agent acts in the UDP Packet, PT_UDP. There are three binding OTCL factors Ampli1, Ampli2 and Ampli3 that maps to
C++’s amp1, amp2 and amp3
respectively.
Line 25 to 31, implements the command
function, that processes the arguments passed from the OTCL. If the argv[1] and the
call-the-private-function is validated, that calls the APrivateFunc();
Line 32 to 38, the
implementation of APrivateFunc() that amplifies the values.
Here is the Tcl
file to test the above agent
#the name of the file is agent.tcl
set myagent [new Agent/AMPLIFY]
$myagent set Ampli1 3
$myagent set Ampli2 4
$myagent set Ampli3 5
$myagent call-the-private-function
To execute the
above agent, here are the steps
·
Copy the ampagent.cc file in
~ns-allinone-2.35/ns-2.35/newagent
·
Make an entry in the
~ns-2.35/Makefile.in
Make an entry in the OBJ_CC =
newfolder/ampagent.o
\
·
In the shell prompt, go to
~ns-2.35 and give the following commands one by one
./configure
Make
·
Run the file agent.tcl
·
If warnings are there, the set
the default values in the ns-default.tcl
file (~ns-2.35/tcl/lib) as shown below
o Agent/AMPLIFY set Ampli1 1
o Agent/AMPLIFY set Ampli2 1
o Agent/AMPLIFY set Ampli3 1
Output:
Message From the
Private Function
The Amplified Value is 9 and the factor is 2
The Amplified Value is 64 and the factor is 3
The Amplified Value is 625 and the factor is
4
Comments
Post a Comment