// SWP5Sender.java package protocol; import java.util.*; import support.*; /** This is the class for a five-column Sliding Window Protocol sender. @author Iain A. Robin, Kenneth J. Turner @version 1.0 (1st September 1999, IAR): initial version
1.4 (9th March 2006, KJT): updated for JDK 1.5
1.5 (27th July 2010, KJT): minor tidying */ public class SWP5Sender implements ProtocolEntity, Timeouts { private static final String SEND = "Send"; private static final String RESEND = "Timeout - resend"; private static final String BLOCKED = "Blocked"; private static final String CLEAR = "Clear"; private int maxSeq; // maximum seq. no. private int winSize; // transmit window private int lowerWindowEdge; // ack seq. no. private int upperWindowEdge; // next seq. no. private boolean[] timerEnabled; private PDU[] recvBuffer; private Medium medium; private SWP5Service user; private ProtocolEntity peer; private Vector userEvents; private boolean windowClosed; public SWP5Sender(int maxSeq, int winSize, Medium m) { setMaxSeq(maxSeq); setWindowSize(winSize); medium = m; initialise(); } public void initialise() { recvBuffer = new PDU[maxSeq + 1]; timerEnabled = new boolean[maxSeq + 1]; for (int i = 0; i <= maxSeq; i++) timerEnabled[i] = false; lowerWindowEdge = 0; upperWindowEdge = 0; windowClosed = false; } public void setMaxSeq(int maxSeq) { this.maxSeq = maxSeq; } public void setWindowSize(int winSize) { this.winSize = winSize; } private int inc(int seq) { return(mod(seq + 1)); } private int mod(int n) { int base = maxSeq + 1; n %= base; return(n >= 0 ? n : n + base); } private boolean isWithinWindow(int seq) { return(lowerWindowEdge <= seq && seq < upperWindowEdge) || (upperWindowEdge < lowerWindowEdge && (seq >= lowerWindowEdge || seq < upperWindowEdge)); } public String getName() { return("Protocol A"); } /** Set the timer for a specified PDU. @param pdu PDU @param enabled whether the timer is enabled */ public void setTimer(PDU pdu, boolean enabled) { timerEnabled[pdu.seq] = enabled; } public void setPeer(ProtocolEntity peer) { this.peer = peer; } public void setUser(ProtocolEntity user) { this.user = (SWP5Service)user; } private void releaseTimers(int lower, int upper) { for (int seq = lower; seq != upper; seq = inc(seq)) { timerEnabled[seq] = false; } } private ProtocolEvent comment(String c) { return(new ProtocolEvent(ProtocolEvent.COMMENT, this, c)); } public boolean hasTimer(String type) { return(true); } public Vector receivePDU(PDU pdu) { Vector events = new Vector(); String pduType = ""; if (pdu != null) pduType = pdu.type; if (pduType.equals("DatReq")) { // DatReq from user PDU pduSent = new PDU("DT", upperWindowEdge, pdu.getSDU()); recvBuffer[upperWindowEdge] = pdu; transmitPDU(pduSent, peer); events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent)); upperWindowEdge = inc(upperWindowEdge); windowClosed = mod(upperWindowEdge - lowerWindowEdge) >= winSize; if (windowClosed) { events.addElement(comment(BLOCKED)); } } if (pduType.equals("AK")) { // AK PDU from peer int seq = pdu.seq; if (isWithinWindow(mod(seq - 1))) { releaseTimers(lowerWindowEdge, seq); lowerWindowEdge = seq; // update sender window if (windowClosed) { // Send window was full, indicate it is now clear: events.addElement(comment(CLEAR)); } windowClosed = false; // and set flag appropriately } } user.setOKToSend(!windowClosed); 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 seq; int first = -1; int last = -1; for (seq = lowerWindowEdge; isWithinWindow(seq); seq = inc(seq)) { if (timerEnabled[seq]) { if (first < 0) first = seq; last = seq; } } if (first >= 0) { // >=1 PDU may time out if (last == first) // only one PDU may be resent services.addElement(RESEND + " DT(" + first + ")"); else // more than one PDU may be resent services.addElement(RESEND + " DT(" + first + ") - (" + last + ")"); } return(services); } public Vector performService(String s) { int startIndex, endIndex; String seqString; Vector events = new Vector(); if (s.startsWith(RESEND)) { // get sequence number of first data PDU to be resent startIndex = s.indexOf( '(' ) + 1; endIndex = s.indexOf( ')' ); seqString = s.substring(startIndex, endIndex); int seq1 = Integer.parseInt(seqString); // get sequence number of last data PDU to be resent startIndex = s.lastIndexOf( '(' ) + 1; endIndex = s.lastIndexOf( ')' ); seqString = s.substring(startIndex, endIndex); int seq2 = Integer.parseInt(seqString); releaseTimers(seq1, inc(seq2)); // retransmit all unacknowledged data PDUs already sent and timed out for (int p = seq1; p != inc(seq2); p = inc(p)) { PDU pdu = new PDU("DT", p, recvBuffer[p].getSDU()); transmitPDU(pdu, peer); events.addElement(new ProtocolEvent(ProtocolEvent.TIMEOUT, pdu)); } } for (Enumeration e = userEvents.elements(); e.hasMoreElements(); ) events.addElement((ProtocolEvent) e.nextElement()); return(events); } }