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.
201 lines
5.9 KiB
Java
201 lines
5.9 KiB
Java
// 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
|
|
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
|
|
<br/> 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<ProtocolEvent> receivePDU(PDU pdu) {
|
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
|
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<String> getServices() {
|
|
Vector<String> services = new Vector<String>();
|
|
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<ProtocolEvent> performService(String s) {
|
|
int startIndex, endIndex;
|
|
String seqString;
|
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
|
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);
|
|
}
|
|
|
|
}
|