J-Sim Official


It's All That Simple!

A Step-by-step Example to Create and Test a Component in J-Sim

June 04, 2002

This document presents a step-by-step example in writing a simple protocol component in J-Sim. We assume that you have read the four examples in the INET tutorial, as some of the materials covered there will not be repeated here. The example implements a simple 'echo' protocol that is similar to 'ping' under the UNIX environment. The sender at a node sends an echo-request UDP packet to a receiver at another node which then returns an echo-reply packet immediately.  With the echo protocol, one can calculate the round trip time between two nodes. Although the example is simple, it covers all the essential aspects in creating a new component in J-Sim, and may serve as a template for you to implement other protocol components.  For complete document, please refer to Component Writer's Guide.

There are three steps in implementing a protocol component:


Defining the Packet Class

In a new file echopkt.java, we first define a new packet class for the 'echo' protocol. The new class is used to carry the information for the echo protocol.

 1 /**
2 * Example application packet class - echopkt.
3 */
4 public class echopkt
5 {
6 public int type;
7 public double time;
8 public echopkt(int type_, double time_) 
9 {
10 type = type_;
11 time = time_;
12 }
13 }

The variable 'type' is set to '1' if the packet is an echo request (sent from a sender to a receiver) and '2' if the packet is an echo reply (sent by a receiver in response to an echo request). The variable 'time' is a time stamp when the packet is sent. It will be copied by a receiver to the corresponding echo reply so that a  sender can calculate the round-trip time.

Writing the Protocol

In a new file echoer.java, we extend the class Module and define the echo protocol:

 1 import drcl.comp.Port;
2 import drcl.comp.Contract;
3 import drcl.inet.contract.DatagramContract;
4
5 /**
6 * Example application class - echoer.
7 */
8 public class echoer extends drcl.net.Module
9 {
10 final static int REQ=1, RPL=2, tos=0;
11
12 static {
13 setContract(echoer.class, drcl.net.Module.PortGroup_DOWN + "@",
14 new DatagramContract(Contract.Role_PEER));
15 }
16
17 public echoer()
18 {
19 super();
20 }
21
22 public echoer(String id_)
23 {
24 super(id_);
25 }
26
27 void sendmsg(int type_, double tm_, long dst_, int dport_)
28 {
29 echopkt pkt_ = new echopkt(type_, tm_);
30 downPort.doSending(new DatagramContract.Message(pkt_, 10/*size*/,
31 drcl.net.Address.NULL_ADDR, dst_, dport_, tos));
32 }
33
34 public void send_echo_request(long dst_, int dport_)
35 {
36 debug("Sending an Echo packet to port " + dport_ + " at node" + dst_);
37 sendmsg(REQ, getTime(), dst_, dport_);
38 }
39
40 protected void dataArriveAtDownPort(Object data_, Port downPort_)
41 {
42 if (!(data_ instanceof DatagramContract.Message))
43 {
44 error(data_, "dataArrivedAtDownPort()", downPort_, "unrecognized data");
45 return;
46 }
47 DatagramContract.Message datagram_ = (DatagramContract.Message) data_;
48 long src_ = datagram_.getSource();
49 int sport_ = datagram_.getSourcePort();
50 echopkt pkt_ = (echopkt)datagram_.getContent();
51 if (pkt_.type==RPL)
52 {
53 double rtt = getTime() - pkt_.time;
54 debug("Getting a reply, round-trip time is: " + rtt);
55 }
56 else {
57 debug("Getting a request, sending time is: " + pkt_.time);
58 sendmsg(RPL, pkt_.time, src_, sport_);
59 }
60 }
61 }
1-3:
We import several classes that are used in this component.
8: 
Define the echoer class as an extended class of drcl.net.Module in which upPort and downPort are defined for a module to fit into a protocol stack.
10: 
Define several constants for the protocol: REQ and RPL are the packet type (echo request or echo reply), and tos is the type of service, all of which are passed to the lower layer protocol (UDP) when an echoer sends a packet.
13-14: 
Bind the downPort of this component with drcl.inet.contract.DatagramContract using the setContract method in the drcl.comp.Component class.
17-25: 
Define the constructors of echoer.
27-32: 
Define the method used to send a packet (an echo request or echo reply) to the peer (specified by dst_ and dport_). The method first creates an echopkt object by setting its type and a timestamp (line 29). Then, it creates and sends a DatagramContract message at downPort (line 30-31).
29-33: 
Define the send_echo_request() method. This method is to be called interactively at runtime.If the destination node and port number are set to valid values, the echoer sends an echo request to the destination.
40-60: 
Implement the dataArriveAtDownPort() method. This method is defined in drcl.net.Module and is invoked when an object arrives at the module's downPort. An echoer only expects to receive an echo request or an echo reply (packaged as defined in the DatagramContract):
  • If the packet is an echo request, the method composes an echo reply with the timestamp copied from the echo request and sends the reply back to the sender.
  • If the packet is an echo reply, the method calculates the RTT and sends the result as a debug message.

