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

// 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
}
}
}