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.

187 lines
5.6 KiB
Java

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