Using the SUDPApplication Class

To facilitate programming, we have implemented several "template" classes in J-Sim. To implement an application layer protocol, one can extend an application layer class SUDPApplication that has been designed to take care of, and hence hide from users, many low-level details (as shown above). In particular, this class provides a set of methods to send/receive a datagram. Below is the new class, new_echoer.java, which does the same thing as echoer.

 1 import drcl.comp.Port;
2 import drcl.comp.Contract;
3
4 /**
5 * Example application class - new_echoer.
6 */
7 public class new_echoer extends drcl.inet.application.SUDPApplication
8 {
9 final static int REQ=1, RPL=2;
10
11 public new_echoer()
12 {
13 super();
14 }
15
16 public new_echoer(String id_)
17 {
18 super(id_);
19 }
20
21 public void send_echo_request(long dst_, int dport_)
22 {
23 debug("Sending an Echo packet to port " + dport_ + " at node " + dst_);
24 sendmsg(new echopkt(REQ, getTime()), 10/*size*/, dst_, dport_);
25 }
26
27 protected void dataArriveAtDownPort(Object data_, Port downPort_)
28 {
29 long src_ = getPeerAddress(data_);
30 int sport_ = getPeerPort(data_);
31 echopkt pkt_ = (echopkt)getContent(data_);
32 if (pkt_.type==RPL)
33 {
34 double rtt = getTime() - pkt_.time;
35 debug("Getting a reply, round-trip time is: " + rtt);
36 }
37 else {
38 debug("Getting a request, sending time is: " + pkt_.time);
39 sendmsg(new echopkt(RPL, pkt_.time), 10/*size*/, src_, sport_);
40 }
41 }
42 }
7:
Define the new_echoer class as an extended class of drcl.inet.application.SUDPApplication. As the downPort of a SUDPApplication class is bound with the DatagramContract, we do not have to bind it explicitly.
21-25:
Define the method used to send an echo request to a peer (specified by dst_ and dport_). This method is similar to the same method in the echoer class except that new_echoer takes advantage of the sendmsg() method defined in the SUDPApplication class to send the packet.  Here we do not have to explicitly create a contract message and send it at the downPort
27-41:
Implement the dataArriveAtDownPort() method. This block of codes is identical to what in the echoer class except that we take advantage of the getPeerAddress(), getPeerPort() and getContent() methods defined in SUDPApplication.


Testing the Protocol

After writing and compiling the Java classes, we are now ready to test (or simulate) the protocol. This is done by writing a TCL script to construct the simulation scenario. The easiest way for a beginner is perhaps to cut-and-paste from existing examples [e.g., Examples 1, 2, 3, 4 in the INET Tutorial].  Here we use the scenario constructed in Example 2. 

