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
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);
|
|
}
|
|
|
|
}
|