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