The TCL script used to test echoer/new_echoer is shown below. (echo.tcl)

 1 # echoer.tcl
2 #
3 # Test echoer/new_echoer in the following topology with echoer at h0 and h2
4 #
5 # Topology:
6 # 
7 # h0 ----- n1 ----- h2
8 #
9
10 cd [mkdir -q drcl.comp.Component /test]
11
12 # create the topology
13 puts "create topology..."
14 set link_ [java::new drcl.inet.Link]
15 $link_ setPropDelay 0.3; # 300ms
16 set adjMatrix_ [java::new {int[][]} 3 {{1} {0 2} {1}}]
17 java::call drcl.inet.InetUtil createTopology [! .] $adjMatrix_ $link_
18
19 puts "create builders..."
20 # NodeBuilder:
21 set nb [mkdir drcl.inet.NodeBuilder .nodeBuilder]
22 $nb setBandwidth 1.0e7; #10Mbps
23
24 puts "build..."
25 $nb build [! n?]
26 $nb build [! h?] {
27 udp drcl.inet.transport.UDP
28 echo 101/udp new_echoer
29 }
30 ! h?/udp setTTL 3
31
32 # Configure the bottleneck bandwidth and buffer size
33 ! n1 setBandwidth 1 1.0e4; # 10Kbps at interface 1
34 ! n1 setBufferSize 1 6000; # ~10 packets at interface 1
35
36 puts "setup static routes..."
37 java::call drcl.inet.InetUtil setupRoutes [! h0] [! h2] "bidirection"
38
39 puts "set up simulator..."
40 set sim [attach_simulator .]
41
42 puts "Done!"

As most of the Tcl and RUV commands are explained in details in Example 2, we do not repeat the efforts here. You may also refer to Tcl/Jacl quick reference and script reference for a detailed account of these commands.

12-17:
Specify the the attributes of links, and configure the topology. 
19-30:
Create a node builder and build the nodes. Note that the echo protocol is connected to UDP at port 101.
32-34:
Configure the bandwidth and buffer size of the bottleneck link.
36-37:
Set up static (shortest path) routes between the hosts.
39-40:
Set up the simulation runtime.

Now, we have every piece of code we need for testing the echo protocol. You can now use command "java drcl.ruv.System echo.tcl" to launch the simulation at a terminal (an xterm in UNIX or a DOS prompt in Windows). After doing that, the following window pops up and the scenario is constructed. Then we use the following command to make both hosts to send echo requests to each other:

! h0/echo send_echo_request 2 101; ! h2/echo send_echo_request 0 101

The session should look like:

The first few lines are created by the TCL script (via the puts command) to inform of the scenario construction process. At the 8th line, we issue the command that makes h0 and h2 send echo requests to each other. The last 4 lines display how  the echoers respond with echo replies, and calculate RTTs (both are  (10 + 8 + 20) * 8 * (10-4 + 3 * 10-7) + 0.3 * 4) = 1.2304912 seconds).

Note that we stop the simulation first by "$sim stop" to make sure that the two hosts send the echo requests at the same time.  If we do not stop simulation first, then the simulation automatically starts when h0 sends the echo request.  The time when h2 sends its request may be different at different runs.

 

Write the protocol to run directly on top of CSL

How about we just run the protocol directly on top of CSL (core service layer, think of it as the IP protocol layer)?  The code is similar but this time we extend drcl.inet.Protocol: (echoer2.java)

 1 import drcl.comp.Port;
