diff --git a/lab8_protocols/CS380_lab8-part1.docx b/lab8_protocols/CS380_lab8-part1.docx
new file mode 100644
index 0000000..3ecf272
Binary files /dev/null and b/lab8_protocols/CS380_lab8-part1.docx differ
diff --git a/lab8_protocols/CS380_lab8-part1.pdf b/lab8_protocols/CS380_lab8-part1.pdf
new file mode 100644
index 0000000..1afbabd
Binary files /dev/null and b/lab8_protocols/CS380_lab8-part1.pdf differ
diff --git a/lab8_protocols/CS380_lab8-part2.pdf b/lab8_protocols/CS380_lab8-part2.pdf
new file mode 100644
index 0000000..84a0482
Binary files /dev/null and b/lab8_protocols/CS380_lab8-part2.pdf differ
diff --git a/lab8_protocols/CS380_lab8.zip b/lab8_protocols/CS380_lab8.zip
new file mode 100644
index 0000000..175b853
Binary files /dev/null and b/lab8_protocols/CS380_lab8.zip differ
diff --git a/lab8_protocols/Lab Assignment - protocols.pdf b/lab8_protocols/Lab Assignment - protocols.pdf
new file mode 100644
index 0000000..e130672
Binary files /dev/null and b/lab8_protocols/Lab Assignment - protocols.pdf differ
diff --git a/lab8_protocols/jasper-1.7.zip b/lab8_protocols/jasper-1.7.zip
new file mode 100644
index 0000000..bd948e7
Binary files /dev/null and b/lab8_protocols/jasper-1.7.zip differ
diff --git a/lab8_protocols/jasper/README.txt b/lab8_protocols/jasper/README.txt
new file mode 100755
index 0000000..128d4d8
--- /dev/null
+++ b/lab8_protocols/jasper/README.txt
@@ -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.
+
diff --git a/lab8_protocols/jasper/build.xml b/lab8_protocols/jasper/build.xml
new file mode 100755
index 0000000..8e4185d
--- /dev/null
+++ b/lab8_protocols/jasper/build.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab8_protocols/jasper/docs/index.html b/lab8_protocols/jasper/docs/index.html
new file mode 100755
index 0000000..9c9457d
--- /dev/null
+++ b/lab8_protocols/jasper/docs/index.html
@@ -0,0 +1,534 @@
+
+
+
+
+
+
+
+
+ Jasper Protocol Simulator (Java Simulation of Protocols for Education and Research)
+
+
+
+
+
+
+
+
+
+
+ Jasper Protocol Simulator
+
+ (Java Simulation of Protocols for Education and Research)
+
+
+
+
+
+
+
Description
+
+
+ This protocol simulator provides:
+
+
+
+
+
+ the capability for interactively and graphically simulating a wide
+ variety of communications protocols
+
+
+
a framework for creating new protocol simulations
+
+
+ pre-defined simulations of various well-known protocols:
+
+
+
+
+
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, 3 and 5 column layout)
+
+
TCP (Transmission Control Protocol)
+
+
TFTP (Trivial File Transfer Protocol)
+
+
UDP (User Datagram Protocol)
+
+
+
+
+
+
+ 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.
+
+ The simulator is provided as a Zip archive. The simulator unpacks
+ to a directory called jasper-N.N according to version number. You
+ might rename this to jasper for simplicity. The distribution
+ contains:
+
+
+
+
+
build.xml
+
Ant build file to manage the code
+
+
docs
+
basic documentation
+
+
html
+
directory for protocol simulation pages and simulator JAR archive
+
+
scenarios
+
example scenario files
+
+
source
+
directories for Java code (protocol, simulator, support)
+
+
+
+
+
+
Simulation as an Applet
+
+
+ The simulator can be used on various protocols by opening
+ html/index.html in a web browser. This assumes you renamed the
+ distribution folder as jasper. 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).
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ If you make a mistake, or just want to backtrack in the simulation, then
+ click Undo. You can undo as many steps as you like, right up to the
+ beginning of the simulation. Clicking on Redo will perform again
+ the last undone step. Clear will restart the simulation with the
+ current protocol parameters. If you click on Run 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 Run button changes to Stop.
+ Click on Stop to return the simulator to user control. You can
+ continue at this point as if you had made all the automatic choices
+ yourself.
+
+
+
+ The Print, Load and Save 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.
+
+
+
+ Some simulations have associated protocol parameters. To change the defaults
+ that are shown, enter new values and click Change Values. 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.
+
+
+
+
+
+
+
+
+
+
+
+
Simulation as an Application
+
+
+ Running a protocol simulation as an application gives access to the
+ Print, Load and Save buttons.
+
+
+
+ Print 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
+ winWidth and winHeight in
+ ProtocolSimulator define the initial window size. Constant
+ maxHeight in TimeSequenceDiagram defines the
+ vertical size of printed pages. The current sizes are appropriate for A4
+ paper. If necessary, change them for (say) US letter.
+
+
+
+ Load loads a simulation scenario file (with a name ending in
+ .scn); this must be for the same protocol as you are currently
+ simulating. It replaces the current simulation scenario (if any).
+ Save saves the current simulation as a scenario file (with a
+ name ending in .scn). If you are adventurous, you can create and
+ edit your own scenarios using a text editor.
+
+
+
+ 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:
+
+ The complete source of the simulator is provided. (Most files have Unix
+ end-of-line.) The code should preferably be rebuilt using the Ant
+ build.xml build file. ant -p will print help
+ information about build targets.
+ ant simulator will rebuild ProtocolSimulator.jar
+ in the html directory. ant clean will remove all
+ compiled class files and backup files, but preserving the JAR file.
+ ant spotless will remove even this.
+
+
+
+ If you do not have Ant you will need to compile the Java source files
+ manually and create a JAR file from the result.
+
+
+
+ To modify an existing protocol simulation or to write a new one will need a
+ knowledge of the simulation framework. See the article An Interactive Visual Protocol Simulator 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.
+
+
+
+ Suppose that you want to develop a new simulation of the protocol
+ EXP ('Example Protocol'). You would need to write
+ EXP.java to instantiate the various entities in the protocol.
+ For a simple protocol, you would then write EXPSender.java and
+ EXPReceiver.java 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 Medium to match these.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+
+
Licence
+
+
+ This program is free software. You can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation - either version 3 of the License, or (at your option)
+ any later version.
+
+
+
+ This program is distributed in the hope that it will be useful but
+ without any warranty, without even the implied warranty
+ of merchantability or fitness for a particular
+ purpose. See the GNU General Public License for more details.
+
+
+
+
+
Acknowledgements
+
+
+ The protocol simulator was developed by Computing Science and Mathematics at the University of Stirling.
+ 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.
+
+
+
+
+
History
+
+
+
+
+
+ Version 1.0: Private internal version, Iain Robin, 1st September 1999
+
+
+
+
+
+ Version 1.1: Private internal version, Ken Turner, 22nd December 2000
+
+
+
+
+
+ Version 1.2: Private internal version, Ken Turner, 5th March 2001
+
+
+
+
+
+ Version 1.3: First public release, Ken Turner 6th June 2001
+
+
+
+
+
+ Version 1.4: General updating, Ken Turner, 9th March 2006:
+
+
+
+
+
+
HTML files updated to be XHTML-compliant.
+
+
+ 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.
+
+
+
+ Top-level directory structure revised to have source,
+ build and docs directories.
+
+
+
+ Makefile replaced by Ant build file. Only
+ build and clean batch files retained. (Thanks
+ to Dr. Peter J. B. King, Heriot-Watt University, for contributing to
+ this.)
+
+
+
+ Blank lines ignored in scenario files.
+
+
+
+ ABP and SWP3 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.)
+
+
+
+ SMTP protocol messages have been slightly renamed for
+ consistency with the RFC.
+
+
+
+ TCP 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.
+
+
+
+
+
+
+ Version 1.5: Extensions for new protocols, Ken Turner, 11th February
+ 2011
+
+
+
+
+
+
+ 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.
+
+
+
+ More comments, particularly JavaDoc, have been added to many files
+ (which have also been reformatted).
+
+
+
+ More thorough checks of values have been added to the JavaScript in HTML
+ files. In addition, the HTML files have been revised and reformatted.
+
+
+
+ The TimeSequenceDiagram 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 TraverseTransmission class
+ has been added.
+
+
+
+ The Medium class has been extended with two
+ isEmpty 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.
+
+
+
+ All TCP classes have been extended to support the slow-start
+ variant (TCP/ss). In addition, some problems with TCP have
+ been corrected (obscure situations in which the protocol did not recover
+ when trying to close). The TIME_WAIT state is now used to
+ cope with these situations, including more abrupt termination when FIN
+ is received in unusual situations.
+
+
+
+ A Protocol can now now implement the methods
+ getRandNumbers and setRandomNumbers (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.
+
+
+
+
+
+
+ Version 1.6: Distribution via SourceForge, Ken Turner, 18th December
+ 2014
+
+
+
+
+
+
+ The simulator has been packaged and made available via SourceForge.
+
+
+
+
+
+
+ Version 1.7: Update for Java 7u51 onwards, Ken Turner, 28th September
+ 2015
+
+
+
+
+
+
+ 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.
+
+
+
+ The pre-built simulator JAR has been signed with a later University of
+ Stirling certificate valid up to August 2018.
+
+ 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 Sliding Window
+ Protocol with a window size of 1. The message sequence numbers simply
+ alternate between 0 and 1.
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This will cause the simulation to restart.
+
+
+
+ Optionally set the level of control that the simulator user needs over
+ the medium:
+
+
+
+
+
Automatic:
+
+ 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.
+
+
+
Delivery:
+
+ 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.
+
+
+
Delivery/Loss:
+
+ Finally, delivery and loss of messages may be completely controlled.
+ This is the most comprehensive option, but also the most complex one to
+ manage.
+
+
+
+
+
+
+
Protocol Simulation
+
+
+ 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 DATA(0)
+ or DATA(1); the content of messages is not identified. These are
+ acknowledged with ACK(1) or ACK(0) respectively. Note
+ that if a DATA message is received again due to re-transmission,
+ it is acknowledged but discarded.
+
+ Abracadabra (Alternating Bit Protocol with Connection and Disconnection)
+ is a connection-oriented protocol that allows data to be sent in either
+ direction using the Alternating Bit Protocol. Data
+ transfer is preceded by connection and followed by disconnection.
+
+
+
+ The initiating user requests a connection with ConReq. This is
+ sent as a CR protocol message. The other user receives
+ ConInd as an indication that a connection attempt has been
+ received. Normally it will respond positively to the connection attempt
+ with ConResp. This leads to a CC confirmation in the
+ protocol, and a ConConf confirmation back to the initiating
+ user. However the responding user may also reject a connection attempt
+ with a DisReq disconnection request. This leads to a DR
+ in the protocol and DisInd at the originator. If CR
+ connection messages are sent by both protocol entities simultaneously,
+ each acknowledges the other and the connection is set up.
+
+
+
+ Once a connection has been made, either user sends data messages as
+ DatReq(DATA0) or DatReq(DATA1); the content of messages
+ is not explicitly identified. These requests lead to delivery at the
+ other user with DatInd(DATA0) or DatInd(DATA1). The
+ protocol carries data as DT(0) or DT(1) messages that
+ give only the sequence number, not the data. These are acknowledged with
+ AK(1) or AK(0) respectively. Note that if a DT
+ message is received again due to re-transmission, it is acknowledged but
+ discarded. Both users may be sending data at the same time.
+
+
+
+ Disconnection is requested with DisReq. This causes a
+ DR message to be sent in the protocol, indicating disconnection
+ at the other user with DisInd. The remote protocol entity
+ confirms disconnection with DC. If DR disconnection
+ messages are sent by both protocol entities simultaneously, each sends
+ back a DC as confirmation. Since both users tried to disconnect
+ at the same time, each has issued DisReq and does not see
+ DisInd.
+
+
+
Protocol Parameters
+
+
+ This simulation has no parameters.
+
+
+
Protocol Simulation
+
+
+ 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.
+
+ 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 UDP (User Datagram Protocol). BOOTP simply discovers
+ the parameters needed for the bootstrap procedure. Typically, TFTP (Trivial File Transfer Protocol) is used to
+ download the bootstrap file itself.
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ This simulation has no parameters.
+
+
+
Protocol Simulation
+
+
+ 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 REQUEST message containing an
+ (arbitrary) transaction identifier and its hardware address
+ (hw). The client may optionally supply its network address if it
+ knows it (e.g. net.43 for some subnetwork net). The
+ client may additionally ask for the location of a particular bootstrap
+ file (boot). 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 REQUEST or REPLY message
+ is lost, the client must time out and send it again.
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ Transmission proceeds in one of the following ways:
+
+
+
+
+
Normal:
+
+ 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.
+
+
+
+
Deferral:
+
+
+ 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.
+
+
+
+
Collision:
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ 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.
+
+
+
+
+
Protocol Simulation
+
+
+ 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 DATA(Dn). Data
+ messages are numbered D0, D1, etc.; no explicit data
+ content is given. If the retry limit is reached, this is reported to a
+ station with the message FAIL(Retry Limit). Protocol messages
+ have the form START(Dn) to start a transmission,
+ FINISH(Dn) to finish the transmission, and JAM to jam
+ transmission.
+
+ HTTP (Hypertext Transfer Protocol) is familiar as the mechanism for
+ delivering web pages. HTTP operates over TCP
+ (Transmission Control Protocol) in client-server mode for reliable
+ transfer of data. URLs (Uniform Resource Locators) and information
+ contents are represented symbolically in the simulation (URLn,
+ DATAn). The protocol simulation deals with the main commands:
+
+
+
+
GET: get data for URL
+
+
HEAD: get header for URL
+
+
POST: append data to URL
+
+
xPUT: send data to URL
+
+
+
+
+ The simulation supports a limited range of response codes:
+
+
+
+
+
200 OK: the command completed successfully
+
+
301 MOVED: the requested URL has moved to another location
+
+
+ 400 ERROR: the command encountered an error (not explicit in
+ the simulation)
+
+
+
+
+
+ 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).
+
+ IP (Internet Protocol) a simple connection-less protocol for transferring
+ datagrams in either direction between a pair of hosts.
+
+
+
+ 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
+ DatReq(DATAn), and receive data transmissions
+ as DatInd(DATAn). Protocol messages are sent as
+ DT(MID,Offset,Length) that gives the message identifier
+ n, 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 More Fragments flag in the
+ protocol.)
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings.
+
+ 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.
+
+
+
+
+
+
+
+
+
+ There are three strategies for sending data from the source to the
+ destinations:
+
+
+
+
+
Broadcast:
+
+
+ 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.
+
+
+
+
Unicast:
+
+
+ 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.
+
+
+
+
Multicast:
+
+
+ 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.
+
+
+
+
+
+
+ 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).
+
+
+
Protocol Parameters
+
+
+ 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.
+
+
+
+
+
Protocol Simulation
+
+
+ The protocol simulation shows a time-sequence diagram with the source and
+ the six routers. Messages have the format
+ DT(Destinations,Mn). For broadcast and unicast, each
+ message has one destination; for multicast, there can be multiple
+ destinations. Messages are numbered M0, M1, etc.; no
+ explicit data
+ content is given.
+
+ 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.
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+ The multiplexer and demultiplexer exchange messages in a format that depends
+ on the kind of multiplexing:
+
+
+
+
+
+
+ For synchronous multiplexing, the multiplexer periodically sends all
+ available data in a format such as DT(D8,D4,...); this means
+ that source 0 is sending data D8, source
+ 1 is sending data D4, etc. If a source has not
+ supplied data before the multiplexer has sent a message, this is shown
+ as '-' (e.g. DT(-,D4) for data from source 1
+ only).
+
+
+
+
+
+ For asynchronous multiplexing, the multiplexer sends individual source
+ data as it arrives in a format such as DT(2,D6); this means
+ that source 2 is sending data D6.
+
+
+
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ 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.
+
+
+
+
+
Protocol Simulation
+
+
+ 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
+ DATA(Source,Dn); the same messages arrive at sinks.
+ Sources/sinks are numbered 0, 1, etc. Data
+ messages are numbered D0, D1, etc.; no explicit data
+ content is given. The source/sink number and data number are usually
+ different (e.g. source 1 might sent data D7).
+
+
+
+
+
+
diff --git a/lab8_protocols/jasper/html/ProtocolSimulator.jar b/lab8_protocols/jasper/html/ProtocolSimulator.jar
new file mode 100755
index 0000000..5297141
Binary files /dev/null and b/lab8_protocols/jasper/html/ProtocolSimulator.jar differ
diff --git a/lab8_protocols/jasper/html/SMTP.html b/lab8_protocols/jasper/html/SMTP.html
new file mode 100755
index 0000000..c43cbbc
--- /dev/null
+++ b/lab8_protocols/jasper/html/SMTP.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+ Simple Mail Transfer Protocol
+
+
+
+
+
+
+
+
+
+
Simple Mail Transfer Protocol Simulator
+
+
+
+
+
+
Protocol Description
+
+
+ SMTP (Simple Mail Transfer Protocol) is used to transfer email messages.
+ SMTP operates over TCP (Transmission Control
+ Protocol) in client-server mode for reliable transfer of data. The
+ protocol simulation deals with the main commands (sent in approximately
+ the order below):
+
+
+
+
+
HELO: names the client (the spelling is deliberate)
+
+
MAIL FROM: names the sender
+
+
RCPT TO: names a recipient
+
+
DATA: asks to send message data
+
+
cMail Message: sends the message datac
+
+
cQUIT: finishes the mail sessionc
+
+
+
+
+ The simulation supports a limited range of response codes:
+
+
+
+
+
+ 220 Server ready: a connection to the server has been made and
+ the server is ready
+
+
+
+ 221 Server closing: the server accepted the QUIT
+ command and is ready to close the connection
+
+
+
+ 250 OK: the server accepted the command (one of several
+ similar responses)
+
+
+
+ 354 Send mail: the server accepted the DATA command
+ and is waiting for the Mail Message
+
+
+
+ 550 Invalid: the server rejected the command (one of several
+ similar responses)
+
+
+
+
+
+ After the client connects to the server using TCP, the server reports its
+ readiness with a 220 Server ready response. The client names
+ itself in HELO, to which the server normally gives a 250
+ Server hello to client response. To send mail, the client issues
+ MAIL FROM and normally gets a 250 Sender OK response.
+ Recipients are named in RCPT TO, normally obtaining 250
+ Recipient OK responses. However the server can reject a sender or
+ recipient with a 550 Sender invalid or 550 Recipient
+ invalid response. Once all parties have been named, the client sends
+ DATA to begin message transmission; a 354 Send mail
+ 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 Mail Message command stands for this. The
+ server will normally give a 250 Message accepted response and
+ further messages can be sent. Finally, the client sends QUIT and
+ the server responds with a 221 Server closing code. At this
+ point the TCP connection is broken.
+
+ 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.
+
+
+
+ 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..
+
+
+
+ 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.
+
+
+
+ The elements of a message are simply numbered 0, 1,
+ etc. withou explicit data content. An Application sends a message with data
+ such as A3. This is then prefixed with a Transport header
+ T3, a Network header N3, a Link header and trailer
+ L3, and a Physical header P3. When sent over the
+ medium, the whole message then looks like P3:L3:N3:T3:A3:L3. On
+ reception, the headers (and Link trailer) are stripped off so that the
+ receiving Application gets A3 as sent.
+
+
+
Protocol Parameters
+
+
+ This simulation has no parameters.
+
+
+
Protocol Simulation
+
+
+ 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).
+
+ 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 Alternating Bit
+ Protocol. The simulation below does not include the users; see the five-column version for this.
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This may cause the simulation to restart.
+
+
+
+ Optionally set the level of control that the simulator user needs over
+ the medium:
+
+
+
+
+
Automatic:
+
+ 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.
+
+
+
Delivery:
+
+ 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.
+
+
+
Delivery/Loss:
+
+ Finally, delivery and loss of messages may be completely controlled.
+ This is the most comprehensive option, but also the most complex one to
+ manage.
+
+
+
+
+
+ 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.
+
+
+
+
+
Protocol Simulation
+
+
+ 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 DT(0),
+ DT(1), 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 AK(n) means that the DT
+ message numbered n 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 DT message is received
+ again due to re-transmission, it is acknowledged but discarded.
+
+ 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 Alternating Bit Protocol. The simulation below includes
+ the users; the three-column version omits them.
+
+
+
+ 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.
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This may cause the simulation to restart.
+
+
+
+
+
Protocol Simulation
+
+
+ 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
+ DatReq(DATAn), and receive data transmissions as
+ DatInd(DATAn). Data messages are simply numbered DATA0,
+ DATA1, etc. without explicit content. The transmitting protocol
+ sends the protocol message DT(n) 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 AK(n) means
+ that the DT message numbered n 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
+ DT message is received again due to re-transmission, it is
+ acknowledged but discarded.
+
+ Transmission Control Protocol Simulator
+
+ (Client-Server)
+
+
+
+
+
+
+
Protocol Description
+
+
+ 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 peer-peer version as an alternative to this
+ client-server simulation. The slow start simulation
+ deals with only congestion avoidance.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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").
+
+
+
+ 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).
+
+
+
+ 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.
+
+
+
+ Things the simulation does not cover include the following. See advanced
+ guides to TCP for more information.
+
+
+
+
+
losing an ACK that opens up the window
+
+
"silly window" syndrome
+
+
adaptive retransmission strategies
+
+
congestion avoidance strategies
+
+
dynamic window management
+
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This may cause the simulation to restart.
+
+
+
+
+
Protocol Simulation
+
+
+ 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.
+
+ Transmission Control Protocol Simulator
+
+ (Peer-Peer)
+
+
+
+
+
+
+
Protocol Description
+
+
+ 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 client-server version as an alternative to this
+ peer-peer simulation. The slow start simulation
+ deals with only congestion avoidance.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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").
+
+
+
+ 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).
+
+
+
+ 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.
+
+
+
+ Things the simulation does not cover include the following. See advanced
+ guides to TCP for more information.
+
+
+
+
+
losing an ACK that opens up the window
+
+
"silly window" syndrome
+
+
adaptive retransmission strategies
+
+
congestion avoidance strategies
+
+
dynamic window management
+
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This may cause the simulation to restart.
+
+
+
+
+
Protocol Simulation
+
+
+ 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.
+
+ Transmission Control Protocol Simulator
+
+ (Slow Start)
+
+
+
+
+
+
+
Protocol Description
+
+
+ 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 client-server and peer-peer
+ simulations as alternatives that illustrate opening and closing connections.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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").
+
+
+
+ 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).
+
+
+
+ Slow start is governed by two protocol variables: cwind
+ (congestion window) and ssthresh (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:
+
+
+
+
+
Initial Phase
+
+ The minimum of the congestion window size and the receiver window size
+ determines how much data can be sent. The protocol starts conservatively
+ with cwind set to the segment size. As each acknowledgement
+ arrives, cwind 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
+ cwind is increased).
+
+
+
Congestion Action
+
+ 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
+ ssthresh is set to half the previous value of
+ cwind. Suppose that the segment size is 200, so that
+ cwind starts at 200. On subsequent acknowledgements,
+ cwind could rise to 1600. If congestion causes loss at this
+ point, cwind will be set back to 200 and ssthresh
+ will be set to 800 (half of 1600).
+
+
+
Congestion Recovery
+
+ Now the window is built up exponentially again. Once it reaches
+ ssthresh, it is no longer increased so aggressively. Instead,
+ cwind 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.
+
+
+
+
+
+ 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 cwind is below or above the threshold.
+
+
+
+ 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.
+
+
+
+ Things the simulation does not cover include the following. See advanced
+ guides to TCP for more information.
+
+
+
+
+
advanced congestion control
+
+
handling duplicate acknowledgements
+
+
fast retransmit
+
+
fast recovery
+
+
+
+
Protocol Parameters
+
+
+ The following settings are adequate for a simple simulation. For a more
+ advanced exploration, choose different options and click Change
+ Settings. This may cause the simulation to restart.
+
+
+
+
+
+
+
Protocol Simulation
+
+
+ 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.
+
+ 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 UDP (User Datagram
+ Protocol) and often in conjunction with BOOTP
+ (Boot Protocol).
+
+
+
+ A client may initially issue:
+
+
+
+
+
+ RRQ: read request, to retrieve a named file from the server
+
+
+
WRQ: write request, to send a named file to the server
+
+
+
+
+ During data transfer, the client or server as appropriate sends:
+
+
+
+
+
+ DATA: with data content numbered Dn, the last data
+ being labelled Dlast
+
+
+
+ ACK: an acknowledgement with the same number as the
+ DATA being acknowledged
+
+
+
ERROR: to send an error message due to a serious problem
+
+
+
+
+ DATA blocks are numbered from 1 onwards with just a name
+ Dn for their data contents. Normally an ACK quotes this
+ number, but in the case of WRQ an acknowledgement with number 0
+ is sent. All DATA blocks except the last one are full. The final
+ block is less than the normal size, shown with contents Dlast.
+
+
+
+ The protocol is unusual in that both sender and receiver may time out. If
+ one party does not receive a fresh DATA block after sending an
+ ACK, it may retransmit the ACK in case it was lost. A
+ complication is that the ACK for the last DATA 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 ACK it needs.
+
+
+
+ After completing transfer of a file, the client may start a new transfer.
+ ERROR 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).
+
+
+
Protocol Parameters
+
+
+ This simulation has no parameters.
+
+
+
Protocol Simulation
+
+
+ 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 RRQ or WRQ from the client. Several
+ files may be transferred consecutively.
+
+ 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).
+
+
+
Protocol Parameters
+
+
+
+
Protocol Simulation
+
+
+ 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
+ DatReq(Src,Dst,Dn) and receive data transmissions as
+ DatInd(Src, Dst,Dn). Data messages are simply numbered D0,
+ D1, etc. in sequence for each user; no explicit data content is
+ given. Each user request leads to the protocol message
+ DT(Src,Dst,Dn) that gives the source port, destination port and
+ data message number.
+
+ The following protocol simulations were developed mainly by Iain Robin and
+ Ken Turner,
+ 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.
+
+
+
+ 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).
+
+
+
+ The simulations are listed in increasing order of complexity. It is
+ suggested that you try the easier protocols first.
+
+ 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.
+
+
+
+ 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 Undo. You can
+ undo as many steps as you like, right up to the beginning of the simulation.
+ Clicking on Redo will perform the last undone step again.
+ Clear will restart the simulation with the current protocol
+ parameters. If you click on Run 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 Run button changes to
+ Stop. Click on Stop to return the simulator to user
+ control. You can continue at this point as if you had made all the automatic
+ choices yourself.
+
+
+
+ The Print, Load and Save 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.
+ Print produces a hard copy of the current simulation scenario.
+ Load loads a scenario file (with a name ending in
+ .scn). This must be for the same protocol as you are currently
+ simulating. It replaces the current simulation scenario (if any).
+ Save saves the current simulation scenario as a scenario file
+ (with a name ending in .scn). If you are adventurous, you can
+ create and edit your own scenarios using a standard text editor.
+
+
+
Protocol Descriptions
+
+
+ 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.
+
+
+
+ Some simulations have associated protocol parameters. To change the defaults
+ that are shown, enter new values and click Change Values. In some
+ cases, this will force the simulation to restart.
+
+ The following protocol simulations were developed mainly by Iain Robin and
+ Ken Turner,
+ 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.
+
+
+
+ The simulations are listed in increasing order of complexity. It is
+ suggested that you try the easier protocols first.
+
+ 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.
+
+
+
+ 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 Undo. You can
+ undo as many steps as you like, right up to the beginning of the simulation.
+ Clicking on Redo will perform the last undone step again.
+ Clear will restart the simulation with the current protocol
+ parameters. If you click on Run 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 Run button changes to
+ Stop. Click on Stop to return the simulator to user
+ control. You can continue at this point as if you had made all the automatic
+ choices yourself.
+
+
+
+ The Print, Load and Save 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.
+ Print produces a hard copy of the current simulation scenario.
+ Load loads a scenario file (with a name ending in
+ .scn). This must be for the same protocol as you are currently
+ simulating. It replaces the current simulation scenario (if any).
+ Save saves the current simulation scenario as a scenario file
+ (with a name ending in .scn). If you are adventurous, you can
+ create and edit your own scenarios using a standard text editor.
+
+
+
Protocol Descriptions
+
+
+ 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.
+
+
+
+ Some simulations have associated protocol parameters. To change the defaults
+ that are shown, enter new values and click Change Values. In some
+ cases, this will force the simulation to restart.
+
+
+
+
+
+
diff --git a/lab8_protocols/jasper/html/multicast.gif b/lab8_protocols/jasper/html/multicast.gif
new file mode 100755
index 0000000..ad8ebee
Binary files /dev/null and b/lab8_protocols/jasper/html/multicast.gif differ
diff --git a/lab8_protocols/jasper/html/multiplexer.gif b/lab8_protocols/jasper/html/multiplexer.gif
new file mode 100755
index 0000000..e4b12b0
Binary files /dev/null and b/lab8_protocols/jasper/html/multiplexer.gif differ
diff --git a/lab8_protocols/jasper/html/simulator.gif b/lab8_protocols/jasper/html/simulator.gif
new file mode 100755
index 0000000..fdde6db
Binary files /dev/null and b/lab8_protocols/jasper/html/simulator.gif differ
diff --git a/lab8_protocols/jasper/html/simulator.jpeg b/lab8_protocols/jasper/html/simulator.jpeg
new file mode 100755
index 0000000..3475f2a
Binary files /dev/null and b/lab8_protocols/jasper/html/simulator.jpeg differ
diff --git a/lab8_protocols/jasper/html/uparrow.gif b/lab8_protocols/jasper/html/uparrow.gif
new file mode 100755
index 0000000..c7587da
Binary files /dev/null and b/lab8_protocols/jasper/html/uparrow.gif differ
diff --git a/lab8_protocols/jasper/scenarios/TCPss.scn b/lab8_protocols/jasper/scenarios/TCPss.scn
new file mode 100755
index 0000000..1bb1c05
--- /dev/null
+++ b/lab8_protocols/jasper/scenarios/TCPss.scn
@@ -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
diff --git a/lab8_protocols/jasper/source/protocol/ABP.java b/lab8_protocols/jasper/source/protocol/ABP.java
new file mode 100755
index 0000000..6257ad9
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABP.java
@@ -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();
+ entities.addElement(sender);
+ entities.addElement(medium);
+ entities.addElement(receiver);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/ABPReceiver.java b/lab8_protocols/jasper/source/protocol/ABPReceiver.java
new file mode 100755
index 0000000..5288159
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABPReceiver.java
@@ -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 entityEvents; // events from entity
+
+ public ABPReceiver(Medium m, String name) {
+ this.name = name;
+ medium = m;
+ initialise();
+ }
+
+ public String getName() {
+ return(name);
+ }
+
+ public Vector getServices() {
+ Vector list = new Vector();
+ 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(); // empty entity events
+ }
+
+ public Vector performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/ABPSender.java b/lab8_protocols/jasper/source/protocol/ABPSender.java
new file mode 100755
index 0000000..ba40903
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABPSender.java
@@ -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
+ 1.4 (9th March 2006, KJT): updated for JDK 1.5
+ 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 entityEvents; // events from entity
+
+ public ABPSender(Medium m, String name) {
+ this.name = name;
+ medium = m;
+ initialise();
+ }
+
+ public String getName() {
+ return(name);
+ }
+
+ public Vector getServices() {
+ Vector list = new Vector();
+ 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(); // empty medium events
+ }
+
+ public Vector performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/ABRA.java b/lab8_protocols/jasper/source/protocol/ABRA.java
new file mode 100755
index 0000000..b96df54
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABRA.java
@@ -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();
+ entities.addElement(abraServA);
+ entities.addElement(abraProtA);
+ entities.addElement(medium);
+ entities.addElement(abraProtB);
+ entities.addElement(abraServB);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/ABRAProtocol.java b/lab8_protocols/jasper/source/protocol/ABRAProtocol.java
new file mode 100755
index 0000000..fc34cd0
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABRAProtocol.java
@@ -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
+ 1.4 (9th March 2006, KJT): updated for JDK 1.5
+ 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 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 getServices() {
+ Vector list = new Vector();
+ 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();
+ state = CLOSED;
+ }
+
+ public boolean hasTimer(String type) {
+ return(type.equals("DT") || type.equals("DR") || type.equals("CR"));
+ }
+
+ public Vector performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ Vector events = new Vector();
+ 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());
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/ABRAService.java b/lab8_protocols/jasper/source/protocol/ABRAService.java
new file mode 100755
index 0000000..90e1a6c
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/ABRAService.java
@@ -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 getServices() {
+ Vector list = new Vector();
+ 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 performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ Vector events = new Vector();
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/BOOTP.java b/lab8_protocols/jasper/source/protocol/BOOTP.java
new file mode 100755
index 0000000..b1924c7
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/BOOTP.java
@@ -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(); // initialise protocol entities
+ entities.addElement(sender); // add sender protocol entity
+ entities.addElement(medium); // add comms medium entity
+ entities.addElement(receiver); // add receive protocol entity
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/BOOTPMedium.java b/lab8_protocols/jasper/source/protocol/BOOTPMedium.java
new file mode 100755
index 0000000..347e348
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/BOOTPMedium.java
@@ -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
+ 1.4 (9th March 2006, KJT): updated for JDK 1.5
+ 1.5 (24th July 2010, KJT): minor tidying
+*/
+public class BOOTPMedium extends Medium { // protocol medium
+
+ // protocol variables
+
+ private static Vector randoms; // random number list
+ private static int randomIndex; // random number index
+
+ public BOOTPMedium() { // construct medium instance
+ super(); // construct as generic medium
+ randoms = new Vector(); // 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
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/BOOTPReceiver.java b/lab8_protocols/jasper/source/protocol/BOOTPReceiver.java
new file mode 100755
index 0000000..b3b11a9
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/BOOTPReceiver.java
@@ -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 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(); // empty medium events
+ }
+
+ public Vector getServices() {
+ Vector events = // initialise events list
+ new Vector();
+ 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 performService(String s) {
+ Vector events = // initialise events list
+ new Vector();
+ 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 receivePDU(PDU pdu) { // handle received PDU
+ pduReceived = pdu; // store PDU
+ return((new Vector())); // 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
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/BOOTPSender.java b/lab8_protocols/jasper/source/protocol/BOOTPSender.java
new file mode 100755
index 0000000..1700bff
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/BOOTPSender.java
@@ -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
+ 1.4 (9th March 2006, KJT): updated for JDK 1.5
+ 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 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(); // 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 getServices() {
+ Vector events = // list of events
+ new Vector();
+ 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 performService(String s) {
+ Vector events = // initialise events list
+ new Vector();
+ 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 receivePDU(PDU pdu) { // handle received PDU
+ pduReceived = pdu; // store PDU
+ return(new Vector()); // 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
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/CSMA.java b/lab8_protocols/jasper/source/protocol/CSMA.java
new file mode 100755
index 0000000..4e9522f
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMA.java
@@ -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 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(); // 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(); // 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 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 randoms) {
+ randomNumbers = randoms; // store the random numbers
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/CSMAMedium.java b/lab8_protocols/jasper/source/protocol/CSMAMedium.java
new file mode 100755
index 0000000..d8d0b29
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMAMedium.java
@@ -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 getServices() {
+ Vector list = new Vector(); // 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 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
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/CSMAPdu.java b/lab8_protocols/jasper/source/protocol/CSMAPdu.java
new file mode 100755
index 0000000..b289370
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMAPdu.java
@@ -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 + ")");
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/CSMAProtocol.java b/lab8_protocols/jasper/source/protocol/CSMAProtocol.java
new file mode 100755
index 0000000..ca435c2
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMAProtocol.java
@@ -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 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 getServices() {
+ // System.err.println("CSMAProtocol.getServices - " + protocolName +
+ // ": protocolState <" + protocolState + "> protocolOut <" + protocolOut +
+ // "> protocolSending <" + protocolSending + ">");
+ String peerName = protocolPeer.getName(); // get peer name
+ Vector list = new Vector(); // 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();// 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 performService(String service) {
+ protocolEvents = new Vector(); // 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 receivePDU(PDU pdu) {
+ protocolEvents = new Vector(); // 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 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));
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/CSMASdu.java b/lab8_protocols/jasper/source/protocol/CSMASdu.java
new file mode 100755
index 0000000..c84dd2b
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMASdu.java
@@ -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 ");
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/CSMAService.java b/lab8_protocols/jasper/source/protocol/CSMAService.java
new file mode 100755
index 0000000..7bf06eb
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/CSMAService.java
@@ -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 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 getServices() {
+ Vector list = new Vector(); // 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();// initialise service events
+ }
+
+ /**
+ Perform service.
+
+ @param service service request
+ @return resulting service events
+ */
+ public Vector performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 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
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/HTTP.java b/lab8_protocols/jasper/source/protocol/HTTP.java
new file mode 100755
index 0000000..51c7135
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/HTTP.java
@@ -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
+ 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();
+ entities.addElement(sender);
+ entities.addElement(medium);
+ entities.addElement(receiver);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/HTTPReceiver.java b/lab8_protocols/jasper/source/protocol/HTTPReceiver.java
new file mode 100755
index 0000000..745b5e0
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/HTTPReceiver.java
@@ -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
+ 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 getServices() {
+ int url, moved; // given/moved URL number
+ Vector list = new Vector();
+ 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 performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/HTTPSender.java b/lab8_protocols/jasper/source/protocol/HTTPSender.java
new file mode 100755
index 0000000..d9302a5
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/HTTPSender.java
@@ -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
+ 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 getServices() {
+ Vector list = new Vector();
+ 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 performService (String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/IP.java b/lab8_protocols/jasper/source/protocol/IP.java
new file mode 100755
index 0000000..1245f9e
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/IP.java
@@ -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();
+ 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);
+ }
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/IPMedium.java b/lab8_protocols/jasper/source/protocol/IPMedium.java
new file mode 100755
index 0000000..a989855
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/IPMedium.java
@@ -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
+ 1.4 (9th March 2006, KJT): updated for JDK 1.5
+ 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 randomNumbers; // random numbers
+ private int randomIndex; // random number index
+
+ public IPMedium() {
+ super(); // construct superclass
+ randomNumbers = new Vector(); // 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 v) {
+ Vector t = new Vector(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 getServices() {
+ Vector list = new Vector();
+ 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 performService(String s) {
+ Vector events = new Vector();
+ 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
+ }
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/IPMessage.java b/lab8_protocols/jasper/source/protocol/IPMessage.java
new file mode 100755
index 0000000..fd421a0
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/IPMessage.java
@@ -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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/IPProtocol.java b/lab8_protocols/jasper/source/protocol/IPProtocol.java
new file mode 100755
index 0000000..460432b
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/IPProtocol.java
@@ -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 expiredMIDs; // expired message IDs
+ private Vector 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();
+ userEvents = new Vector();
+ recvFragments = new Vector();
+ }
+
+ 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 receivePDU(PDU pdu) {
+ Vector events = new Vector();
+ 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 getServices() {
+ Vector services = new Vector();
+ int oldestMID = oldestMessageID();
+ if (oldestMID >= 0)
+ services.addElement(TTL_EXPIRY + oldestMID);
+ return(services);
+ }
+
+ public Vector performService(String s) {
+ Vector events = new Vector();
+ 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);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/IPService.java b/lab8_protocols/jasper/source/protocol/IPService.java
new file mode 100755
index 0000000..8bd0818
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/IPService.java
@@ -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 receivePDU(PDU pdu) {
+ return(new Vector());
+ }
+
+ public void transmitPDU(PDU pdu, ProtocolEntity dest) {
+ pdu.setSource(this);
+ pdu.setDestination(dest);
+ providerEvents = dest.receivePDU(pdu);
+ }
+
+ public Vector getServices() {
+ Vector list = new Vector();
+ list.addElement("Send " + DAT_REQ + "(D" + block + ")");
+ return(list);
+ }
+
+ public Vector performService(String s) {
+ Vector events = new Vector();
+ 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);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/MCAST.java b/lab8_protocols/jasper/source/protocol/MCAST.java
new file mode 100755
index 0000000..88b3737
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MCAST.java
@@ -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 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();
+ 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 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 + "'");
+ }
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MCASTRouter.java b/lab8_protocols/jasper/source/protocol/MCASTRouter.java
new file mode 100755
index 0000000..8f720d6
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MCASTRouter.java
@@ -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 serviceEvents;
+
+ /** Service data unit output */
+ private Vector 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 getSDUs() {
+ return(sdus); // return service data units
+ }
+
+ /**
+ Return services currently offered.
+
+ @return list of services
+ */
+ public Vector getServices() {
+ Vector list = new Vector(); // 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();// initialise service events
+ sdus = new Vector(); // 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 performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 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));
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MCASTSdu.java b/lab8_protocols/jasper/source/protocol/MCASTSdu.java
new file mode 100755
index 0000000..09fdc12
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MCASTSdu.java
@@ -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 ");
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MCASTSource.java b/lab8_protocols/jasper/source/protocol/MCASTSource.java
new file mode 100755
index 0000000..02a5598
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MCASTSource.java
@@ -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 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 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 getServices() {
+ Vector list = new Vector(); // 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();// initialise service events
+ }
+
+ /**
+ Perform service.
+
+ @param service service request
+ @return resulting service events
+ */
+ public Vector performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 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));
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUX.java b/lab8_protocols/jasper/source/protocol/MUX.java
new file mode 100755
index 0000000..f676b61
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUX.java
@@ -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(); // 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");
+ }
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUXMedium.java b/lab8_protocols/jasper/source/protocol/MUXMedium.java
new file mode 100755
index 0000000..079bc68
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUXMedium.java
@@ -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);
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUXPdu.java b/lab8_protocols/jasper/source/protocol/MUXPdu.java
new file mode 100755
index 0000000..049af6e
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUXPdu.java
@@ -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 >");
+ }
+
+ /**
+ 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
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUXProtocol.java b/lab8_protocols/jasper/source/protocol/MUXProtocol.java
new file mode 100755
index 0000000..96ea7fe
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUXProtocol.java
@@ -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 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 getServices() {
+ Vector list = new Vector(); // 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();// 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 performService(String service) {
+ protocolEvents = new Vector(); // 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 receivePDU(PDU pdu) {
+ protocolEvents = new Vector(); // 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 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));
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUXSdu.java b/lab8_protocols/jasper/source/protocol/MUXSdu.java
new file mode 100755
index 0000000..4dda674
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUXSdu.java
@@ -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 ");
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/MUXService.java b/lab8_protocols/jasper/source/protocol/MUXService.java
new file mode 100755
index 0000000..a70d84d
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/MUXService.java
@@ -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 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 getServices() {
+ Vector list = new Vector(); // 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();// initialise service events
+ }
+
+ /**
+ Perform service.
+
+ @param service service request
+ @return resulting service events
+ */
+ public Vector performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 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
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/SMTP.java b/lab8_protocols/jasper/source/protocol/SMTP.java
new file mode 100755
index 0000000..e53633c
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/SMTP.java
@@ -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();
+ entities.addElement(client);
+ entities.addElement(medium);
+ entities.addElement(server);
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/SMTPReceiver.java b/lab8_protocols/jasper/source/protocol/SMTPReceiver.java
new file mode 100755
index 0000000..e3fc72d
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/SMTPReceiver.java
@@ -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 getServices() {
+ Vector list = new Vector();
+ 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 performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/SMTPSender.java b/lab8_protocols/jasper/source/protocol/SMTPSender.java
new file mode 100755
index 0000000..4dbff25
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/SMTPSender.java
@@ -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 getServices() {
+ Vector list = new Vector();
+ 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 performService(String s) {
+ Vector events = new Vector();
+ 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 receivePDU(PDU pdu) {
+ pduReceived = pdu;
+ return(new Vector());
+ }
+
+ 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;
+ }
+
+}
diff --git a/lab8_protocols/jasper/source/protocol/STACK.java b/lab8_protocols/jasper/source/protocol/STACK.java
new file mode 100755
index 0000000..101b350
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACK.java
@@ -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(); // 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
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/STACKApplication.java b/lab8_protocols/jasper/source/protocol/STACKApplication.java
new file mode 100755
index 0000000..00282e0
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACKApplication.java
@@ -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 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();// initialise service events
+ serviceIn = null; // initialise SDU input
+ serviceOut = null; // initialise SDU output
+ }
+
+ /**
+ Return services currently offered.
+
+ @return list of services
+ */
+ public Vector getServices() {
+ Vector list = new Vector(); // 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 performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 receiveEvents = // receive SDU at destination
+ destination.receivePDU(sdu);
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/STACKDataLink.java b/lab8_protocols/jasper/source/protocol/STACKDataLink.java
new file mode 100755
index 0000000..e6f1356
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACKDataLink.java
@@ -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 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();// initialise service events
+ serviceIn = null; // initialise SDU input
+ serviceOut = null; // initialise SDU output
+ }
+
+ /**
+ Return services currently offered.
+
+ @return list of services
+ */
+ public Vector getServices() {
+ Vector list = new Vector(); // 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 performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 receiveEvents = // receive SDU at destination
+ destination.receivePDU(sdu);
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/STACKMedium.java b/lab8_protocols/jasper/source/protocol/STACKMedium.java
new file mode 100755
index 0000000..56ec8e0
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACKMedium.java
@@ -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 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 getServices() {
+ Vector list = new Vector(); // 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();// 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 performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceIn = sdu; // store SDU from service
+ serviceEvents = new Vector();// 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 receiveEvents = // receive SDU at destination
+ destination.receivePDU(sdu);
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/STACKNetwork.java b/lab8_protocols/jasper/source/protocol/STACKNetwork.java
new file mode 100755
index 0000000..89c06a2
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACKNetwork.java
@@ -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 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();// initialise service events
+ serviceIn = null; // initialise SDU input
+ serviceOut = null; // initialise SDU output
+ }
+
+ /**
+ Return services currently offered.
+
+ @return list of services
+ */
+ public Vector getServices() {
+ Vector list = new Vector(); // 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 performService(String service) {
+ serviceEvents = new Vector();// 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 receivePDU(PDU sdu) {
+ serviceEvents = new Vector();// 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 receiveEvents = // receive SDU at destination
+ destination.receivePDU(sdu);
+ }
+
+}
+
diff --git a/lab8_protocols/jasper/source/protocol/STACKPhysical.java b/lab8_protocols/jasper/source/protocol/STACKPhysical.java
new file mode 100755
index 0000000..fcc7975
--- /dev/null
+++ b/lab8_protocols/jasper/source/protocol/STACKPhysical.java
@@ -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 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