added lab 9

master
Flavien Haas 3 years ago
parent 7979b80a52
commit 089b6a04d0

Binary file not shown.

Binary file not shown.

@ -0,0 +1,16 @@
README.txt K. J. Turner 28th September 2015
This is version 1.7 of Jasper (Java Simulation of Protocols for Education and
Research): https://sourceforge.net/projects/jaspersimulator.
Open "html/index.html" in a web browser to try out the protocol simulations.
(Due to Java security restrictions you must authorise running of code created by
the University of Stirling.)
Open "docs/index.html" in a web browser for more detail and the licence
conditions.
Note that simulations of CSMA/CD, Multicast, Multiplexing, Protocol Stack and
TCP Slow Start were created for Pearson Education to accompany the ninth edition
of "Data and Computer Communications" by William Stallings.

@ -0,0 +1,72 @@
<?xml version="1.0"?>
<!-- build.xml (C) K. J. Turner 28/09/15 -->
<project name="jasper" default="simulator" basedir=".">
<property name="source.directory" value="source"/>
<property name="build.directory" value="build"/>
<property name="compile.debug" value="true"/>
<property name="compile.optimize" value="true"/>
<property name="main.class" value="simulator.ProtocolSimulator"/>
<property name="simulator.jar" value="html/ProtocolSimulator.jar"/>
<!-- Uncomment this if you have a keystore and certificate
<property name="key.pass" value="PASS_WORD"/>
<property name="store.alias" value="AN_ALIAS"/>
<property name="store.file" value="FILE_PATH"/>
<property name="store.pass" value="PASS_WORD"/>
<property name="timestamp.url" value="TSA_URL"/>
-->
<target name="clean" description="Remove build directory and backup files">
<delete dir="${build.directory}"/>
<delete>
<fileset dir="." includes="**/*~ **/*.bak" defaultexcludes="no"/>
</delete>
</target>
<target name="compile" depends="prepare"
description="Compile source files to build directory">
<javac srcdir="${source.directory}" destdir="${build.directory}"
debug="${compile.debug}" optimize="${compile.optimize}"
includeantruntime="false"/>
</target>
<target name="manifest" depends="prepare">
<tstamp>
<format property="NOW" pattern="hh:mm dd-MMMM-yyyy" locale="en-gb"/>
</tstamp>
<manifest file="${build.directory}/MANIFEST.MF">
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Built-On" value="${NOW}"/>
<attribute name="Permissions" value="sandbox"/>
<!-- KJT 28/09/15: added for Java 7u51 security change -->
<attribute name="Caller-Allowable-Codebase" value="*"/>
</manifest>
</target>
<target name="prepare">
<mkdir dir="${build.directory}"/>
</target>
<target name="simulator" depends="compile, manifest"
description="Build simulator JAR file">
<jar jarfile="${simulator.jar}" manifest="${build.directory}/MANIFEST.MF">
<fileset dir="${build.directory}"/>
<fileset dir="${source.directory}" includes="resources/*.gif"/>
</jar>
<!-- Uncomment this if you have a keystore and certificate
<signjar jar="${simulator.jar}" keystore="${store.file}"
alias="${store.alias}" storepass="${store.pass}" keypass="${key.pass}"
tsaurl="${timestamp.url}"/>
-->
</target>
<target name="spotless" depends="clean"
description="Clean up and remove simulator JAR file">
<delete file="html/ProtocolSimulator.jar"/>
</target>
</project>