2 import drcl.inet.InetPacket;
3
4 /**
5 * Example protocol class - echoer2.
6 */
7 public class echoer2 extends drcl.inet.Protocol
8 {
9 final static int REQ=1, RPL=2, tos=0;
10
11 public echoer2()
12 { super(); }
13
14 public echoer2(String id_)
15 { super(id_); }
16
17 void sendmsg(int type_, double tm_, long dst_)
18 {
19 echopkt pkt_ = new echopkt(type_, tm_);
20
21 forward(pkt_, 10/*size*/, drcl.net.Address.NULL_ADDR/*src*/, dst_,
22 false/*routerAlert*/, 255/*TTL*/, tos);
23 }
24
25 public void send_echo_request(long dst_)
26 {
27 debug("Sending an Echo packet to node" + dst_);
28 sendmsg(REQ, getTime(), dst_);
29 }
30
31 protected void dataArriveAtDownPort(Object data_, Port downPort_)
32 {
33 InetPacket ipkt_ = (InetPacket)data_;
34 echopkt pkt_ = (echopkt)ipkt_.getBody();
35 long src_ = ipkt_.getSource();
36 if (pkt_.type==RPL)
37 {
38 double rtt = getTime() - pkt_.time;
39 debug("Getting a reply, round-trip time is: " + rtt);
40 }
41 else {
42 debug("Getting a request, sending time is: " + pkt_.time);
43 sendmsg(RPL, pkt_.time, src_);
44 }
45 }
46 }

The differences here are:

  1. We use the forward() method to send out our packet (in raw InetPacket) instead of using datagram (line 21-22).
  2. We don't specify port number here as it is now the "protocol ID" (as in the TCP/IP jargon) and will be specified in the script when we build the nodes.
  3. The data received is an InetPacket instead of a datagram service message (line 33).

The TCL script now becomes: (echo2.tcl)

 1 # echoer2.tcl
2 #
3 # Test echoer2 in the following topology with echoer at h0 and h2
4 #
5 # Topology:
6 # 
7 # h0 ----- n1 ----- h2
8 #
9
10 cd [mkdir -q drcl.comp.Component /test]
11
12 # create the topology
13 puts "create topology..."
14 set link_ [java::new drcl.inet.Link]
15 $link_ setPropDelay 0.3; # 300ms
16 set adjMatrix_ [java::new {int[][]} 3 {{1} {0 2} {1}}]
17 java::call drcl.inet.InetUtil createTopology [! .] $adjMatrix_ $link_
18
19 puts "create builders..."
20 # NodeBuilder:
21 set nb [mkdir drcl.inet.NodeBuilder .nodeBuilder]
22 $nb setBandwidth 1.0e7; #10Mbps
23
24 puts "build..."
25 $nb build [! n?]
26 $nb build [! h?] {
27 echo 1111/csl echoer2
28 }
29
30 # Configure the bottleneck bandwidth and buffer size
31 ! n1 setBandwidth 1 1.0e4; # 10Kbps at interface 1
32 ! n1 setBufferSize 1 6000; # ~10 packets at interface 1
33
34 puts "setup static routes..."
35 java::call drcl.inet.InetUtil setupRoutes [! h0] [! h2] "bidirection"
36
37 puts "set up simulator..."
38 set sim [attach_simulator .]
39
40 puts "Done!"

The only difference is that now we put the new echo2 protocol directly on top of CSL (line 27).  A testing session is shown as follows:

The round-trip time now is a bit smaller than the previous example because now the packet size is 10 + 20 = 30 bytes.  The exact calculation is (30 * 8 * (10-4 + 3 * 10-7) + 0.3 * 4) = 1.224072 (seconds).

OK, we have written a new application protocol and test it with a TCL script! it is all that simple!  To implement a specific protocol, we recommend that you browse through some of the Java class examples in the same protocol family.  For example, you may want to browse through DV classes (TCP classes) before you implement a new routing protocol (transport layer protocol).

Happy coding and we hope that you find J-Sim useful.

Attachments (6)

  • echo.tcl - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    1k Download
  • echo2.tcl - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    1k Download
  • echoer.java - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    2k Download
  • echoer2.java - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    1k Download
  • echopkt.java - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    1k Download
  • new_echoer.java - on Jun 22, 2008 9:23 AM by jsim java (version 1)
    1k Download