added lab 9
@ -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 simulator</var> will rebuild <var>ProtocolSimulator.jar</var>
|
||||
in the <var>html</var> directory. <var>ant clean</var> will remove all
|
||||
compiled class files and backup files, but preserving the JAR file.
|
||||
<var>ant 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> ('Example Protocol'). 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'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>
|
||||
|
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 `+'
|
||||
to mean that it is not the last; the very last fragment is followed by
|
||||
`-'. (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'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'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 ("Deliver octets to user"). 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
|
||||
("Send octets to peer").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Messages may contain a send sequence number (the offset of where the message
|
||||
starts in the user'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>"silly window" 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> </td>
|
||||
<td> </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> </td>
|
||||
<td> </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'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 ("Deliver octets to user"). 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
|
||||
("Send octets to peer").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Messages may contain a send sequence number (the offset of where the message
|
||||
starts in the user'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>"silly window" 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> </td>
|
||||
<td> </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> </td>
|
||||
<td> </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 "slow start". 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'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 ("Deliver
|
||||
octets to user"). 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 ("Send octets to peer").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Messages may contain a send sequence number (the offset of where the message
|
||||
starts in the user'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 "exp." 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 "lin." 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 "presume all transmissions
|
||||
over" 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>
|
||||
|
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>
|
||||
|
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 2.4 KiB |
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() + ">");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|