@ -0,0 +1,534 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- index.html K. J. Turner 28/09/15 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
Jasper Protocol Simulator (Java Simulation of Protocols for Education and Research)
</title>
<link rev="made" href="mailto:kjt@cs.stir.ac.uk"/>
<meta name="keywords"
content="communication communications protocol network interactive graphical visual visualisation simulation simulator ABP Alternating Bit Protocol ABRA Abracadabra Protocol BOOTP Boot Protocol HTTP HyperText Transfer Protocol IP Internet Protocol SMTP Simple Mail Transfer Protocol SWP Sliding Window Protocol TCP Transmission Control Protocol TFTP Trivial File Transfer Protocol UDP User Datagram Protocol"/>
</head>
<body>
<div style="text-align: center">
<h1>
Jasper Protocol Simulator
<br/>
(Java Simulation of Protocols for Education and Research)
</h1>
</div>
<!-- =================== Description =================== -->
<h2>Description</h2>
<p>
This protocol simulator provides:
</p>
<ul>
<li>
the capability for interactively and graphically simulating a wide
variety of communications protocols
</li>
<li>a framework for creating new protocol simulations</li>
<li>
pre-defined simulations of various well-known protocols:
</li>
<ul>
<li>ABP (Alternating Bit Protocol)</li>
<li>ABRA (Abracadabra Protocol)</li>
<li>BOOTP (Boot Protocol)</li>
<li>HTTP (HyperText Transfer Protocol)</li>
<li>IP (Internet Protocol)</li>
<li>SMTP (Simple Mail Transfer Protocol)</li>
<li>SWP (Sliding Window Protocol, 3 and 5 column layout)</li>
<li>TCP (Transmission Control Protocol)</li>
<li>TFTP (Trivial File Transfer Protocol)</li>
<li>UDP (User Datagram Protocol)</li>
</ul>
</ul>
<p>
The simulator is written in Java, and so can be used on many platforms with
a web browser (subject to applet security) and/or a Java environment. To
compile or extend the simulator requires a Java development environment such
as the Oracle JDK (and ideally also Apache Ant). To run simulations requires
a Java runtime environment such as the Oracle JRE. The code has been
pre-built using JDK 1.8. However, it should compile and run using Java 5
onwards.
</p>
<p>
(A <a
href="http://science.webhostinggeeks.com/jasper-java-simulacija">Serbo-Croat
version</a> of this page was produced by Anja Skrba.)
</p>
<!-- =================== Installation =================== -->
<h2>Installation</h2>
<p>
The simulator is provided as a <var>Zip</var> archive. The simulator unpacks
to a directory called <var>jasper-N.N</var> according to version number. You
might rename this to <var>jasper</var> for simplicity. The distribution
contains:
</p>
<dl>
<dt><strong>build.xml</strong></dt>
<dd><var>Ant</var> build file to manage the code</dd>
<dt><strong>docs</strong></dt>
<dd>basic documentation</dd>
<dt><strong>html</strong></dt>
<dd>directory for protocol simulation pages and simulator JAR archive</dd>
<dt><strong>scenarios</strong></dt>
<dd>example scenario files</dd>
<dt><strong>source</strong></dt>
<dd>directories for Java code (protocol, simulator, support)</dd>
</dl>
<!-- =================== Applet Simulation =================== -->
<h2>Simulation as an Applet</h2>
<p>
The simulator can be used on various protocols by opening
<var>html/index.html</var> in a web browser. This assumes you renamed the
distribution folder as <var>jasper</var>. This will bring up the main page,
with general instructions and a list of protocols that can be simulated.
Your web browser will need to be configured to run Java applets and
(ideally) JavaScript. Due to Java security restrictions you must authorise
running of the pre-compiled code created by the University of Stirling.
Alternatively, use an applet viewer on the files (though the JavaScript to
set protocol parameters will not work).
</p>
<p>
Most simulations are in three-column format: two protocol entities
(sender/receiver or A/B) and a communications medium (link or network). A
few simulations add the sending and receiving users (applications) in outer
columns. This format is useful for showing what the user sees; typically
this is only part of what is happening in the protocol.
</p>
<p>
In a web browser, select an action by clicking on the list at the bottom
right of the diagram. Actions are things like a user sending a data message
or the medium delivering a protocol message. You are completely in control
of the simulation. For example you may decide when to send messages, whether
to acknowledge messages, and whether to deliver or lose messages in the
medium. Since the simulation does not run in real-time, a timeout is
possible as soon as a message has been sent.
</p>
<p>
The last action in the diagram is shown in red. Various protocol comments
may also be noted in green the diagram, e.g. that a timeout occurred or that
a message was ignored.
</p>
<p>
If you make a mistake, or just want to backtrack in the simulation, then
click <em>Undo</em>. You can undo as many steps as you like, right up to the
beginning of the simulation. Clicking on <em>Redo</em> will perform again
the last undone step. <em>Clear</em> will restart the simulation with the
current protocol parameters. If you click on <em>Run</em> the simulator will
run automatically, making random choices for you. If you are not sure what
to experiment with, this is an easy way of seeing the protocol in action.
While this is happening, the <em>Run</em> button changes to <em>Stop</em>.
Click on <em>Stop</em> to return the simulator to user control. You can
continue at this point as if you had made all the automatic choices
yourself.
</p>
<p>
The <em>Print</em>, <em>Load</em> and <em>Save</em> buttons are disabled
since the simulations are running as applets. If you wish hard copy of the
simulation, position the scroll bar in the simulation pane at an interesting
point and print out the whole web page.
</p>
<p>
Some simulations have associated protocol parameters. To change the defaults
that are shown, enter new values and click <em>Change Values</em>. In some
cases, this will force the simulation to restart. The following is a
screen-shot of a TCP client-server simulation, showing the protocol
parameters and the main simulation controls.
</p>
<!-- for SourceForge
<div style="text-align: center">
<img
src="https://a.fsdn.com/con/app/proj/jaspersimulator/screenshots/tcp-simulation.gif"
alt="TCP Simulation"/>
</div>
-->
<!-- for local file -->
<div style="text-align: center">
<img src="tcp-simulation.gif" alt="TCP Simulation"/>
</div>
<!-- =================== Application Simulation =================== -->
<h2>Simulation as an Application</h2>
<p>
Running a protocol simulation as an application gives access to the
<em>Print</em>, <em>Load</em> and <em>Save</em> buttons.
</p>
<p>
<em>Print</em> produces a hard copy of the whole simulation scenario.
Note that individual pages cannot be selected for printing. The width of the
printout is determined by the width of the on-screen window. Constants
<var>winWidth</var> and <var>winHeight</var> in
<var>ProtocolSimulator</var> define the initial window size. Constant
<var>maxHeight</var> in <var>TimeSequenceDiagram</var> defines the
vertical size of printed pages. The current sizes are appropriate for A4
paper. If necessary, change them for (say) US letter.
</p>
<p>
<em>Load</em> loads a simulation scenario file (with a name ending in
<em>.scn</em>); this must be for the same protocol as you are currently
simulating. It replaces the current simulation scenario (if any).
<em>Save</em> saves the current simulation as a scenario file (with a
name ending in <em>.scn</em>). If you are adventurous, you can create and
edit your own scenarios using a text editor.
</p>
<p>
When the simulator is run as an application, a mandatory protocol name
follows the main simulator class. Protocol parameters may then be given if
required; protocols have defaults for these. Assume that the simulator has
been built and is to be started from the top level of Jasper. The following
(split here across two lines) will run TCP in client-server mode, with
message window sizes other than the default:
</p>
<pre>
java -cp html/ProtocolSimulator.jar simulator.ProtocolSimulator
TCP/cs windowSizeA=500 windowSizeB=300
</pre>
<!-- =================== Development =================== -->
<h2>Development</h2>
<p>
The complete source of the simulator is provided. (Most files have Unix
end-of-line.) The code should preferably be rebuilt using the Ant
<var>build.xml</var> build file. <var>ant -p</var> will print help
information about build targets.
<var>ant&nbsp;simulator</var> will rebuild <var>ProtocolSimulator.jar</var>
in the <var>html</var> directory. <var>ant&nbsp;clean</var> will remove all
compiled class files and backup files, but preserving the JAR file.
<var>ant&nbsp;spotless</var> will remove even this.
</p>
<p>
If you do not have Ant you will need to compile the Java source files
manually and create a JAR file from the result.
</p>
<p>
To modify an existing protocol simulation or to write a new one will need a
knowledge of the simulation framework. See the article <a
href="http://www.cs.stir.ac.uk/~kjt/research/pdf/prot-sim.pdf"
target="_blank">An Interactive Visual Protocol Simulator</a> for details of
this and an extended example of how to develop a simulation. Once the
framework is understood, a simple simulation can be developed in a day;
complex protocols could take a week or two to develop.
</p>
<p>
Suppose that you want to develop a new simulation of the protocol
<var>EXP</var> (&#39;Example Protocol&#39;). You would need to write
<var>EXP.java</var> to instantiate the various entities in the protocol.
For a simple protocol, you would then write <var>EXPSender.java</var> and
<var>EXPReceiver.java</var> to define the behaviour of a sending or
receiving protocol entity. More complex protocols could involve defining
separate entities to handle the service interface and the protocol entity.
It might also be necessary to define the formats of protocol messages and a
variation on the underlying <var>Medium</var> to match these.
</p>
<p>
Due to increased Java security, applets need to be signed by a proper
certificate. This has been done for the pre-compiled code. If you need to
rebuild the code you will need your own keystore and digital certificate.
See the Ant build file for how to use these.
</p>
<p>
Bear in mind that much of the development work was undertaken by
students, so the level of comments in the code is somewhat limited in
places. The ABP simulation is the simplest of the protocols and is a good
place to start. The TFTP simulation is the best commented and best
explained of the protocols. It illustrates nearly all the key points in
simulation development.
</p>
<!-- =================== Licence =================== -->
<h2>Licence</h2>
<p>
This program is free software. You can redistribute it and/or modify it
under the terms of the <a href="http://www.gnu.org/copyleft/gpl.html"
target="_blank">GNU General Public License</a> as published by the Free
Software Foundation - either version 3 of the License, or (at your option)
any later version.
</p>
<p>
This program is distributed in the hope that it will be useful but
<strong>without any warranty</strong>, without even the implied warranty
of <strong>merchantability</strong> or <strong>fitness for a particular
purpose</strong>. See the GNU General Public License for more details.
</p>
<!-- =================== Acknowledgements =================== -->
<h2>Acknowledgements</h2>
<p>
The protocol simulator was developed by <a href="http://www.cs.stir.ac.uk/"
target="_blank">Computing Science and Mathematics</a> at the <a
href="http://www.stir.ac.uk/" target="_blank">University of Stirling</a>.
Iain A. Robin undertook most of the development for his Master's project
under Ken Turner&#39;s supervision. Paul Johnson and Kenneth A. Whyte
contributed to the development of some of the simulations for their Master's
projects. Dr. Peter J. B. King, Heriot-Watt University, provided helpful
ideas and suggestions.
</p>
<!-- =================== History =================== -->
<h2>History</h2>
<ul>
<li>
<p>
Version 1.0: Private internal version, Iain Robin, 1st September 1999
</p>
</li>
<li>
<p>
Version 1.1: Private internal version, Ken Turner, 22nd December 2000
</p>
</li>
<li>
<p>
Version 1.2: Private internal version, Ken Turner, 5th March 2001
</p>
</li>
<li>
<p>
Version 1.3: First public release, Ken Turner 6th June 2001
</p>
</li>
<li>
<p>
Version 1.4: General updating, Ken Turner, 9th March 2006:
</p>
</li>
<ul>
<li>HTML files updated to be XHTML-compliant.</li>
<li>
Source updated for JDK 1.5, and Swing graphics used. Note that JDK 1.5
or later is now required to re-compile the source or to run the code.
</li>
<li>
Top-level directory structure revised to have <var>source</var>,
<var>build</var> and <var>docs</var> directories.
</li>
<li>
<var>Makefile</var> replaced by Ant <var>build</var> file. Only
<var>build</var> and <var>clean</var> batch files retained. (Thanks
to Dr. Peter J. B. King, Heriot-Watt University, for contributing to
this.)
</li>
<li>
Blank lines ignored in scenario files.
</li>
<li>
<var>ABP</var> and <var>SWP3</var> medium control is now
offered through a parameter (delivery/loss, delivery only, automatic).
It would be possible in principle use this with other protocols, but
makes sense in only some cases. (Thanks to Dr. Peter J. B. King,
Heriot-Watt University, for contributing to this.)
</li>
<li>
<var>SMTP</var> protocol messages have been slightly renamed for
consistency with the RFC.
</li>
<li>
<var>TCP</var> default window size restored on restart.
Acknowledgements now sent on receipt of data, and not when
receiving window becomes full. Some complex changes caused by this.
Data pending delivery now sent to user prior to Closed. Open while
still Closing now leads to Closed when fully closed rather than
immediately. Duplicate SYN plus ACK now cancels any retransmissions
while Established.
</li>
</ul>
<li>
<p>
Version 1.5: Extensions for new protocols, Ken Turner, 11th February
2011
</p>
</li>
<ul>
<li>
Major new work has been undertaken for Pearson Education on new
simulations (CSMA/CD, Multicast, Multiplexing, Protocol Stack, TCP Slow
Start) to accompany the ninth edition of "Data and Computer
Communications" by William Stallings.
</li>
<li>
More comments, particularly JavaDoc, have been added to many files
(which have also been reformatted).
</li>
<li>
More thorough checks of values have been added to the JavaScript in HTML
files. In addition, the HTML files have been revised and reformatted.
</li>
<li>
The <var>TimeSequenceDiagram</var> class has been modified. Vertical
space is now added before a DELIVER protocol event, and also before a
COMMENT (even if it is not the first). A TRAVERSE protocol event has
been added to deal with the situation that a dashed arrow crosses
multiple columns. A corresponding <var>TraverseTransmission</var> class
has been added.
</li>
<li>
The <var>Medium</var> class has been extended with two
<var>isEmpty</var> methods: one to check if the medium is completely
empty of messages, and one to check if the medium is empty of messages
from a particular source.
</li>
<li>
All <var>TCP</var> classes have been extended to support the slow-start
variant (<var>TCP/ss</var>). In addition, some problems with TCP have
been corrected (obscure situations in which the protocol did not recover
when trying to close). The <var>TIME_WAIT</var> state is now used to
cope with these situations, including more abrupt termination when FIN
is received in unusual situations.
</li>
<li>
A <var>Protocol</var> can now now implement the methods
<var>getRandNumbers</var> and <var>setRandomNumbers</var> (by default
these do nothing useful). If these methods are implemented, a list of
the random numbers is appended to the scenario header line when the
scenario is saved, and is restored when the scenario is loaded. This is
for protocols such as CSMA that generate their own random numbers (as
opposed to media that do so as per previous releases). The header line
is now in a format such as "Jasper CSMA 0.3,0.01,0.891". If no random
numbers are present following the protocol type (as is the case with
previous scenario files) then no action is taken.
</li>
</ul>
<li>
<p>
Version 1.6: Distribution via SourceForge, Ken Turner, 18th December
2014
</p>
</li>
<ul>
<li>
The simulator has been packaged and made available via SourceForge.
</li>
</ul>
<li>
<p>
Version 1.7: Update for Java 7u51 onwards, Ken Turner, 28th September
2015
</p>
</li>
<ul>
<li>
The build file now sets the "Caller-Allowable-Codebase" attribute in the
simulator JAR manifest. This is so that more recent Java versions will
allow JavaScript access to the simulator applet. The user will be asked
to grant access to the applet from any file URL.
</li>
<li>
The pre-built simulator JAR has been signed with a later University of
Stirling certificate valid up to August 2018.
</li>
</ul>
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -0,0 +1,161 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- ABP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Alternating Bit Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var mediumType;
var mediumTypeOld;
function set() {
mediumType =
document.settings.medium[0].checked
? 2
: document.settings.medium[1].checked
? 1
: 0;
if (mediumType != mediumTypeOld) {
mediumTypeOld = mediumType;
simulator.setParameter("mediumType", mediumType);
simulator.restart();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>Alternating Bit Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
ABP (Alternating Bit Protocol) is a connection-less protocol for
transferring messages in one direction between a pair of protocol
entities. It is a simple form of the <a href="SWP3.html">Sliding Window
Protocol</a> with a window size of 1. The message sequence numbers simply
alternate between 0 and 1.
</p>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This will cause the simulation to restart.
</p>
<p>
Optionally set the level of control that the simulator user needs over
the medium:
</p>
<dl>
<dt><b>Automatic</b>:</dt>
<dd>
Messages are delivered immediately without loss. This is suitable for
initial experimentation, but limits what can be explored. For example,
message are never lost and never have to be timed out and resent.
</dd>
<dt><b>Delivery</b>:</dt>
<dd>
Alternatively, message delivery may be controlled - though messages
will still never be lost. Choose this option to allow messages to be
delivered in different orders and to be resent.
</dd>
<dt><b>Delivery/Loss</b>:</dt>
<dd>
Finally, delivery and loss of messages may be completely controlled.
This is the most comprehensive option, but also the most complex one to
manage.
</dd>
</dl>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">Medium Control:</td>
<td>
<input type="radio" name="medium" value="2"
checked="checked"/>Automatic
</td>
<td><input type="radio" name="medium" value="1"/>Delivery</td>
<td><input type="radio" name="medium" value="0"/>Delivery/Loss</td>
</tr>
<tr>
<td align="center" colspan="4">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
<td colspan="3"></td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with transmitting
and receiving protocol entities, and a communications medium that carries
messages. The transmitter simply sends messages numbered <em>DATA(0)</em>
or <em>DATA(1)</em>; the content of messages is not identified. These are
acknowledged with <em>ACK(1)</em> or <em>ACK(0)</em> respectively. Note
that if a <em>DATA</em> message is received again due to re-transmission,
it is acknowledged but discarded.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="600" height="700"
name="ProtocolSimulator">
<param name="protocol" value="ABP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,107 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- ABRA.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Abracadabra Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Abracadabra Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
Abracadabra (Alternating Bit Protocol with Connection and Disconnection)
is a connection-oriented protocol that allows data to be sent in either
direction using the <a href="ABP.html">Alternating Bit Protocol</a>. Data
transfer is preceded by connection and followed by disconnection.
</p>
<p>
The initiating user requests a connection with <em>ConReq</em>. This is
sent as a <em>CR</em> protocol message. The other user receives
<em>ConInd</em> as an indication that a connection attempt has been
received. Normally it will respond positively to the connection attempt
with <em>ConResp</em>. This leads to a <em>CC</em> confirmation in the
protocol, and a <em>ConConf</em> confirmation back to the initiating
user. However the responding user may also reject a connection attempt
with a <em>DisReq</em> disconnection request. This leads to a <em>DR</em>
in the protocol and <em>DisInd</em> at the originator. If <em>CR</em>
connection messages are sent by both protocol entities simultaneously,
each acknowledges the other and the connection is set up.
</p>
<p>
Once a connection has been made, either user sends data messages as
<em>DatReq(DATA0)</em> or <em>DatReq(DATA1)</em>; the content of messages
is not explicitly identified. These requests lead to delivery at the
other user with <em>DatInd(DATA0)</em> or <em>DatInd(DATA1)</em>. The
protocol carries data as <em>DT(0)</em> or <em>DT(1)</em> messages that
give only the sequence number, not the data. These are acknowledged with
<em>AK(1)</em> or <em>AK(0)</em> respectively. Note that if a <em>DT</em>
message is received again due to re-transmission, it is acknowledged but
discarded. Both users may be sending data at the same time.
</p>
<p>
Disconnection is requested with <em>DisReq</em>. This causes a
<em>DR</em> message to be sent in the protocol, indicating disconnection
at the other user with <em>DisInd</em>. The remote protocol entity
confirms disconnection with <em>DC</em>. If <em>DR</em> disconnection
messages are sent by both protocol entities simultaneously, each sends
back a <em>DC</em> as confirmation. Since both users tried to disconnect
at the same time, each has issued <em>DisReq</em> and does not see
<em>DisInd</em>.
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with users A and B,
protocol entities A and B that support them, and a communications medium
that carries messages. Either user may open a connection, then send data,
and finally break the connection. There may be only one connection at a
time between a pair of users.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="ABRA"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,93 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- BOOTP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Boot Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Boot Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
BOOTP (Boot Protocol) is a simple connection-less protocol, typically
used by a discless workstation to discover its Internet address and/or
the name of its bootstrap file. BOOTP operates over <a
href="UDP.html">UDP (User Datagram Protocol)</a>. BOOTP simply discovers
the parameters needed for the bootstrap procedure. Typically, <a
href="TFTP.html">TFTP (Trivial File Transfer Protocol)</a> is used to
download the bootstrap file itself.
</p>
<p>
A boot client supplies a transaction identifier and its hardware address.
The client may optionally supply its network address; the server will
allocate a unique network address if required. The client may optionally
supply the name of the boot file; the server will supply the full path
name if this file is given, or will determine the boot file the client
needs. Addresses and the boot file are given symbolic names in the
simulation.
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with client and
server protocol entities, and a communications medium that carries
messages. The client sends a <em>REQUEST</em> message containing an
(arbitrary) transaction identifier and its hardware address
(<em>hw</em>). The client may optionally supply its network address if it
knows it (e.g. <em>net.43</em> for some subnetwork <em>net</em>). The
client may additionally ask for the location of a particular bootstrap
file (<em>boot</em>). The server reply starts with the original
parameters. A network address is allocated to the client if it did not
know it. The full filestore path to a boot file is returned if the client
did not know which file to use. If the client named a boot file, the full
path to this is returned. If a <em>REQUEST</em> or <em>REPLY</em> message
is lost, the client must time out and send it again.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="BOOTP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,220 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- CSMA.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSMA/CD ("Ethernet")</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var serviceCount;
var serviceMode;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
retryLimit = document.settings.retryLimit.value;
if (validInteger("Retry Limit", retryLimit, 0, 5)) {
simulator.setParameter("retryLimit", retryLimit);
simulator.restart();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>CSMA/CD (Ethernet)</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
CSMA/CD (Carrier Sense, Multiple Access, Collision Detection) illustrates
how multiple systems can share a common communications medium. CSMA/CD is
best known in the form of Ethernet - a kind of LANs (Local Area Network).
LANs have a MAC layer (Medium Access Control) that operates the data link
protocol.
</p>
<p>
Many systems (known as stations) can be attached to an Ethernet - the
Multiple Access aspect. A station will not transmit if it finds that another
station is already using the Ethernet - the Carrier Sense aspect. However,
it is still possible for two stations to transmit at almost the same time.
While a station is transmitting, it may find that another station has
already begun its own transmission - the Collision Detection aspect. In such
a case, each station backs off and tries again - hopefully avoiding a
collision on the second or later attempt.
</p>
<p>
An Ethernet is a broadcast medium: whatever one station sends is received by
all others. Each message carries the address of its intended destination;
only the station with this address will act on the message. A transmission
takes a very short (but not zero) time to arrive at its destination. Since
stations will be at different distances from each other, the transmission
time between them varies. The maximum transmission time between any two
stations is called the slot time.
</p>
<p>
Ethernet does not provide any guarantee of correct delivery, so its protocol
can be simple. Instead, a higher-level protocol such as TCP (Transmission
Control Protocol) is responsible for detecting and correcting errors.
</p>
<p>
Transmission proceeds in one of the following ways:
</p>
<dl>
<dt><b>Normal:</b></dt>
<dd>
The station transmits its message from start to finish. When the message
has been fully received at the intended destination, that station
processes the message.
</p>
</dd>
<dt><b>Deferral:</b></dt>
<dd>
<p>
In fact, a station listens for a transmission from another station
before beginning its own transmission. If it hears such a transmission,
it defers to the other station. Once that transmission has finished, the
station begins its own transmission.
</p>
</dd>
<dt><b>Collision:</b></dt>
<dd>
<p>
However, this does not avoid interference. For example, a distant
station may have started transmission but its signal has not yet
arrived. The local station may therefore think the network is not in use
and begin its own transmission. Both transmissions will then collide in
the network. This can be detected by the transmitting stations, but this
is not always fully reliable. The stations therefore ensure that the
collision is properly detected by sending a jam signal.
</p>
<p>
Following this, each station backs off a random delay (a number of slot
times) before retrying its transmission. Ideally, one station should
choose a smaller delay and so start retransmitting before the other one.
</p>
<p>
For the first retransmission, the random delay is 0 or 1 slot times.
Since two stations may choose the same delay, there is a 50% chance that
they retry at the same point (and therefore collide again). On further
collisions, the maximum delay is doubled (0 to 2, 0 to 4, etc.). A limit
is set on the maximum number of retries.
</p>
</dd>
</dl>
<p>
For this simulation, only two stations are involved; addresses are therefore
not required. For simplicity, the protocol simulation below assumes that the
LAN works perfectly (no message corruption, loss or misordering). However,
interference among transmissions is still a source of potential error that
the protocol must cope with.
</p>
<h2>Protocol Parameters</h2>
<p>
By default, the simulation has a retry limit of 0. Since this means that
retries are not allowed, the simulation internally ensures that collisions
cannot occur. Retry limits from 1 to 5 can be used, but the possibility of
collisions complicates the behaviour. Click Change Settings after altering
the retry limit. This will restart the whole simulation.
</p>
<form name="settings">
<center>
<table cellspacing="5">
<tr>
<td align="right">Retry Limit (0 = no collisions, 5 maximum):</td>
<td><input name="retryLimit" size="4" value="0"></td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with two stations, the
MAC entities that support them, and a LAN that carries messages between
them. Stations transmit messages in the format <var>DATA(Dn)</var>. Data
messages are numbered <var>D0</var>, <var>D1</var>, etc.; no explicit data
content is given. If the retry limit is reached, this is reported to a
station with the message <var>FAIL(Retry Limit)</var>. Protocol messages
have the form <var>START(Dn)</var> to start a transmission,
<var>FINISH(Dn)</var> to finish the transmission, and <var>JAM</var> to jam
transmission.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="CSMA"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,102 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- HTTP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HyperText Transfer Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>HyperText Transfer Protocol Simulator
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
HTTP (Hypertext Transfer Protocol) is familiar as the mechanism for
delivering web pages. HTTP operates over <a href="TCPcs.html">TCP
(Transmission Control Protocol)</a> in client-server mode for reliable
transfer of data. URLs (Uniform Resource Locators) and information
contents are represented symbolically in the simulation (URL<em>n</em>,
DATA<em>n</em>). The protocol simulation deals with the main commands:
</p>
<ul>
<li><em>GET</em>: get data for URL</li>
<li><em>HEAD</em>: get header for URL</li>
<li><em>POST</em>: append data to URL</li>
<li>x<em>PUT</em>: send data to URL</li>
</ul>
<p>
The simulation supports a limited range of response codes:
</p>
<ul>
<li><em>200 OK</em>: the command completed successfully</li>
<li><em>301 MOVED</em>: the requested URL has moved to another location</li>
<li>
<em>400 ERROR</em>: the command encountered an error (not explicit in
the simulation)
</li>
</ul>
<p>
The protocol simulation shows a time-sequence diagram with client and
server protocol entities, and a communications medium that carries
messages. The client sends a one of the above commands and a URL. The
server makes one of the above replies. Since the medium is assumed to be
reliable, messages are never lost (though they may be delayed).
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="600" height="700"
name="ProtocolSimulator">
<param name="protocol" value="HTTP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,199 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- IP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
Internet Protocol
</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var userMessageSize;
var maxProtocolMessageSize;
var maxMediumMessageSize;
var lossRate;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function validFloat(name, value, min, max) {
if (!value.match("\\d+\.\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
userMessageSize = document.settings.userMessageSize.value;
maxProtocolMessageSize = document.settings.maxProtocolMessageSize.value;
maxMediumMessageSize = document.settings.maxMediumMessageSize.value;
lossRate = document.settings.lossRate.value;
if (validInteger("User Message Size", userMessageSize, 10, 1000) &&
validInteger(
"Maximum Protocol Message Size", maxProtocolMessageSize, 10, 1000) &&
validInteger(
"Maximum Medium Message Size", maxMediumMessageSize, 10, 1000) &&
validFloat("Loss Rate", lossRate, 0.0, 1.0)) {
simulator.setParameter("userMessageSize", userMessageSize);
simulator.setParameter("maxProtocolMessageSize", maxProtocolMessageSize);
simulator.setParameter("maxMediumMessageSize", maxMediumMessageSize);
simulator.setParameter("lossRate", lossRate);
if (document.settings.Misordering.checked)
simulator.setParameter("misordering","true");
else
simulator.setParameter("misordering","false");
simulator.updateActionList();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>Internet Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<p>
IP (Internet Protocol) a simple connection-less protocol for transferring
datagrams in either direction between a pair of hosts.
</p>
<p>
The protocol simulation shows a time-sequence diagram with users A and B,
protocol entities A and B that support them, and a communications medium
that carries messages. Users request data transmissions with
<em>DatReq(DATA<strong>n</strong>),</em> and receive data transmissions
as <em>DatInd(DATA<strong>n</strong>)</em>. Protocol messages are sent as
<em>DT(MID,Offset,Length)</em> that gives the message identifier
<em>n</em>, its byte offset relative to the whole user message, and the
length of the message (fragment). The user message size may exceed the
maximum protocol message size, which leads to fragmentation. The maximum
protocol message size may also exceed that for the medium, in which case
there may be further fragmentation. Each fragment is followed by `+&#39;
to mean that it is not the last; the very last fragment is followed by
`-&#39;. (This is equivalent to the <em>More Fragments</em> flag in the
protocol.)
</p>
<p>
You may choose if the receiving protocol entity should time out a partly
received message. Since the simulation does not run in real-time, a
message&#39;s Time-To-Live (TTL) may expire as soon as it has been
received in part. There is no control over fragmentation in the
simulation; this is handled automatically based on the protocol
parameters. Messages may also be randomly lost or misordered, based on
the parameter settings.
</p>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">User Message Size (10 to 1000):</td>
<td>
<input type="text" name="userMessageSize" value="400" size="4"/>
</td>
</tr>
<tr>
<td align="right">Maximum Protocol Message Size (10 to 1000):</td>
<td>
<input type="text" name="maxProtocolMessageSize" value="200"
size="4"/>
</td>
</tr>
<tr>
<td align="right">Maximum Medium Message Size (10 to 1000):</td>
<td>
<input type="text" name="maxMediumMessageSize" value="100"
size="4"/>
</td>
</tr>
<tr>
<td align="right">Loss Rate (0.0 = lose none, 1.0 = lose all):</td>
<td><input type="text" name="lossRate" value="0.2" size="4"/> </td>
</tr>
<tr>
<td align="right">Medium Message Misordering</td>
<td align="left">
<input type="checkbox" name="Misordering" checked="checked"/>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="IP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,182 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- MUX.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Multicasting</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var serviceMode;
function set() {
serviceMode = document.settings.serviceMode.value;
simulator.setParameter("serviceMode", serviceMode);
simulator.restart();
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>Multicasting</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
MCAST (Multicasting) illustrates how data can be sent from a source to
multiple destinations over a network. The following example shows a source,
three destinations, and a further host that has no interest in the data.
These are interconnected by routers A to F.
</p>
<center>
<img src="multicast.gif" alt="Multicast Illustration"/>
</center>
<p>
There are three strategies for sending data from the source to the
destinations:
</p>
<dl>
<dt><b>Broadcast</b>:</dt>
<dt>
<p>
If the source does not know which networks the destinations are on, it
must send a copy of the messages to each router that gives access to a
possible destination. In this example, the source must send data to
routers B, D, E and F. The result is inefficient in that 10 copies of
the message must be sent.
</p>
</dt>
<dt><b>Unicast</b>:</dt>
<dt>
<p>
If the source knows which networks the destinations are on, it can send
a copy of the messages only to the routers that gives access to these
destinations. In this example, the source must send data to routers B, D
and E. The result is more efficient than broadcast, but 8 copies of the
message must still be sent.
</p>
</dt>
<dt><b>Multicast</b>:</dt>
<dt>
<p>
The source can instead rely on the routers to distribute messages,
making copies only when necessary. In this example, the source sends
just one message to router A, stating that it is for routers B, D and E.
Router A looks at where the message is going, and delivers copies of the
message to routers B and C (when it states that the message is for
routers D and E). Router C then delivers copies of the message to
routers D and E. The result is more efficient than unicast, with only 5
copies of messages being sent. This is half the number for broadcast. On
a much larger network, the transmission savings of multicast can be
substantial.
</p>
</dt>
</dl>
<p>
Each router stores the messages it receives and forwards them to their
destination. The messages may be forwarded in any order since it depends on
how busy the communications links are. When trying the simulation, you may
find it easier to understand if you immediately forward router messages
rather than let them build up. For this simulation, the communications
channels are assumed to operate perfectly (no message corruption, loss or
misordering).
</p>
<h2>Protocol Parameters</h2>
<p>
By default, multicasting uses the broadcast strategy. You can modify the way
in which the protocol works by modifying the strategy. Click Change Settings
after making this alteration. This will restart the whole simulation.
</p>
<form name="settings">
<center>
<table cellspacing="5">
<tr>
<td align="right">Multicasting Strategy:</td>
<td>
<select name="serviceMode">
<option selected>Broadcast</option>
<option>Unicast</option>
<option>Multicast</option>
</select>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with the source and
the six routers. Messages have the format
<var>DT(Destinations,Mn)</var>. For broadcast and unicast, each
message has one destination; for multicast, there can be multiple
destinations. Messages are numbered <var>M0</var>, <var>M1</var>, etc.; no
explicit data
content is given.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="800" height="700"
name="ProtocolSimulator">
<param name="protocol" value="MCAST"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,190 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- MUX.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Multiplexer</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var serviceCount;
var serviceMode;
function valid(count, mode, overwrite) {
if (!count.match("\\d+") || count < 1 || count > 5) {
alert ("Source/sink count " + count + " must be in range 0-5");
return false;
}
else
return true;
}
function set() {
serviceCount = document.settings.serviceCount.value.toString();
serviceMode = document.settings.serviceMode.checked;
serviceOverwrite = document.settings.serviceOverwrite.checked;
if (valid(serviceCount, serviceMode, serviceOverwrite)) {
simulator.setParameter("serviceCount", serviceCount);
simulator.setParameter("serviceMode", serviceMode);
simulator.setParameter("serviceOverwrite", serviceOverwrite);
simulator.restart();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>Multiplexer</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
MUX (Multiplexer) illustrates how data can be multiplexed among multiple
sources and sinks via a shared communications channel. Each source
independently sends data indexed by its number to the corresponding sink
with the same number. At the source end, a multiplexer combines data from
the sources and sends it over a shared channel. At the sink end, a
demultiplexer splits the incoming channel data and sends it to the
corresponding sinks.
</p>
<center>
<img src="multiplexer.gif" alt="Multiplexer Illustration"/>
</center>
<p>
For this simulation, the communications channel is assumed to operate
perfectly (no message corruption, loss or misordering). When the multiplexer
sends a message, it therefore arrives directlyat the demultiplexer. It
follows that acknowledgements, sequence number and timeouts are not
applicable.
</p>
<p>
The multiplexer and demultiplexer exchange messages in a format that depends
on the kind of multiplexing:
</p>
<ul>
<li>
<p>
For synchronous multiplexing, the multiplexer periodically sends all
available data in a format such as <var>DT(D8,D4,...)</var>; this means
that source <var>0</var> is sending data <var>D8</var>, source
<var>1</var> is sending data <var>D4</var>, etc. If a source has not
supplied data before the multiplexer has sent a message, this is shown
as '-' (e.g. <var>DT(-,D4)</var> for data from source <var>1</var>
only).
</p>
</li>
<li>
<p>
For asynchronous multiplexing, the multiplexer sends individual source
data as it arrives in a format such as <var>DT(2,D6)</var>; this means
that source <var>2</var> is sending data <var>D6</var>.
</p>
</li>
</ul>
<p>
Perfect multiplexing would always operate faster than sources supply data
and sinks consume it. As an option, the simulation can allow multiplexing to
be slower than this. The result is that new data can overwrite data that has
been previously stored but not yet delivered.
</p>
<h2>Protocol Parameters</h2>
<p>
By default, multiplexing uses 2 sources/sinks, is synchronous, and does not
overwrite previous data. You can modify the way in which the protocol works
by modifying these settings (e.g. 1 to 5 sources/sinks). Click Change
Settings after making these alterations. This will restart the whole
simulation.
</p>
<form name="settings">
<center>
<table cellspacing="5">
<tr>
<td align="right">Number of Sources/Sinks:</td>
<td><input name="serviceCount" size="4" value="2"></td>
<td align="right">Asynchronous Multiplexing:</td>
<td align="left"><input type="checkbox" name="serviceMode"></td>
<td align="right">Data Overwriting:</td>
<td align="left"><input type="checkbox" name="serviceOverwrite"></td>
</tr>
<tr>
<td align="center" colspan="6">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with sources on one
side and sinks on the other, the multiplexer and demultiplexer that support
them, and a communications channel that carries messages. Sources request
data transmission with
<var>DATA(Source,Dn)</var>; the same messages arrive at sinks.
Sources/sinks are numbered <var>0</var>, <var>1</var>, etc. Data
messages are numbered <var>D0</var>, <var>D1</var>, etc.; no explicit data
content is given. The source/sink number and data number are usually
different (e.g. source <var>1</var> might sent data <var>D7</var>).
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="MUX"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- SMTP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Simple Mail Transfer Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Simple Mail Transfer Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
SMTP (Simple Mail Transfer Protocol) is used to transfer email messages.
SMTP operates over <a href="TCPcs.html">TCP (Transmission Control
Protocol)</a> in client-server mode for reliable transfer of data. The
protocol simulation deals with the main commands (sent in approximately
the order below):
</p>
<ul>
<li><em>HELO</em>: names the client (the spelling is deliberate)</li>
<li><em>MAIL FROM</em>: names the sender</li>
<li><em>RCPT TO</em>: names a recipient</li>
<li><em>DATA</em>: asks to send message data</li>
<li>c<em>Mail Message</em>: sends the message datac</li>
<li>c<em>QUIT</em>: finishes the mail sessionc</li>
</ul>
<p>
The simulation supports a limited range of response codes:
</p>
<ul>
<li>
<em>220 Server ready</em>: a connection to the server has been made and
the server is ready
</li>
<li>
<em>221 Server closing</em>: the server accepted the <em>QUIT</em>
command and is ready to close the connection
</li>
<li>
<em>250 OK</em>: the server accepted the command (one of several
similar responses)
</li>
<li>
<em>354 Send mail</em>: the server accepted the <em>DATA</em> command
and is waiting for the <em>Mail Message</em>
</li>
<li>
<em>550 Invalid</em>: the server rejected the command (one of several
similar responses)
</li>
</ul>
<p>
After the client connects to the server using TCP, the server reports its
readiness with a <em>220 Server ready</em> response. The client names
itself in <em>HELO</em>, to which the server normally gives a <em>250
Server hello to client</em> response. To send mail, the client issues
<em>MAIL FROM</em> and normally gets a <em>250 Sender OK</em> response.
Recipients are named in <em>RCPT TO</em>, normally obtaining <em>250
Recipient OK</em> responses. However the server can reject a sender or
recipient with a <em>550 Sender invalid</em> or <em>550 Recipient
invalid</em> response. Once all parties have been named, the client sends
<em>DATA</em> to begin message transmission; a <em>354 Send mail</em>
response is expected from the server. At this point, the real protocol
would send the lines of the message followed by a full stop. In the
simulation, a single <em>Mail Message</em> command stands for this. The
server will normally give a <em>250 Message accepted</em> response and
further messages can be sent. Finally, the client sends <em>QUIT</em> and
the server responds with a <em>221 Server closing</em> code. At this
point the TCP connection is broken.
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="600" height="700"
name="ProtocolSimulator">
<param name="protocol" value="SMTP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,101 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- STACK.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Protocol Stack</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>Protocol Stack</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
STACK (Protocol Stack) illustrates how data flows through a typical protocol
stack. As an application message passes down through the layers towards the
medium, each layer prefixes the message with its own control header.
Eventually the message with all headers is sent via the medium to its
destination. In the reverse direction, as a medium message passes up through
the layers towards the application, each layer interprets and strips off its
control header. Eventually the message with no headers is passed to the
application.
</p>
<p>
The Data Link layer is an exception because it usually adds a trailer
(typically a checksum) as well as its header. This trailer and header are
stripped off on reception..
</p>
<p>
For this simulation, the communications channel is assumed to operate
perfectly (no message corruption, loss or misordering). There is also no
fragmentation (layers do not split messages up) and no blocking (layers do
not combine messages). It follows that each application message corresponds
to one message over the medium.
</p>
<p>
The elements of a message are simply numbered <var>0</var>, <var>1</var>,
etc. withou explicit data content. An Application sends a message with data
such as <var>A3</var>. This is then prefixed with a Transport header
<var>T3</var>, a Network header <var>N3</var>, a Link header and trailer
<var>L3</var>, and a Physical header <var>P3</var>. When sent over the
medium, the whole message then looks like <var>P3:L3:N3:T3:A3:L3</var>. On
reception, the headers (and Link trailer) are stripped off so that the
receiving Application gets <var>A3</var> as sent.
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with the following
layers: Application (e.g. File Transfer Protocol), Transport (e.g.
Transmission Control Protocol), Network (e.g. Internet Protocol), Data Link
(e.g. Ethernet), Physical (e.g. Ethernet) and Medium (e.g. Unshielded
Twisted Pair cable).
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="800" height="700"
name="ProtocolSimulator">
<param name="protocol" value="STACK"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,234 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- SWP3.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Sliding Window Protocol (3-Column)</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var mediumType;
var mediumTypeOld;
var maxSeq;
var maxSeqOld = 7;
var winSize
var winSizeOld = 3;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
mediumType =
document.settings.medium[0].checked
? 2
: document.settings.medium[1].checked
? 1
: 0;
if (mediumType != mediumTypeOld) {
mediumTypeOld = mediumType;
simulator.setParameter("mediumType", mediumType);
simulator.restart();
}
maxSeq = document.settings.maxSeq.value;
winSize = document.settings.winSize.value;
if (validInteger("Maximum Sequence Number", maxSeq, 1, 31) &&
validInteger("Window Size", winSize, 1, 31)) {
maxSeq = parseInt(maxSeq);
winSize = parseInt(winSize);
if (winSize <= maxSeq) {
if (maxSeq != maxSeqOld || winSize != winSizeOld) {
maxSeqOld = maxSeq;
winSizeOld = winSize;
simulator.setParameter("maxSeq", maxSeq);
simulator.setParameter("winSize", winSize);
simulator.restart();
}
}
else
alert("Window Size must be 1 to the Maximum Sequence Number");
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>
Sliding Window Protocol Simulator
<br/>
(3-Column)
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
SWP (Sliding Window Protocol) a connection-less protocol. It allows data
to be sent in one direction between a pair of protocol entities, subject to
a maximum number of unacknowledged messages. If SWP is operated with a
window size of 1, it is equivalent to the <a href="ABP.html">Alternating Bit
Protocol</a>. The simulation below does not include the users; see the <a
href="SWP5.html">five-column</a> version for this.
</p>
<p>
The protocol has a maximum number of messages that can be sent without
acknowledgement. If this window becomes full, the protocol is blocked
until an acknowledgement is received for the earliest outstanding
message. At this point the transmitter is clear to send more messages.
</p>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This may cause the simulation to restart.
</p>
<p>
Optionally set the level of control that the simulator user needs over
the medium:
</p>
<dl>
<dt><b>Automatic</b>:</dt>
<dd>
Messages are delivered immediately without loss. This is suitable for
initial experimentation, but limits what can be explored. For example,
message are never lost and never have to be timed out and resent.
</dd>
<dt><b>Delivery</b>:</dt>
<dd>
Alternatively, message delivery may be controlled - though messages
will still never be lost. Choose this option to allow messages to be
delivered in different orders and to be resent.
</dd>
<dt><b>Delivery/Loss</b>:</dt>
<dd>
Finally, delivery and loss of messages may be completely controlled.
This is the most comprehensive option, but also the most complex one to
manage.
</dd>
</dl>
<p>
Optionally set the maximum sequence number used by the protocol: this is
one less than the modulus. Sequence numbers wrap round to zero when they
pass the maximum. Optionally set the maximum window size permitted: this
must not exceed the maximum sequence number. Changing either of these
parameters will restart the simulation.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">Medium Control:</td>
<td>
<input type="radio" name="medium" value="2"
checked="checked"/>Automatic
</td>
<td>
<input type="radio" name="medium" value="1"/>Delivery
</td>
<td>
<input type="radio" name="medium" value="0"/>Delivery/Loss
</td>
</tr>
<tr>
<td align="right">Maximum Sequence Number (1 to 31):</td>
<td colspan="3">
<input type="text" name="maxSeq" value="7" size="2"/>
</td>
</tr>
<tr>
<td align="right">Window Size (1 to Maximum Sequence Number):</td>
<td colspan="3">
<input type="text" name="winSize" value="3" size="2"/>
</td>
</tr>
<tr>
<td align="center" colspan="4">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with transmitting
and receiving protocol entities, and a communications medium that carries
messages. The transmitter simply sends messages numbered <em>DT(0)</em>,
<em>DT(1)</em>, etc. Once sequence numbers reach a maximum number (like
7), they wrap back round to 0. The content of messages is not explicitly
identified. An acknowledgement <em>AK(n)</em> means that the <em>DT</em>
message numbered <em>n</em> is the next one expected (i.e. all messages
up to but not including this number have been received). Since sequence
numbers wrap round, an acknowledgement with sequence number 1 refers to
messages 0, 1, 7, 6, etc. Note that if a <em>DT</em> message is received
again due to re-transmission, it is acknowledged but discarded.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="600" height="700"
name="ProtocolSimulator">
<param name="protocol" value="SWP3"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,169 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- SWP5.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
Sliding Window Protocol (5-Column)
</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var maxSeq;
var maxSeqOld = 7;
var winSize
var winSizeOld = 3;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set () {
maxSeq = document.settings.maxSeq.value;
winSize = document.settings.winSize.value;
if (validInteger("Maximum Sequence Number", maxSeq, 1, 31) &&
validInteger("Window Size", winSize, 1, 31)) {
maxSeq = parseInt(maxSeq);
winSize = parseInt(winSize);
if (winSize <= maxSeq) {
if (maxSeq != maxSeqOld || winSize != winSizeOld) {
maxSeqOld = maxSeq;
winSizeOld = winSize;
simulator.setParameter("maxSeq", maxSeq);
simulator.setParameter("winSize", winSize);
simulator.restart();
}
}
else
alert("Window Size must be 1 to the Maximum Sequence Number");
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator">
<div style="text-align: center">
<h1>
Sliding Window Protocol Simulator
<br/>
(5-Column)
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<p>
SWP (Sliding Window Protocol) is a connection-less protocol in one
direction between a pair of users. It allows data to be sent in one
direction subject to a maximum number of unacknowledged messages. If SWP is
operated with a window size of 1, it is equivalent to the <a
href="ABP.html">Alternating Bit Protocol</a>. The simulation below includes
the users; the <a href="SWP3.html">three-column</a> version omits them.
</p>
<p>
The protocol has a maximum number of messages that can be sent without
acknowledgement. If this window becomes full, the protocol is blocked
until an acknowledgement is received for the earliest outstanding
message. At this point the transmitter is clear to send more messages.
</p>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This may cause the simulation to restart.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">Maximum Sequence Number (1 to 31):</td>
<td><input type="text" name="maxSeq" value="7" size="2"/></td>
</tr>
<tr>
<td align="right">Window Size (1 to Maximum Sequence Number):</td>
<td><input type="text" name="winSize" value="3" size="2"/></td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with users A and B,
protocol entities A and B that support them, and a communications medium
that carries messages. Users request data transmissions with
<em>DatReq(DATAn),</em> and receive data transmissions as
<em>DatInd(DATAn)</em>. Data messages are simply numbered <em>DATA0</em>,
<em>DATA1</em>, etc. without explicit content. The transmitting protocol
sends the protocol message <em>DT(n)</em> that gives only the sequence
number, not the data. Once sequence numbers reach a maximum number (like
7), they wrap back round to 0. An acknowledgement <em>AK(n)</em> means
that the <em>DT</em> message numbered <em>n</em> is the next one expected
(i.e. all messages up to but not including this number have been
received). Since sequence numbers wrap round, an acknowledgement with
sequence number 1 refers to messages 0, 1, 7, 6, etc. Note that if a
<em>DT</em> message is received again due to re-transmission, it is
acknowledged but discarded.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="SWP5"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,280 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- TCPcs.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Transmission Control Protocol (Client-Server)</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var userAMessageSize;
var userAMessageSizeOld = 100;
var userBMessageSize;
var userBMessageSizeOld = 300;
var windowSizeA;
var windowSizeAOld = 500;
var windowSizeB;
var windowSizeBOld = 400;
var maxSendPacket;
var maxSendPacketOld = 200;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function validFloat(name, value, min, max) {
if (!value.match("\\d+\.\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
userAMessageSize = document.settings.userAMessageSize.value;
userBMessageSize = document.settings.userBMessageSize.value;
windowSizeA = document.settings.windowSizeA.value;
windowSizeB = document.settings.windowSizeB.value;
maxSendPacket = document.settings.maxSendPacket.value;
lossRate = document.settings.lossRate.value;
if (validInteger("User A Message Size", userAMessageSize, 10, 1000) &&
validInteger("User B Message Size", userBMessageSize, 10, 1000) &&
validInteger("Protocol A Receive Window", windowSizeA, 10, 1000) &&
validInteger("Protocol B Receive Window", windowSizeB, 10, 1000) &&
validInteger("Medium Maximum Packet Size", maxSendPacket, 10, 1000) &&
validFloat("Loss Rate", lossRate, 0.0, 1.0)) {
if (userAMessageSize != userAMessageSizeOld ||
userBMessageSize != userBMessageSizeOld ||
windowSizeA != windowSizeAOld ||
windowSizeB != windowSizeBOld ||
maxSendPacket != maxSendPacketOld)
simulator.restart();
userAMessageSizeOld = userAMessageSize;
userBMessageSizeOld = userBMessageSize;
windowSizeAOld = windowSizeA;
windowSizeBOld = windowSizeB;
maxSendPacketOld = maxSendPacket;
simulator.setParameter("userAMessageSize", userAMessageSize);
simulator.setParameter("userBMessageSize", userBMessageSize);
simulator.setParameter("windowSizeA", windowSizeA);
simulator.setParameter("windowSizeB", windowSizeB);
simulator.setParameter("maxSendPacket", maxSendPacket);
simulator.setParameter("lossRate", lossRate);
if (document.settings.pushA.checked)
simulator.setParameter("pushA", "true");
else
simulator.setParameter("pushA", "false");
if (document.settings.pushB.checked)
simulator.setParameter("pushB", "true");
else
simulator.setParameter("pushB", "false");
simulator.updateActionList();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator">
<div style="text-align: center">
<h1>
Transmission Control Protocol Simulator
<br/>
(Client-Server)
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
TCP (Transmission Control Protocol) is a connection-oriented protocol for
transferring data reliably in either direction between a pair of users. TCP
is a rather complex protocol, so it is easy to lose track of the simulation.
Try not to do anything too complicated! There is a <a
href="TCPpp.html">peer-peer</a> version as an alternative to this
client-server simulation. The <a href="TCPss.html">slow start</a> simulation
deals with only congestion avoidance.
</p>
<p>
Users simply send messages of a fixed size; the content of messages is not
identified. The medium maximum packet size is the protocol segment size.
Depending on this, messages may be sent as a number of fragments. Data
transfer is also subject to the current window size of the receiver, and may
be held up if the receiver&#39;s window becomes full.
</p>
<p>
To open a connection, a message is sent with the SYN (synchronise) flag.
To close a connection, a message is sent with the FIN (finish) flag.
Urgent messages may also be sent by selecting the PSH (push) flag as a
protocol parameter.
</p>
<p>
When data arrives, it is not immediately delivered to the receiving user
unless the PSH flag is set. Ordinary data is accumulated, and can be
delivered later (&quot;Deliver octets to user&quot;). If the destination's
receiving window becomes full, new requests to send data will be buffered.
When the receiving window opens again, this buffered data can be sent
(&quot;Send octets to peer&quot;).
</p>
<p>
Messages may contain a send sequence number (the offset of where the message
starts in the user&#39;s octet stream), an acknowledgement sequence number
(the offset of the next octet expected), and the current window (how many
octets can be received).
</p>
<p>
TCP is rather complex, so the simulation does not attempt to faithfully
reflect all its details. Although the main paths should work as expected, it
may be possible to get the simulation into unusual states in which it does
not behave correctly.
</p>
<p>
Things the simulation does not cover include the following. See advanced
guides to TCP for more information.
</p>
<ul>
<li>losing an ACK that opens up the window</li>
<li>&quot;silly window&quot; syndrome</li>
<li>adaptive retransmission strategies</li>
<li>congestion avoidance strategies</li>
<li>dynamic window management</li>
</ul>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This may cause the simulation to restart.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">User A Message Size (10 to 1000):</td>
<td>
<input type="text" name="userAMessageSize" value="100" size="4"/>
</td>
<td align="right">User A Push Flag:</td>
<td align="left"><input type="checkbox" name="pushA"/> </td>
</tr>
<tr>
<td align="right">User B Message Size (10 to 1000):</td>
<td><input name="userBMessageSize" size="4" value="300"/> </td>
<td align="right">User B Push Flag:</td>
<td align="left"><input type="checkbox" name="pushB"/></td>
</tr>
<tr>
<td align="right">Protocol A Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeA" value="500" size="4"/></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">Protocol B Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeB" value="400" size="4"/></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">Medium/Protocol Segment Size (10 to 1000):</td>
<td>
<input type="text" name="maxSendPacket" value="200" size="4"/>
</td>
</tr>
<tr>
<td align="right">Loss Rate (0.0 = lose none, 1.0 = lose any):</td>
<td><input type="text" name="lossRate" value="0.2" size="4"/> </td>
</tr>
<tr>
<td align="center" colspan="4">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with a client and a
server, protocol entities that support them, and a communications medium
(network) that carries messages. The server initially passively opens
(waits) for a connection. The client may actively open a connection to the
waiting server. After a connection has been made, the client and the server
may send data messages to each other.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="TCP/cs"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,279 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- TCPpp.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Transmission Control Protocol (Peer-Peer)</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var userAMessageSize;
var userAMessageSizeOld = 100;
var userBMessageSize;
var userBMessageSizeOld = 300;
var windowSizeA;
var windowSizeAOld = 500;
var windowSizeB;
var windowSizeBOld = 400;
var maxSendPacket;
var maxSendPacketOld = 200;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function validFloat(name, value, min, max) {
if (!value.match("\\d+\.\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
userAMessageSize = document.settings.userAMessageSize.value;
userBMessageSize = document.settings.userBMessageSize.value;
windowSizeA = document.settings.windowSizeA.value;
windowSizeB = document.settings.windowSizeB.value;
maxSendPacket = document.settings.maxSendPacket.value;
lossRate = document.settings.lossRate.value;
if (validInteger("User A Message Size", userAMessageSize, 10, 1000) &&
validInteger("User B Message Size", userBMessageSize, 10, 1000) &&
validInteger("Protocol A Receive Window", windowSizeA, 10, 1000) &&
validInteger("Protocol B Receive Window", windowSizeB, 10, 1000) &&
validInteger("Medium Maximum Packet Size", maxSendPacket, 10, 1000) &&
validFloat("Loss Rate", lossRate, 0.0, 1.0)) {
if (userAMessageSize != userAMessageSizeOld ||
userBMessageSize != userBMessageSizeOld ||
windowSizeA != windowSizeAOld ||
windowSizeB != windowSizeBOld ||
maxSendPacket != maxSendPacketOld)
simulator.restart();
userAMessageSizeOld = userAMessageSize;
userBMessageSizeOld = userBMessageSize;
windowSizeAOld = windowSizeA;
windowSizeBOld = windowSizeB;
maxSendPacketOld = maxSendPacket;
simulator.setParameter("userAMessageSize", userAMessageSize);
simulator.setParameter("userBMessageSize", userBMessageSize);
simulator.setParameter("windowSizeA", windowSizeA);
simulator.setParameter("windowSizeB", windowSizeB);
simulator.setParameter("maxSendPacket", maxSendPacket);
simulator.setParameter("lossRate", lossRate);
if (document.settings.pushA.checked)
simulator.setParameter("pushA", "true");
else
simulator.setParameter("pushA", "false");
if (document.settings.pushB.checked)
simulator.setParameter("pushB", "true");
else
simulator.setParameter("pushB", "false");
simulator.updateActionList();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator">
<div style="text-align: center">
<h1>
Transmission Control Protocol Simulator
<br/>
(Peer-Peer)
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
TCP (Transmission Control Protocol) is a connection-oriented protocol for
transferring data reliably in either direction between a pair of users. TCP
is a rather complex protocol, so it is easy to lose track of the simulation.
Try not to do anything too complicated! There is a <a
href="TCPcs.html">client-server</a> version as an alternative to this
peer-peer simulation. The <a href="TCPss.html">slow start</a> simulation
deals with only congestion avoidance.
</p>
<p>
Users simply send messages of a fixed size; the content of messages is not
identified. The medium maximum packet size is the protocol segment size.
Depending on this, messages may be sent as a number of fragments. Data
transfer is also subject to the current window size of the receiver, and may
be held up if the receiver&#39;s window becomes full.
</p>
<p>
To open a connection, a message is sent with the SYN (synchronise) flag.
To close a connection, a message is sent with the FIN (finish) flag.
Urgent messages may also be sent by selecting the PSH (push) flag as a
protocol parameter.
</p>
<p>
When data arrives, it is not immediately delivered to the receiving user
unless the PSH flag is set. Ordinary data is accumulated, and can be
delivered later (&quot;Deliver octets to user&quot;). If the destination's
receiving window becomes full, new requests to send data will be buffered.
When the receiving window opens again, this buffered data can be sent
(&quot;Send octets to peer&quot;).
</p>
<p>
Messages may contain a send sequence number (the offset of where the message
starts in the user&#39;s octet stream), an acknowledgement sequence number
(the offset of the next octet expected), and the current window (how many
octets can be received).
</p>
<p>
TCP is rather complex, so the simulation does not attempt to faithfully
reflect all its details. Although the main paths should work as expected, it
may be possible to get the simulation into unusual states in which it does
not behave correctly.
</p>
<p>
Things the simulation does not cover include the following. See advanced
guides to TCP for more information.
</p>
<ul>
<li>losing an ACK that opens up the window</li>
<li>&quot;silly window&quot; syndrome</li>
<li>adaptive retransmission strategies</li>
<li>congestion avoidance strategies</li>
<li>dynamic window management</li>
</ul>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This may cause the simulation to restart.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">User A Message Size (10 to 1000):</td>
<td>
<input type="text" name="userAMessageSize" value="100" size="4"/>
</td>
<td align="right">User A Push Flag:</td>
<td align="left"><input type="checkbox" name="pushA"/> </td>
</tr>
<tr>
<td align="right">User B Message Size (10 to 1000):</td>
<td><input name="userBMessageSize" size="4" value="300"/> </td>
<td align="right">User B Push Flag:</td>
<td align="left"><input type="checkbox" name="pushB"/></td>
</tr>
<tr>
<td align="right">Protocol A Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeA" value="500" size="4"/></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">Protocol B Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeB" value="400" size="4"/></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">Medium/Protocol Segment Size (10 to 1000):</td>
<td>
<input type="text" name="maxSendPacket" value="200" size="4"/>
</td>
</tr>
<tr>
<td align="right">Loss Rate (0.0 = lose none, 1.0 = lose any):</td>
<td><input type="text" name="lossRate" value="0.2" size="4"/> </td>
</tr>
<tr>
<td align="center" colspan="4">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with two peer service
users, protocol entities that support them, and a communications medium
(network) that carries messages. Either peer actively opens a connection, to
which the other peer responds. After a connection has been made, the two
peers may send data messages to each other.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="TCP/pp"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,330 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- TCPss.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Transmission Control Protocol (Slow Start)</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var userAMessageSize;
var userAMessageSizeOld = 100;
var userBMessageSize;
var userBMessageSizeOld = 300;
var windowSizeA;
var windowSizeAOld = 500;
var windowSizeB;
var windowSizeBOld = 400;
var maxSendPacket;
var maxSendPacketOld = 200;
function validInteger(name, value, min, max) {
if (!value.match("\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function validFloat(name, value, min, max) {
if (!value.match("\\d+\.\\d+") || value < min || value > max) {
alert("Value for " + name + " must be in range " + min + " to " + max);
return false;
}
else
return true;
}
function set() {
userAMessageSize = document.settings.userAMessageSize.value;
userBMessageSize = document.settings.userBMessageSize.value;
windowSizeA = document.settings.windowSizeA.value;
windowSizeB = document.settings.windowSizeB.value;
maxSendPacket = document.settings.maxSendPacket.value;
lossRate = document.settings.lossRate.value;
if (validInteger("User A Message Size", userAMessageSize, 10, 1000) &&
validInteger("User B Message Size", userBMessageSize, 10, 1000) &&
validInteger("Protocol A Receive Window", windowSizeA, 10, 1000) &&
validInteger("Protocol B Receive Window", windowSizeB, 10, 1000) &&
validInteger("Medium Maximum Packet Size", maxSendPacket, 10, 1000) &&
validFloat("Loss Rate", lossRate, 0.0, 1.0)) {
if (userAMessageSize != userAMessageSizeOld ||
userBMessageSize != userBMessageSizeOld ||
windowSizeA != windowSizeAOld ||
windowSizeB != windowSizeBOld ||
maxSendPacket != maxSendPacketOld)
simulator.restart();
userAMessageSizeOld = userAMessageSize;
userBMessageSizeOld = userBMessageSize;
windowSizeAOld = windowSizeA;
windowSizeBOld = windowSizeB;
maxSendPacketOld = maxSendPacket;
simulator.setParameter("userAMessageSize", userAMessageSize);
simulator.setParameter("userBMessageSize", userBMessageSize);
simulator.setParameter("windowSizeA", windowSizeA);
simulator.setParameter("windowSizeB", windowSizeB);
simulator.setParameter("maxSendPacket", maxSendPacket);
simulator.setParameter("lossRate", lossRate);
simulator.updateActionList();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>
Transmission Control Protocol Simulator
<br/>
(Slow Start)
</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
TCP (Transmission Control Protocol) is a connection-oriented protocol for
transferring data reliably in either direction between a pair of users. TCP
is a rather complex protocol, so it is easy to lose track of the simulation.
Try not to do anything too complicated! There are <a
href="TCPcs.html">client-server</a> and <a href="TCPpp.html">peer-peer</a>
simulations as alternatives that illustrate opening and closing connections.
</p>
<p>
This simulation focuses on dynamic window management - specifically what is
called &quot;slow start&quot;. This is designed to avoid the protocol
flooding the network with packets when it starts, and to ensure that the
protocol recovers slowly following message loss and timeout due to
congestion.
</p>
<p>
Users simply send messages of a fixed size; the content of messages is not
identified. The medium maximum packet size is the protocol segment size.
Depending on this, messages may be sent as a number of fragments. Data
transfer is also subject to the current window size of the receiver, and may
be held up if the receiver&#39;s window becomes full.
</p>
<p>
When data arrives, it is not immediately delivered to the receiving user.
Instead, data is accumulated and can be delivered later (&quot;Deliver
octets to user&quot;). If the receiving window becomes full, new requests to
send data will be buffered. When the receiving window opens again, this
buffered data can be sent (&quot;Send octets to peer&quot;).
</p>
<p>
Messages may contain a send sequence number (the offset of where the message
starts in the user&#39;s octet stream), an acknowledgement sequence number
(the offset of the next octet expected), and the current window (how many
octets can be received).
</p>
<p>
Slow start is governed by two protocol variables: <var>cwind</var>
(congestion window) and <var>ssthresh</var> (slow start threshold). These
are measured in octets for this simulation, but are sometimes counted as
numbers of segments. (Multiply the number of segments by the segment size to
get the number of octets.) The slow start procedure operates as follows:
</p>
<dl>
<dt><b>Initial Phase</b></dt>
<dd>
The minimum of the congestion window size and the receiver window size
determines how much data can be sent. The protocol starts conservatively
with <var>cwind</var> set to the segment size. As each acknowledgement
arrives, <var>cwind</var> is increased by the segment size. The amount of
data that can be sent thus typically doubles in each round-trip time (i.e.
the time to send a message and get a response). The amount is ultimately
limited by the receiver's window. The available window thus increases
exponentially (shown as &quot;exp.&quot; in the simulation when
<var>cwind</var> is increased).
</dd>
<dt><b>Congestion Action</b></dt>
<dd>
When a timeout occurs and the protocol has to retransmit, the congestion
window is set back to one segment size. At this point, the threshold
<var>ssthresh</var> is set to half the previous value of
<var>cwind</var>. Suppose that the segment size is 200, so that
<var>cwind</var> starts at 200. On subsequent acknowledgements,
<var>cwind</var> could rise to 1600. If congestion causes loss at this
point, <var>cwind</var> will be set back to 200 and <var>ssthresh</var>
will be set to 800 (half of 1600).
</dd>
<dt><b>Congestion Recovery</b></dt>
<dd>
Now the window is built up exponentially again. Once it reaches
<var>ssthresh</var>, it is no longer increased so aggressively. Instead,
<var>cwind</var> increases by one segment size for each round-trip time.
This is irrespective of how many acknowledgements arrive during this
period, unlike the exponential phase where every acknowledgement causes
the window to double per round trip time. During the recovery phase, the
available window increases linearly (shown as &quot;lin.&quot; in the
simulation). The window will then become 900, 1000, etc. up to the
receiver maximum. If congestion again causes loss, the procedure is
repeated.
</dd>
</dl>
<p>
Because the simulation does not run in real time, it does not reflect
round-trip times. As a result, its behaviour during the exponential and
linear phases appears similar. However, the phase is indicated depending on
whether <var>cwind</var> is below or above the threshold.
</p>
<p>
TCP is rather complex, so the simulation does not attempt to faithfully
reflect all its details. Although the main paths should work as expected, it
may be possible to get the simulation into unusual states in which it does
not behave correctly.
</p>
<p>
Things the simulation does not cover include the following. See advanced
guides to TCP for more information.
</p>
<ul>
<li>advanced congestion control</li>
<li>handling duplicate acknowledgements</li>
<li>fast retransmit</li>
<li>fast recovery</li>
</ul>
<h2>Protocol Parameters</h2>
<p>
The following settings are adequate for a simple simulation. For a more
advanced exploration, choose different options and click <em>Change
Settings</em>. This may cause the simulation to restart.
</p>
<form name="settings">
<center>
<table cellpadding="5">
<tr>
<td align="right">User A Message Size (10 to 1000):</td>
<td>
<input type="text" name="userAMessageSize" value="800" size="4"/>
</td>
</tr>
<tr>
<td align="right">User B Message Size (10 to 1000):</td>
<td><input name="userBMessageSize" size="4" value="800"/> </td>
</tr>
<tr>
<td align="right">Protocol A Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeA" value="1000" size="4"/></td>
</tr>
<tr>
<td align="right">Protocol B Receive Window (10 to 1000):</td>
<td><input type="text" name="windowSizeB" value="1000" size="4"/></td>
</tr>
<tr>
<td align="right">Medium/Protocol Segment Size (10 to 1000):</td>
<td>
<input type="text" name="maxSendPacket" value="200" size="4"/>
</td>
</tr>
<tr>
<td align="right">Loss Rate (0.0 = lose none, 1.0 = lose any):</td>
<td><input type="text" name="lossRate" value="0.2" size="4"/> </td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<script type="text/javascript" language="JavaScript">
<!--
// initialise settings from the above and not the default protocol settings
set();
//-->
</script>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with two peer service
users, protocol entities that support them, and a communications medium
(network) that carries messages. The connection phase is not shown in this
simulation as it is assumed to have just occurred. Equally, the
disconnection phase is not shown.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="TCP/ss"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- TFTP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Trivial File Transfer Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Trivial File Transfer Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
TFTP (Trivial File Transfer Protocol) is an elementary file transfer
protocol that is typically used by a discless workstation to download its
bootstrap file. TFTP operates over <a href="UDP.html">UDP (User Datagram
Protocol)</a> and often in conjunction with <a href="BOOTP.html">BOOTP
(Boot Protocol)</a>.
</p>
<p>
A client may initially issue:
</p>
<ul>
<li>
<em>RRQ</em>: read request, to retrieve a named file from the server
</li>
<li><em>WRQ</em>: write request, to send a named file to the server</li>
</ul>
<p>
During data transfer, the client or server as appropriate sends:
</p>
<ul>
<li>
<em>DATA</em>: with data content numbered D<em>n</em>, the last data
being labelled <em>Dlast</em>
</li>
<li>
<em>ACK</em>: an acknowledgement with the same number as the
<em>DATA</em> being acknowledged
</li>
<li><em>ERROR</em>: to send an error message due to a serious problem</li>
</ul>
<p>
<em>DATA</em> blocks are numbered from 1 onwards with just a name
<em>D</em>n for their data contents. Normally an <em>ACK</em> quotes this
number, but in the case of <em>WRQ</em> an acknowledgement with number 0
is sent. All <em>DATA</em> blocks except the last one are full. The final
block is less than the normal size, shown with contents D<em>last</em>.
</p>
<p>
The protocol is unusual in that both sender and receiver may time out. If
one party does not receive a fresh <em>DATA</em> block after sending an
<em>ACK</em>, it may retransmit the <em>ACK</em> in case it was lost. A
complication is that the <em>ACK</em> for the last <em>DATA</em> may be
lost. For this reason, the receiver must wait until it is satisfied that
data transfer is complete. If decision &quot;presume all transmissions
over&quot; is made prematurely, the sender will become stuck because it
cannot obtain the last <em>ACK</em> it needs.
</p>
<p>
After completing transfer of a file, the client may start a new transfer.
<em>ERROR</em> messages may be sent in situations such as incorrect
sequence numbers or local disc errors. The full protocol allows for
different modes of transfer, but the simulation supports only octet mode
(the norm).
</p>
<h2>Protocol Parameters</h2>
<p>
This simulation has no parameters.
</p>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with client and
server protocol entities, and a communications medium that carries
messages. The client and server exchange the messages described above,
starting with an <em>RRQ</em> or <em>WRQ</em> from the client. Several
files may be transferred consecutively.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="TFTP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

@ -0,0 +1,139 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- UDP.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>User Datagram Protocol</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
<script type="text/javascript" language="JavaScript">
<!--
var simulator;
var spA;
var dpA;
var spB;
var dpB;
function valid(port, address, user) {
if (address < 0 || address > 65535) {
alert ("Port address for User " + user + " must be in range 0-65535");
return false;
}
else
return true;
}
function set() {
spA = document.settings.SourcePortA.value.toString();
dpA = document.settings.DestPortA.value.toString();
spB = document.settings.SourcePortB.value.toString();
dpB = document.settings.DestPortB.value.toString();
if (valid("source", spA, "A") && valid("destination", dpA, "A") &&
valid("source", spB, "B") && valid("destination", dpB, "B")) {
simulator.setParameter("sourcePortA", spA);
simulator.setParameter("destPortA", dpA);
simulator.setParameter("sourcePortB", spB);
simulator.setParameter("destPortB", dpB);
simulator.updateActionList();
}
}
//-->
</script>
</head>
<body background="simulator.jpeg"
onload="simulator=document.ProtocolSimulator; set();">
<div style="text-align: center">
<h1>User Datagram Protocol Simulator</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Protocol Description</h2>
<p>
UDP (User Datagram Protocol) is a simple connection-less protocol for
transferring datagrams in either direction between a pair of user ports.
Each datagram is identified by its source and destination port numbers
(in the range 0 to 65535).
</p>
<h2>Protocol Parameters</h2>
<form name="settings">
<center>
<table cellspacing="5">
<tr>
<td align="right">User A Source Port</td>
<td><input type="text" name="SourcePortA" value="11" size="5"/></td>
<td align="right">User A Destination Port</td>
<td><input type="text" name="DestPortA" value="22" size="5"/> </td>
</tr>
<tr>
<td align="right">User B Source Port</td>
<td><input type="text" name="SourcePortB" value="33" size="5"/></td>
<td align="right">User B Destination Port</td>
<td><input type="text" name="DestPortB" value="44" size="5"/></td>
</tr>
<tr>
<td align="center" colspan="4">
<input type="button" name="btnSet" value="Change Settings"
onclick="set()"/>
</td>
</tr>
</table>
</center>
</form>
<h2>Protocol Simulation</h2>
<p>
The protocol simulation shows a time-sequence diagram with users A and B,
protocol entities A and B that support them, and a communications medium
that carries messages. Users request data transmissions with
<em>DatReq(Src,Dst,Dn)</em> and receive data transmissions as
<em>DatInd(Src, Dst,Dn)</em>. Data messages are simply numbered <em>D0</em>,
<em>D1</em>, etc. in sequence for each user; no explicit data content is
given. Each user request leads to the protocol message
<em>DT(Src,Dst,Dn)</em> that gives the source port, destination port and
data message number.
</p>
<center>
<applet code="simulator.ProtocolSimulator.class"
archive="ProtocolSimulator.jar" width="750" height="700"
name="ProtocolSimulator">
<param name="protocol" value="UDP"/>
</applet>
</center>
<hr/>
<p>
<a href="index.html"><img src="uparrow.gif" alt="Up Arrow"/></a>
Up one level to <a href="index.html">Protocol Simulators</a>
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

@ -0,0 +1,188 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- index.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Protocol Simulators</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Protocol Simulators</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Available Simulations</h2>
<p>
The following protocol simulations were developed mainly by Iain Robin and
<a href="http://www.cs.stir.ac.uk/~kjt/" target="_blank">Ken Turner</a>,
with contributions from Paul Johnson and Kenneth Whyte. They should be
useful in allowing you to experiment with a variety of protocols. Bug
reports should be sent to Ken Turner.
</p>
<p>
When you run a simulation, due to Java security restrictions you will need
to authorise running the code (assuming the simulator JAR file is properly
signed).
</p>
<p>
The simulations are listed in increasing order of complexity. It is
suggested that you try the easier protocols first.
</p>
<blockquote>
<img src="dot-orange.gif" alt="Orange Dot"/>
<a href="ABP.html">Alternating Bit Protocol (ABP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="UDP.html">User Datagram Protocol (UDP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="BOOTP.html">Boot Protocol (BOOTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="HTTP.html">HyperText Transfer Protocol (HTTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SMTP.html">Simple Mail Transfer Transfer Protocol (SMTP)
Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="IP.html">Internet Protocol (IP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SWP3.html">Sliding Window Protocol (SWP) 3-Column Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SWP5.html">Sliding Window Protocol (SWP) 5-Column Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="ABRA.html">Abracadabra Protocol Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TFTP.html">Trivial File Transfer Protocol (TFTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPcs.html">Transmission Control Protocol (TCP) Client-Server
Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPpp.html">Transmission Control Protocol (TCP) Peer-Peer
Simulator</a>
</blockquote>
<!--
<h2>Additional Simulations</h2>
<p>
The following protocol simulations were developed by <a
href="http://www.cs.stir.ac.uk/~kjt/" target="_blank">Ken Turner</a> for
Pearson Education. Bug reports should be sent to Ken Turner.
</p>
<p>
The simulations are listed in increasing order of complexity. It is
suggested that you try the easier protocols first.
</p>
<blockquote>
<img src="dot-orange.gif" alt="Orange Dot"/>
<a href="STACK.html">Protocol Stack (STACK) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="MUX.html">Multiplexing (MUX) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="MCAST.html">Multicasting (MCAST) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="CSMA.html">Carrier Sense Multiple Access with Collision Detection
(CSMA/CD, Ethernet) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPss.html">Transmission Control Protocol (TCP) Slow Start
Simulator</a>
</blockquote>
-->
<h2>General Instructions</h2>
<p>
Select an action by clicking on the list at the bottom of the diagram.
Actions are things like a user sending a data message or the medium
delivering a protocol message. You are completely in control of the
simulation. For example you may have to decide when to send messages,
whether to acknowledge messages, and whether messages are lost in the medium
or are delivered. Since the simulation does not run in real-time, a timeout
is possible as soon as a message has been sent.
</p>
<p>
The last action in the diagram is shown in red. If you make a mistake, or
just want to backtrack in the simulation, then click <em>Undo</em>. You can
undo as many steps as you like, right up to the beginning of the simulation.
Clicking on <em>Redo</em> will perform the last undone step again.
<em>Clear</em> will restart the simulation with the current protocol
parameters. If you click on <em>Run</em> the simulator will run
automatically, making random choices for you. If you are not sure what to
experiment with, this is an easy way of seeing the protocol in action. While
this is happening, the <em>Run</em> button changes to
<em>Stop</em>. Click on <em>Stop</em> to return the simulator to user
control. You can continue at this point as if you had made all the automatic
choices yourself.
</p>
<p>
The <em>Print</em>, <em>Load</em> and <em>Save</em> buttons are disabled
since these simulations are running as applets. If you wish hard copy of the
simulation, position the scroll bar in the simulation pane at an interesting
point and print out the whole web page. If you have the code for the
simulator, you can run it as an application to enable these buttons.
<em>Print</em> produces a hard copy of the current simulation scenario.
<em>Load</em> loads a scenario file (with a name ending in
<em>.scn</em>). This must be for the same protocol as you are currently
simulating. It replaces the current simulation scenario (if any).
<em>Save</em> saves the current simulation scenario as a scenario file
(with a name ending in <em>.scn</em>). If you are adventurous, you can
create and edit your own scenarios using a standard text editor.
</p>
<h2>Protocol Descriptions</h2>
<p>
The available simulations vary quite widely, though they all behave in a
similar way. The terminology used to describe each protocol is that of its
standard. The term "octet" is commonly used in international communications
standards to mean eight bits, i.e. a byte.
</p>
<p>
Some simulations have associated protocol parameters. To change the defaults
that are shown, enter new values and click <em>Change Values</em>. In some
cases, this will force the simulation to restart.
</p>
</body>
</html>

@ -0,0 +1,178 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- index.html (C) K. J. Turner 18/12/14 -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Protocol Simulators</title>
<link rev="made" href="http://www.cs.stir.ac.uk/~kjt/"/>
</head>
<body background="simulator.jpeg">
<div style="text-align: center">
<h1>Protocol Simulators</h1>
<img src="simulator.gif" alt="Simulator Logo"/>
</div>
<h2>Available Simulations</h2>
<p>
The following protocol simulations were developed mainly by Iain Robin and
<a href="http://www.cs.stir.ac.uk/~kjt/" target="_blank">Ken Turner</a>,
with contributions from Paul Johnson and Kenneth Whyte. They should be
useful in allowing you to experiment with a variety of protocols. Bug
reports should be sent to Ken Turner.
</p>
<p>
The simulations are listed in increasing order of complexity. It is
suggested that you try the easier protocols first.
</p>
<blockquote>
<img src="dot-orange.gif" alt="Orange Dot"/>
<a href="ABP.html">Alternating Bit Protocol (ABP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="UDP.html">User Datagram Protocol (UDP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="BOOTP.html">Boot Protocol (BOOTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="HTTP.html">HyperText Transfer Protocol (HTTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SMTP.html">Simple Mail Transfer Transfer Protocol (SMTP)
Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="IP.html">Internet Protocol (IP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SWP3.html">Sliding Window Protocol (SWP) 3-Column Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="SWP5.html">Sliding Window Protocol (SWP) 5-Column Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="ABRA.html">Abracadabra Protocol Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TFTP.html">Trivial File Transfer Protocol (TFTP) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPcs.html">Transmission Control Protocol (TCP) Client-Server
Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPpp.html">Transmission Control Protocol (TCP) Peer-Peer
Simulator</a>
</blockquote>
<h2>Additional Simulations</h2>
<p>
The following protocol simulations were developed by <a
href="http://www.cs.stir.ac.uk/~kjt/" target="_blank">Ken Turner</a> for
Pearson Education. Bug reports should be sent to Ken Turner.
</p>
<p>
The simulations are listed in increasing order of complexity. It is
suggested that you try the easier protocols first.
</p>
<blockquote>
<img src="dot-orange.gif" alt="Orange Dot"/>
<a href="STACK.html">Protocol Stack (STACK) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="MUX.html">Multiplexing (MUX) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="MCAST.html">Multicasting (MCAST) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="CSMA.html">Carrier Sense Multiple Access with Collision Detection
(CSMA/CD, Ethernet) Simulator</a>
<br/><img src="dot-orange.gif" alt="Orange Dot"/>
<a href="TCPss.html">Transmission Control Protocol (TCP) Slow Start
Simulator</a>
</blockquote>
<h2>General Instructions</h2>
<p>
Select an action by clicking on the list at the bottom of the diagram.
Actions are things like a user sending a data message or the medium
delivering a protocol message. You are completely in control of the
simulation. For example you may have to decide when to send messages,
whether to acknowledge messages, and whether messages are lost in the medium
or are delivered. Since the simulation does not run in real-time, a timeout
is possible as soon as a message has been sent.
</p>
<p>
The last action in the diagram is shown in red. If you make a mistake, or
just want to backtrack in the simulation, then click <em>Undo</em>. You can
undo as many steps as you like, right up to the beginning of the simulation.
Clicking on <em>Redo</em> will perform the last undone step again.
<em>Clear</em> will restart the simulation with the current protocol
parameters. If you click on <em>Run</em> the simulator will run
automatically, making random choices for you. If you are not sure what to
experiment with, this is an easy way of seeing the protocol in action. While
this is happening, the <em>Run</em> button changes to
<em>Stop</em>. Click on <em>Stop</em> to return the simulator to user
control. You can continue at this point as if you had made all the automatic
choices yourself.
</p>
<p>
The <em>Print</em>, <em>Load</em> and <em>Save</em> buttons are disabled
since these simulations are running as applets. If you wish hard copy of the
simulation, position the scroll bar in the simulation pane at an interesting
point and print out the whole web page. If you have the code for the
simulator, you can run it as an application to enable these buttons.
<em>Print</em> produces a hard copy of the current simulation scenario.
<em>Load</em> loads a scenario file (with a name ending in
<em>.scn</em>). This must be for the same protocol as you are currently
simulating. It replaces the current simulation scenario (if any).
<em>Save</em> saves the current simulation scenario as a scenario file
(with a name ending in <em>.scn</em>). If you are adventurous, you can
create and edit your own scenarios using a standard text editor.
</p>
<h2>Protocol Descriptions</h2>
<p>
The available simulations vary quite widely, though they all behave in a
similar way. The terminology used to describe each protocol is that of its
standard. The term "octet" is commonly used in international communications
standards to mean eight bits, i.e. a byte.
</p>
<p>
Some simulations have associated protocol parameters. To change the defaults
that are shown, enter new values and click <em>Change Values</em>. In some
cases, this will force the simulation to restart.
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

@ -0,0 +1,41 @@
Jasper TCP/ss
User A: Send 800 octets
Medium: Deliver Seq 0, Win 1200 [Protocol A] - no loss
Medium: Deliver Ack 200, Win 1000 [Protocol B] - no loss
Protocol A: Send 400 octets to peer
Medium: Deliver Seq 200, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 400, Win 1200 [Protocol A] - no loss
Medium: Deliver Ack 400, Win 800 [Protocol B] - no loss
Medium: Deliver Ack 600, Win 600 [Protocol B] - no loss
Protocol B: Deliver 600 octets to user
Medium: Deliver Win 1200 [Protocol B] - no loss
Medium: Deliver Ack 100, Win 1200 [Protocol A] - no loss
User A: Send 800 octets
Medium: Deliver Seq 600, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 800, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 1000, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 1200, Win 1200 [Protocol A] - no loss
Medium: Deliver Ack 800, Win 1000 [Protocol B] - no loss
Medium: Deliver Ack 1000, Win 800 [Protocol B] - no loss
Medium: Deliver Ack 1200, Win 600 [Protocol B] - no loss
Medium: Deliver Ack 1400, Win 400 [Protocol B] - no loss
Protocol B: Deliver 800 octets to user
Medium: Deliver Win 1200 [Protocol B] - no loss
Medium: Deliver Ack 100, Win 1200 [Protocol A] - no loss
User A: Send 800 octets
Medium: Deliver Seq 1400, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 1600, Win 1200 [Protocol A] - no loss
Medium: Deliver Seq 1800, Win 1200 [Protocol A] - no loss
Medium: Lose Ack 2000, Win 600 [Protocol B] - congestion/error
Medium: Deliver Ack 1600, Win 1000 [Protocol B] - no loss
Medium: Lose Seq 2000, Win 1200 [Protocol A] - congestion/error
Protocol A: Timeout - resend Seq 1600, Win 1200
Medium: Deliver Seq 1600, Win 1200 [Protocol A] - no loss
Medium: Deliver Ack 1800, Win 800 [Protocol B] - no loss
Medium: Deliver Ack 2000, Win 600 [Protocol B] - no loss
Protocol B: Deliver 600 octets to user
Medium: Deliver Win 1200 [Protocol B] - no loss
Medium: Deliver Ack 100, Win 1200 [Protocol A] - no loss
Protocol A: Timeout - resend Seq 2000, Win 1200
Medium: Deliver Seq 2000, Win 1200 [Protocol A] - no loss
Medium: Deliver Ack 2200, Win 1000 [Protocol B] - no loss

@ -0,0 +1,25 @@
// ABRAServiceEntity.java (C) I. A. Robin, K. J. Turner 08/03/06
package protocol;
import java.util.*;
import support.*;
public class ABP extends Protocol {
private ABPSender sender;
private ABPReceiver receiver;
public ABP() {
medium = new Medium();
sender = new ABPSender(medium, "Sender");
receiver = new ABPReceiver(medium, "Receiver");
sender.setPeer(receiver);
receiver.setPeer(sender);
entities = new Vector<ProtocolEntity>();
entities.addElement(sender);
entities.addElement(medium);
entities.addElement(receiver);
}
}

@ -0,0 +1,86 @@
// ABPReceiver.java (C) I. A. Robin, K. J. Turner 08/03/06
package protocol;
import java.util.Enumeration; // enumeration
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
public class ABPReceiver implements ProtocolEntity {
private int seqExpected;
private PDU pduReceived;
private PDU ackPDU;
private ProtocolEntity peer;
private Medium medium;
private String name;
private Vector<ProtocolEvent> entityEvents; // events from entity
public ABPReceiver(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
if (pduReceived != null && pduReceived.type.equals("DATA")) {
if (pduReceived.seq == seqExpected) seqExpected = inc(seqExpected);
list.addElement(
"Send ACK(" + seqExpected +
") - with sequence number of next message");
}
return(list);
}
/** Increment PDU sequence number (0 or 1 only in ABP protocol) */
private int inc(int seq) {
return(1 - seq);
}
public void initialise() {
seqExpected = 0;
pduReceived = null;
entityEvents = new Vector<ProtocolEvent>(); // empty entity events
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith("Send ACK")) {
int startIndex = s.indexOf( '(' ) + 1;
int endIndex = s.indexOf( ')' );
int seq = Integer.parseInt(s.substring(startIndex, endIndex));
transmitPDU(new PDU("ACK", seq), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, ackPDU));
}
for (Enumeration e = entityEvents.elements(); // get medium events
e.hasMoreElements(); )
events.addElement( // add medium event
(ProtocolEvent) e.nextElement());
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
ackPDU = pdu;
entityEvents = medium.receivePDU(pdu);
pduReceived = null;
}
}

@ -0,0 +1,119 @@
// ABPSender.java
package protocol; // protocol package
import java.util.Enumeration; // enumeration
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
/**
This is the class for the alternating bit protocol sender.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): minor tidying
*/
public class ABPSender implements ProtocolEntity, Timeouts {
private PDU pduBeingSent;
private PDU pduReceived;
private ProtocolEntity peer;
private Medium medium;
private String name;
private boolean timerEnabled;
private Vector<ProtocolEvent> entityEvents; // events from entity
public ABPSender(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
if (pduReceived != null && pduReceived.type.equals("ACK")) {
list.addElement("Send DATA(" + pduReceived.seq + ")");
timerEnabled = false;
}
if (timerEnabled)
list.addElement("Timeout - presume loss of message and resend");
return(list);
}
public boolean hasTimer(String type) {
return(true);
}
/** Increment PDU sequence number (0 or 1 only in ABP protocol) */
private int inc(int seq) {
return(1 - seq);
}
public void initialise() {
// dummy initial data PDU
pduBeingSent = new PDU("DATA", 1);
pduBeingSent.setSource(this);
// dummy initial ack PDU
pduReceived = new PDU("ACK", 0);
timerEnabled = false;
entityEvents = new Vector<ProtocolEvent>(); // empty medium events
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith("Send DATA")) {
// PDU seq number delimited by brackets:
int startIndex = s.indexOf( '(' ) + 1;
int endIndex = s.indexOf( ')' );
int seq = Integer.parseInt(s.substring(startIndex, endIndex));
transmitPDU(new PDU("DATA", seq), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduBeingSent));
}
if (s.startsWith("Timeout")) {
transmitPDU(pduBeingSent, peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduBeingSent));
}
for (Enumeration e = entityEvents.elements(); // get medium events
e.hasMoreElements(); )
events.addElement( // add medium event
(ProtocolEvent) e.nextElement());
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) {
timerEnabled = enabled;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
pduBeingSent = pdu;
entityEvents = medium.receivePDU(pdu); // medium receives PDU
pduReceived = null;
timerEnabled = false;
}
}

@ -0,0 +1,35 @@
// ABRA.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class ABRA extends Protocol {
private ABRAService abraServA;
private ABRAProtocol abraProtA;
private ABRAProtocol abraProtB;
private ABRAService abraServB;
public ABRA() {
medium = new Medium();
abraServA = new ABRAService("User A");
abraServB = new ABRAService("User B");
abraProtA = new ABRAProtocol(medium, "Protocol A");
abraProtB = new ABRAProtocol(medium, "Protocol B");
abraServA.setProvider(abraProtA);
abraServB.setProvider(abraProtB);
abraProtA.setUser(abraServA);
abraProtA.setPeer(abraProtB);
abraProtB.setUser(abraServB);
abraProtB.setPeer(abraProtA);
entities = new Vector<ProtocolEntity>();
entities.addElement(abraServA);
entities.addElement(abraProtA);
entities.addElement(medium);
entities.addElement(abraProtB);
entities.addElement(abraServB);
}
}

@ -0,0 +1,386 @@
// ABRAProtocol.java
package protocol;
import java.util.*;
import support.*;
/**
This is the class for the Abracadabra protocol sender.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): minor tidying
*/
public class ABRAProtocol implements ProtocolEntity, Timeouts {
// Protocol state constants
private static final int CLOSED = 0; // waiting for connection request
private static final int CR_SENT = 1; // waiting for connection confirmation
private static final int CR_RECV = 2; // waiting for ConResp from user
private static final int SEND = 3; // prepared to send data PDU
private static final int WAIT = 4; // waiting for acknowledgement of data
private static final int DR_SENT = 5; // waiting for disconnection confirm
// Protocol data unit types
public static final String CR = "Connection Request";
public static final String CC = "Connection Confirmation";
public static final String DT = "Data Transfer";
public static final String AK = "Acknowledgement";
public static final String DR = "Disconnection Request";
public static final String DC = "Disconnection Confirmation";
public static final int maxRetries = 3;
private PDU pduSent;
private PDU lastDTpdu;
private int sendSeq;
private int recvSeq;
private ProtocolEntity peer;
private ABRAService user;
private Vector<ProtocolEvent> entityEvents; // events from entity
private Medium medium;
private String name;
private boolean timerEnabled;
private int crRemaining;
private int drRemaining;
private int dtRemaining;
private boolean dtOrAk;
private int state;
public ABRAProtocol(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
switch (state) {
case CR_SENT: // waiting for connection confirmation
if (timerEnabled) {
if (crRemaining > 1)
list.addElement("Timeout - resend " + CR);
else
list.addElement("Retry limit reached - send " + DR);
}
break;
case WAIT: // waiting for acknowledgement of data
if (timerEnabled) {
if (dtRemaining > 1)
list.addElement("Timeout - resend DT(" + lastDTpdu.seq + ")" );
else
list.addElement("Retry limit reached - send " + DR);
}
break;
case DR_SENT: // waiting for disconnection confirmation
if (timerEnabled) {
if (drRemaining > 1) {
list.addElement("Timeout - resend " + DR);
}
else {
// Retry limit reached
dtRemaining--;
state = CLOSED;
}
}
break;
}
return(list);
}
/** Increment PDU sequence number (alternating bit) */
private int inc(int seq) {
return(1 - seq);
}
public void initialise() {
entityEvents = new Vector<ProtocolEvent>();
state = CLOSED;
}
public boolean hasTimer(String type) {
return(type.equals("DT") || type.equals("DR") || type.equals("CR"));
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
switch (state) {
case CR_SENT:
if (s.startsWith("Timeout")) {
crRemaining--;
transmitPDU(new PDU("CR"), peer); // resend connection request PDU
events.addElement(
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
if (s.startsWith("Retry limit")) {
crRemaining--;
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DR"), peer); // send disconnection request PDU
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
break;
case WAIT:
if (s.startsWith("Timeout")) {
dtRemaining--;
transmitPDU(lastDTpdu, peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
if (s.startsWith("Retry limit")) {
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
dtRemaining--;
transmitPDU(new PDU("DR"), peer); // send disconnection request PDU
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
break;
case DR_SENT:
if (s.startsWith("Timeout")) {
drRemaining--;
transmitPDU(new PDU("DR"), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
break;
}
for (Enumeration e = entityEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
String pduType = "";
if (pdu != null)
pduType = pdu.type;
switch (state) {
case CLOSED:
if (pduType.equals("ConReq")) { // ConReq primitive?
transmitPDU(new PDU("CR"), peer); // send connection request PDU
dtOrAk = false;
sendSeq = 0;
recvSeq = 0;
crRemaining = maxRetries;
state = CR_SENT;
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
}
else if (pduType.equals("CR")) { // connection request PDU?
transmitPDU(new PDU("ConInd"), user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
dtOrAk = false;
sendSeq = 0;
recvSeq = 0;
state = CR_RECV;
}
else if (pduType.equals("DR")) { // got disconnect request PDU
transmitPDU(new PDU("DC"), peer); // send disconnect confirm PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
}
break;
case CR_SENT:
if (pduType.equals("CC") || // connection confirmation PDU?
pduType.equals("CR")) { // connection request PDU?
// (both stations have requested connections at the same time)
transmitPDU(new PDU("ConConf"), user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
timerEnabled = false;
state = SEND;
}
else if (pduType.equals("DR")) { // disconnection request PDU?
transmitPDU(new PDU("DisInd"), user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
timerEnabled = false;
state = CLOSED;
}
else if (pduType.equals("DisReq")) { // disconnection request prim?
// transmitPDU(new PDU("DisInd"), user);
// events.addElement(
// new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
break;
case CR_RECV:
if (pduType.equals("ConResp")) {
transmitPDU(new PDU("CC"), peer); // send connection confirm PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
state = SEND;
}
else if (pduType.equals("DR")) {
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DC"), peer); // send disconnection confirm PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
state = CLOSED;
}
else if (pduType.equals("ConReq")) {
transmitPDU(new PDU("ConConf"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("CC"), peer); // send connection confirm PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
state = SEND;
}
else if (pduType.equals("DisReq")) {
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
state = CLOSED;
}
break;
case WAIT:
if (pduType.equals("AK")) {
if (pdu.seq == sendSeq) {
dtOrAk = true;
timerEnabled = false;
user.setOKToSend(true);
state = SEND;
}
else { // wrong AK : enter error phase
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
}
// break intentionally omitted
case SEND:
if (state == SEND // avoid drop-through from WAIT
&& pduType.equals("DatReq")) { // DatReq received from user
transmitPDU(new PDU("DT", sendSeq, pdu.getSDU()), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
user.setOKToSend(false);
sendSeq = inc(sendSeq);
dtRemaining = maxRetries;
state = WAIT;
}
else if (pduType.equals("DR")) { // disconnection request PDU?
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DC"), peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
timerEnabled = false;
state = CLOSED;
}
else if (pduType.equals("DT")) { // data PDU received
dtOrAk = true;
if (pdu.seq == recvSeq) { // check sequence number correct
recvSeq = inc(recvSeq);
transmitPDU(new PDU("DatInd", pdu.getSDU()), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
}
transmitPDU(new PDU("AK", recvSeq), peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
// no state transition
}
if (pduType.equals("CC") || pduType.equals("DC")) {
transmitPDU(new PDU("DisInd"), user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DR"), peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
if (pduType.equals("CR")) { // connection request PDU?
if (!dtOrAk) {
transmitPDU(new PDU("CC"), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
// no state transition
}
else {
transmitPDU(new PDU("DisInd"), user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
transmitPDU(new PDU("DR"), peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
}
if (pduType.equals("DisReq")) {
transmitPDU(new PDU("DR"), peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
drRemaining = maxRetries;
state = DR_SENT;
}
break;
case DR_SENT: // awaiting disconnect confirm
if (pduType.equals("DC") || // disconnect confirm PDU?
pduType.equals("DR")) { // disconnect request PDU?
// both stations have requested disconnection at the same time
timerEnabled = false;
state = CLOSED;
}
if (pduType.equals("ConReq")) {
transmitPDU(new PDU("DisInd"), user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
}
if (timerEnabled && drRemaining <= 1) {
drRemaining--;
state = CLOSED;
}
break;
}
return(events);
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) {
timerEnabled = enabled;
}
public void setUser(ProtocolEntity user) {
this.user = (ABRAService)user;
}
public void transmitPDU(PDU pdu, ProtocolEntity destination) {
pdu.setSource(this);
pdu.setDestination(destination);
if (destination == peer)
entityEvents = medium.receivePDU(pdu);
else
entityEvents = user.receivePDU(pdu);
pduSent = pdu;
if (pdu.type.equals("DT"))
lastDTpdu = pdu;
for (Enumeration e = entityEvents.elements(); e.hasMoreElements(); )
System.err.println("ABRAP transmitPDU: " + (ProtocolEvent) e.nextElement());
}
}

@ -0,0 +1,171 @@
// ABRAService.java (C) I. A. Robin, K. J. Turner 08/03/06
package protocol;
import java.util.*;
import support.*;
public class ABRAService implements ProtocolEntity {
// Service state constants
private static final int DISCONNECTED = 0; // no connection in progress
// or active
private static final int CALLING = 1; // connection initiated by local
// user is being established
private static final int CALLED = 2; // connection initiated by remote
// user is being established
private static final int CONNECTED = 3; // data transfer is possible
// Service primitives
public static final String CON_REQ = "Connection Request";
public static final String CON_IND = "Connection Indication";
public static final String CON_RESP = "Connection Response";
public static final String CON_CONF = "Connection Confirmation";
public static final String DAT_REQ = "Data Request";
public static final String DAT_IND = "Data Indication";
public static final String DIS_REQ = "Disconnection Request";
public static final String DIS_IND = "Disconnection Indication";
private ProtocolEntity provider; // protocol providing service
private Vector providerEvents;
private PDU pduSent;
private String name;
private int state;
private int block; // sequence number of data block
private boolean okToSend; // OK to send DatReq to provider
public ABRAService(String name) {
this.name = name;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
switch (state) {
case DISCONNECTED:
list.addElement("Send " + CON_REQ);
break;
case CALLING:
list.addElement("Send " + DIS_REQ);
break;
case CALLED:
list.addElement("Send " + CON_RESP);
list.addElement("Send " + DIS_REQ);
break;
case CONNECTED:
if (okToSend)
list.addElement("Send " + DAT_REQ + "(D" + block + ")");
list.addElement("Send " + DIS_REQ);
break;
}
return(list);
}
public void initialise() {
block = 0;
okToSend = true;
providerEvents = new Vector();
state = DISCONNECTED;
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
switch (state) {
case DISCONNECTED:
if (s.equals("Send " + CON_REQ)) {
transmitPDU(new PDU("ConReq"), provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
state = CALLING;
}
case CALLING:
if (s.equals("Send " + DIS_REQ)) {
transmitPDU(new PDU("DisReq"), provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
state = DISCONNECTED;
}
break;
case CALLED:
if (s.equals("Send " + CON_RESP)) {
transmitPDU(new PDU("ConResp"), provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
state = CONNECTED;
}
if (s.equals("Send " + DIS_REQ)) {
transmitPDU(new PDU("DisReq"), provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
state = DISCONNECTED;
}
break;
case CONNECTED:
if (s.startsWith("Send " + DAT_REQ)) {
String sdu = "D" + block;
transmitPDU(new PDU("DatReq", sdu), provider);
block++;
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
// No state transition
}
if (s.equals("Send " + DIS_REQ)) {
transmitPDU(new PDU("DisReq"), provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.SEND, pduSent));
state = DISCONNECTED;
}
}
for (Enumeration e = providerEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
/** Respond to PDU received from underlying protocol */
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
String pduType = pdu.type;
switch (state) {
case DISCONNECTED:
if (pduType.equals("ConInd")) state = CALLED;
break;
case CALLING:
// Is the ConInd possibility below needed?
if (pduType.equals("ConConf")
|| pduType.equals("ConInd")) state = CONNECTED;
if (pduType.equals("DisInd")) state = DISCONNECTED;
break;
case CALLED:
if (pduType.equals("DisInd")) state = DISCONNECTED;
break;
case CONNECTED:
if (pduType.equals("DisInd")) state = DISCONNECTED;
break;
}
return(events);
}
/** Implements flow control by back-pressure. DatReq allowed only when
okToSend is true */
public void setOKToSend(boolean ok) {
okToSend = ok;
}
public void setProvider(ProtocolEntity provider) {
this.provider = provider;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
providerEvents = dest.receivePDU(pdu);
pduSent = pdu;
}
}

@ -0,0 +1,29 @@
// BOOTP.java (C) K. J. Turner, K. A. Whyte 04/03/06
// Boot Protocol
package protocol; // protocol package
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
public class BOOTP extends Protocol { // BOOTP protocol
private BOOTPSender sender; // protocol sender (client)
private BOOTPReceiver receiver; // protocol receiver (server)
public BOOTP() { // construct protocol instance
medium = new BOOTPMedium(); // construct comms medium
sender = // construct sender (client)
new BOOTPSender (medium, "Client");
receiver = // construct receiver (server)
new BOOTPReceiver (medium, "Server");
sender.setPeer(receiver); // sender is receiver's peer
receiver.setPeer(sender); // receiver is sender's peer
entities = new Vector<ProtocolEntity>(); // initialise protocol entities
entities.addElement(sender); // add sender protocol entity
entities.addElement(medium); // add comms medium entity
entities.addElement(receiver); // add receive protocol entity
}
}

@ -0,0 +1,75 @@
// BOOTPMedium.java (C) K. J. Turner 08/03/06
// Boot Protocol medium
package protocol; // protocol package
import java.util.*; // utility support
import support.*; // protocol entity support
/**
This is the class for an IP medium.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version <br/>
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (24th July 2010, KJT): minor tidying
*/
public class BOOTPMedium extends Medium { // protocol medium
// protocol variables
private static Vector<Float> randoms; // random number list
private static int randomIndex; // random number index
public BOOTPMedium() { // construct medium instance
super(); // construct as generic medium
randoms = new Vector<Float>(); // initialise list of randoms
}
protected PDU getMatchingPDU(String s) { // get matching PDU on channel
PDU pdu; // PDU
String sdu; // PDU contents
int sourceStart = s.indexOf ('[') + 1; // get start of entity name
int sourceEnd = s.indexOf (']'); // get end of entity name
String sourceName = // get PDU source
s.substring(sourceStart, sourceEnd);
int typeStart = s.indexOf (' ') + 1; // get start of PDU type
int typeEnd = s.indexOf ('('); // get end of PDU type
String type = // get PDU type
s.substring(typeStart, typeEnd);
int parEnd = s.indexOf (')'); // get end of PDU parameters
sdu = s.substring(typeEnd + 1, parEnd); // get PDU parameters
for (Enumeration e = pdus.elements(); // go through PDUs on channel
e.hasMoreElements(); ) {
pdu = (PDU) e.nextElement(); // get next PDU on channel
if (pdu != null && // valid PDU and ...
pdu.type.equals(type) && // type matches and ...
pdu.getSource().getName(). // source matches and ...
equals(sourceName) &&
sdu.equals(pdu.sdu)) // SDU matches
return((pdu)); // return with this PDU
}
return((null)); // return no PDU as no match
}
public void initialise() { // initialise medium
super.initialise(); // initialise generic medium
randomIndex = 0; // initialise randoms index
}
protected static float random() { // random number (from list)
Float rand; // random number
if (randomIndex < randoms.size()) // get number from list?
rand = (Float) randoms.elementAt(randomIndex++); // get number from list
else { // make new random number
rand = new Float(Math.random()); // get random number
randoms.addElement(rand); // add to list
randomIndex++; // increment list index
}
return((rand.floatValue())); // return random number
}
}

@ -0,0 +1,139 @@
// BOOTPReceiver.java (C) K. A. Whyte, K. J. Turner 08/03/06
package protocol; // protocol package
import java.util.Enumeration; // enumeration
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
public class BOOTPReceiver // protocol receiver (server)
implements ProtocolEntity { // protocol entity
// simulator variables
private ProtocolEntity peer; // peer entity (client)
private Medium medium; // communications medium
private String name; // entity name
// protocol variables
private String ipAddress = "net."; // IP address root
private String bootFile = "boot"; // boot file name
private String bootPath = "\\path\\"; // boot file root
private PDU pduSent; // PDU sent
private PDU pduReceived; // PDU received
private Vector<ProtocolEvent> entityEvents; // events from entity
// protocol messages
final static String request = "REQUEST"; // boot request message
final static String reply = "REPLY"; // boot reply message
public BOOTPReceiver(Medium m, String name) { // construct receiver instance
this.name = name; // set protocol entity name
medium = m; // set underlying medium
initialise(); // initialise protocol
}
public String getName() { // get protocol entity name
return((name)); // return protocol entity name
}
public void initialise() { // initialise protocol
pduReceived = null; // initialise no PDU received
pduSent = null; // initialise no PDU sent
entityEvents = new Vector<ProtocolEvent>(); // empty medium events
}
public Vector<String> getServices() {
Vector<String> events = // initialise events list
new Vector<String>();
String pduType; // received PDU type
String pduData; // PDU data
String pduTrans; // transaction identifier
int hwPos, ipPos, bootPos; // hw/ip/boot file positions
int trans; // transaction identifier
String hw, ip; // hardware/IP addr address
String boot; // boot file name
if (pduReceived != null) { // PDU received?
pduType = pduReceived.type; // get received PDU type
pduData = pduReceived.sdu; // get received PDU data
if (pduType.equals(request)) { // boot request?
hwPos = pduData.indexOf(','); // get hardware position
trans = // get transaction identifier
Integer.parseInt(pduData.substring(0, hwPos));
ipPos = pduData.indexOf(',', hwPos + 1); // get IP address position
if (ipPos == -1) { // no IP address parameter
hw = pduData.substring(hwPos + 1); // get hardware address
ip = // random IP address 10..99
ipAddress + (10 + (int) (BOOTPMedium.random() * 99));
boot = bootPath + bootFile; // set full boot file name
}
else { // IP address parameter
hw = // get hardware address
pduData.substring(hwPos + 1, ipPos);
bootPos = // get boot file position
pduData.indexOf(',', ipPos + 1);
if (bootPos == -1) { // no boot file parameter
ip = pduData.substring(ipPos + 1); // get IP address
boot = bootPath + bootFile; // set full boot file name
}
else { // boot file parameter
ip = // get IP address
pduData.substring(ipPos + 1, bootPos);
boot = // get boot file name
pduData.substring(bootPos + 1);
boot = bootPath + boot; // prefix with boot file path
}
}
events.addElement( // send reply
reply + "(" + trans +
"," + hw + "," + ip + "," + boot +
") - reply with IP address and boot file path");
}
}
return(events);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = // initialise events list
new Vector<ProtocolEvent>();
int start, middle, end; // start/middle/end positions
String pduData; // PDU data
if (s.startsWith(reply)) { // reply?
start = s.indexOf('(') + 1; // get contents start
end = s.indexOf(')'); // get contents end
pduData = s.substring(start, end); // get data contents
transmitPDU( // send reply
new PDU(reply, pduData), peer);
events.addElement( // transmit PDU
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
}
for (Enumeration e = entityEvents.elements(); // go through medium events
e.hasMoreElements(); )
events.addElement( // add medium event
(ProtocolEvent) e.nextElement());
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
pduReceived = pdu; // store PDU
return((new Vector<ProtocolEvent>())); // return no events
}
public void setPeer(ProtocolEntity peer) { // set protocol peer
this.peer = peer; // set this entity's peer
}
public void transmitPDU( // transmit PDU
PDU pdu, ProtocolEntity dest) { // for given PDU, destination
pdu.setSource(this); // source is this entity
pdu.setDestination(dest); // destination is as given
pduSent = pdu; // copy PDU sent
entityEvents = medium.receivePDU(pdu); // medium receives PDU
pduReceived = null; // note no PDU in response
}
}

@ -0,0 +1,177 @@
// BOOTPSender.java (C) K. J. Turner, K. A. Whyte 08/03/06
// Boot Protocol sender (client)
package protocol; // protocol package
import java.util.Enumeration; // enumeration
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
/**
This is the class for a boot protocol sender.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): unchecked warning suppressed
*/
public class BOOTPSender // protocol sender (client)
implements ProtocolEntity, Timeouts { // protocol entity, timeout
// simulator variables
private ProtocolEntity peer; // peer entity (client)
private Medium medium; // communications medium
private String name; // entity name
// protocol variables
private int transId; // transaction identifier
private String hwAddress = "hw"; // hardware address
private String ipAddress = "net.91"; // IP address
private String bootFile = "boot"; // boot file name
private PDU pduSent; // PDU sent
private PDU pduReceived; // PDU received
private boolean timerEnabled; // whether timer is enabled
private Vector<ProtocolEvent> entityEvents; // events from entity
// protocol state
int state; // current protocol state
final static int idle = 0; // no request outstanding
final static int wait = 1; // waiting for reply
// protocol messages
final static String request = "REQUEST"; // boot request message
final static String reply = "REPLY"; // boot reply message
// protocol methods
public BOOTPSender (Medium m, String name) { // construct sender instance
this.name = name; // set protocol entity name
medium = m; // set underlying medium
initialise (); // initialise protocol
}
public String getName () { // get protocol entity name
return((name)); // return protocol entity name
}
public boolean hasTimer (String type) { // protocol uses timer?
return((true)); // report it does
}
public void initialise() { // initialise protocol
state = idle; // initialise state
pduReceived = null; // initialise no PDU received
pduSent = null; // initialise no PDU sent
timerEnabled = false; // initialise no timeout
entityEvents = new Vector<ProtocolEvent>(); // empty medium events
}
public void setPeer(ProtocolEntity peer) { // set protocol peer
this.peer = peer; // set this entity's peer
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) {
timerEnabled = enabled; // store timer status
}
public Vector<String> getServices() {
Vector<String> events = // list of events
new Vector<String>();
String pduType; // received PDU type
String pduData; // PDU data
String pduTrans; // transaction identifier
int transPos, hwPos; // trans/hw address positions
int trans; // transaction identifier
if (pduReceived != null) { // PDU received?
pduType = pduReceived.type; // get received PDU type
pduData = pduReceived.sdu; // get received PDU data
transPos = pduData.indexOf('(') + 1; // get contents start
hwPos = pduData.indexOf(','); // get transaction end
trans = // get transaction identifier
Integer.parseInt(pduData.substring(transPos, hwPos));
if (pduType.equals(reply) && // reply message and ...
trans == transId) { // same transaction identifier?
timerEnabled = false;
state = idle; // no longer waiting
}
}
if (state == idle) { // not awaiting reply
trans = // make random id 10..99
10 + ((int) (BOOTPMedium.random() * 90));
events.addElement( // send request for IP/file
request + "(" + trans + "," +
hwAddress + ") - send IP address and boot file path request");
events.addElement( // send request for file
request + "(" + trans + "," +
hwAddress + "," + ipAddress +
") - send boot file path request");
events.addElement( // send request for file path
request + "(" + trans + "," +
hwAddress + "," + ipAddress + "," +
bootFile + ") - send path request for given boot file");
}
if (timerEnabled)
events.addElement("Timeout - presume loss of message and resend");
return(events); // return list of events
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = // initialise events list
new Vector<ProtocolEvent>();
int start, middle, end; // start/mid/end positions
String pduData; // PDU data
if (s.startsWith(request)) {
start = s.indexOf('(') + 1; // get contents start
middle = s.indexOf(','); // get trans ident end
end = s.indexOf(')' ); // get contents end
transId = // get transaction ident
Integer.parseInt(s.substring(start, middle));
pduData = s.substring(start, end); // get SDU
transmitPDU( // send request
new PDU(request, pduData), peer);
events.addElement( // transmit PDU
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
state = wait; // awaiting reply
}
if (s.startsWith("Timeout")) { // timeout?
transmitPDU(pduSent, peer); // re-send PDU
events.addElement( // add timeout event and PDU
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
for (Enumeration e = entityEvents.elements(); // go through medium events
e.hasMoreElements(); )
events.addElement( // add medium event
(ProtocolEvent) e.nextElement());
return((events)); // return list of events
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
pduReceived = pdu; // store PDU
return(new Vector<ProtocolEvent>()); // return no events
}
public void transmitPDU( // transmit PDU
PDU pdu, ProtocolEntity dest) { // for given PDU, destination
pdu.setSource(this); // source is this entity
pdu.setDestination(dest); // destination is as given
pduSent = pdu; // copy PDU sent
entityEvents = medium.receivePDU(pdu); // medium receives PDU
pduReceived = null; // note no PDU in response
timerEnabled = false; // note no timeout
}
}

@ -0,0 +1,140 @@
// CSMA.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of CSMA/CD.
@author Kenneth J. Turner
@version 1.0 (24th July 2010, KJT): initial version
*/
public class CSMA extends Protocol {
/** Maximum protocol retry limit */
private final static int MAX = 5;
/** Default protocol retry limit (0 means no collisions or retries) */
private final static int RETRIES = 0;
/** MAC 1 */
private CSMAProtocol protocolA;
/** MAC 2 */
private CSMAProtocol protocolB;
/** Protocol retry limit (default 0, i.e. no collisions or retries) */
protected static int retryLimit = RETRIES;
/** System 1 */
private CSMAService userA;
/** System 2 */
private CSMAService userB;
/** Index into random numbers */
protected static int randomIndex;
/** List of generated random numbers */
protected static Vector<Float> randomNumbers;
/**
Constructor for a CSMA object.
*/
public CSMA() {
medium = new CSMAMedium("LAN"); // create Medium
userA = new CSMAService("Station 1"); // create Station 1
userB = new CSMAService("Station 2"); // create Station 2
protocolA = // create MAC 1
new CSMAProtocol(medium, "MAC 1");
protocolB = // create MAC 2
new CSMAProtocol(medium, "MAC 2");
medium.setMediumType( // set medium delivery control
Medium.CONTROL_DELIVERY);
userA.setProvider(protocolA); // set Station 1 -> MAC 1
userB.setProvider(protocolB); // set Station 2 -> MAC 2
protocolA.setUser(userA); // set MAC 1 -> Station 1
protocolA.setPeer(protocolB); // set MAC 1 -> MAC 2
protocolB.setUser(userB); // set MAC 2 -> Station 2
protocolB.setPeer(protocolA); // set MAC 2 -> MAC 1
entities = new Vector<ProtocolEntity>(); // create entity list
entities.addElement(userA); // add Station 1
entities.addElement(protocolA); // add MAC 1
entities.addElement(medium); // add Medium
entities.addElement(protocolB); // add MAC 2
entities.addElement(userB); // add Station 2
randomNumbers = new Vector<Float>(); // initialise random numbers
}
/**
Return a random float. If the list of randoms contains an unused value then
use this, otherwise generate a fresh value and add to the list. This allows
random numbers to be generated consistently when simulation steps are
undone/redone.
@return random number in the range (0..1]
*/
protected static float getRandom() {
if (randomIndex < randomNumbers.size()) // index within list?
return( // return this random
((Float)randomNumbers.elementAt(randomIndex++)).floatValue());
else { // index not within list
Float random = new Float(Math.random()); // get random number
randomNumbers.addElement(random); // add random to list
randomIndex++; // increment list index
return(random.floatValue()); // return rand number
}
}
/**
Return the random numbers maintained by this protocol. The numbers are
stored in a scenario file.
@return random number list
*/
public Vector<Float> getRandomNumbers() {
return(randomNumbers); // return the random numbers
}
/**
Set a parameter of the CSMA simulation.
@param parameter parameter name (retryLimit)
@param value parameter value
*/
public void setParameter(String parameter, String value) {
try {
if (parameter.equals("retryLimit")) { // retry limit?
int count = Integer.parseInt(value); // get value as int (if any)
if (0 <= count && count <= MAX) // retry limit within range?
retryLimit = count; // set retry limit
else // retry limit out of range
System.err.println( // report error
"CSMA.setParameter: retry limit '" + value + "' out of range");
}
}
catch (NumberFormatException e) { // retry limit format exception?
System.err.println( // report error
"CSMA.setParameter: retry limit '" + value + "' not an integer");
}
}
/**
Set the random numbers maintained by this protocol. The numbers are
retrieved from a scenario file.
@param randoms random number list
*/
public void setRandomNumbers(Vector<Float> randoms) {
randomNumbers = randoms; // store the random numbers
}
}

@ -0,0 +1,105 @@
// CSMAMedium.java
package protocol; // protocol package
import java.util.Enumeration; // import Java enumerations
import java.util.HashSet; // import Java hash sets
import java.util.StringTokenizer; // import Java string tokenisers
import java.util.Vector; // import Java vectors
import support.*; // import Jasper support classes
/**
This is the class that defines a CSMA/CD medium.
@author Kenneth J. Turner
@version 1.0 (24th July 2010): initial version
*/
public class CSMAMedium extends Medium {
/** Medium deliver offer */
private final static String DELIVER = "Deliver ";
/** Medium name */
private String mediumName;
/**
Constructor for a CSMA/CD medium.
@param mediumName medium name
*/
public CSMAMedium(String mediumName) {
this.mediumName = mediumName; // set protocol name
}
/**
Return the PDU currently with the same destination and SDU, in a format such
as "START(D1) to MAC 1".
@param description service description
@return corresponding PDU (or null if not found)
*/
protected PDU getMatchingPDU(String description) {
description = // remove "Deliver "
description.substring(DELIVER.length());
for (Enumeration enumeration = pdus.elements();
enumeration.hasMoreElements(); ) { // go through PDUs
CSMAPdu pdu = // get next PDU
(CSMAPdu) enumeration.nextElement();
if (pdu.getDescription().equals(description)) // matching PDU found?
return(pdu); // return matched PDU
}
return(null); // return no PDU
}
/**
Get the medium name.
@return medium name
*/
public String getName() {
return(mediumName); // return protocol name
}
/**
Return a list of strings describing actions (services) that can be carried
out in the current state.
@return service descriptions
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
for (Enumeration enumeration = pdus.elements();
enumeration.hasMoreElements(); ) { // go through PDUs in medium
PDU pdu = (PDU) enumeration.nextElement();// get PDU
if (pdu != null) { // non-null PDU?
String description = pdu.getID(); // get PDU id
String destination = // get PDU destination name
pdu.getDestination().getName();
if (!contains(destination, list)) // nothing for this destination?
list.addElement(DELIVER + description + " to " + destination);
}
}
return(list);
}
/**
Check if the given string in contained in the given list.
@param string string to search for
@param list list to search
@return true/false if the medium has no/has PDUs
*/
public boolean contains(String string, Vector<String> list) {
for (int i = 0; i < list.size(); i++) { // go through list
String text = (String) list.get(i); // get list text
if (text.indexOf(string) >= 0) // text contains string?
return(true); // return true immediately
}
return(false); // return false as no match
}
}

@ -0,0 +1,67 @@
// CSMAPdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines CSMA/CD protocol messages.
@author Kenneth J. Turner
@version 1.0 (27th July 2010, KJT): initial version
*/
public class CSMAPdu extends PDU {
/** Protocol transmission finished PDU */
public final static String FINISH = "FINISH";
/** Protocol transmission collision PDU */
public final static String JAM = "JAM";
/** Protocol transmission started PDU */
public final static String START = "START";
/**
Constructor for a CSMA/CD PDU for the given type and with the given SDU.
@param type PDU type
@param sdu PDU payload as SDU
*/
public CSMAPdu(String type, String sdu) {
super(type, sdu); // construct PDU
}
/**
Return the PDU description with destination and SDU, in a format such as
"START(D1) to MAC 1".
@return PDU description
*/
public String getDescription() {
return(
getLabel() + " to " + getDestination().getName());
}
/**
Return the label for an arrow representing a CSMA/CD PDU in a time sequence
diagram.
@return PDU label
*/
public String getLabel() {
return( // return PDU as string
sdu == null || sdu.length() == 0 ? type : type + "(" + sdu + ")");
}
/**
Convert PDU to string.
@return PDU as string
*/
public String toString() {
return( // return PDU as string
sdu == null || sdu.length() == 0 ? type : type + "(" + sdu + ")");
}
}

@ -0,0 +1,414 @@
// CSMAProtocol.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the CSMA/CD MAC layer.
@author Kenneth J. Turner
@version 1.0 (24th July 2010, KJT): initial version
*/
public class CSMAProtocol implements ProtocolEntity {
////////////////////////// User Interface Messages ///////////////////////////
/** Protocol deliver offer */
private final static String DELIVER = "Deliver data to ";
/** Protocol finish transmission offer */
private final static String FINISH = "Finish sending data to ";
/** Protocol jam offer */
private final static String JAM = "Jam transmission to ";
/** Protocol retry limit report */
private final static String RETRIES =
"Report failure due to excessive retries";
/** Protocol start transmission offer */
private final static String START = "Start sending data to ";
////////////////////////////// Protocol States ///////////////////////////////
/** Protocol state - collision */
protected final static int NORMAL = 0;
/** Protocol state - collision detected */
protected final static int COLLISION = 1;
/** Protocol state - jam received following collision */
protected final static int JAM_IN = 2;
/** Protocol state - jam sent following collision */
protected final static int JAM_OUT = 3;
/** Protocol state - backing off following jam */
protected final static int BACKOFF = 4;
///////////////////////////// Protocol Variables /////////////////////////////
/** Protocol backoff count */
protected int protocolBackoff;
/** Protocol deferring to an incoming transmission */
private boolean protocolDeferring;
/** Protocol events */
private Vector<ProtocolEvent> protocolEvents;
/** Protocol PDU received */
protected CSMAPdu protocolIn;
/** Protocol channel */
protected CSMAMedium protocolMedium;
/** Protocol name */
protected String protocolName;
/** Protocol PDU sent */
protected CSMAPdu protocolOut;
/** Protocol peer */
protected CSMAProtocol protocolPeer;
/** Protocol in the process of receiving a message */
protected boolean protocolReceiving;
/** Protocol retry count */
protected int protocolRetries;
/** Protocol in the process of sending a message */
protected boolean protocolSending;
/** Protocol collision state */
protected int protocolState;
/** Protocol user */
protected CSMAService protocolUser;
////////////////////////////// Protocol Methods //////////////////////////////
/**
Constructor for a (de)multiplexer.
@param protocolMedium channel
@param protocolName protocol name
*/
public CSMAProtocol(Medium protocolMedium, String protocolName) {
this.protocolName = protocolName; // set protocol name
this.protocolMedium = // set protocol medium
(CSMAMedium) protocolMedium;
initialise(); // initialise protocol
}
/**
Return the backoff count as a random integer in the range (0, 2^retries].
This is 0..1 if there have been no retries, 0..2 if there has been one
retry, etc. Technically this is the number of slot times, but actual time is
irrelevant in the simulation approach.
@return backoff interval
*/
public int backoffCount() {
float backoff = // get random in (0, 2^retries]
(float) (CSMA.getRandom() * Math.pow(2.0, protocolRetries));
return(Math.round(backoff)); // return nearest integer
}
/**
Return a protocol event with the given comment.
@param comment protocol comment
@return protocol event
*/
public ProtocolEvent comment(String comment) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, comment));
}
/**
Get the protocol name.
@return protocol name
*/
public String getName() {
return(protocolName); // return protocol name
}
/**
Get the protocol peer.
@return protocol peer
*/
public CSMAProtocol getPeer() {
return(protocolPeer); // return protocol peer
}
/**
Return services currently offered.
@return list of protocol services
*/
public Vector<String> getServices() {
// System.err.println("CSMAProtocol.getServices - " + protocolName +
// ": protocolState <" + protocolState + "> protocolOut <" + protocolOut +
// "> protocolSending <" + protocolSending + ">");
String peerName = protocolPeer.getName(); // get peer name
Vector<String> list = new Vector<String>(); // initialise protocol services
if (protocolState != NORMAL) { // handling collision?
if (protocolState == COLLISION || // collision detected or
protocolState == JAM_IN) { // jam received?
list.add(JAM + peerName); // append jam sending offer
}
else if (protocolState == BACKOFF) { // backing off?
// System.err.println("CSMAProtocol.getServices - " + protocolName +
// ": state local <" + protocolState + "> remote <" +
// protocolPeer.protocolState + ">, backoff local <" +
// protocolBackoff + "> remote <" + protocolPeer.protocolBackoff +
// ">, protocolRetries local <" + protocolRetries + "> remote <" +
// protocolPeer.protocolRetries + ">\n");
int peerState = protocolPeer.protocolState; // get peer state
if (peerState == BACKOFF || // peer also backing off or
peerState == NORMAL) { // peer recovered from backoff?
if (protocolBackoff <= // local protocol can retry?
protocolPeer.protocolBackoff) {
protocolRetries++; // increment retry count
if (protocolRetries > CSMA.retryLimit) { // retry limit reached?
list.add(RETRIES); // add retry limit report
}
else { // retry limit not reached
protocolState = NORMAL; // set collision state to normal
protocolOut.type = CSMAPdu.START; // set PDU back to start
initialise_part(); // partly re-initialise protocol
list.add(START+ peerName + // append retry sending offer
" (retry " + protocolRetries + ")");
}
}
else { // local entity must wait
initialise_part(); // partly re-initialise protocol
protocolDeferring = true; // note deferring
}
}
}
} // not handling collision hereon
else if (protocolOut != null) { // outgoing PDU available?
if (protocolSending) { // already sending?
if (protocolMedium.isEmpty(protocolName)) { // no local PDUs sent?
list.add(FINISH + peerName); // append finish sending offer
}
}
else if ((protocolMedium.isEmpty() || // nothing in medium or
CSMA.retryLimit > 0) && // retries allowed, and
protocolPeer.protocolState == // peer not in collision and
NORMAL &&
!protocolDeferring) { // not deferring?
list.add(START + peerName); // append start sending offer
}
}
if (protocolIn != null && // incoming PDU available and
protocolState == NORMAL) { // not in collision?
String serviceName = protocolUser.getName(); // get service name
list.add(DELIVER + serviceName); // append deliver offer
}
return (list); // return protocol service list
}
/**
Initialise the protocol entity.
*/
public void initialise() {
initialise_part(); // partly initialise protocol
protocolIn = null; // initialise incoming PDU
protocolOut = null; // initialise outgoing PDu
protocolRetries = 0; // initialise no retries
CSMA.randomIndex = 0; // initialise random index
}
/**
Partly initialise the protocol entity in the event of backoff and retry.
*/
public void initialise_part() {
protocolDeferring = false; // initialise not deferring
protocolEvents = new Vector<ProtocolEvent>();// initialise protocol events
protocolReceiving = false; // initialise not receiving
protocolSending = false; // initialise not sending
protocolState = NORMAL; // initialise no collision
}
/**
Perform service.
@param service service request
@return resulting protocol events
*/
public Vector<ProtocolEvent> performService(String service) {
protocolEvents = new Vector<ProtocolEvent>(); // initialise protocol events
if (service.startsWith(DELIVER)) { // deliver request?
CSMASdu sdu = // create SDU from PDU
new CSMASdu(CSMASdu.DATA, protocolIn.sdu);
transmitPDU(sdu, protocolUser); // deliver SDU to service user
protocolIn = null; // re-initialise incoming PDU
}
else if (service.startsWith(FINISH)) { // finish sending request?
String message = protocolOut.sdu; // get current SDU
protocolOut = // create finish PDU
new CSMAPdu(CSMAPdu.FINISH, message);
protocolSending = false; // note not sending
protocolEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.TRANSMIT, protocolOut));
transmitPDU(protocolOut, protocolPeer); // send protocol PDU
if (protocolPeer.protocolState == NORMAL) // peer is in normal state?
protocolOut = null; // re-initialise outgoing PDU
}
else if (service.startsWith(JAM)) { // jamming request?
if (protocolState == JAM_IN) { // jam received?
protocolState = BACKOFF; // note backing off
protocolBackoff = backoffCount(); // compute backoff "time"
protocolEvents.addElement( // add backoff event
comment("backoff " + protocolBackoff));
}
else // jam not received
protocolState = JAM_OUT; // note jam sent
CSMAPdu pdu = new CSMAPdu(CSMAPdu.JAM, ""); // set jam PDU
protocolEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
transmitPDU(pdu, protocolPeer); // send protocol PDU
}
else if (service.startsWith(RETRIES)) { // retries response?
initialise(); // re-initialise whole protocol
CSMASdu sdu = // construct failure SDU
new CSMASdu(CSMASdu.FAIL, "Retry Limit");
transmitPDU(sdu, protocolUser); // deliver SDU to service user
}
else if (service.startsWith(START)) { // start sending request?
String message = protocolOut.sdu; // get current SDU
protocolOut = // create start PDU
new CSMAPdu(CSMAPdu.START, message);
protocolSending = true; // note sending
if (protocolReceiving) { // already receiving?
protocolState = COLLISION; // note collision
protocolEvents.addElement( // add collision event
comment("collision"));
}
protocolEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.TRANSMIT, protocolOut));
transmitPDU(protocolOut, protocolPeer); // send protocol PDU
}
return(protocolEvents); // return protocol events
}
/**
Receive PDU.
@param pdu PDU
@return resulting protocol events
*/
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
protocolEvents = new Vector<ProtocolEvent>(); // initialise event list
if (pdu != null) { // non-empty PDU?
String type = pdu.type; // get PDU type
String data = pdu.sdu; // get SDU
if (type.equals(CSMASdu.DATA)) { // service user message?
protocolOut = // store outgoing PDU
new CSMAPdu(CSMAPdu.START, data);
if (protocolReceiving) { // already receiving
protocolDeferring = true; // note deferring
protocolEvents.addElement( // add defer event
comment("defer"));
}
}
else if (type.equals(CSMAPdu.FINISH)) { // finish receiving message?
protocolReceiving = false; // note not receiving
if (protocolState == NORMAL) // normal state?
protocolIn = (CSMAPdu) pdu; // store incoming PDU
if (protocolDeferring) { // deferring?
protocolDeferring = false; // not deferring
protocolEvents.addElement( // add resume event
comment("resume"));
}
}
else if (type.equals(CSMAPdu.JAM)) { // jam message?
if (protocolState == JAM_OUT) { // jam sent?
protocolState = BACKOFF; // note backing off
protocolBackoff = backoffCount(); // compute backoff "time"
protocolEvents.addElement( // add backoff event
comment("backoff " + protocolBackoff));
}
else { // jam not sent
if (protocolState == NORMAL) { // normal state?
protocolEvents.addElement( // add collision event
comment("collision"));
}
protocolState = JAM_IN; // note jam received
}
}
else if (type.equals(CSMAPdu.START)) { // start receiving message?
protocolReceiving = true; // note receiving
if (protocolSending) { // already sending?
protocolState = COLLISION; // note collision
protocolEvents.addElement( // add collision event
comment("collision"));
}
else if (protocolOut != null) { // PDU to be sent?
protocolDeferring = true; // note deferring
if (protocolPeer.protocolState == NORMAL) // peer in normal state?
protocolEvents.addElement( // add defer event
comment("defer"));
}
if (protocolState == NORMAL && // normal state and
protocolDeferring) { // deferring to peer?
protocolPeer.protocolRetries = 0; // reset its retry count
}
}
}
return(protocolEvents); // return protocol events
}
/**
Set the protocol peer.
@param protocolPeer protocol peer
*/
public void setPeer(ProtocolEntity protocolPeer) {
this.protocolPeer = // set protocol peer
(CSMAProtocol) protocolPeer;
}
/**
Set the protocol service.
@param protocolUser protocol service user
*/
public void setUser(ProtocolEntity protocolUser) {
this.protocolUser = // set service user
(CSMAService) protocolUser;
}
/**
Send PDU.
@param pdu PDU
@param destination protocol destination
*/
public void transmitPDU(PDU pdu, ProtocolEntity destination) {
pdu.setSource(this); // set protocol entity as source
pdu.setDestination(destination); // set message destination
Vector<ProtocolEvent> receiveEvents; // declare receive events
if (destination == protocolPeer) { // for protocol peer?
receiveEvents = // receive PDU at medium
protocolMedium.receivePDU(pdu);
}
else // for service user?
receiveEvents = // receive PDU at user
protocolUser.receivePDU(pdu);
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
protocolEvents.addElement( // append receive event
receiveEvents.get(i));
}
}

@ -0,0 +1,51 @@
// CSMASdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines (de)multiplexer service messages.
@author Kenneth J. Turner
@version 1.0 (24th July 2010, KJT): initial version
*/
public class CSMASdu extends PDU {
/** Service SDU type */
public final static String DATA = "DATA";
/** Service retry limit failure */
public final static String FAIL = "FAIL";
/**
Constructor for a source/sink service message.
@param type SDU type
@param sdu SDU data
*/
public CSMASdu(String type, String sdu) {
super(type); // construct with type
this.sdu = sdu; // set SDU data
}
/**
Return the label for an arrow representing a (de)multiplexer SDU in a time
sequence diagram.
@return the label name
*/
public String getLabel() {
return(type + "(" + sdu + ")");
}
/**
Convert SDU to string.
*/
public String toString() {
return("SDU <Type " + type + ", Data " + sdu + ">");
}
}

@ -0,0 +1,179 @@
// CSMAService.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports sources/sinks for (de)multiplexing.
@author Kenneth J. Turner
@version 1.0 (24th July 2010, KJT): initial version
*/
public class CSMAService implements ProtocolEntity {
/** Service send offer */
private final static String SEND = "Send data to ";
/** Service message count */
private static int messageCount;
/** PDU sent by service */
private PDU sduSent;
/** Service entity name */
private String serviceName;
/** Service provider */
private CSMAProtocol serviceProvider;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public CSMAService(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return a protocol event with the given comment.
@param comment protocol comment
@return protocol event
*/
public ProtocolEvent comment(String comment) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, comment));
}
/**
Return a protocol event with an empty comment as a gap.
@return protocol event
*/
public ProtocolEvent gap() {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, ""));
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
CSMAProtocol remoteProvider = // get remote service provider
serviceProvider.protocolPeer;
CSMAMedium protocolMedium = // get protocol medium
serviceProvider.protocolMedium;
String providerName = // get provider name
serviceProvider.protocolName;
// System.err.println("CSMAService.getServices - " + serviceName +
// ": in <" + serviceProvider.protocolIn + "> out <" +
// serviceProvider.protocolOut + ">");
boolean localIdle = // check if local protocol idle
serviceProvider.protocolIn == null && // no incoming data pending?
serviceProvider.protocolOut == null && // no outgoing data pending?
!serviceProvider.protocolReceiving && // not receiving data?
protocolMedium.isEmpty(providerName); // no outgoing PDUs in transit?
boolean remoteIdle = // check if remote protocol idle
remoteProvider.protocolIn == null && // no incoming data pending and
remoteProvider.protocolState == CSMAProtocol.NORMAL; // no collision?
// System.err.println("CSMAService.getServices - localIdle <" +
// localIdle + "> remoteIdle <" + remoteIdle + ">\n");
if (localIdle && remoteIdle) { // local and remote idle?
String name = // get peer system name
serviceProvider.protocolPeer.protocolUser.getName();
list.addElement(SEND + name); // add send to list
}
return(list); // return service list
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.startsWith(SEND)) { // send request?
String message = "D" + messageCount; // create data message
PDU sdu = // create SDU
new CSMASdu(CSMASdu.DATA, message);
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceEvents.addElement( // deliver SDU
new ProtocolEvent(ProtocolEvent.DELIVER, sdu));
serviceEvents.addElement(gap()); // add a vertical gap
return(serviceEvents); // return service events
}
/**
Set the local service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = // set local service provider
(CSMAProtocol) serviceProvider;
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
serviceEvents.addElement( // append receive event
receiveEvents.get(i));
sduSent = sdu; // stored the sent SDU
}
}

@ -0,0 +1,34 @@
// HTTPSender.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of HTTP.
@author Kenneth J. Turner, Kenneth A. Whyte
@version 1.4 (9th March 2006, KJT/KAW): initial version
<br/> 1.5 (19th July 2010, KJT): minor tidying
*/
public class HTTP extends Protocol {
private HTTPSender sender;
private HTTPReceiver receiver;
public HTTP() {
medium = new Medium();
sender = new HTTPSender(medium, "Client");
receiver = new HTTPReceiver(medium, "Server");
sender.setPeer(receiver);
receiver.setPeer(sender);
entities = new Vector<ProtocolEntity>();
entities.addElement(sender);
entities.addElement(medium);
entities.addElement(receiver);
}
}

@ -0,0 +1,139 @@
// HTTPReceiver.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of an HTTP receiver (i.e. server).
@author Kenneth J. Turner, Kenneth A. Whyte
@version 1.4 (9th March 2006, KJT/KAW): initial version
<br/> 1.5 (24th July 2010, KJT): minor tidying
*/
public class HTTPReceiver implements ProtocolEntity {
private PDU pduReceived;
private PDU pduSent;
private ProtocolEntity peer;
private Medium medium;
private String name;
private int index; // data/URL index for move
public HTTPReceiver(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public void initialise() {
pduReceived = null;
index = 1;
}
public Vector<String> getServices() {
int url, moved; // given/moved URL number
Vector<String> list = new Vector<String>();
String sdu; // SDU
if (pduReceived != null && // PDU not null?
(sdu = pduReceived.sdu) != null && // SDU not null?
sdu.startsWith("URL")) { // URL and number?
try { // parse number
url = Integer.parseInt(sdu.substring(3)); // get URL number
}
catch (NumberFormatException exc) { // incorrect number
url = 0; // set default URL number
}
}
else // not URL
url = 0; // set zero URL number
if (pduReceived != null && pduReceived.type.equals("GET")) {
if (url == index) // URL same as local one?
moved = index + 1; // use next local for move
else // URL differs from local
moved = index; // use local for move
list.addElement("200 OK(DATA" + url + ") - send requested data");
list.addElement("301 MOVED(URL" + moved + ") - report moved URL");
list.addElement("400 ERROR(CODE) - report requested data unavailable");
}
if (pduReceived != null && pduReceived.type.equals("HEAD")) {
if (url == index) // URL same as local one?
moved = index + 1; // use next local for move
else // URL differs from local
moved = index; // use local for move
list.addElement
("200 OK(HEADER" + url + ") - send requested header");
list.addElement
("301 MOVED(URL" + moved + ") - report moved URL");
list.addElement
("400 ERROR(CODE) - report requested header unavailable");
}
if (pduReceived != null && pduReceived.type.equals("POST")) {
list.addElement("200 OK - acknowledge receipt of data");
list.addElement("400 ERROR(CODE) - report data not posted");
}
if (pduReceived != null && pduReceived.type.equals("PUT")) {
list.addElement("200 OK - acknowledge receipt of data");
list.addElement("400 ERROR(CODE) - report data not posted");
}
return(list);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
pduSent = null;
String data, url;
int startIndex, endIndex;
startIndex = s.indexOf ('(') + 1;
endIndex = s.indexOf (')');
if (s.startsWith ("200")) {
if (startIndex < endIndex) // any data?
data = s.substring(startIndex, endIndex);
else // no data
data = "";
transmitPDU(new PDU("200 OK", data), peer);
}
if (s.startsWith ("301")) {
url = s.substring(startIndex, endIndex); // get URL
index++; // update local index
transmitPDU(new PDU("301 MOVED", url), peer);
}
if (s.startsWith("400")) {
data = s.substring(startIndex, endIndex); // get data
transmitPDU(new PDU("400 ERROR", data), peer);
}
if (pduSent != null) {
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
events.addElement(new ProtocolEvent(ProtocolEvent.RECEIVE, pduSent));
}
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
pduSent = pdu;
peer.receivePDU(pdu);
pduReceived = null;
}
}

@ -0,0 +1,155 @@
// HTTPSender.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of an HTTP sender (i.e. client).
@author Kenneth J. Turner, Kenneth A. Whyte
@version 1.4 (9th March 2006, KJT/KAW): initial version
<br/> 1.5 (19th July 2010, KJT): minor tidying
*/
public class HTTPSender implements ProtocolEntity {
// Protocol state constants
private static final int IDLE = 0; // ready to send
private static final int GET_SENT = 1; // waiting GET resp.
private static final int HEAD_SENT = 2; // waiting HEAD resp.
private static final int POST_SENT = 3; // waiting POST resp.
private static final int PUT_SENT = 4; // waiting PUT resp.
private int state;
private PDU pduSent;
private PDU pduReceived;
private ProtocolEntity peer;
private Medium medium;
private String name;
private int index; // data/URL index
public HTTPSender(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
String pduType, pduData;
if (pduReceived != null) {
pduType = pduReceived.type;
pduData = pduReceived.sdu;
}
else {
pduType = "";
pduData = "";
}
switch (state) {
case GET_SENT:
if (pduType.startsWith("200") || pduType.startsWith("400"))
state = IDLE;
else if (pduType.startsWith("301"))
list.addElement(pduSent.type + "(" + pduData + ") - get data for new URL");
break;
case HEAD_SENT:
if (pduType.startsWith("200") || pduType.startsWith("400"))
state = IDLE;
else if (pduType.startsWith("301"))
list.addElement(pduSent.type + "(" + pduData + ") - get header for new URL");
break;
case POST_SENT:
case PUT_SENT:
if (pduType.startsWith("200") || pduType.startsWith("400"))
state = IDLE;
break;
}
if (state == IDLE) {
list.addElement("GET(URL" + index + ") - get data for URL");
list.addElement("HEAD(URL" + index + ") - get header for URL");
list.addElement("POST(URL" + index + ",DATA" +
index + ") - append data to URL");
list.addElement("PUT(URL" + index + ",DATA" +
index + ") - send data to URL");
}
return(list);
}
public void initialise() {
state = IDLE;
index = 1;
pduSent = null;
pduReceived = null;
}
public Vector<ProtocolEvent> performService (String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
int startIndex, midIndex, endIndex; // start/mid/end subscripts
String url = ""; // current URL
String data; // URL data
pduSent = null;
startIndex = s.indexOf ('(') + 1; // get URL start
endIndex = s.indexOf (')'); // get URL end
if (s.startsWith ("GET")) { // GET?
url = s.substring(startIndex, endIndex); // get URL
transmitPDU(new PDU("GET", url), peer);
state = GET_SENT; // GET now sent
}
else if (s.startsWith ("HEAD")) { // HEAD?
url = s.substring(startIndex, endIndex); // get URL
transmitPDU(new PDU("HEAD", url), peer);
state = HEAD_SENT; // HEAD now sent
}
else if (s.startsWith ("POST")) { // POST?
midIndex = s.indexOf (','); // get URL end
url = s.substring(startIndex, midIndex); // get URL
data = s.substring(midIndex + 1, endIndex); // get URL data
transmitPDU(new PDU("POST", url + "," + data), peer);
state = POST_SENT; // POST now sent
}
else if (s.startsWith ("PUT")) { // PUT?
midIndex = s.indexOf (','); // get URL end
url = s.substring(startIndex, midIndex); // get URL
data = s.substring(midIndex + 1, endIndex); // get URL data
transmitPDU(new PDU("PUT", url + "," + data), peer);
state = PUT_SENT; // PUT now sent
}
if (pduSent != null) {
startIndex = url.indexOf ("URL"); // get URL start
index = // extract/increment index
Integer.parseInt(url.substring(startIndex + 3)) + 1;
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
events.addElement( new ProtocolEvent(ProtocolEvent.RECEIVE, pduSent));
}
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
pduSent = pdu;
peer.receivePDU(pdu);
pduReceived = null;
}
}

@ -0,0 +1,72 @@
// IP.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class IP extends Protocol {
private IPService userA;
private IPService userB;
private IPProtocol protA;
private IPProtocol protB;
public IP() {
medium = new IPMedium();
userA = new IPService("User A");
userB = new IPService("User B");
protA = new IPProtocol(medium, "Protocol A");
protB = new IPProtocol(medium, "Protocol B");
userA.setProvider(protA);
userB.setProvider(protB);
protA.setUser(userA);
protA.setPeer(protB);
protB.setUser(userB);
protB.setPeer(protA);
entities = new Vector<ProtocolEntity>();
entities.addElement(userA);
entities.addElement(protA);
entities.addElement(medium);
entities.addElement(protB);
entities.addElement(userB);
}
public void setParameter(String param, String value) {
IPMedium ipMedium = (IPMedium)medium;
if (param.equals("misordering")) {
ipMedium.setMisordering(Boolean.valueOf(value).booleanValue());
System.out.println(param + " set: " + value);
return;
}
try {
if (param.equals("lossRate")) {
ipMedium.setLossRate(Float.valueOf(value).floatValue());
System.out.println(param + " set: " + value);
return;
}
int size = Integer.parseInt(value);
if (param.equals("userMessageSize")) {
userA.setMessageSize(size);
userB.setMessageSize(size);
System.out.println(param + " set: " + size);
return;
}
if (param.equals("maxProtocolMessageSize")) {
protA.setMaxMessageSize(size);
protB.setMaxMessageSize(size);
System.out.println(param + " set: " + size);
return;
}
if (param.equals("maxMediumMessageSize")) {
ipMedium.setMaxMessageSize(size);
System.out.println(param + " set: " + size);
return;
}
}
catch (NumberFormatException e) { // invalid number value
System.out.println(param + " number format exception: " + value);
}
}
}

@ -0,0 +1,195 @@
// IPMedium.java
package protocol;
import java.util.*;
import support.*;
/**
This is the class for an IP medium.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version <br/>
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (24th July 2010, KJT): minor tidying
*/
public class IPMedium extends Medium {
private int maxMessageSize = 100; // maximum message size
private boolean misordering = true; // misordering allowed?
private float lossRate = 0.2f; // message loss rate
private Vector<Float> randomNumbers; // random numbers
private int randomIndex; // random number index
public IPMedium() {
super(); // construct superclass
randomNumbers = new Vector<Float>(); // initialise random numbers
}
public void initialise() {
super.initialise();
randomIndex = 0; // initialise random index
}
public void setMaxMessageSize(int size) {
maxMessageSize = size;
}
public void setMisordering(boolean b) {
misordering = b;
}
public void setLossRate(float rate) {
lossRate = rate;
}
// randomise the order of the elements of vector v
private void misorder(Vector<ProtocolEvent> v) {
Vector<ProtocolEvent> t = new Vector<ProtocolEvent>(v);
int size = v.size();
v.removeAllElements();
while (size > 0) {
// choose an element of t at random and add it to v
int index = Math.round(--size * random());
v.addElement(t.elementAt(index));
t.removeElementAt(index);
}
}
// Identify and return PDU currently on channel with
// type and parameters matching those described in given string
// Parameters are:
// ( messageID [,fragment offset] [,D] [,M] )
// where D and M are booleans
// "D" indicates Don't Fragment
// "M" indicates More Fragments Follow
protected PDU getMatchingPDU(String s) {
IPMessage ipd;
int messageID = -1;
int offset = -1;
// extract name of source entity for this datagram:
int sourceStart = s.indexOf('[') + 1;
int sourceEnd = s.indexOf( ']' );
String sourceName = s.substring(sourceStart, sourceEnd);
// get type and parameters of PDU from action string
// PDU type starts after first space following "Deliver" or "Lose":
int typeStart = s.indexOf(' ') + 1;
int typeEnd = s.indexOf( '(' );
if (typeEnd < 0) typeEnd = sourceStart - 2;
String type = s.substring(typeStart, typeEnd);
String[] params = getParams(s);
messageID = Integer.parseInt(params[0]);
if (params.length > 1) { // there is a fragment offset parameter
try {
offset = Integer.parseInt(params[1]); // fragment offset
}
catch (NumberFormatException e) { // not offset parameter - ignore
}
}
// try to match IP datagram type and messageID, and fragment offset where
// applicable, with a datagram currently on channel:
for (Enumeration e = pdus.elements(); e.hasMoreElements(); ) {
ipd = (IPMessage)e.nextElement();
if (ipd != null && ipd.type.equals(type)
&& ipd.getSource().getName().equals(sourceName)
&& messageID == ipd.messageID
&& (offset < 0 || (offset >= 0 && offset == ipd.fragOffset)))
return(ipd);
}
return(null); // no match found
}
/** Return a list of strings describing actions (services) that can be carried
out in the current state */
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
for (Enumeration e = pdus.elements(); e.hasMoreElements(); ) {
PDU pdu = (PDU)e.nextElement();
if (pdu != null) {
String s = pdu.getID();
s += " [" + pdu.getSource().getName() + "]";
if (misordering)
list.addElement("Deliver " + s + " - fragmentation/misordering");
else
list.addElement("Deliver " + s + " - fragmentation");
list.addElement("Lose " + s + " - congestion/error");
}
}
return(list);
}
/** Carry out the action specified in the given string, and return a list of
protocol events resulting from this action */
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
IPMessage frag;
IPMessage ipd = (IPMessage)getMatchingPDU(s);
if (ipd == null) return(events);
if (s.startsWith("Deliver")) {
ProtocolEntity destination = ipd.getDestination();
// Split message into fragments (up to size maxMessageSize)
int messageSize = ipd.size;
for (int relOffset = 0; relOffset < messageSize;
relOffset += maxMessageSize) {
int size = Math.min(messageSize - relOffset, maxMessageSize);
int offset = ipd.fragOffset + relOffset;
frag = new IPMessage("DT", ipd.messageID, offset, size);
frag.setSDU(ipd.getSDU());
frag.setMoreFrags(ipd.hasMoreFrags() ||
relOffset + maxMessageSize < messageSize);
frag.setSource(ipd.getSource());
frag.setDestination(destination);
// decide randomly whether to lose fragment
if (random() >= lossRate)
events.addElement(new ProtocolEvent(ProtocolEvent.FRAGMENT, frag));
else
events.addElement(new ProtocolEvent(ProtocolEvent.LOSE, frag));
}
if (misordering)
misorder(events); // transmit fragments in random order
for (Enumeration e = events.elements(); e.hasMoreElements(); ) {
ProtocolEvent event = (ProtocolEvent) e.nextElement();
if (event.getType() == ProtocolEvent.FRAGMENT) {
IPMessage ipdSent = (IPMessage)event.getPDU();
transmitPDU(ipdSent, destination);
}
}
pdus.removeElement(ipd);
}
if (s.startsWith("Lose")) {
destinationEvents.removeAllElements();
pdus.removeElement(ipd);
events.addElement(new ProtocolEvent(ProtocolEvent.LOSE, ipd));
}
// tack on any events triggered by delivery of a message
// to its destination protocol entity
for (Enumeration e = destinationEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
/**
Return a random float. If the list of randoms contains an unused value then
use this, otherwise generate a fresh value and add to the list. This allows
random numbers to be generated consistently when simulation steps are
undone/redone.
@return random number in the range (0..1]
*/
private float random() {
if (randomIndex < randomNumbers.size()) // index within list?
return( // return this random
((Float)randomNumbers.elementAt(randomIndex++)).floatValue());
else { // index not within list
Float random = new Float(Math.random()); // get random number
randomNumbers.addElement(random); // add random to list
randomIndex++; // increment list index
return(random.floatValue()); // return rand number
}
}
}

@ -0,0 +1,77 @@
// IPMessage.java (C) I. A. Robin, K. J. Turner 01/03/01
package protocol;
import support.*;
public class IPMessage extends PDU {
int messageID;
int fragOffset = -1; // fragment offset
private boolean dontFrag = false;
private boolean moreFrags = false;
public IPMessage(String type, int mid, int length) {
super(type);
messageID = mid;
this.size = length;
}
public IPMessage(String type, int mid, int offset, int length) {
super(type);
messageID = mid;
fragOffset = offset;
this.size = length;
}
public void setDontFrag(boolean d) {
dontFrag = d;
}
public boolean dontFrag() {
return dontFrag;
}
public void setMoreFrags(boolean m) {
moreFrags = m;
}
public boolean hasMoreFrags() {
return moreFrags;
}
public boolean matches(PDU pdu) {
if (pdu == null || pdu.getClass() != IPMessage.class)
return false;
IPMessage ipd = (IPMessage)pdu;
if (type.equals(ipd.type) && source == ipd.getSource()
&& messageID == ipd.messageID
&& (fragOffset < 0 ||
fragOffset >= 0 &&
ipd.fragOffset >= fragOffset &&
ipd.fragOffset < fragOffset + size)) return true;
return false;
}
// return label for arrow representing this ip datagram
// in a time sequence diagram
public String getLabel() {
String label = getID();
if (fragOffset >= 0) label += moreFrags? " +" : " -";
return label;
}
// return string representing this pdu in actions menu
public String getID() {
String id = type + "(" + messageID;
if (fragOffset >= 0) {
id += "," + fragOffset;
if (dontFrag) id += ",D";
}
id += "," + size + ")";
return id;
}
}

@ -0,0 +1,186 @@
// IPProtocol.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class IPProtocol implements ProtocolEntity {
private static final String TTL_EXPIRY = "Time-To-Live expiry: Message ID ";
private ProtocolEntity peer;
private IPService user;
private Vector userEvents;
private Medium medium;
private String name;
private int maxMessageSize = 200;
private Vector<Integer> expiredMIDs; // expired message IDs
private Vector<IPMessage> recvFragments; // message fragments
private int messageID; // current message ID
public IPProtocol(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public void initialise() {
messageID = 0;
expiredMIDs = new Vector<Integer>();
userEvents = new Vector();
recvFragments = new Vector<IPMessage>();
}
public String getName() {
return(name);
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void setUser(ProtocolEntity user) {
this.user = (IPService)user;
}
public void setMaxMessageSize(int maxSize) {
maxMessageSize = maxSize;
}
// if all fragments of message with message identifier mID
// have arrived, return total message size, else return 0
private int completeMessageSize(int mID) {
int expectedSize = 0;
int sizeSoFar = 0;
for (Enumeration e = recvFragments.elements(); e.hasMoreElements(); ) {
IPMessage ipd = (IPMessage)e.nextElement();
if (ipd.messageID == mID) {
sizeSoFar += ipd.size;
if (!ipd.hasMoreFrags()) {
// last fragment has "More Fragments" flag unset; get
// message size from offset and size of last fragment
expectedSize = ipd.fragOffset + ipd.size;
}
}
}
if (expectedSize > 0 && sizeSoFar == expectedSize) return(expectedSize);
return(0); // message incomplete
}
private void removeFragments(int mID) {
// remove all message fragments with message identifier mID
Enumeration e = recvFragments.elements();
while (e.hasMoreElements()) {
IPMessage ipd = (IPMessage)e.nextElement();
if (ipd.messageID == mID) {
recvFragments.removeElement(ipd);
e = recvFragments.elements();
}
}
}
// add new message ID to expired list
// but not if this message ID already appears in list
private void addExpired(int mID) {
Integer iMID = new Integer(mID);
if (expiredMIDs.indexOf(iMID) < 0)
expiredMIDs.addElement(iMID);
}
// return true if TTL for message ID has expired
private boolean expired(int mID) {
Integer iMID = new Integer(mID);
return(expiredMIDs.indexOf(iMID) >= 0);
}
// find oldest (ie smallest) message identifier of
// any message fragment received so far
// return -1 if no messages have been received yet
private int oldestMessageID() {
if (recvFragments.isEmpty()) return(-1);
IPMessage ipd = (IPMessage)recvFragments.firstElement();
int oldestSoFar = ipd.messageID;
for (Enumeration e = recvFragments.elements(); e.hasMoreElements(); ) {
ipd = (IPMessage)e.nextElement();
oldestSoFar = Math.min(oldestSoFar, ipd.messageID);
}
return(oldestSoFar);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
String pduType = "";
int size;
if (pdu != null) {
pduType = pdu.type;
if (pduType.equals("DatReq")) { // DatReq from user
int messageSize = pdu.size;
// fragment message
for (int offset = 0; offset < messageSize; offset += maxMessageSize) {
size = Math.min(messageSize - offset, maxMessageSize);
IPMessage fragment = new IPMessage("DT", messageID, offset, size);
fragment.setSDU(pdu.getSDU());
fragment.setMoreFrags(offset + maxMessageSize < messageSize);
transmitPDU(fragment, peer);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, fragment));
}
messageID++;
}
if (pduType.equals("DT")) { // data PDU received
// simulate reconstruction of message fragments
IPMessage ipd = (IPMessage)pdu;
int mID = ipd.messageID;
if (!expired(mID)) recvFragments.addElement(ipd);
size = completeMessageSize(mID);
if (size > 0) { // all fragments rcvd.
PDU pduSent = new PDU("DatInd", pdu.getSDU());
transmitPDU(pduSent, user);
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
// dispose of fragments of delivered message:
removeFragments(mID);
}
}
}
return(events);
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
if (dest == peer)
userEvents = medium.receivePDU(pdu);
else
userEvents = user.receivePDU(pdu);
}
public Vector<String> getServices() {
Vector<String> services = new Vector<String>();
int oldestMID = oldestMessageID();
if (oldestMID >= 0)
services.addElement(TTL_EXPIRY + oldestMID);
return(services);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith(TTL_EXPIRY)) {
int mIDIndex = s.indexOf("ID") + 3;
int mID = Integer.parseInt(s.substring(mIDIndex));
removeFragments(mID);
addExpired(mID);
events.addElement(
new ProtocolEvent(ProtocolEvent.COMMENT, this,
"TTL expiry " + mID));
}
for (Enumeration e = userEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
}

@ -0,0 +1,71 @@
// IPService.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class IPService implements ProtocolEntity {
public static final String DAT_REQ = "Data Request";
private ProtocolEntity provider; // protocol for service
private Vector providerEvents;
private String name;
private int block; // block seq. no.
private int messageSize = 400;
public IPService(String name) {
this.name = name;
initialise();
}
public void initialise() {
block = 0;
providerEvents = new Vector();
}
public String getName() {
return(name);
}
public void setProvider(ProtocolEntity provider) {
this.provider = provider;
}
public void setMessageSize(int size) {
messageSize = size;
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
return(new Vector<ProtocolEvent>());
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
providerEvents = dest.receivePDU(pdu);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
list.addElement("Send " + DAT_REQ + "(D" + block + ")");
return(list);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith("Send " + DAT_REQ)) {
String sdu = "D" + block;
PDU pdu = new PDU("DatReq", sdu);
pdu.size = messageSize;
transmitPDU(pdu, provider);
block++;
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
}
for (Enumeration e = providerEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
}

@ -0,0 +1,132 @@
// MCAST.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of multicasting. It handles broadcast,
unicast and multicast.
@author Kenneth J. Turner
@version 1.0 (22nd July 2010, KJT): initial version
*/
public class MCAST extends Protocol {
/** Broadcast service mode */
public final static int BROADCAST = 0;
/** Multiple unicast service mode */
public final static int UNICAST = 1;
/** Multicast service mode */
public final static int MULTICAST = 2;
/** Service entities */
private static Vector<ProtocolEntity> serviceEntities;
/** Service mode */
public static int serviceMode = BROADCAST;
/** Source */
private MCASTSource source;
/** Router A */
private MCASTRouter userA;
/** Router B */
private MCASTRouter userB;
/** Router C */
private MCASTRouter userC;
/** Router D */
private MCASTRouter userD;
/** Router E */
private MCASTRouter userE;
/** Router F */
private MCASTRouter userF;
/**
Constructor for an MCAST object.
*/
public MCAST() {
source = new MCASTSource("Source"); // create source
userA = new MCASTRouter("Router A"); // create router A
userB = new MCASTRouter("Router B"); // create router B
userC = new MCASTRouter("Router C"); // create router C
userD = new MCASTRouter("Router D"); // create router D
userE = new MCASTRouter("Router E"); // create router E
userF = new MCASTRouter("Router F"); // create router F
serviceEntities = new Vector<ProtocolEntity>();
serviceEntities.addElement(source); // add source
serviceEntities.addElement(userA); // add router A
serviceEntities.addElement(userB); // add router B
serviceEntities.addElement(userC); // add router C
serviceEntities.addElement(userD); // add router D
serviceEntities.addElement(userE); // add router E
serviceEntities.addElement(userF); // add router F
entities = serviceEntities; // store entities for protocol
}
/**
Return a protocol event with the given comment.
@param entity protocol entity
@param comment protocol comment
@return protocol event
*/
public static ProtocolEvent comment(ProtocolEntity entity, String comment) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, entity, comment));
}
/**
Get an entity by letter.
@param entityLetter entity letter ('A', etc.)
@return protocol entity
*/
public static ProtocolEntity getEntity(char entityLetter) {
int index = entityLetter - 'A' + 1;
return(serviceEntities.get(index)); // return entity for index
}
/**
Get an entity's SDUs.
@param entityLetter entity router letter ('A', etc.)
@return SDU held by router
*/
public static Vector<MCASTSdu> getSDUs(char entityLetter) {
ProtocolEntity entity = // get entity for letter
getEntity(entityLetter);
return(((MCASTRouter) entity).getSDUs()); // return SDUs
}
/**
Set a parameter of the MCAST simulation.
@param parameter parameter name (broadcast, multicast, unicast)
@param value parameter value
*/
public void setParameter(String parameter, String value) {
if (parameter.equals("serviceMode")) { // service count?
if (value.equalsIgnoreCase("broadcast")) // broadcast?
serviceMode = BROADCAST; // note as broadcast
else if (value.equalsIgnoreCase("multicast")) // multicast?
serviceMode = MULTICAST; // note as multicast
else if (value.equalsIgnoreCase("unicast")) // unicast?
serviceMode = UNICAST; // note as unicast
else // not broad/multi/unicast
System.err.println( // report error
"MUX.setParameter: invalid service mode '" + value + "'");
}
}
}

@ -0,0 +1,273 @@
// MCASTRouterA.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports a router for broad/uni/multicast.
@author Kenneth J. Turner
@version 1.0 (22nd July 2010, KJT): initial version
*/
public class MCASTRouter implements ProtocolEntity {
/** Service send offer */
private final static String SEND = "Forward message for router ";
/** Current router letter */
public char currentRouter;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit output */
private Vector<MCASTSdu> sdus;
/** Service entity name */
private String serviceName;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public MCASTRouter(String serviceName) {
this.serviceName = serviceName; // set service name
currentRouter = lastOf(serviceName); // set current router letter
initialise(); // initialise service entity
}
/**
Find the SDU with the given destinations.
@param destinations destinations
@return the corresponding SDU (or null if none)
*/
public MCASTSdu findSDU(String destinations) {
MCASTSdu result = null; // initialise SDU result
for (int i = 0; i < sdus.size(); i++) { // go through SDUs
MCASTSdu sdu = sdus.get(i); // get SDU
if (sdu.destinations.equals(destinations)) { // destinations found?
result = sdu; // save result
break; // exit loop
}
}
return(result); // return SDU
}
/**
Get first character of string.
@param string string to extract from
@return first character of string
*/
public char firstOf(String string) {
char letter = '?'; // initialise letter
if (string != null) { // non-null string?
int length = string.length(); // get string length
if (length > 0) // non-empty string?
letter = string.charAt(0); // get first character
}
return(letter); // return first character
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Return the service data units.
@return service data units
*/
public Vector<MCASTSdu> getSDUs() {
return(sdus); // return service data units
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (sdus != null && sdus.size() > 0) { // SDUs from service user?
for (int i = 0; i < sdus.size(); i++) { // go through SDUs
MCASTSdu sdu = sdus.get(i); // get SDU
String destinations = sdu.destinations; // get SDU destinations
String destination = ""; // initialise destination
for (int j = 0; j < destinations.length(); j++) { // go through dests.
if (j > 0) // not first destination?
destination += ", "; // append comma
destination += destinations.charAt(j);// append destination
}
char router = firstOf(destination); // get router letter
if (router != currentRouter) // not current router?
list.addElement(SEND + destination); // add send to list
}
}
return(list); // return service list
}
/**
Initialise the service entity.
*/
public void initialise() {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
sdus = new Vector<MCASTSdu>(); // initialise SDUs
}
/**
Get last character of string.
@param string string to extract from
@return last character of string
*/
public char lastOf(String string) {
char letter = '?'; // initialise letter
if (string != null) { // non-null string?
int length = string.length(); // get string length
if (length > 0) // non-empty string?
letter = string.charAt(length - 1); // get last character
}
return(letter); // return last character
}
/**
Check if the destination router is more than one hop from the current router
(i.e. is not the next router letter.
@param destination entity destination
@return true/false if destination is not/is adjacent
*/
public boolean laterRouter(ProtocolEntity destination) {
int currentIndex = (int) currentRouter; // get current router index
int destinationIndex = // get destination router index
(int) ((MCASTRouter) destination).currentRouter;
return(destinationIndex > currentIndex + 1);// return router letter check
}
/**
Return the next router to reach the destination. This is a very restricted
routing table for the purposes of this example.
@param destination entity destination
@return next entity destination
*/
public ProtocolEntity nextRouter(ProtocolEntity destination) {
char destinationLetter = // get destination router letter
((MCASTRouter) destination).currentRouter;
char nextLetter = destinationLetter; // assume destination by default
switch (currentRouter) { // route based on current router
case 'A': // at router A?
switch (destinationLetter) { // check destination index
case 'D': // to router D?
nextLetter = 'C'; // via C
break;
case 'E': // to router E?
nextLetter = 'C'; // via C
break;
}
break;
}
return(MCAST.getEntity(nextLetter)); // return next router entity
}
/**
Perform service. Note that the current implementation works for a particular
topology but is not general. When there are multiple destinations, the
router forward to the first two of these. A more general implementation
would embody particular knowledge about routing.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.startsWith(SEND)) { // send request?
String destinations = // get destinations
service.substring(SEND.length());
String destination = // remove destination commas
destinations.replaceAll(", ", ""); // get destination(s)
MCASTSdu sdu = findSDU(destination); // find corresponding SDU
char router = firstOf(destination); // get destination router letter
serviceEvents.addElement( // add forward comment
MCAST.comment(this, "forward"));
transmitPDU(sdu, router); // transmit SDU
sdus.remove(sdu); // remove SDU from SDUs
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
String destinations = // get SDU destination(s)
((MCASTSdu) sdu).destinations;
if (destinations.length() > 1) { // more than one destination?
String message = ((MCASTSdu) sdu).sdu; // get SDU message
sdu = // get SDU for first destination
new MCASTSdu(destinations.substring(0, 1), message);
sdus.addElement((MCASTSdu) sdu); // store SDU
sdu = // get SDU for later dests.
new MCASTSdu(destinations.substring(1), message);
sdus.addElement((MCASTSdu) sdu); // store SDU
}
else // one destination
sdus.addElement((MCASTSdu) sdu); // store SDU
}
return(serviceEvents); // return service events
}
/**
Send an SDU to the given destination letter.
@param sdu SDU
@param destination destination letter
*/
public void transmitPDU(PDU sdu, char destination) {
ProtocolEntity entityDestination = // get protocol entity dest.
MCAST.getEntity(destination);
transmitPDU(sdu, entityDestination); // transmit PDU
}
/**
Send an SDU to the given destination entity.
@param sdu SDU
@param destination destination entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
destination = nextRouter(destination); // set next router destination
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
if (laterRouter(destination)) { // later router?
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.TRAVERSE, sdu));
}
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
serviceEvents.addElement( // append receive event
receiveEvents.get(i));
}
}

@ -0,0 +1,107 @@
// MCASTSdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines SDUs for broad/uni/multicast.
@author Kenneth J. Turner
@version 1.0 (22nd July 2010, KJT): initial version
*/
public class MCASTSdu extends PDU {
/** Service SDU type */
public final static String TYPE = "DT";
/** Service destinations (router letters) */
public String destinations;
/** Service message */
public String sdu;
/**
Constructor for a broad/uni/multicast service message.
@param destination destination letter
@param sdu SDU data
*/
public MCASTSdu(char destination, String sdu) {
super(TYPE); // construct with type
this.destinations = destination + ""; // set SDU destinations
this.sdu = sdu; // set SDU data
}
/**
Constructor for a broad/uni/multicast service message.
@param destinations destinations
@param sdu SDU data
*/
public MCASTSdu(String destinations, String sdu) {
super(TYPE); // construct with type
this.destinations = destinations; // set SDU destinations
this.sdu = sdu; // set SDU data
}
/**
Return the destinations.
@return destinations (router letters)
*/
public String getDestinations() {
return(destinations);
}
/**
Return the label for an arrow representing a protocol stack SDU in a time
sequence diagram.
@return the label name
*/
public String getLabel() {
return type + "(" + destinations + "," + sdu + ")";
}
/**
Return the SDU.
@return SDU
*/
public String getSDU() {
return(sdu);
}
/**
Set the destinations.
@param destinations destinations
*/
public void setDestinations(String destinations) {
this.destinations = destinations;
}
/**
Set the SDU.
@param sdu SDU
*/
public void setSDU(String sdu) {
this.sdu = sdu;
}
/**
Convert SDU to string.
@return SDU as string
*/
public String toString() {
return(
"SDU <Type " + type + ", Destinations " + destinations +
", Data " + sdu + ">");
}
}

@ -0,0 +1,228 @@
// MCASTSource.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the source for broad/uni/multicast.
@author Kenneth J. Turner
@version 1.0 (24th July 2010, KJT): initial version
*/
public class MCASTSource implements ProtocolEntity {
/** Service broadcast send offer */
private final static String SEND_BROADCAST =
"Broadcast message for routers B, D, E, F";
/** Service multicast send offer */
private final static String SEND_MULTICAST =
"Multicast message for routers B, D, E";
/** Service unicast send offer */
private final static String SEND_UNICAST =
"Unicast message for routers B, D, E";
/** Service message count */
private int messageCount;
/** Service data unit output */
private PDU sdu;
/** Service data unit destination letters */
private String serviceDestinations;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service entity name */
private String serviceName;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public MCASTSource(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Check if the service destinations have received an SDU. If so, re-initialise
these destinations.
@return true/false if all service destinations have/have not
received an SDU
*/
public boolean checkDestinations() {
boolean result = false; // initialise result
int sduCount = 0; // initialise SDU count
int length = serviceDestinations.length(); // get number of destinations
for (int i = 0; i < length; i++) { // go through destinations
Vector<MCASTSdu> sdus = // get SDUs for destination
MCAST.getSDUs(serviceDestinations.charAt(i));
if (sdus != null && sdus.size() > 0) // destination has SDUs?
sduCount++; // increment SDU count
}
if (sduCount == length) { // all destinations have SDUs?
result = true; // note true result
for (int i = 0; i < length; i++) { // go through destinations
ProtocolEntity entity = // get destination entity
MCAST.getEntity(serviceDestinations.charAt(i));
entity.initialise(); // re-initialise entity
}
}
return(result); // return check result
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (sdu == null || checkDestinations()) { // no SDU sent or all received?
if (MCAST.serviceMode == MCAST.BROADCAST) // broadcast?
list.addElement(SEND_BROADCAST); // add broadcast send to list
else if (MCAST.serviceMode == MCAST.MULTICAST) // multicast?
list.addElement(SEND_MULTICAST); // add multicast send to list
else if (MCAST.serviceMode == MCAST.UNICAST) // multicast?
list.addElement(SEND_UNICAST); // add unicast send to list
}
return(list); // return service list
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
sdu = null; // initialise SDU output
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
String message = "M" + messageCount; // create message
messageCount++; // increment message count
if (service.equals(SEND_BROADCAST)) { // send broadcast request?
MCAST.serviceMode = MCAST.BROADCAST; // set broadcast mode
serviceDestinations = "BDEF"; // set service destinations
sdu = new MCASTSdu("B", message); // create SDU to B
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
sdu = new MCASTSdu("D", message); // create SDU to D
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
sdu = new MCASTSdu("E", message); // create SDU to E
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
sdu = new MCASTSdu("F", message); // create SDU to F
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
}
else if (service.equals(SEND_MULTICAST)) { // send multicast request?
MCAST.serviceMode = MCAST.MULTICAST; // set multicast mode
serviceDestinations = "BDE"; // set service destinations
sdu = new MCASTSdu("BDE", message); // create SDU to B, D, E
transmitPDU(sdu, 'A'); // send message to router A
}
else if (service.equals(SEND_UNICAST)) { // send unicast request?
MCAST.serviceMode = MCAST.UNICAST; // set unicast mode
serviceDestinations = "BDE"; // set service destinations
sdu = new MCASTSdu("B", message); // create SDU to B
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
sdu = new MCASTSdu("D", message); // create SDU to D
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
sdu = new MCASTSdu("E", message); // create SDU to E
serviceEvents.addElement( // add copy comment
MCAST.comment(this, "copy"));
transmitPDU(sdu, 'A'); // send message to router A
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
return(serviceEvents); // return service events
}
/**
Send an SDU.
@param sdu SDU
*/
public void transmitPDU(PDU sdu) {
String destinations = // get destinations
((MCASTSdu) sdu).getDestinations();
ProtocolEntity entityDestination = // get protocol entity dest.
MCAST.getEntity(destinations.charAt(0));
transmitPDU(sdu, entityDestination); // transmit PDU
}
/**
Send an SDU to the given destination letter.
@param sdu SDU
@param destination destination letter
*/
public void transmitPDU(PDU sdu, char destination) {
ProtocolEntity entityDestination = // get protocol entity dest.
MCAST.getEntity(destination);
transmitPDU(sdu, entityDestination); // transmit PDU
}
/**
Send an SDU to the given destination entity.
@param sdu SDU
@param destination destination entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
serviceEvents.addElement( // append receive event
receiveEvents.get(i));
}
}

@ -0,0 +1,116 @@
// MUX.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of (de)multiplexing. It handles both
synchronous and asynchronous modes.
@author Kenneth J. Turner
@version 1.0 (23rd July 2010, KJT): initial version
*/
public class MUX extends Protocol {
/** Default service count */
private final static int COUNT = 2;
/** Maximum service count */
private final static int MAX = 10;
/** Multiplexer */
private MUXProtocol protocolA;
/** Demultiplexer */
private MUXProtocol protocolB;
/** Sources */
private MUXService userA;
/** Sinks */
private MUXService userB;
/**
Constructor for a MUX object.
*/
public MUX() {
medium = new MUXMedium(); // create channel
userA = new MUXService("Sources"); // create sources
userB = new MUXService("Sinks"); // create sinks
protocolA = // create multiplexer
new MUXProtocol(medium, "Multiplexer");
protocolB = // create demultiplexer
new MUXProtocol(medium, "Demultiplexer");
userA.setProvider(protocolA); // set multiplexer for sources
userB.setProvider(protocolB); // set demultiplexer for sinks
protocolA.setUser(userA); // set sources for multiplexer
protocolA.setPeer(protocolB); // set (de)multiplexer pair
protocolB.setUser(userB); // set sinks for demultiplexer
protocolB.setPeer(protocolA); // set (de)multiplexer pair
entities = new Vector<ProtocolEntity>(); // create entity list
entities.addElement(userA); // add sources
entities.addElement(protocolA); // add multiplexer
entities.addElement(medium); // add channel
entities.addElement(protocolB); // add demultiplexer
entities.addElement(userB); // add sinks
userA.setMode(true); // initialise sources
userB.setMode(false); // initialise sinks
protocolA.setMode(false); // initialise asynchronous mux
protocolB.setMode(false); // initialise asynchronous demux
userA.setCount(COUNT); // initialise source count
userB.setCount(COUNT); // initialise sink count
}
/**
Set a parameter of the MUX simulation.
@param parameter parameter name (source/sinkCount, [a]synchronousMode)
@param value parameter value
*/
public void setParameter(String parameter, String value) {
try {
if (parameter.equals("serviceCount")) { // service count?
int count = Integer.parseInt(value); // get value as int (if any)
if (0 <= count && count <= MAX) { // service count within range?
userA.setCount(count); // set service count
userB.setCount(count); // set service count
protocolA.initialise(); // re-initialise multiplexer
protocolB.initialise(); // re-initialise demultiplexer
}
else // service count out of range
System.err.println( // report error
"CSMA.setParameter: service count '" + value + "' out of range");
}
else if (parameter.equals("serviceMode")) { // service mode?
boolean asynchronous = false; // initialise async setting
if (value.equalsIgnoreCase("true")) // true?
asynchronous = true; // note as synchronous
else if (!value.equalsIgnoreCase("false")) // not false
System.err.println( // report error
"MUX.setParameter: invalid asynchronous setting '" + value + "'");
protocolA.setMode(asynchronous); // set multiplexer mode
protocolB.setMode(asynchronous); // set demultiplexer mode
}
else if (parameter.equals("serviceOverwrite")) { // service overwrite?
boolean overwrite = false; // initialise overwrite setting
if (value.equalsIgnoreCase("true")) // true?
overwrite = true; // note as overwriting
else if (!value.equalsIgnoreCase("false")) // not false
System.err.println( // report error
"MUX.setParameter: invalid overwrite setting '" + value + "'");
userA.setOverwrite(overwrite); // set overwriting setting
userB.setOverwrite(overwrite); // set overwriting setting
}
}
catch (NumberFormatException e) { // count format exception?
System.err.println( // report error
"MUX.setParameter: service count '" + value + "' not an integer");
}
}
}

@ -0,0 +1,29 @@
// MUXMedium.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines the channel between (de)multiplexers.
@author Kenneth J. Turner
@version 1.0 (20th July 2010): initial version
*/
public class MUXMedium extends Medium {
/** Medium name */
private final static String NAME = "Channel";
/**
Gets the medium name.
@return medium name
*/
public String getName() {
return(NAME);
}
}

@ -0,0 +1,126 @@
// MUXPdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines (de)multiplexer protocol messages.
@author Kenneth J. Turner
@version 1.0 (23rd July 2010, KJT): initial version
*/
public class MUXPdu extends PDU {
/** Protocol PDU type */
public final static String BLANK = "-";
/** Protocol PDU type */
public final static String TYPE = "DT";
/** Protocol SDU list */
private String sduList[];
/**
Constructor for a (de)multiplexer PDU for the required number of SDUs.
*/
public MUXPdu() {
super(TYPE); // construct with type
sduList = new String[MUXService.serviceCount]; // initialise SDU list
}
/**
Get the PDU list of SDUs as a comma-separated string.
@return comma-separated list of SDUs
*/
public String getData() {
String dataList = ""; // initialise SDU data list
for (int i = 0; i < sduList.length; i++) { // go through SDU data
if (i > 0) // not first SDU?
dataList += ","; // append a comma
String data = sduList[i]; // get SDU data
if (data == null) // SDU data missing?
data = BLANK; // set data blank
dataList += data; // append SDU data
}
return(dataList); // return SDU data list
}
/**
Return the label for an arrow representing a (de)multiplexer PDU in a time
sequence diagram.
@return PDU label
*/
public String getLabel() {
String label; // declare protocol label
if (MUXProtocol.protocolMode) { // asynchronous?
int first = firstSDU(); // get first SDU label
if (first >= 0) // first SDU known?
label = first + "," + sduList[first]; // set first index and data
else // first SDU unknown
label = "?,?"; // set unknown index and data
}
else // synchronous
label = getData(); // set type and SDU data list
label = type + "(" + label + ")"; // set protocol label
return(label); // return protocol label
}
/**
Return SDU for given entity.
@param entity entity index
@return SDU (or null if no such entity)
*/
public String getSDU(int entity) {
return(0 <= entity && entity < sduList.length ? sduList[entity] : null);
}
/**
Return SDU list.
@return SDU list
*/
public String[] getSDUs() {
return(sduList);
}
/**
Return index of first available SDU.
@return index of first available SDU (-1 means none)
*/
public int firstSDU() {
int index = -1; // initialise index
for (int i = 0; i < sduList.length; i++) { // go through SDU data
if (sduList[i] != null) { // data present?
index = i; // note data available
break; // leave loop
}
}
return(index); // return index
}
/**
Convert PDU to string.
@return PDU as string
*/
public String toString() {
return("PDU <Type " + type + ", Data <" + getData() + ">>");
}
/**
Set source SDU data.
@param source source entity index
@param sdu source data
*/
public void setSDU(int source, String sdu) {
sduList[source] = sdu; // set SDU data for source
}
}

@ -0,0 +1,280 @@
// MUXProtocol.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the (de)multiplexing protocol. It handles
both synchronous and asynchronous modes.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class MUXProtocol implements ProtocolEntity {
/** Service send offer */
private final static String RECEIVE = "Send data to ";
/** Protocol send offer */
private final static String SEND =
"Multiplex and send ";
/** Protocol send all available offer */
private final static String SEND_ALL = SEND + "all available data";
/** Protocol send one offer */
private final static String SEND_ONE = SEND + "the individual data";
/** Service source offer */
private final static String SINK = "Sink ";
/** Protocol events */
private Vector<ProtocolEvent> protocolEvents;
/** Protocol PDU received */
private MUXPdu protocolIn;
/** Protocol channel */
private Medium protocolMedium;
/** Protocol protocol mode (true = asynchronous, false = synchronous) */
public static boolean protocolMode;
/** Protocol name */
private String protocolName;
/** Protocol PDU sent */
private MUXPdu protocolOut;
/** Protocol peer */
private MUXProtocol protocolPeer;
/** Protocol user */
private MUXService protocolUser;
/**
Constructor for a (de)multiplexer.
@param protocolMedium channel
@param protocolName protocol name
*/
public MUXProtocol(Medium protocolMedium, String protocolName) {
this.protocolName = protocolName; // set protocol name
this.protocolMedium = protocolMedium; // set protocol medium
initialise(); // initialise protocol
}
/**
Return a protocol event with the given comment.
@param comment protocol comment
@return protocol event
*/
private ProtocolEvent comment(String comment) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, comment));
}
/**
Get the protocol mode.
@return protocol mode (true = asynchronous, false = synchronous)
*/
public boolean getMode() {
return(protocolMode); // return protocol mode
}
/**
Get the protocol name.
@return protocol name
*/
public String getName() {
return(protocolName); // return protocol name
}
/**
Get the protocol peer.
@return protocol peer
*/
public MUXProtocol getPeer() {
return(protocolPeer); // return protocol peer
}
/**
Get protocol input.
@return protocol input
*/
public MUXPdu getProtocolIn() {
return(protocolIn); // return protocol input
}
/**
Get protocol output.
@return protocol output
*/
public MUXPdu getProtocolOut() {
return(protocolOut); // return protocol output
}
/**
Return services currently offered.
@return list of protocol services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise protocol services
int firstSDU = protocolOut.firstSDU(); // get first SDU index
if (firstSDU >= 0) { // SDU available?
if (protocolMode) // asynchronous?
list.add(SEND_ONE); // append send one offer
else // synchronous
list.add(SEND_ALL); // append send all offer
}
String[] sduList = // get SDU list from PDU
((MUXPdu) protocolIn).getSDUs();
for (int i = 0; i < sduList.length; i++) { // go through SDUs
String data = sduList[i]; // get SDU data
if (data != null) // SDU available?
list.add(RECEIVE + SINK + i); // append protocol receive offer
}
return (list); // return protocol service list
}
/**
Initialise the protocol entity.
*/
public void initialise() {
protocolEvents = new Vector<ProtocolEvent>();// initialise protocol events
protocolIn = new MUXPdu(); // initialise protocol input
protocolOut = new MUXPdu(); // initialise protocol output
}
/**
Perform service.
@param service service request
@return resulting protocol events
*/
public Vector<ProtocolEvent> performService(String service) {
protocolEvents = new Vector<ProtocolEvent>(); // initialise protocol events
if (service.startsWith(SEND)) { // send all request?
protocolEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.TRANSMIT, protocolOut));
protocolEvents.addElement( // add receive event
new ProtocolEvent(ProtocolEvent.RECEIVE, protocolOut));
transmitPDU(protocolOut, protocolPeer); // send protocol PDU
protocolOut = new MUXPdu(); // re-initialise sent PDU
}
else if (service.startsWith(RECEIVE)) { // receive request?
int sinkStart = // get start of sink index
service.indexOf(SINK) + SINK.length();
int sink = // get source index
Integer.parseInt(service.substring(sinkStart));
String[] sduList = protocolIn.getSDUs(); // get SDU list from PDU
String data = sduList[sink]; // get SDU data
MUXSdu sdu = new MUXSdu(sink, data); // create SDU
transmitPDU(sdu, protocolUser); // send to service user
protocolIn.setSDU(sink, null); // remove sink SDU data
}
return(protocolEvents); // return protocol events
}
/**
Receive PDU.
@param pdu PDU
@return resulting protocol events
*/
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
protocolEvents = new Vector<ProtocolEvent>(); // initialise event list
if (pdu != null) { // non-empty PDU?
String pduType = pdu.type; // get PDU type
if (pduType.equals(MUXSdu.TYPE)) { // service user message?
int source = ((MUXSdu) pdu).entity; // get source index
String data = ((MUXSdu) pdu).sdu; // get service user data
String comment; // declare protocol comment
if (protocolMode) { // asynchronous?
comment = // set comment from presence
protocolOut.firstSDU() >= 0 ? "Overwritten" : "Stored";
protocolOut = new MUXPdu(); // initialise protocol output
}
else // synchronous
comment = // set comment from presence
protocolOut.getSDU(source) != null ? "Overwritten" : "Stored";
protocolOut.setSDU(source, data); // store source SDU data
protocolEvents.addElement( // add receive comment event
comment(comment));
}
else if (pduType.equals(MUXPdu.TYPE)) { // protocol peer message?
String comment = // set comment from presence
protocolIn.firstSDU() >= 0 ? "Overwritten" : "Stored";
protocolIn = (MUXPdu) pdu; // store received PDU
protocolEvents.addElement( // add receive comment event
comment(comment));
}
}
return(protocolEvents); // return protocol events
}
/**
Set the protocol mode.
@param protocolMode protocol mode (true = asynchronous,
false = synchronous)
*/
public void setMode(boolean protocolMode) {
this.protocolMode = protocolMode; // set protocol mode
}
/**
Set the protocol peer.
@param protocolPeer protocol peer
*/
public void setPeer(ProtocolEntity protocolPeer) {
this.protocolPeer = // set protocol peer
(MUXProtocol) protocolPeer;
}
/**
Set the protocol service.
@param protocolUser protocol service user
*/
public void setUser(ProtocolEntity protocolUser) {
this.protocolUser = // set service user
(MUXService) protocolUser;
}
/**
Send PDU.
@param pdu PDU
@param destination protocol destination
*/
public void transmitPDU(PDU pdu, ProtocolEntity destination) {
pdu.setSource(this); // set protocol entity as source
pdu.setDestination(destination); // set message destination
Vector<ProtocolEvent> receiveEvents; // declare receive events
if (destination == protocolPeer) { // for protocol peer?
receiveEvents = // receive PDU at medium
protocolPeer.receivePDU(pdu);
}
else // for service user?
receiveEvents = // receive PDU at user
protocolUser.receivePDU(pdu);
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
protocolEvents.addElement( // append receive event
receiveEvents.get(i));
}
}

@ -0,0 +1,55 @@
// MUXSdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines (de)multiplexer service messages.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class MUXSdu extends PDU {
/** Service SDU type */
public final static String TYPE = "DATA";
/** Service entity */
public int entity;
/** Service message */
public String sdu;
/**
Constructor for a source/sink service message.
@param entity service entity index
@param sdu SDU data
*/
public MUXSdu(int entity, String sdu) {
super(TYPE); // construct with type
this.entity = entity; // set entity index
this.sdu = sdu; // set SDU data
}
/**
Return the label for an arrow representing a (de)multiplexer SDU in a time
sequence diagram.
@return the label name
*/
public String getLabel() {
return(type + "(" + entity + "," + sdu + ")");
}
/**
Convert SDU to string.
*/
public String toString() {
return("SDU <Type " + type + ", Entity " + entity + ", Data " + sdu + ">");
}
}

@ -0,0 +1,198 @@
// MUXService.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports sources/sinks for (de)multiplexing.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class MUXService implements ProtocolEntity {
/** Service send offer */
private final static String SEND = "Send data from ";
/** Service source offer */
private final static String SOURCE = "Source ";
/** Service message count */
private int messageCount;
/** PDU sent by service */
private PDU sduSent;
/** Service entity count */
public static int serviceCount = 2;
/** Service mode (true = source, false = sink) */
public boolean serviceMode;
/** Service entity name */
private String serviceName;
/** Service overwriting (true = overwrite, false = no overwrite) */
public static boolean serviceOverwrite;
/** Service provider */
private MUXProtocol serviceProvider;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public MUXService(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceMode) { // source mode?
int first = // get protocol peer's first SDU
serviceProvider.getPeer().getProtocolIn().firstSDU();
if (first == -1 || // protocol peer has no data or
serviceOverwrite) { // overwrite?
for (int i = 0; i < serviceCount; i++) {// go through sources
String data = // get SDU data for source
serviceProvider.getProtocolOut().getSDU(i);
first = // get provider's first SDU
((MUXProtocol) serviceProvider).getProtocolOut().firstSDU();
boolean mode = // get provider mode
serviceProvider.getMode();
if ((!mode && data == null) || // sync and no source data or
(mode && first == -1) || // async and no provider data or
serviceOverwrite) { // overwrite?
String service = SEND + SOURCE + i; // send from source service
list.addElement(service); // add service to list
}
}
}
}
return(list); // return service list
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.startsWith(SEND)) { // send request?
String message = "D" + messageCount; // create data message
int sourceStart = // get start of source index
service.indexOf(SOURCE) + SOURCE.length();
int source = // get source index
Integer.parseInt(service.substring(sourceStart));
PDU sdu = new MUXSdu(source, message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceEvents.addElement( // deliver SDU
new ProtocolEvent(ProtocolEvent.DELIVER, sdu));
return(serviceEvents); // return service events
}
/**
Set the service count.
@param serviceCount service count
*/
public void setCount(int serviceCount) {
this.serviceCount = serviceCount; // set service count
}
/**
Set the service mode.
@param serviceMode service mode (true = source, false = sink)
*/
public void setMode(boolean serviceMode) {
this.serviceMode = serviceMode; // set service mode
}
/**
Set service overwriting.
@param serviceOverwrite service overwriting (true = overwrite,
false = no overwrite)
*/
public void setOverwrite(boolean serviceOverwrite) {
this.serviceOverwrite = serviceOverwrite; // set overwriting setting
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = // set service provider
(MUXProtocol) serviceProvider;
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
serviceEvents.addElement( // append receive event
receiveEvents.get(i));
sduSent = sdu; // stored the sent SDU
}
}

@ -0,0 +1,27 @@
// SMTP.java (C) K. J. Turner, P. K. Johnson 04/03/06
// Simple Mail Transfer Protocol
package protocol;
import java.util.*;
import support.*;
public class SMTP extends Protocol {
private SMTPSender client;
private SMTPReceiver server;
public SMTP() {
medium = new Medium();
client = new SMTPSender(medium, "Client");
server = new SMTPReceiver(medium, "Server");
client.setPeer(server);
server.setPeer(client);
entities = new Vector<ProtocolEntity>();
entities.addElement(client);
entities.addElement(medium);
entities.addElement(server);
}
}

@ -0,0 +1,122 @@
// SMTPReceiver.java (C) K. J. Turner, P. K. Johnson 04/03/06
// Simple Mail Transfer Protocol receiver (server)
package protocol;
import java.util.Vector;
import support.*;
public class SMTPReceiver implements ProtocolEntity {
private PDU pduReceived;
private ProtocolEntity peer;
private Medium medium;
private String name;
private PDU pduSent;
final static String clientData = "DATA";
final static String clientFrom = "MAIL FROM: sender";
final static String clientHello = "HELO client";
final static String clientMail = "Mail message";
final static String clientQuit = "QUIT";
final static String clientRecipient = "RCPT TO: recipient";
final static String invalidRecipient = "550 Recipient invalid";
final static String invalidSender = "550 Sender invalid";
final static String okRecipient = "250 Recipient OK";
final static String okSender = "250 Sender OK";
final static String serverAccept = "250 Message accepted";
final static String serverClosing = "221 Server Closing";
final static String serverHello = "250 Server hello to client";
final static String serverReady = "220 Server ready";
final static String serverSend = "354 Send mail";
final static String tcpConnect = "TCP connect";
final static String tcpDisconnect = "TCP disconnect";
public SMTPReceiver(Medium m, String name) {
this.name = name;
medium = m;
initialise();
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
String pduType;
if (pduReceived != null) { // non-null PDU received?
pduType = pduReceived.type; // get PDU type
if (pduType.equals(clientData)) // got client data?
list.addElement(serverSend); // reply server send
else if (pduType.startsWith(clientFrom)) { // got sender?
list.addElement(okSender); // reply sender OK
list.addElement(invalidSender); // reply sender invalid
}
else if (pduType.equals(clientHello)) // got client hello?
list.addElement(serverHello); // reply server hello
else if (pduType.equals(clientMail)) // got client mail message?
list.addElement(serverAccept); // reply server accept
else if (pduType.equals(clientQuit)) // got client quit?
list.addElement(serverClosing); // reply server closing
else if (pduType.startsWith(clientRecipient)) { // got recipient?
list.addElement(okRecipient); // reply recipient OK
list.addElement(invalidRecipient); // reply recipient invalid
}
else if (pduType.equals(tcpConnect)) // got TCP disconnect?
list.addElement(serverReady); // reply server ready?
// no action on TCP disconnect
}
return(list);
}
public void initialise() {
pduReceived = null;
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.equals(invalidRecipient)) // send recipient invalid?
transmitPDU(new PDU(invalidRecipient), peer);
else if (s.equals(invalidSender)) // send sender invalid?
transmitPDU(new PDU(invalidSender), peer);
else if (s.equals(okRecipient)) // send recipient OK?
transmitPDU(new PDU(okRecipient), peer);
else if (s.equals(okSender)) // send sender OK?
transmitPDU(new PDU(okSender), peer);
else if (s.equals(serverAccept)) // send message accepted?
transmitPDU(new PDU(serverAccept), peer);
else if (s.equals(serverClosing)) // send server closing?
transmitPDU(new PDU(serverClosing), peer);
else if (s.equals(serverHello)) // send server hello?
transmitPDU(new PDU(serverHello), peer);
else if (s.equals(serverReady)) // send server ready?
transmitPDU(new PDU(serverReady), peer);
else if (s.equals(serverSend)) // send server send?
transmitPDU(new PDU(serverSend), peer);
if (pduSent != null) { // PDU to send?
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
events.addElement(new ProtocolEvent(ProtocolEvent.RECEIVE, pduSent));
}
pduSent = null; // nullify just in case
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
pduSent = pdu;
this.peer.receivePDU(pdu);
pduReceived = null;
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
}

@ -0,0 +1,177 @@
// SMTPSender.java (C) K. J. Turner, P. K. Johnson 04/03/06
// Simple Mail Transfer Protocol sender (client)
package protocol;
import java.util.Vector;
import support.*;
public class SMTPSender implements ProtocolEntity {
private PDU pduReceived;
private PDU pduSent;
private ProtocolEntity peer;
private Medium medium;
private String name;
final static String clientData = "DATA";
final static String clientFrom = "MAIL FROM: sender";
final static String clientHello = "HELO client";
final static String clientMail = "Mail message";
final static String clientQuit = "QUIT";
final static String clientRecipient = "RCPT TO: recipient";
final static String invalidRecipient = "550 Recipient invalid";
final static String invalidSender = "550 Sender invalid";
final static String okRecipient = "250 Recipient OK";
final static String okSender = "250 Sender OK";
final static String serverAccept = "250 Message accepted";
final static String serverClosing = "221 Server Closing";
final static String serverHello = "250 Server hello to client";
final static String serverReady = "220 Server ready";
final static String serverSend = "354 Send mail";
final static String tcpConnect = "TCP connect";
final static String tcpDisconnect = "TCP disconnect";
int state; // protocol state
final static int idle = 0; // no connection
final static int waitReady = 1; // await server ready
final static int waitHello = 2; // await server hello
final static int ready = 3; // ready for mail
final static int waitSender = 4; // await sender answer
final static int waitRecipient = 5; // await recip answer
final static int waitSend = 6; // await server send
final static int waitAccept = 7; // await server accept
final static int waitClose = 8; // await server closing
int person = 1; // sender/recipient
int recipients; // number of recipients
public SMTPSender(Medium m, String name) {
this.name = name;
medium = m;
}
public String getName() {
return(name);
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
String pduType;
if (state == idle) // waiting to connect?
list.addElement(tcpConnect); // connect
else if (pduReceived != null) { // non-empty reply?
pduType = pduReceived.type; // get PDU type
if (state == waitReady && // awaiting server ready?
pduType.equals(serverReady)) // reply server ready?
list.addElement(clientHello); // send hello from client
else if (state == waitHello && // awaiting server hello?
pduType.equals(serverHello)) // reply server hello?
state = ready; // now ready
else if (state == waitSender) { // awaiting sender response?
if (pduType.equals(okSender)) { // sender is OK?
recipients = 0; // no recipients yet
state = waitSend; // now ready to send
}
else if (pduType.equals(invalidSender)) // sender is invalid?
state = ready; // back to ready
}
else if (state == waitRecipient && // awaiting recipient response?
(pduType.equals(okRecipient) || // recipient is OK or ...
pduType.equals(invalidRecipient))) { // not?
if (pduType.equals(okRecipient)) // recipient is OK?
recipients++; // add to recipients
state = waitSend; // still ready to send
}
else if (state == waitSend && // awaiting server send?
pduType.equals(serverSend)) { // response is server send?
list.addElement(clientMail); // send client mail message
state = waitAccept; // wait for server accept
}
else if (state == waitAccept && // awaiting server accept?
pduType.equals(serverAccept)) { // reply is server accept?
state = ready; // back to ready
}
else if (state == waitClose && // awaiting server closing?
pduType.equals(serverClosing)) { // reply is server closing?
list.addElement(tcpDisconnect); // disconnect
}
if (state == ready) { // ready?
list.addElement(clientFrom + person++); // propose sender
list.addElement(clientQuit); // propose quit
}
else if (state == waitSend) { // waiting to send?
list.addElement(clientRecipient + person++); // propose recipient
if (recipients > 0) // recipients?
list.addElement(clientData); // propose to send data
}
}
return(list);
}
public void initialise() {
state = idle; // initialise state
pduReceived = null; // note no PDU received
person = 1; // initialise sender/recipient
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.equals(clientData)) { // send client data?
transmitPDU(new PDU(clientData), peer); // send client data
state = waitSend; // await server send
}
else if (s.startsWith(clientFrom)) { // send sender?
transmitPDU(new PDU(s), peer); // send sender
state = waitSender; // await sender response
}
else if (s.equals(clientHello)) { // send client hello?
transmitPDU(new PDU(s), peer); // send client hello
state = waitHello; // await server hello
}
else if (s.equals(clientMail)) // send client mail message?
transmitPDU(new PDU(clientMail), peer); // send client mail message
else if (s.equals(clientQuit)) { // send client quit?
transmitPDU(new PDU(clientQuit), peer); // send client quit
state = waitClose; // await server closing
}
else if (s.startsWith(clientRecipient)) { // send recipient?
transmitPDU(new PDU(s), peer); // send recipient
state = waitRecipient; // await recipient response
}
if (s.equals(tcpConnect)) { // send TCP connect?
transmitPDU(new PDU(tcpConnect), peer); // send TCP connect
state = waitReady; // await server ready
}
else if (s.equals(tcpDisconnect)) { // send TCP disconnect?
transmitPDU(new PDU(tcpDisconnect), peer); // send TCP disconnect
state = idle; // back to start
}
if (pduSent != null) { // PDU to send?
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
events.addElement(new ProtocolEvent(ProtocolEvent.RECEIVE, pduSent));
}
pduSent = null; // nullify just in case
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
pduReceived = pdu;
return(new Vector<ProtocolEvent>());
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
pduSent = pdu;
this.peer.receivePDU(pdu);
pduReceived = null;
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
}

@ -0,0 +1,68 @@
// STACK.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for simulation of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACK extends Protocol {
/** Application layer */
private STACKApplication userA;
/** Transport layer */
private STACKTransport userB;
/** Network layer */
private STACKNetwork userC;
/** Data link layer */
private STACKDataLink userD;
/** Physical layer */
private STACKPhysical userE;
/** Medium */
private STACKMedium medium;
/**
Constructor for a STACK object.
*/
public STACK() {
userA = new STACKApplication("Application");// create application layer
userB = new STACKTransport("Transport"); // create transport layer
userC = new STACKNetwork("Network"); // create network layer
userD = new STACKDataLink("Data Link"); // create data link layer
userE = new STACKPhysical("Physical"); // create physical layer
medium = new STACKMedium(); // create medium
userA.setProvider(userB); // set application->transport
userB.setProvider(userC); // set transport->network
userC.setProvider(userD); // set network->data link
userD.setProvider(userE); // set data link->physical
userE.setProvider(medium); // set physical->medium
userB.setUser(userA); // set transport->application
userC.setUser(userB); // set network->transport
userD.setUser(userC); // set data link->network
userE.setUser(userD); // set physical->data link
medium.setUser(userE); // set medium->physical
entities = new Vector<ProtocolEntity>(); // create entity list
entities.addElement(userA); // add application layer
entities.addElement(userB); // add transport layer
entities.addElement(userC); // add network layer
entities.addElement(userD); // add data link layer
entities.addElement(userE); // add physical layer
entities.addElement(medium); // add medium
}
}

@ -0,0 +1,157 @@
// STACKApplication.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the application layer of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACKApplication implements ProtocolEntity {
/** Service message prefix */
private final static String PREFIX = "A";
/** Service send offer */
private final static String SEND =
"Send application message to transport layer";
/** Service message count */
private int messageCount;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service entity name */
private String serviceName;
/** Service provider */
private ProtocolEntity serviceProvider;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public STACKApplication(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceOut == null) // no SDU sent?
list.addElement(SEND); // add send SDU service to list
return(list); // return service list
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.equals(SEND)) { // send request?
String message = PREFIX + messageCount; // create service message
serviceOut = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, serviceOut));
transmitPDU(serviceOut, serviceProvider); // send service message
messageCount++; // increment message count
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
ProtocolEntity sduSource = sdu.source; // get SDU source
String sduType = sdu.type; // get SDU type
if (sduSource.equals(serviceUser)) { // service user message?
serviceOut = sdu; // store SDU from service user
}
else if (sduSource.equals(serviceProvider)) // service provider message?
serviceOut = null; // re-initialise SDU out
}
return(serviceEvents); // return service events
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = serviceProvider; // set service provider
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,180 @@
// STACKDataLink.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the transport layer of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACKDataLink implements ProtocolEntity {
/** Service message prefix (and suffix) */
private final static String PREFIX = "L";
/** Service receive offer */
private final static String RECEIVE =
"Send data link message to network layer";
/** Service send offer */
private final static String SEND =
"Send data link message to physical layer";
/** Service message count */
private int messageCount;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service entity name */
private String serviceName;
/** Service provider */
private ProtocolEntity serviceProvider;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public STACKDataLink(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceOut != null) // SDU from service user?
list.addElement(SEND); // add send SDU service to list
else if (serviceIn != null) // SDU from service provider?
list.addElement(RECEIVE); // add send SDU service to list
return(list); // return service list
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.equals(SEND)) { // send request?
String message = // create service message
PREFIX + messageCount + ":" + serviceOut.getSDU() +
":" + PREFIX + messageCount;
PDU sdu = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
serviceOut = null; // re-initialise SDU out
}
else if (service.equals(RECEIVE)) { // receive request?
String message = serviceIn.getSDU(); // get SDU data
int colon = message.indexOf(':'); // get first colon location
if (colon >= 0) // colon present?
message = message.substring(colon + 1); // remove prefix
colon = message.lastIndexOf(':'); // get last colon location
if (colon >= 0) // colon present?
message = message.substring(0, colon); // remove prefix
serviceIn = new STACKSdu(message); // create new message
transmitPDU(serviceIn, serviceUser); // send service message
serviceEvents.addElement( // add receive event
new ProtocolEvent(ProtocolEvent.SEND, serviceIn));
serviceIn = null; // re-initialise SDU in
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
ProtocolEntity sduSource = sdu.source; // get SDU source
String sduType = sdu.type; // get SDU type
if (sduSource.equals(serviceUser)) { // service user message?
serviceOut = sdu; // store SDU from service user
}
else if (sduSource.equals(serviceProvider)) // service provider message?
serviceIn = sdu; // store SDU from provider
}
return(serviceEvents); // return service events
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = serviceProvider; // set service provider
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,114 @@
// STACKMedium.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that defines the medium for a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010): initial version
*/
public class STACKMedium extends Medium {
/** Service send offer */
private final static String SEND =
"Send medium message to physical layer";
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for protocol stack medium.
*/
public STACKMedium() {
initialise(); // initialise service entity
}
/**
Return services currently offered.
@return list of services (empty)
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceIn != null) // SDU from medium?
list.addElement(SEND); // add send SDU service to list
return(list); // return service list
}
/**
Initialise the service entity.
*/
public void initialise() {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.startsWith(SEND)) { // send request?
String message = serviceIn.getSDU(); // create service message
PDU sdu = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceUser); // send service message
serviceIn = null; // re-initialise SDU in
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceIn = sdu; // store SDU from service
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
return(serviceEvents); // return service events
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,176 @@
// STACKNetwork.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the transport layer of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACKNetwork implements ProtocolEntity {
/** Service message prefix */
private final static String PREFIX = "N";
/** Service receive offer */
private final static String RECEIVE =
"Send network message to transport layer";
/** Service send offer */
private final static String SEND =
"Send network message to data link layer";
/** Service message count */
private int messageCount;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service entity name */
private String serviceName;
/** Service provider */
private ProtocolEntity serviceProvider;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public STACKNetwork(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceOut != null) // SDU from service user?
list.addElement(SEND); // add send SDU service to list
else if (serviceIn != null) // SDU from service provider?
list.addElement(RECEIVE); // add send SDU service to list
return(list); // return service list
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.equals(SEND)) { // send request?
String message = // create service message
PREFIX + messageCount + ":" + serviceOut.getSDU();
PDU sdu = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
serviceOut = null; // re-initialise SDU out
}
else if (service.equals(RECEIVE)) { // receive request?
String message = serviceIn.getSDU(); // get SDU data
int colon = message.indexOf(':'); // get first colon location
if (colon >= 0) // colon present?
message = message.substring(colon + 1); // remove prefix
serviceIn = new STACKSdu(message); // create new message
transmitPDU(serviceIn, serviceUser); // send service message
serviceEvents.addElement( // add receive event
new ProtocolEvent(ProtocolEvent.SEND, serviceIn));
serviceIn = null; // re-initialise SDU in
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
ProtocolEntity sduSource = sdu.source; // get SDU source
String sduType = sdu.type; // get SDU type
if (sduSource.equals(serviceUser)) { // service user message?
serviceOut = sdu; // store SDU from service user
}
else if (sduSource.equals(serviceProvider)) // service provider message?
serviceIn = sdu; // store SDU from provider
}
return(serviceEvents); // return service events
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = serviceProvider; // set service provider
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,177 @@
// STACKPhysical.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the transport layer of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACKPhysical implements ProtocolEntity {
/** Service message prefix */
private final static String PREFIX = "P";
/** Service receive offer */
private final static String RECEIVE =
"Send physical message to data link layer";
/** Service send offer */
private final static String SEND =
"Send physical message to medium";
/** Service message count */
private int messageCount;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service entity name */
private String serviceName;
/** Service provider */
private ProtocolEntity serviceProvider;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public STACKPhysical(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceOut != null) // SDU from service user?
list.addElement(SEND); // add send SDU service to list
else if (serviceIn != null) // SDU from service provider?
list.addElement(RECEIVE); // add send SDU service to list
return(list); // return service list
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.equals(SEND)) { // send request?
String message = // create service message
PREFIX + messageCount + ":" + serviceOut.getSDU();
PDU sdu = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
serviceOut = null; // re-initialise SDU out
}
else if (service.equals(RECEIVE)) { // receive request?
String message = serviceIn.getSDU(); // get SDU data
int colon = message.indexOf(':'); // get first colon location
if (colon >= 0) // colon present?
message = message.substring(colon + 1); // remove prefix
serviceIn = new STACKSdu(message); // create new message
transmitPDU(serviceIn, serviceUser); // send service message
serviceEvents.addElement( // add receive event
new ProtocolEvent(ProtocolEvent.SEND, serviceIn));
serviceIn = null; // re-initialise SDU in
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
ProtocolEntity sduSource = sdu.source; // get SDU source
String sduType = sdu.type; // get SDU type
if (sduSource.equals(serviceUser)) { // service user message?
serviceOut = sdu; // store SDU from service user
}
else if (sduSource.equals(serviceProvider)) // service provider message?
serviceIn = sdu; // store SDU from provider
}
return(serviceEvents); // return service events
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = serviceProvider; // set service provider
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,70 @@
// STACKSdu.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class that defines SDUs for a protocol stack.
@author Kenneth J. Turner
@version 1.0 (23rd July 2010, KJT): initial version
*/
public class STACKSdu extends PDU {
/** Service SDU type */
public final static String TYPE = "DATA";
/** Service message */
public String sdu;
/**
Constructor for a source/sink service message.
@param sdu SDU data
*/
public STACKSdu(String sdu) {
super(TYPE); // construct with type
this.sdu = sdu; // set SDU data
}
/**
Return the label for an arrow representing a protocol stack SDU in a time
sequence diagram.
@return the label name
*/
public String getLabel() {
return type + "(" + sdu + ")";
}
/**
Return the SDU.
@return SDU
*/
public String getSDU() {
return(sdu);
}
/**
Return the SDU.
@param sdu SDU
*/
public void setSDU(String sdu) {
this.sdu = sdu;
}
/**
Convert SDU to string.
@return SDU as string
*/
public String toString() {
return("SDU <Type " + type + ", Data " + sdu + ">");
}
}

@ -0,0 +1,177 @@
// STACKTransport.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class that supports the transport layer of a protocol stack.
@author Kenneth J. Turner
@version 1.0 (20th July 2010, KJT): initial version
*/
public class STACKTransport implements ProtocolEntity {
/** Service message prefix */
private final static String PREFIX = "T";
/** Service receive offer */
private final static String RECEIVE =
"Send transport message to application layer";
/** Service send offer */
private final static String SEND =
"Send transport message to network layer";
/** Service message count */
private int messageCount;
/** Service provider events */
private Vector<ProtocolEvent> serviceEvents;
/** Service data unit input */
private PDU serviceIn;
/** Service data unit output */
private PDU serviceOut;
/** Service entity name */
private String serviceName;
/** Service provider */
private ProtocolEntity serviceProvider;
/** Service user */
private ProtocolEntity serviceUser;
/**
Constructor for sources/sinks.
@param serviceName service name
*/
public STACKTransport(String serviceName) {
this.serviceName = serviceName; // set service name
initialise(); // initialise service entity
}
/**
Return the service name.
@return service name
*/
public String getName() {
return(serviceName); // return service name
}
/**
Initialise the service entity.
*/
public void initialise() {
messageCount = 0; // initialise message count
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
serviceIn = null; // initialise SDU input
serviceOut = null; // initialise SDU output
}
/**
Return services currently offered.
@return list of services
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
if (serviceOut != null) // SDU from service user?
list.addElement(SEND); // add send SDU service to list
else if (serviceIn != null) // SDU from service provider?
list.addElement(RECEIVE); // add send SDU service to list
return(list); // return service list
}
/**
Perform service.
@param service service request
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (service.equals(SEND)) { // send request?
String message = // create service message
PREFIX + messageCount + ":" + serviceOut.getSDU();
PDU sdu = new STACKSdu(message); // create SDU
serviceEvents.addElement( // add send event
new ProtocolEvent(ProtocolEvent.SEND, sdu));
transmitPDU(sdu, serviceProvider); // send service message
messageCount++; // increment message count
serviceOut = null; // re-initialise SDU out
}
else if (service.equals(RECEIVE)) { // receive request?
String message = serviceIn.getSDU(); // get SDU data
int colon = message.indexOf(':'); // get first colon location
if (colon >= 0) // colon present?
message = message.substring(colon + 1); // remove prefix
serviceIn = new STACKSdu(message); // create new message
transmitPDU(serviceIn, serviceUser); // send service message
serviceEvents.addElement( // add receive event
new ProtocolEvent(ProtocolEvent.SEND, serviceIn));
serviceIn = null; // re-initialise SDU in
}
return(serviceEvents); // return service events
}
/**
Receive an SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
serviceEvents = new Vector<ProtocolEvent>();// initialise service events
if (sdu != null) { // non-empty SDU?
ProtocolEntity sduSource = sdu.source; // get SDU source
String sduType = sdu.type; // get SDU type
if (sduSource.equals(serviceUser)) { // service user message?
serviceOut = sdu; // store SDU from service user
}
else if (sduSource.equals(serviceProvider)) // service provider message?
serviceIn = sdu; // store SDU from provider
}
return(serviceEvents); // return service events
}
/**
Set the service provider.
@param serviceProvider service provider
*/
public void setProvider(ProtocolEntity serviceProvider) {
this.serviceProvider = serviceProvider; // set service provider
}
/**
Set the service user.
@param serviceUser service user
*/
public void setUser(ProtocolEntity serviceUser) {
this.serviceUser = serviceUser; // set service user
}
/**
Send an SDU.
@param sdu SDU
@param dest destination protocol entity
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this); // set source as this entity
sdu.setDestination(destination); // set destination
Vector<ProtocolEvent> receiveEvents = // receive SDU at destination
destination.receivePDU(sdu);
}
}

@ -0,0 +1,44 @@
// SWP3.java (C) I. A. Robin, K. J. Turner 08/03/06
package protocol;
import java.util.*;
import support.*;
public class SWP3 extends Protocol {
private int maxSeq = 7;
private int winSize = 3;
private SWP3Sender sender;
private SWP3Receiver receiver;
public SWP3() {
medium = new Medium();
sender = new SWP3Sender(maxSeq, winSize, medium);
receiver = new SWP3Receiver(maxSeq, winSize, medium);
sender.setPeer(receiver);
receiver.setPeer(sender);
entities = new Vector<ProtocolEntity>();
entities.addElement(sender);
entities.addElement(medium);
entities.addElement(receiver);
}
public void setParameter(String param, String value) {
super.setParameter(param, value);
try {
if (param.equals("maxSeq")) {
maxSeq = Integer.parseInt(value);
sender.setMaxSeq(maxSeq);
receiver.setMaxSeq(maxSeq);
}
else if (param.equals("winSize")) {
winSize = Integer.parseInt(value);
sender.setWindowSize(winSize);
receiver.setWindowSize(winSize);
}
}
catch (NumberFormatException e) {}
}
}

@ -0,0 +1,154 @@
// SWP3Receiver.java (C) I. A. Robin, K. J. Turner 08/03/06
package protocol;
import java.util.Enumeration;
import java.util.Vector;
import support.*;
public class SWP3Receiver implements ProtocolEntity {
private int maxSeq;
private int winSize;
private int lowerWindowEdge;
private int upperWindowEdge;
private PDU pduReceived;
private boolean[] pduArrived;
private Medium medium;
private ProtocolEntity peer;
private Vector<ProtocolEvent> entityEvents; // events from entity
public SWP3Receiver(int maxSeq, int winSize, Medium m) {
this.maxSeq = maxSeq;
this.winSize = winSize;
pduArrived = new boolean[maxSeq + 1];
medium = m;
initialise();
}
private ProtocolEvent comment(String c) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, c));
}
public String getName() {
return("Receiver");
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
PDU pdu = pduReceived;
if (pdu != null && pdu.type.equals("DT")) {
int seq = pdu.seq;
if (isWithinWindow(seq)) {
int s = lowerWindowEdge;
for (int i = 0; i < winSize && pduArrived[s]; i++) {
s = inc(s);
}
list.addElement("Send AK(" + s + ")");
}
else // duplicate seq. no.
list.addElement("Send AK(" + lowerWindowEdge +")");
}
return(list);
}
private int inc(int seq) {
return(mod(seq + 1));
}
public void initialise() {
for (int i = 0; i <= maxSeq; i++) pduArrived[i] = false;
lowerWindowEdge = 0;
upperWindowEdge = winSize;
pduReceived = null;
entityEvents = new Vector<ProtocolEvent>(); // empty entity events
}
private boolean isWithinWindow(int seq) {
return
(lowerWindowEdge <= seq && seq < upperWindowEdge) ||
(upperWindowEdge < lowerWindowEdge &&
(seq >= lowerWindowEdge || seq < upperWindowEdge));
}
private int mod(int n) {
int base = maxSeq + 1;
n %= base;
return(n >= 0 ? n : n + base);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith("Send AK")) {
int startIndex = s.indexOf( '(' ) + 1;
int endIndex = s.indexOf( ')' );
int seq = Integer.parseInt(s.substring(startIndex, endIndex));
PDU pdu = new PDU("AK", seq);
transmitPDU(pdu, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
pduReceived = null;
}
for (Enumeration e = entityEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (pdu != null && pdu.type.equals("DT")) {
int seq = pdu.seq;
if (isWithinWindow(seq)) {
boolean alreadyBuffered = pduArrived[seq];
boolean delivered = false;
pduArrived[seq] = true;
int s = lowerWindowEdge;
// deliver sequence of data messages to user
for (int i = 0; i < winSize && pduArrived[s]; i++) {
events.addElement(comment("DT(" + s + ") delivered"));
s = inc(s);
}
// clear pduArrived flags for messages passed to user
for (int i = lowerWindowEdge; i != s; i = inc(i)) {
pduArrived[i] = false;
if (i == seq) {
alreadyBuffered = true;
delivered = true;
}
}
if (alreadyBuffered && !delivered)
events.addElement(comment("Ignored"));
if (!alreadyBuffered) {
events.addElement(comment("Buffered"));
alreadyBuffered = true;
}
// update window edges
lowerWindowEdge = s;
upperWindowEdge = mod(lowerWindowEdge + winSize);
}
else { // duplicate sequence number received
events.addElement(comment("Ignored"));
}
}
pduReceived = pdu;
return(events);
}
public void setMaxSeq(int maxSeq) {
this.maxSeq = maxSeq;
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void setWindowSize(int winSize) {
this.winSize = winSize;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
entityEvents = medium.receivePDU(pdu);
}
}

@ -0,0 +1,220 @@
// SWP3Sender.java
package protocol;
import java.util.Enumeration; // enumeration
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
/**
This is the class for a three-column Sliding Window Protocol sender.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): minor tidying
*/
public class SWP3Sender implements ProtocolEntity, Timeouts {
// SWP3 Sliding Window sender protocol entity
private static final String SEND = "Send";
private static final String RESEND = "Timeout - resend";
private static final String BLOCKED = "Blocked";
private static final String CLEAR = "Clear";
private int maxSeq; // maximum seq. no.
private int winSize; // transmit window
private int lowerWindowEdge; // ack seq. no.
private int upperWindowEdge; // next seq. no.
private boolean[] timerEnabled;
private Medium medium;
private ProtocolEntity peer;
private Vector<String> services;
private boolean windowClosed;
private Vector<ProtocolEvent> entityEvents; // events from entity
public SWP3Sender(int maxSeq, int winSize, Medium m) {
setMaxSeq(maxSeq);
setWindowSize(winSize);
medium = m;
initialise();
}
private void addService(String s) {
if (services.indexOf(s) < 0)
services.addElement(s);
}
private ProtocolEvent comment(String c) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, c));
}
public String getName() {
return("Sender");
}
public Vector<String> getServices() {
int seq;
int first = -1;
int last = -1;
// remove any previous resend actions
for (Enumeration e = services.elements(); e.hasMoreElements(); ) {
String s = (String)e.nextElement();
if(s.startsWith(RESEND)) services.removeElement(s);
}
for (seq = lowerWindowEdge; isWithinWindow(seq); seq = inc(seq)) {
if (timerEnabled[seq]) {
if (first < 0) first = seq;
last = seq;
}
}
if (first >= 0) { // >=1 PDU may time out
// ensure there is no option to send new data until timeout dealt with
services.removeAllElements();
if (last == first) // 1 PDU may be resent
addService(RESEND + " DT(" + first + ")");
else // >1 PDU may be resent
addService(RESEND + " DT(" + first + ") - (" + last + ")");
}
if (!windowClosed) {
addService(SEND + " DT(" + seq + ")");
}
return(services);
}
public boolean hasTimer(String type) {
return(true);
}
private int inc(int seq) {
return(mod(seq + 1));
}
public void initialise() {
timerEnabled = new boolean[maxSeq + 1];
for (int i = 0; i <= maxSeq; i++) timerEnabled[i] = false;
lowerWindowEdge = 0;
upperWindowEdge = 0;
services = new Vector<String>();
windowClosed = false;
entityEvents = new Vector<ProtocolEvent>(); // empty medium events
}
private boolean isWithinWindow(int seq) {
return (lowerWindowEdge <= seq && seq < upperWindowEdge) ||
(upperWindowEdge < lowerWindowEdge &&
(seq >= lowerWindowEdge || seq < upperWindowEdge));
}
private int mod(int n) {
int base = maxSeq + 1;
n %= base;
return(n >= 0 ? n : n + base);
}
public Vector<ProtocolEvent> performService(String s) {
int startIndex, endIndex;
String seqString;
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith(SEND)) {
PDU pdu = new PDU("DT", upperWindowEdge);
transmitPDU(pdu, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
removeService(s);
upperWindowEdge = inc(upperWindowEdge);
windowClosed = mod(upperWindowEdge - lowerWindowEdge) >= winSize;
if (windowClosed)
events.addElement(comment(BLOCKED));
}
if (s.startsWith(RESEND)) {
// get sequence number of first data PDU to be resent
startIndex = s.indexOf( '(' ) + 1;
endIndex = s.indexOf( ')' );
seqString = s.substring(startIndex, endIndex);
int seq1 = Integer.parseInt(seqString);
// get sequence number of last data PDU to be resent
startIndex = s.lastIndexOf( '(' ) + 1;
endIndex = s.lastIndexOf( ')' );
seqString = s.substring(startIndex, endIndex);
int seq2 = Integer.parseInt(seqString);
releaseTimers(seq1, inc(seq2));
// retransmit all unacknowledged data PDUs already sent and timed out
for (int p = seq1; p != inc(seq2); p = inc(p)) {
PDU pdu = new PDU("DT", p);
transmitPDU(pdu, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TIMEOUT, pdu));
}
removeService(s);
}
for (Enumeration e = entityEvents.elements(); // get medium events
e.hasMoreElements(); )
events.addElement( // add medium event
(ProtocolEvent) e.nextElement());
return(events);
}
private void releaseTimers(int lower, int upper) {
for (int seq = lower; seq != upper; seq = inc(seq)) {
timerEnabled[seq] = false;
}
}
private void removeService(String s) {
if (services.isEmpty())
return;
for (Enumeration e = services.elements(); e.hasMoreElements(); ) {
String s1 = (String)e.nextElement();
if (s1.equals(s)) {
services.removeElement(s1);
break;
}
}
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) {
timerEnabled[pdu.seq] = enabled;
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (pdu != null && pdu.type.equals("AK")) { // respond to AK
int seq = pdu.seq;
if (isWithinWindow(mod(seq - 1))) {
releaseTimers(lowerWindowEdge, seq);
lowerWindowEdge = seq; // update sender window
if (windowClosed) {
// send window was full, indicate it is now clear:
events.addElement(comment(CLEAR));
}
windowClosed = false;
}
}
return(events);
}
public void setMaxSeq(int maxSeq) {
this.maxSeq = maxSeq;
}
public void setWindowSize(int winSize) {
this.winSize = winSize;
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
entityEvents = medium.receivePDU(pdu);
}
}

@ -0,0 +1,53 @@
// SWP5.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class SWP5 extends Protocol {
private int maxSeq = 7;
private int winSize = 3;
private SWP5Service userA;
private SWP5Service userB;
private SWP5Sender sender;
private SWP5Receiver receiver;
public SWP5() {
medium = new Medium();
userA = new SWP5Service("User A", true);
userB = new SWP5Service("User B", false);
sender = new SWP5Sender(maxSeq, winSize, medium);
receiver = new SWP5Receiver(maxSeq, winSize, medium);
userA.setProvider(sender);
userB.setProvider(receiver);
sender.setUser(userA);
receiver.setUser(userB);
sender.setPeer(receiver);
receiver.setPeer(sender);
entities = new Vector<ProtocolEntity>();
entities.addElement(userA);
entities.addElement(sender);
entities.addElement(medium);
entities.addElement(receiver);
entities.addElement(userB);
}
public void setParameter(String param, String value) {
try {
if (param.equals("maxSeq")) {
maxSeq = Integer.parseInt(value);
sender.setMaxSeq(maxSeq);
receiver.setMaxSeq(maxSeq);
}
if (param.equals("winSize")) {
winSize = Integer.parseInt(value);
sender.setWindowSize(winSize);
receiver.setWindowSize(winSize);
}
}
catch (NumberFormatException e) {}
}
}

@ -0,0 +1,144 @@
// SWP5Receiver.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class SWP5Receiver implements ProtocolEntity {
private int maxSeq;
private int winSize;
private int lowerWindowEdge;
private int upperWindowEdge;
private boolean[] pduArrived;
private PDU[] recvBuffer;
private SWP5Service user;
private ProtocolEntity peer;
private Medium medium;
private Vector userEvents;
private int ackSeq; // next AK seq. no.
public SWP5Receiver(int maxSeq, int winSize, Medium m) {
setMaxSeq(maxSeq);
setWindowSize(winSize);
medium = m;
initialise();
}
public void setMaxSeq(int maxSeq) {
this.maxSeq = maxSeq;
}
public void setWindowSize(int winSize) {
this.winSize = winSize;
}
public void initialise() {
recvBuffer = new PDU[maxSeq + 1];
pduArrived = new boolean[maxSeq + 1];
for (int i = 0; i <= maxSeq; i++) pduArrived[i] = false;
lowerWindowEdge = 0;
upperWindowEdge = winSize;
ackSeq = -1;
}
private int inc(int seq) {
return(mod(seq + 1));
}
private int mod(int n) {
int base = maxSeq + 1;
n %= base;
return(n >= 0 ? n : n + base);
}
private boolean isWithinWindow(int seq) {
return(lowerWindowEdge <= seq && seq < upperWindowEdge) ||
(upperWindowEdge < lowerWindowEdge &&
(seq >= lowerWindowEdge || seq < upperWindowEdge));
}
private ProtocolEvent comment(String c) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, c));
}
public String getName() {
return("Protocol B");
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void setUser(ProtocolEntity user) {
this.user = (SWP5Service)user;
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (pdu != null && pdu.type.equals("DT")) {
ackSeq = -1;
int seq = pdu.seq;
if (isWithinWindow(seq)) {
pduArrived[seq] = true;
recvBuffer[seq] = pdu;
seq = lowerWindowEdge;
// deliver sequence of data messages to user
for (int i = 0; i < winSize && pduArrived[seq]; i++) {
PDU pduSent = new PDU("DatInd", recvBuffer[seq].getSDU());
transmitPDU(pduSent, user);
events.addElement(
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
seq = inc(seq);
}
ackSeq = seq;
// clear pduArrived flags for messages passed to user
for (int i = lowerWindowEdge; i != seq; i = inc(i))
pduArrived[i] = false;
// update window edges
lowerWindowEdge = seq;
upperWindowEdge = mod(lowerWindowEdge + winSize);
}
else { // duplicate seq. no.
ackSeq = lowerWindowEdge;
events.addElement(comment("Ignored"));
}
}
return(events);
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
if (dest == peer)
userEvents = medium.receivePDU(pdu);
else
userEvents = user.receivePDU(pdu);
}
public Vector<String> getServices() {
Vector<String> services = new Vector<String>();
if (ackSeq >= 0)
services.addElement("Send AK(" + ackSeq + ")");
return(services);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith("Send AK")) {
int startIndex = s.indexOf( '(' ) + 1;
int endIndex = s.indexOf( ')' );
int seq = Integer.parseInt(s.substring(startIndex, endIndex));
// send AK for next sequence number required
PDU ackPDU = new PDU("AK", seq);
transmitPDU(ackPDU, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, ackPDU));
ackSeq = -1;
}
for (Enumeration e = userEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
}

@ -0,0 +1,200 @@
// SWP5Sender.java
package protocol;
import java.util.*;
import support.*;
/**
This is the class for a five-column Sliding Window Protocol sender.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): minor tidying
*/
public class SWP5Sender implements ProtocolEntity, Timeouts {
private static final String SEND = "Send";
private static final String RESEND = "Timeout - resend";
private static final String BLOCKED = "Blocked";
private static final String CLEAR = "Clear";
private int maxSeq; // maximum seq. no.
private int winSize; // transmit window
private int lowerWindowEdge; // ack seq. no.
private int upperWindowEdge; // next seq. no.
private boolean[] timerEnabled;
private PDU[] recvBuffer;
private Medium medium;
private SWP5Service user;
private ProtocolEntity peer;
private Vector userEvents;
private boolean windowClosed;
public SWP5Sender(int maxSeq, int winSize, Medium m) {
setMaxSeq(maxSeq);
setWindowSize(winSize);
medium = m;
initialise();
}
public void initialise() {
recvBuffer = new PDU[maxSeq + 1];
timerEnabled = new boolean[maxSeq + 1];
for (int i = 0; i <= maxSeq; i++) timerEnabled[i] = false;
lowerWindowEdge = 0;
upperWindowEdge = 0;
windowClosed = false;
}
public void setMaxSeq(int maxSeq) {
this.maxSeq = maxSeq;
}
public void setWindowSize(int winSize) {
this.winSize = winSize;
}
private int inc(int seq) {
return(mod(seq + 1));
}
private int mod(int n) {
int base = maxSeq + 1;
n %= base;
return(n >= 0 ? n : n + base);
}
private boolean isWithinWindow(int seq) {
return(lowerWindowEdge <= seq && seq < upperWindowEdge) ||
(upperWindowEdge < lowerWindowEdge &&
(seq >= lowerWindowEdge || seq < upperWindowEdge));
}
public String getName() {
return("Protocol A");
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) {
timerEnabled[pdu.seq] = enabled;
}
public void setPeer(ProtocolEntity peer) {
this.peer = peer;
}
public void setUser(ProtocolEntity user) {
this.user = (SWP5Service)user;
}
private void releaseTimers(int lower, int upper) {
for (int seq = lower; seq != upper; seq = inc(seq)) {
timerEnabled[seq] = false;
}
}
private ProtocolEvent comment(String c) {
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, c));
}
public boolean hasTimer(String type) {
return(true);
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
String pduType = "";
if (pdu != null) pduType = pdu.type;
if (pduType.equals("DatReq")) { // DatReq from user
PDU pduSent = new PDU("DT", upperWindowEdge, pdu.getSDU());
recvBuffer[upperWindowEdge] = pdu;
transmitPDU(pduSent, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
upperWindowEdge = inc(upperWindowEdge);
windowClosed = mod(upperWindowEdge - lowerWindowEdge) >= winSize;
if (windowClosed) {
events.addElement(comment(BLOCKED));
}
}
if (pduType.equals("AK")) { // AK PDU from peer
int seq = pdu.seq;
if (isWithinWindow(mod(seq - 1))) {
releaseTimers(lowerWindowEdge, seq);
lowerWindowEdge = seq; // update sender window
if (windowClosed) {
// Send window was full, indicate it is now clear:
events.addElement(comment(CLEAR));
}
windowClosed = false; // and set flag appropriately
}
}
user.setOKToSend(!windowClosed);
return(events);
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
if (dest == peer)
userEvents = medium.receivePDU(pdu);
else
userEvents = user.receivePDU(pdu);
}
public Vector<String> getServices() {
Vector<String> services = new Vector<String>();
int seq;
int first = -1;
int last = -1;
for (seq = lowerWindowEdge; isWithinWindow(seq); seq = inc(seq)) {
if (timerEnabled[seq]) {
if (first < 0)
first = seq;
last = seq;
}
}
if (first >= 0) { // >=1 PDU may time out
if (last == first) // only one PDU may be resent
services.addElement(RESEND + " DT(" + first + ")");
else // more than one PDU may be resent
services.addElement(RESEND + " DT(" + first + ") - (" + last + ")");
}
return(services);
}
public Vector<ProtocolEvent> performService(String s) {
int startIndex, endIndex;
String seqString;
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (s.startsWith(RESEND)) {
// get sequence number of first data PDU to be resent
startIndex = s.indexOf( '(' ) + 1;
endIndex = s.indexOf( ')' );
seqString = s.substring(startIndex, endIndex);
int seq1 = Integer.parseInt(seqString);
// get sequence number of last data PDU to be resent
startIndex = s.lastIndexOf( '(' ) + 1;
endIndex = s.lastIndexOf( ')' );
seqString = s.substring(startIndex, endIndex);
int seq2 = Integer.parseInt(seqString);
releaseTimers(seq1, inc(seq2));
// retransmit all unacknowledged data PDUs already sent and timed out
for (int p = seq1; p != inc(seq2); p = inc(p)) {
PDU pdu = new PDU("DT", p, recvBuffer[p].getSDU());
transmitPDU(pdu, peer);
events.addElement(new ProtocolEvent(ProtocolEvent.TIMEOUT, pdu));
}
}
for (Enumeration e = userEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
}

@ -0,0 +1,80 @@
// SWP5Service.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class SWP5Service implements ProtocolEntity {
public static final String DAT_REQ = "Data Request";
private ProtocolEntity provider; // protocol for service
private Vector providerEvents;
private PDU pduSent;
private String name;
private boolean sending; // sending/receiving
private int block; // data seq. no.
private boolean okToSend; // OK to send DatReq
public SWP5Service(String name, boolean sending) {
this.name = name;
this.sending = sending;
initialise();
}
public void initialise() {
block = 0;
okToSend = true;
providerEvents = new Vector();
}
public String getName() {
return(name);
}
public void setProvider(ProtocolEntity provider) {
this.provider = provider;
}
// DatReq allowed only when okToSend is true
// (sender protocol window not closed)
public void setOKToSend(boolean ok) {
okToSend = ok;
}
// accept message but don't need to do anything with it
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
return(new Vector<ProtocolEvent>());
}
public void transmitPDU(PDU pdu, ProtocolEntity dest) {
pdu.setSource(this);
pdu.setDestination(dest);
providerEvents = dest.receivePDU(pdu);
pduSent = pdu;
}
public Vector<String> getServices() {
Vector<String> list = new Vector<String>();
if (sending && okToSend)
list.addElement("Send " + DAT_REQ + "(D" + block + ")");
return(list);
}
public Vector<ProtocolEvent> performService(String s) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
if (sending && s.startsWith("Send " + DAT_REQ)) {
String sdu = "D" + block;
transmitPDU(new PDU("DatReq", sdu), provider);
block++;
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
}
for (Enumeration e = providerEvents.elements(); e.hasMoreElements(); )
events.addElement((ProtocolEvent) e.nextElement());
return(events);
}
}

@ -0,0 +1,200 @@
// TCP.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the main class for the TCP simulation.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (26th July 2010, KJT): minor tidying; additions of constants
for initial values; addition of a loss rate; addition of
support for the slow-start TCP simulation
*/
public class TCP extends Protocol {
// role constants
/** Peer-to-peer role */
public final static int PEER = 0;
/** Client-server role */
public final static int CLIENT = 1;
/** Server role */
public final static int SERVER = 2;
// protocol constants
/** Default medium loss rate */
public final static float LOSS_RATE = 0.2f;
// protocol constants
/** Default initial sequence number for protocol A */
public final static int INITIAL_SEQUENCE_A = 0;
/** Default initial sequence number for protocol A */
public final static int INITIAL_SEQUENCE_B = 100;
/** Default initial window size for protocol A */
public final static int INITIAL_WINDOW_A = 500;
/** Default initial window size for protocol B */
public final static int INITIAL_WINDOW_B = 400;
/** Default segment size for protocol */
public final static int SEGMENT_SIZE = 200;
// service constants
/** Default message size for service A */
public final static int MESSAGE_SIZE_A = 100;
/** Default message size for service A */
public final static int MESSAGE_SIZE_B = 300;
// simulation variables
/** Protocol type ("cs", "pp", "ss") */
private static String protocolSubtype;
/** Service entities A and B */
private TCPService servA, servB;
/** Protocol entities A and B */
private TCPProtocol protA, protB;
/** Role of A and B */
private int roleA, roleB;
/** Names of A and B */
private String nameA, nameB;
/**
Constructor for the TCP object
@param type protocol type ("cs", "pp", "ss")
@exception unknown protocol type
*/
public TCP(String type) throws Exception {
protocolSubtype = // store protocol type in l. c.
type.toLowerCase();
medium = new TCPMedium(); // construct medium
// medium.setMediumType(Medium.CONTROL_NOTHING);
TCPProtocol.setSegmentSize(SEGMENT_SIZE); // set protocol segment size
if (protocolSubtype.equals("cs")) { // client-server subtype?
roleA = CLIENT; // A is client
nameA = "Client";
roleB = SERVER; // B is server
nameB = "Server";
}
else if (protocolSubtype.equals("pp")) { // peer-peer subtype?
roleA = PEER; // A is peer
nameA = "User A";
roleB = PEER; // B is peer
nameB = "User B";
}
else if (protocolSubtype.equals("ss")) { // slow start subtype?
roleA = PEER; // A is peer
nameA = "User A";
roleB = PEER; // B is peer
nameB = "User B";
}
else // unknown subtype
throw new Exception("unknown protocol subtype '" + protocolSubtype + "'");
((TCPMedium) medium).setLossRate(LOSS_RATE);// set medium loss rate
servA = new TCPService(nameA, roleA); // create service A
servB = new TCPService(nameB, roleB); // create service B
servA.setMessageSize(MESSAGE_SIZE_A); // set service A message size
servB.setMessageSize(MESSAGE_SIZE_B); // set service B message size
if (protocolSubtype.equals("ss")) // slow start?
protA = // create protocol A
new TCPProtocol(
medium, "Protocol A", roleA, INITIAL_SEQUENCE_A, INITIAL_WINDOW_A,
INITIAL_WINDOW_B, INITIAL_SEQUENCE_B);
else // client-server/peer-peer
protA = // create protocol A
new TCPProtocol(medium, "Protocol A", roleA, INITIAL_SEQUENCE_A,
INITIAL_WINDOW_A);
protB = // create protocol B
new TCPProtocol(medium, "Protocol B", roleB, INITIAL_SEQUENCE_B,
INITIAL_WINDOW_B);
servA.setProvider(protA); // service A -> protocol A
servB.setProvider(protB); // service B -> protocol B
protA.setUser(servA); // protocol A -> service A
protA.setPeer(protB); // protocol A -> protocol B
protB.setUser(servB); // protocol B -> service B
protB.setPeer(protA); // protocol B -> protocol A
entities = new Vector<ProtocolEntity>(); // initialise entities list
entities.addElement(servA); // add service A
entities.addElement(protA); // add protocol A
entities.addElement(medium); // add medium
entities.addElement(protB); // add protocol B
entities.addElement(servB); // add service B
}
/**
Check if the protocol is slow start (i.e. the protocol subtype is for slow
start).
@return true/false if slow start is/is not in use
*/
public static boolean isSlowStart() {
return( // return check
protocolSubtype.equals("ss")); // slow start subtype
}
/**
Set a TCP parameter.
@param parameter parameter
@param value value
*/
public void setParameter(String parameter, String value) {
if (parameter.equals("pushA")) {
boolean push = Boolean.valueOf(value).booleanValue();
servA.setPush(push);
return;
}
else if (parameter.equals("pushB")) {
boolean push = Boolean.valueOf(value).booleanValue();
servB.setPush(push);
return;
}
try {
if (parameter.equals("lossRate")) { // loss rate?
float lossRate = Float.valueOf(value).floatValue();
((TCPMedium) medium).setLossRate(lossRate);
}
else { // other integer parameter
int size = Integer.parseInt(value);
if (parameter.equals("userAMessageSize"))
servA.setMessageSize(size);
else if (parameter.equals("userBMessageSize"))
servB.setMessageSize(size);
else if (parameter.equals("windowSizeA"))
protA.setWindowSizeDefault(size);
else if (parameter.equals("windowSizeB"))
protB.setWindowSizeDefault(size);
else if (parameter.equals("maxSendPacket"))
TCPProtocol.setSegmentSize(size);
else
System.err.println("unknown parameter '" + parameter + ";");
}
}
catch (NumberFormatException e) { // invalid numeric value
System.err.println(
"invalid number '" + value + "' for '" + parameter + "'");
}
}
}

@ -0,0 +1,125 @@
// TCPMedium.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class for a TCP medium.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (26th July 2010, KJT): minor tidying; a loss rate has been
introduced for medium messages
*/
public class TCPMedium extends Medium {
/** Message loss rate (0.2 means 20% of messages are lost) */
private float lossRate = 0.2f;
/** Random number index */
private int randomIndex;
/** Random numbers */
private Vector<Float> randomNumbers;
/**
Constructor for a TCP medium.
*/
public TCPMedium() {
super(); // construct superclass
randomNumbers = new Vector<Float>(); // initialise random numbers
}
/**
Initialise the medium.
*/
public void initialise() {
super.initialise();
randomIndex = 0; // initialise random index
}
/**
Gets the matching PDU.
@param description PDU description
@return matching PDU
*/
protected PDU getMatchingPDU(String description) {
// identify and return PDU currently on channel with
// type and parameters matching those described in given string
TCPMessage tcpdu;
// try to match PDU type and seq with a PDU currently on channel:
for (Enumeration enumeration = pdus.elements();
enumeration.hasMoreElements(); ) {
tcpdu = (TCPMessage) enumeration.nextElement();
if (description.indexOf(tcpdu.getID()) > 0)
return (tcpdu);
}
return (null); // no match found
}
/**
Return a list of strings describing actions (services) that can be carried
out in the current state.
@return service descriptions
*/
public Vector<String> getServices() {
Vector<String> list = new Vector<String>(); // initialise service list
HashSet<String> pdusSent = // initialise list of sources
new HashSet<String>();
for (Enumeration enumeration = pdus.elements(); // go through PDUs
enumeration.hasMoreElements(); ) {
PDU pdu = (PDU) enumeration.nextElement();// get next PDU
if (pdu != null) { // non-null PDU?
String name = pdu.getSource().getName();// get PDU source name
String description = // get PDU id and name
pdu.getID() + " [" + name + "]";
if (!pdusSent.contains(name)) { // no PDU with this source?
pdusSent.add(name); // add source to list
list.addElement( // add delivery service
"Deliver " + description + " - no loss");
}
if (random() < lossRate) // loss is possible?
list.addElement( // add loss service
"Lose " + description + " - congestion/error");
}
}
return(list); // return service list
}
/**
Return a random float. If the list of randoms contains an unused value then
use this, otherwise generate a fresh value and add to the list. This allows
random numbers to be generated consistently when simulation steps are
undone/redone.
@return random number in the range (0..1]
*/
private float random() {
if (randomIndex < randomNumbers.size()) // index within list?
return( // return this random
((Float)randomNumbers.elementAt(randomIndex++)).floatValue());
else { // index not within list
Float random = new Float(Math.random()); // get random number
randomNumbers.addElement(random); // add random to list
randomIndex++; // increment list index
return(random.floatValue()); // return rand number
}
}
/**
Set the medium loss rate.
@param lossRate loss rate
*/
public void setLossRate(float lossRate) {
this.lossRate = lossRate; // set loss rate
}
}

@ -0,0 +1,217 @@
// TCPMessage.java
package protocol; // protocol package
import support.*; // import Jasper support classes
/**
This is the class for a TCP segment.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (26th July 2010, KJT): minor tidying, proper "toString"
method added
*/
public class TCPMessage extends PDU {
/** Urgent flag */
public final static int URG = 32;
/** Acknowledgement flag */
public final static int ACK = 16;
/** Push flag */
public final static int PSH = 8;
/** Reset flag */
public final static int RST = 4;
/** Synchronise flag */
public final static int SYN = 2;
/** Finish flag */
public final static int FIN = 1;
/** Acknowledgement sequence number */
protected int ack = -1;
/** Flag setting */
protected int flags = 0;
/** Window sequence number */
protected int win = -1;
/** Protocol flags */
protected boolean urgFlag, ackFlag, pshFlag, rstFlag, synFlag, finFlag;
/**
Constructor for a TCP segment.
@param seq sequence number
@param flags flags
@param size message size
*/
public TCPMessage(int seq, int flags, int size) {
this.seq = seq;
this.flags = flags;
setFlags();
this.size = size;
}
/**
Constructor for a TCP segment.
@param seq sequence number
@param ack acknowlegement sequence number
@param flags flags
@param size message size
*/
public TCPMessage(int seq, int ack, int flags, int size) {
this.seq = seq;
this.ack = ack;
this.flags = flags;
setFlags();
this.size = size;
}
/**
Return the label of a TCP segment.
@return segment label
*/
public String getLabel() {
// return label for arrow representing this segment
// in a time sequence diagram
String label = "";
if (size > 0)
label += "Seq " + seq + ", ";
if (ackFlag)
label += "Ack " + ack + ", ";
if (win >= 0)
label += "Win " + win;
if (urgFlag)
label += ", URG";
if (pshFlag)
label += ", PSH";
if (rstFlag)
label += ", RST";
if (synFlag)
label += ", SYN";
if (finFlag)
label += ", FIN";
return (label);
}
/**
Return the Acknowledgement attribute of a TCP segment.
@return Acknowledgement value
*/
public boolean isAck() {
return (ackFlag);
}
/**
Return the Finish attribute of a TCP segment.
@return Finish value
*/
public boolean isFin() {
return (finFlag);
}
/**
Return the Push attribute of a TCP segment.
@return Push value
*/
public boolean isPsh() {
return (pshFlag);
}
/**
Return the Reset attribute of a TCP segment.
@return Reset value
*/
public boolean isRst() {
return (rstFlag);
}
/**
Return the Synchronise attribute of a TCP segment.
@return Synchronise value
*/
public boolean isSyn() {
return (synFlag);
}
/**
Return the Urgent attribute of a TCP segment.
@return Urgent value
*/
public boolean isUrg() {
return (urgFlag);
}
/**
Check if the given PDU matches this one.
@param pdu PDU
@return true/false if PDU does/does not match
*/
public boolean matches(PDU pdu) {
if (pdu == null)
return (false);
if (this.getSource() != pdu.getSource()) // entities must match
return (false);
TCPMessage tcpdu = (TCPMessage) pdu;
// if both segments have valid ACK numbers, check that they match
if (this.isAck() && tcpdu.isAck() && this.ack != tcpdu.ack)
return (false);
return (this.seq == tcpdu.seq && this.flags == tcpdu.flags);
}
/**
Set the flags attribute of the TCPMessage object
*/
private void setFlags() {
int f = flags;
finFlag = f % 2 > 0;
f /= 2;
synFlag = f % 2 > 0;
f /= 2;
rstFlag = f % 2 > 0;
f /= 2;
pshFlag = f % 2 > 0;
f /= 2;
ackFlag = f % 2 > 0;
f /= 2;
urgFlag = f % 2 > 0;
}
/**
Set the window size of a TCP message.
@param win window size
*/
public void setWindowSize(int win) {
if (win >= 0)
this.win = win;
}
/**
Convert a PDU to a string representation.
@return string representation of a PDU
*/
public String toString() {
return ("PDU <" + getLabel() + ">");
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,285 @@
// TCPService.java
package protocol; // protocol package
import java.util.*; // import Java utility classes
import support.*; // import Jasper support classes
/**
This is the class for a TCP service entity.
@author Iain A. Robin, Kenneth J. Turner
@version 1.0 (1st September 1999, IAR): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (26th July 2010, KJT): minor tidying
*/
public class TCPService implements ProtocolEntity {
/** Debug flag */
private final static boolean DEBUG = false;
// Service primitives (based on Halsall Figs 11.6 - 11.8):
/** Active open message */
public final static String ACTIVE_OPEN = "Active Open";
/** Passive open message */
public final static String PASSIVE_OPEN = "Passive Open";
/** Open failure message */
public final static String OPEN_FAILURE = "Open Failure";
/** Open received message */
public final static String OPEN_RECEIVED = "Open Received";
/** Open success message */
public final static String OPEN_SUCCESS = "Open Success";
/** Send message */
public final static String SEND = "Send";
/** Deliver message */
public final static String DELIVER = "Deliver";
/** Close message */
public final static String CLOSE = "Close";
/** Closing message */
public final static String CLOSING = "Closing";
/** Closed message */
public final static String CLOSED = "Closed";
/** Abort message */
public final static String ABORT = "Abort";
/** Push message */
public final static String PUSH = "(Push)";
/** Open confirmed message (internal use) */
public final static String OPEN_CONFIRMED = "Open Confirmed";
// State constants
/** Connected state */
private final static int CONNECTED = 0;
/** Calling state */
private final static int CALLING = 1;
/** Listening state */
private final static int LISTENING = 2;
/** Close sent state */
private final static int CLOSE_SENT = 3;
/** Disconnected state */
private final static int DISCONNECTED = 4;
/** Protocol for service */
private ProtocolEntity provider;
/** Events from provider */
private Vector<ProtocolEvent> providerEvents;
/** Service name */
private String name;
/** Service entity role */
private int role;
/** Protocol state */
private int state;
/** Request Push flag */
private boolean push;
/** Message size */
private int messageSize;
/**
Constructor for a TCP service entity.
@param name service name
@param role service role
*/
public TCPService(String name, int role) {
this.name = name;
this.role = role;
initialise();
}
/**
Return the TCP service entity name.
@return service name
*/
public String getName() {
return (name);
}
/**
Return the services offered by the entity.
@return services offered
*/
public Vector<String> getServices() {
Vector<String> services = new Vector<String>();
if (state == CONNECTED) { // connected?
if (!TCP.isSlowStart() || // not slow start and
name.equals("User A")) { // user A?
String service = // set send service
SEND + " " + messageSize + " octets";
if (push) // push flag set?
service += " " + PUSH; // append push
services.addElement(service); // add send service
}
if (!TCP.isSlowStart()) // not slow start?
services.addElement(CLOSE); // add close service
}
else if (state == DISCONNECTED) {
if (role == TCP.SERVER)
services.addElement(PASSIVE_OPEN);
else
services.addElement(ACTIVE_OPEN);
}
return (services);
}
/**
Initialise service entity.
*/
public void initialise() {
providerEvents = new Vector<ProtocolEvent>();
push = false;
if (TCP.isSlowStart()) // slow start?
setState(CONNECTED); // start directly as connected
else // client-server/peer-peer
setState(DISCONNECTED); // start as disconnected
}
/**
Perform entity service.
@param service service requested
@return resulting service events
*/
public Vector<ProtocolEvent> performService(String service) {
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
PDU pdu;
switch (state) {
case CONNECTED:
if (service.startsWith(SEND)) {
String type = SEND + " (" + messageSize + ")";
if (service.indexOf(PUSH) > 0)
type += " " + PUSH;
pdu = new PDU(type);
pdu.size = messageSize;
transmitPDU(pdu, provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
}
if (service.startsWith(CLOSE)) {
pdu = new PDU(CLOSE);
transmitPDU(pdu, provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
setState(CLOSE_SENT);
}
break;
case CALLING:
break;
case DISCONNECTED:
if (service.equals(ACTIVE_OPEN)) {
pdu = new PDU(service);
transmitPDU(pdu, provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
setState(CALLING);
}
if (service.equals(PASSIVE_OPEN)) {
pdu = new PDU(service);
transmitPDU(pdu, provider);
events.addElement(
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
setState(LISTENING);
}
break;
}
for (Enumeration enumeration = providerEvents.elements();
enumeration.hasMoreElements(); )
events.addElement((ProtocolEvent) enumeration.nextElement());
return (events);
}
/**
Receive SDU.
@param sdu SDU
@return resulting service events
*/
public Vector<ProtocolEvent> receivePDU(PDU sdu) {
// respond to PDU received from underlying protocol
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
String sduType = sdu.type;
if (sduType.equals(OPEN_SUCCESS) || sduType.equals(OPEN_CONFIRMED))
setState(CONNECTED);
else if (sduType.equals(OPEN_FAILURE) || sduType.equals(CLOSED))
setState(DISCONNECTED);
return (events);
}
/**
Sets the messageSize attribute of the TCPService object
*
@param size The new messageSize value
*/
public void setMessageSize(int size) {
messageSize = size;
}
/**
Set entity service provider
@param provider service provider
*/
public void setProvider(ProtocolEntity provider) {
this.provider = provider;
}
/**
Set the Push attribute of a service entity.
@param push Push value
*/
public void setPush(boolean push) {
this.push = push;
}
/**
Set the state attribute of a service entity.
@param state state
*/
public void setState(int state) {
if (DEBUG)
System.err.println("state (" + name + "): " + state);
this.state = state;
}
/**
Transmit an SDU.
@param sdu SDU
@param destination destination
*/
public void transmitPDU(PDU sdu, ProtocolEntity destination) {
sdu.setSource(this);
sdu.setDestination(destination);
providerEvents = destination.receivePDU(sdu);
}
}

@ -0,0 +1,29 @@
// TFTP.java (C) K. J. Turner, K. A. Whyte 04/03/06
// Trivial File Transfer Protocol
package protocol; // protocol package
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
public class TFTP extends Protocol { // TFTP protocol
private TFTPSender sender; // protocol sender (client)
private TFTPReceiver receiver; // protocol receiver (server)
public TFTP() { // construct protocol instance
medium = new TFTPMedium(); // construct comms medium
sender = // construct sender (client)
new TFTPSender(medium, "Client");
receiver = // construct receiver (server)
new TFTPReceiver(medium, "Server");
sender.setPeer(receiver); // sender is receiver's peer
receiver.setPeer(sender); // receiver is sender's peer
entities = new Vector<ProtocolEntity>(); // initialise protocol entities
entities.addElement(sender); // add sender protocol entity
entities.addElement(medium); // add comms medium entity
entities.addElement(receiver); // add receive protocol entity
}
}

@ -0,0 +1,75 @@
// TFTPMedium.java (C) K. J. Turner 04/03/06
package protocol; // protocol package
import java.util.*; // utility support
import support.*; // protocol entity support
public class TFTPMedium extends Medium { // protocol medium
// protocol variables
private static Vector<Float> randoms; // random number list
private static int randomIndex; // random number index
public TFTPMedium() { // construct medium instance
super(); // construct as generic medium
randoms = new Vector<Float>(); // initialise list of randoms
}
protected PDU getMatchingPDU(String s) { // get matching PDU on channel
PDU pdu; // PDU
int seq = -1; // sequence number
String sdu = ""; // data
int sourceStart = s.indexOf ('[') + 1; // get start of entity name
int sourceEnd = s.indexOf (']'); // get end of entity name
String sourceName = // get PDU source
s.substring(sourceStart, sourceEnd);
int typeStart = s.indexOf (' ') + 1; // get start of PDU type
int typeEnd = s.indexOf ('('); // get end of PDU type
String type = // get PDU type
s.substring(typeStart, typeEnd);
String[] params = getParams(s); // get PDU parameters
if (type.equals("RRQ") || // read request or ..
type.equals("WRQ") || // write request or ...
type.equals("ERROR")) // error?
sdu = params[0]; // get filename/error message
else if (type.equals("ACK")) // acknowledgement?
seq = Integer.parseInt(params[0]); // get sequence number
else { // data
seq = Integer.parseInt(params[0]); // get sequence number
sdu = params[1]; // get data
}
for (Enumeration e = pdus.elements(); // get next PDU on channel ...
e.hasMoreElements(); ) { // as long as more to check
pdu = (PDU) e.nextElement(); // get next PDU on channel
if (pdu != null && // valid PDU and ...
pdu.type.equals(type) && // type matches and ...
pdu.getSource().getName(). // source ...
equals(sourceName) && // matches and ...
seq == pdu.seq && // seq number matches and ...
sdu.equals(pdu.sdu)) // SDU matches
return((pdu)); // return with this PDU
}
return((null)); // return no PDU as no match
}
public void initialise () { // initialise medium
super.initialise (); // initialise generic medium
randomIndex = 0; // initialise randoms index
}
protected static float random() { // random number (from list)
Float rand; // random number
if (randomIndex < randoms.size ()) // number is in list?
rand = (Float) randoms.elementAt(randomIndex++); // get number from list
else { // make new random number
rand = new Float(Math.random()); // get random number
randoms.addElement(rand); // add to list
randomIndex++; // increment list index
}
return((rand.floatValue ())); // return random number
}
}

@ -0,0 +1,38 @@
// TFTPMessage.java (C) K. J. Turner 01/03/01
// Trivial File Transfer Protocol message format
package protocol; // protocol package
import support.*; // protocol entity support
public class TFTPMessage extends PDU { // protocol data unit format
public TFTPMessage (String type, int seq) { // construct PDU type/seq
super (type, seq); // use generic PDU constructor
}
public TFTPMessage (String type, String sdu) { // construct PDU type/SDU
super (type, sdu); // use generic PDU constructor
}
public TFTPMessage ( // construct PDU type/seq/SDU
String type, int seq, String sdu) {
super(type, seq, sdu); // use generic PDU constructor
}
public String getLabel () { // get PDU "type(contents)"
String label = type; // get PDU type
if (seq >= 0) { // sequence number present?
label += "(" + seq; // append sequence number
if (sdu.equals ("")) // SDU absent?
label += ")"; // finish contents
else // SDU present
label += "," + sdu + ")"; // append SDU, finish contents
}
else if (!sdu.equals ("")) // no seq no, SDU present?
label += "(" + sdu + ")"; // append SDU
return (label); // return PDU label
}
}

@ -0,0 +1,232 @@
// TFTPReceiver.java (C) K. J. Turner, K. A. Whyte 05/06/01
// Trivial File Transfer Protocol receiver (server)
package protocol; // protocol package
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
/**
This is the class for a Trivial File Transfer Protocol sender.
@author Kenneth J. Turner, Kenneth A. Whyte
@version 1.0 (5th June 2001, KAW): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): unchecked warning suppressed
*/
public class TFTPReceiver // protocol receiver (server)
implements ProtocolEntity, Timeouts { // protocol entity, timeout
// simulator variables
private ProtocolEntity peer; // peer entity (client)
private Medium medium; // communications medium
private String name; // entity name
// protocol variables
private int pduNo; // PDU seq number sent/expected
private PDU pduSent; // PDU sent
private PDU pduReceived; // PDU received
private boolean timerEnabled; // whether timer is enabled
private float errorProb = 0.8f; // file I/O error probability
// protocol state
int state; // current protocol state
final static int idle = 0; // no connection
final static int reading = 2; // reading data
final static int writing = 4; // writing data
final static int waitLast = 5; // wait for last re-send
// protocol messages
final static String ack = "ACK"; // acknowledgement message type
final static String data = "DATA"; // data message type
final static String error = "ERROR"; // error message type
final static String rrq = "RRQ"; // read request message type
final static String wrq = "WRQ"; // write request messagetype
// protocol methods
public TFTPReceiver(Medium m, String name) { // construct receiver instance
this.name = name; // set protocol entity name
medium = m; // set underlying medium
initialise (); // initialise protocol
}
public String getName () { // get protocol entity name
return((name)); // return protocol entity name
}
public Vector<String> getServices() { // get protocol entity services
Vector<String> events = // list of events
new Vector<String>();
String pduType; // received PDU type
int pduSeq; // received PDU seq number
String pduData; // PDU data
if (pduReceived != null) { // PDU received?
pduType = pduReceived.type; // get received PDU type
if (pduType.equals(rrq) || // read request or ...
pduType.equals(wrq)) // write request?
pduSeq = 0; // treat as sequence number 0
else
pduSeq = pduReceived.seq; // get received PDU seq number
pduData = pduReceived.sdu; // get received PDU data
if (((state == idle || // idle or ...
state == reading) && // reading, and ...
pduType.equals(rrq)) || // read request, or ...
((state == reading || // reading or ...
state == waitLast) && // awaiting re-send, and ...
pduType.equals(ack))) { // acknowledgement?
if (pduSeq == pduNo) { // expected acknowledgement?
timerEnabled = false; // cancel timeout
if (pduSent != null && // valid previous PDU and ...
pduSent.sdu.equals("Dlast")) // last data sent?
initialise (); // re-initialise protocol
else { // more data to send
events.addElement( // send data
data + "(" + (pduNo + 1) + ",D" + (pduNo + 1) + ") - send data");
events.addElement( // send last data
data + "(" + (pduNo + 1) + ",Dlast) - send last data");
}
}
else if (pduSeq == pduNo - 1) // repeated acknowledgement?
events.addElement( // send data
data + "(" + pduSent.seq + "," + pduSent.sdu + ") - re-send data");
}
else if (((state == idle || // idle or ...
state == writing) && // writing, and ...
pduType.equals(wrq)) || // write request, or ...
(state == writing && // writing and ...
pduType.equals(data))) { // data?
if (pduSeq == pduNo || // expected data or ...
pduSeq == pduNo - 1) { // repeated data?
timerEnabled = false; // cancel timeout
events.addElement( // send acknowledgement
ack + "(" + pduSeq + ") - send acknowledgement");
}
}
}
if (state == waitLast) // waiting for last re-send?
events.addElement( // add close event
"Close - presume all retransmissions over");
if (state == reading && // reading and ...
pduSent != null && // PDU was sent and ...
!pduSent.sdu.equals("Dlast") && // PDU was not last and ...
TFTPMedium.random() < errorProb) // file read error?
events.addElement( // report reading error
error +"(data for read unavailable) - report error");
if (timerEnabled) // timer is enabled?
events.addElement( // add timeout event
"Timeout - presume loss of message and resend");
return(events); // return list of events
}
public boolean hasTimer(String type) { // protocol uses timer?
return((true)); // report it does
}
public void initialise () { // initialise protocol
state = idle; // initialise state
pduNo = 0; // initialise seq number
pduReceived = null; // initialise no PDU received
pduSent = null; // initialise no PDU sent
timerEnabled = false; // initialise no timeout
}
public Vector<ProtocolEvent> performService (String s) { // protocol service
Vector<ProtocolEvent> events = // initialise events list
new Vector<ProtocolEvent>();
int start, middle, end; // start/middle/end positions
int pduSeq; // PDU sequence number
String pduData; // PDU data
if (s.startsWith (ack)) { // send acknowledgement?
start = s.indexOf ('(') + 1; // get seq number start
end = s.indexOf (')'); // get seq number end
pduSeq = // get sequence number
Integer.parseInt(s.substring(start, end));
if (pduReceived != null && // valid PDU received and ...
pduReceived.sdu.equals("Dlast")) // last data?
state = waitLast; // wait for last re-send
else { // still reading
pduNo = pduSeq + 1; // update sequence number
state = writing; // (now) writing
}
transmitPDU( // send acknowledgement
new TFTPMessage(ack, pduSeq), peer);
}
else if (s.startsWith (data)) { // send data?
start = s.indexOf ('(') + 1; // get seq number start
middle = s.indexOf (','); // get comma position
end = s.indexOf (')'); // get seq number end
pduSeq = // get sequence number
Integer.parseInt(s.substring(start, middle));
pduData = s.substring(middle + 1, end); // get data contents
transmitPDU( // send data
new TFTPMessage(data, pduSeq, pduData), peer);
pduNo = pduSeq; // update sequence number
state = reading; // (now) reading
}
else if (s.startsWith (error)) { // send error?
start = s.indexOf ('(') + 1; // get error message start
end = s.indexOf (')'); // get error message end
pduData = s.substring(start, end); // get error message
transmitPDU( // send error
new TFTPMessage(error, pduData), peer);
state = waitLast; // wait for last re-send
}
else if (s.startsWith ("Close")) { // close?
events.addElement( // add closed comment
new ProtocolEvent(ProtocolEvent.COMMENT, this, "Closed"));
initialise (); // initialise protocol
}
if (s.startsWith ("Timeout")) { // timeout?
transmitPDU(pduSent, peer); // re-send PDU
events.addElement( // add timeout event and PDU
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
else if (pduSent != null) { // PDU to send?
events.addElement( // transmit PDU
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
}
return(events); // return list of events
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
pduReceived = pdu; // store PDU
if (pduReceived.type.equals(error)) // error message?
initialise(); // re-initialise protocol
return((new Vector<ProtocolEvent>())); // return no events
}
public void setPeer(ProtocolEntity peer) { // set protocol peer
this.peer = peer; // set this entity's peer
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) { // set timer status
if (state != idle) // not idle?
timerEnabled = enabled; // store timer status
}
public void transmitPDU( // transmit PDU
PDU pdu, ProtocolEntity dest) { // for given PDU, destination
pdu.setSource (this); // source is this entity
pdu.setDestination(dest); // destination is as given
pduSent = pdu; // copy PDU sent
medium.receivePDU(pdu); // medium receives PDU
pduReceived = null; // note no PDU in response
timerEnabled = false; // note no timeout
}
}

@ -0,0 +1,263 @@
// TFTPSender.java (C) K. J. Turner, K. A. Whyte 05/06/01
// Trivial File Transfer Protocol sender (client)
package protocol; // protocol package
import java.util.Vector; // vector (list)
import support.*; // protocol entity support
/**
This is the class for a Trivial File Transfer Protocol sender.
@author Kenneth J. Turner, Kenneth A. Whyte
@version 1.0 (5th June 2001, KAW): initial version
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
<br/> 1.5 (27th July 2010, KJT): unchecked warning suppressed
*/
public class TFTPSender // protocol sender (client)
implements ProtocolEntity, Timeouts { // protocol entity, timeout
// simulator variables
private ProtocolEntity peer; // peer entity (server)
private Medium medium; // communications medium
private String name; // entity name
// protocol variables
private int pduNo; // PDU seq number sent/expected
private PDU pduReceived; // PDU received
private PDU pduSent; // PDU sent
private boolean timerEnabled; // whether timer is enabled
private float errorProb = 0.8f; // file I/O error probability
private int fileNo; // file number to transfer
// protocol state
int state; // current protocol state
final static int idle = 0; // no connection
final static int readRequest = 1; // file to be read
final static int reading = 2; // reading data
final static int writeRequest = 3; // file to be written
final static int writing = 4; // writing data
final static int waitLast = 5; // wait for last re-send
// protocol messages
final static String ack = "ACK"; // acknowledgement message type
final static String data = "DATA"; // data message type
final static String error = "ERROR"; // error message type
final static String rrq = "RRQ"; // read request message type
final static String wrq = "WRQ"; // write request messagetype
// protocol methods
public TFTPSender(Medium m, String name) { // construct sender instance
this.name = name; // set protocol entity name
medium = m; // set underlying medium
initialise (); // initialise protocol
}
public String getName () { // get protocol entity name
return((name)); // return protocol entity name
}
public Vector<String> getServices() { // get protocol entity services
Vector<String> events = // list of events
new Vector<String>();
String pduType; // received PDU type
int pduSeq; // received PDU seq number
if (pduReceived != null) { // PDU received?
pduType = pduReceived.type; // get received PDU type
pduSeq = pduReceived.seq; // get received PDU seq number
if ((state == readRequest || // read request or ...
state == reading || // reading or ...
state == waitLast) && // awaiting re-send, and ...
pduType.equals(data)) { // data message?
if (pduSeq == pduNo) { // expected sequence number?
timerEnabled = false; // cancel timeout
events.addElement( // send acknowledgement
ack + "(" + pduNo + ") - send acknowledgement");
}
else if (state == readRequest) // wrong sequence, read req?
events.addElement( // report seq number error
error +"(wrong data sequence number) - report error");
}
else if ((state == writeRequest || // write request or
state == writing) && // writing, and ...
pduType.equals(ack)) { // write and acknowledgement?
if (pduSeq == pduNo) { // expected sequence number?
timerEnabled = false; // cancel timeout
if (pduSent != null && // valid previous PDU and ...
pduSent.sdu.equals("Dlast")) // last data sent?
reinitialise(); // re-initialise protocol
else { // more data to send
events.addElement( // send data
data + "(" + (pduNo + 1) + ",D" + pduNo + ") - send data");
events.addElement( // send last data
data + "(" + (pduNo + 1) + ",Dlast) - send last data");
}
}
else if (state == writing && // writing and ...
pduSeq == pduNo - 1) // repeated acknowledgement?
events.addElement( // send data
data + "(" + pduSent.seq + "," + pduSent.sdu + ") - re-send data");
else if (state == writeRequest) // wrong sequence, write req?
events.addElement( // report seq number error
error +"(wrong acknowledgement sequence number) - report error");
}
else if (pduType.equals(error)) { // error message?
state = idle; // back to not connected
}
}
if (state == idle) { // not connected?
events.addElement( // read file
rrq + "(file" + fileNo + ") - ask to read file");
events.addElement( // write file
wrq + "(file" + fileNo +") - ask to write file");
}
if (state == waitLast) // waiting for last re-send?
events.addElement( // add close event
"Close - presume all retransmissions over");
if (state == writing && // writing and ...
pduSent != null && // PDU was sent and ...
!pduSent.sdu.equals("Dlast") && // PDU was not last and ...
TFTPMedium.random() < errorProb) // file I/O error occurs?
events.addElement( // report I/O error
error +"(data for write unavailable) - report error");
if (timerEnabled) // timer is enabled?
events.addElement( // add timeout event
"Timeout - presume loss of message and resend");
return(events); // return list of events
}
public boolean hasTimer(String type) { // PDU needs timer?
return((true)); // report it does
}
public void initialise () { // initialise protocol
fileNo = 0; // initialise file number
reinitialise(); // re-initialise protocol
}
public Vector<ProtocolEvent> performService (String s) { // protocol service
Vector<ProtocolEvent> events = // initialise events list
new Vector<ProtocolEvent>();
int start, middle, end; // start/middle/end subscripts
int pduSeq; // PDU sequence number
String pduData; // PDU data
if (s.startsWith (rrq)) { // send read request?
start = s.indexOf ('(') + 1; // get filename start
end = s.indexOf (')'); // get filename finish
pduData = s.substring(start, end); // get filename
transmitPDU( // send read request
new TFTPMessage(rrq , pduData), peer);
pduNo = 1; // expect seq number 1
state = readRequest; // now requested write
}
else if (s.startsWith (ack)) { // send acknowledgement?
start = s.indexOf ('(') + 1; // get seq number start
end = s.indexOf (')'); // get seq number end
pduSeq = // get sequence number
Integer.parseInt(s.substring(start, end));
if (pduReceived != null && // valid PDU received and ...
pduReceived.sdu.equals("Dlast")) // last data?
state = waitLast; // wait for last re-send
else { // still reading
pduNo++; // to next sequence number
state = reading; // (now) reading
}
transmitPDU( // send acknowledgement
new TFTPMessage(ack, pduSeq), peer);
}
else if (s.startsWith (wrq)) { // send write request?
start = s.indexOf ('(') + 1; // get filename start
end = s.indexOf (')'); // get filename finish
pduData = s.substring(start, end); // get filename
transmitPDU( // send write request
new TFTPMessage(wrq , pduData), peer);
state = writeRequest; // now requested write
}
else if (s.startsWith (data)) { // send data?
start = s.indexOf ('(') + 1; // get seq number start
middle = s.indexOf (','); // get comma position
end = s.indexOf (')'); // get seq number end
pduSeq = // get sequence number
Integer.parseInt(s.substring(start, middle));
pduData = // get data content
s.substring(middle + 1, end);
transmitPDU( // send data
new TFTPMessage(data, pduSeq, pduData), peer);
pduNo++; // to next sequence number
state = writing; // (now) writing
}
else if (s.startsWith (error)) { // send error?
start = s.indexOf ('(') + 1; // get error message start
end = s.indexOf (')'); // get error message end
pduData = s.substring(start, end); // get error message
transmitPDU( // send error
new TFTPMessage(error, pduData), peer);
state = waitLast; // wait for last re-send
}
else if (s.startsWith ("Close")) { // close?
events.addElement( // add closed comment
new ProtocolEvent(ProtocolEvent.COMMENT, this, "Closed"));
reinitialise(); // re-initialise protocol
}
if (s.startsWith ("Timeout")) { // timeout?
transmitPDU(pduSent, peer); // re-send PDU
events.addElement( // add timeout event and PDU
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
}
else if (pduSent != null) // PDU to send?
events.addElement( // transmit PDU
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
return(events); // return list of events
}
public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
pduReceived = pdu; // store PDU
if (pduReceived.type.equals(error)) // error message?
reinitialise(); // re-initialise protocol
return((new Vector<ProtocolEvent>())); // return no events
}
public void reinitialise() { // re-initialise protocol
state = idle; // initialise state
pduNo = 0; // initialise seq number
pduReceived = null; // initialise no PDU received
pduSent = null; // initialise no PDU sent
timerEnabled = false; // initialise no timeout
fileNo++; // to next file number
}
public void setPeer(ProtocolEntity peer) { // set protocol peer
this.peer = peer; // set this entity's peer
}
/**
Set the timer for a specified PDU.
@param pdu PDU
@param enabled whether the timer is enabled
*/
public void setTimer(PDU pdu, boolean enabled) { // set timer status
if (state != idle) // not idle?
timerEnabled = enabled; // store timer status
}
public void transmitPDU( // transmit PDU
PDU pdu, ProtocolEntity dest) { // for given PDU, destination
pdu.setSource (this); // source is this entity
pdu.setDestination(dest); // destination is as given
pduSent = pdu; // copy PDU sent
medium.receivePDU(pdu); // medium receives PDU
pduReceived = null; // note no PDU in response
timerEnabled = false; // note no timeout
}
}

@ -0,0 +1,53 @@
// UDP.java (C) I. A. Robin, K. J. Turner 04/03/06
package protocol;
import java.util.*;
import support.*;
public class UDP extends Protocol {
private UDPService userA;
private UDPService userB;
private UDPProtocol protA;
private UDPProtocol protB;
public UDP() {
medium = new UDPMedium();
userA = new UDPService("User A");
userB = new UDPService("User B");
protA = new UDPProtocol(medium, "Protocol A");
protB = new UDPProtocol(medium, "Protocol B");
userA.setProvider(protA);
userB.setProvider(protB);
protA.setUser(userA);
protA.setPeer(protB);
protB.setUser(userB);
protB.setPeer(protA);
entities = new Vector<ProtocolEntity>();
entities.addElement(userA);
entities.addElement(protA);
entities.addElement(medium);
entities.addElement(protB);
entities.addElement(userB);
userA.setSourcePort(1111); // initialise A source
userA.setDestPort(2222); // initialise A destination
userB.setSourcePort(3333); // initialise B source
userB.setDestPort(4444); // initialise B destination
}
public void setParameter(String param, String value) {
try {
int port = Integer.parseInt(value);
if (param.equals("sourcePortA"))
userA.setSourcePort(port);
if (param.equals("destPortA"))
userA.setDestPort(port);
if (param.equals("sourcePortB"))
userB.setSourcePort(port);
if (param.equals("destPortB"))
userB.setDestPort(port);
}
catch (NumberFormatException e) {}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save