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