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.
387 lines
12 KiB
Java
387 lines
12 KiB
Java
4 years ago
|
// ABRAProtocol.java
|
||
|
|
||
|
package protocol;
|
||
|
|
||
|
import java.util.*;
|
||
|
import support.*;
|
||
|
|
||
|
/**
|
||
|
This is the class for the Abracadabra 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 ABRAProtocol implements ProtocolEntity, Timeouts {
|
||
|
|
||
|
// Protocol state constants
|
||
|
private static final int CLOSED = 0; // waiting for connection request
|
||
|
private static final int CR_SENT = 1; // waiting for connection confirmation
|
||
|
private static final int CR_RECV = 2; // waiting for ConResp from user
|
||
|
private static final int SEND = 3; // prepared to send data PDU
|
||
|
private static final int WAIT = 4; // waiting for acknowledgement of data
|
||
|
private static final int DR_SENT = 5; // waiting for disconnection confirm
|
||
|
|
||
|
// Protocol data unit types
|
||
|
public static final String CR = "Connection Request";
|
||
|
public static final String CC = "Connection Confirmation";
|
||
|
public static final String DT = "Data Transfer";
|
||
|
public static final String AK = "Acknowledgement";
|
||
|
public static final String DR = "Disconnection Request";
|
||
|
public static final String DC = "Disconnection Confirmation";
|
||
|
|
||
|
public static final int maxRetries = 3;
|
||
|
|
||
|
private PDU pduSent;
|
||
|
private PDU lastDTpdu;
|
||
|
private int sendSeq;
|
||
|
private int recvSeq;
|
||
|
private ProtocolEntity peer;
|
||
|
private ABRAService user;
|
||
|
private Vector<ProtocolEvent> entityEvents; // events from entity
|
||
|
private Medium medium;
|
||
|
private String name;
|
||
|
private boolean timerEnabled;
|
||
|
private int crRemaining;
|
||
|
private int drRemaining;
|
||
|
private int dtRemaining;
|
||
|
private boolean dtOrAk;
|
||
|
private int state;
|
||
|
|
||
|
public ABRAProtocol(Medium m, String name) {
|
||
|
this.name = name;
|
||
|
medium = m;
|
||
|
initialise();
|
||
|
}
|
||
|
|
||
|
public String getName() {
|
||
|
return(name);
|
||
|
}
|
||
|
|
||
|
public Vector<String> getServices() {
|
||
|
Vector<String> list = new Vector<String>();
|
||
|
switch (state) {
|
||
|
case CR_SENT: // waiting for connection confirmation
|
||
|
if (timerEnabled) {
|
||
|
if (crRemaining > 1)
|
||
|
list.addElement("Timeout - resend " + CR);
|
||
|
else
|
||
|
list.addElement("Retry limit reached - send " + DR);
|
||
|
}
|
||
|
break;
|
||
|
case WAIT: // waiting for acknowledgement of data
|
||
|
if (timerEnabled) {
|
||
|
if (dtRemaining > 1)
|
||
|
list.addElement("Timeout - resend DT(" + lastDTpdu.seq + ")" );
|
||
|
else
|
||
|
list.addElement("Retry limit reached - send " + DR);
|
||
|
}
|
||
|
break;
|
||
|
case DR_SENT: // waiting for disconnection confirmation
|
||
|
if (timerEnabled) {
|
||
|
if (drRemaining > 1) {
|
||
|
list.addElement("Timeout - resend " + DR);
|
||
|
}
|
||
|
else {
|
||
|
// Retry limit reached
|
||
|
dtRemaining--;
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return(list);
|
||
|
}
|
||
|
|
||
|
/** Increment PDU sequence number (alternating bit) */
|
||
|
|
||
|
private int inc(int seq) {
|
||
|
return(1 - seq);
|
||
|
}
|
||
|
|
||
|
public void initialise() {
|
||
|
entityEvents = new Vector<ProtocolEvent>();
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
|
||
|
public boolean hasTimer(String type) {
|
||
|
return(type.equals("DT") || type.equals("DR") || type.equals("CR"));
|
||
|
}
|
||
|
|
||
|
public Vector<ProtocolEvent> performService(String s) {
|
||
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
||
|
switch (state) {
|
||
|
case CR_SENT:
|
||
|
if (s.startsWith("Timeout")) {
|
||
|
crRemaining--;
|
||
|
transmitPDU(new PDU("CR"), peer); // resend connection request PDU
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
|
||
|
}
|
||
|
if (s.startsWith("Retry limit")) {
|
||
|
crRemaining--;
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DR"), peer); // send disconnection request PDU
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
break;
|
||
|
case WAIT:
|
||
|
if (s.startsWith("Timeout")) {
|
||
|
dtRemaining--;
|
||
|
transmitPDU(lastDTpdu, peer);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
|
||
|
}
|
||
|
if (s.startsWith("Retry limit")) {
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
dtRemaining--;
|
||
|
transmitPDU(new PDU("DR"), peer); // send disconnection request PDU
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
break;
|
||
|
case DR_SENT:
|
||
|
if (s.startsWith("Timeout")) {
|
||
|
drRemaining--;
|
||
|
transmitPDU(new PDU("DR"), peer);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
for (Enumeration e = entityEvents.elements(); e.hasMoreElements(); )
|
||
|
events.addElement((ProtocolEvent) e.nextElement());
|
||
|
return(events);
|
||
|
}
|
||
|
|
||
|
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
|
||
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
||
|
String pduType = "";
|
||
|
if (pdu != null)
|
||
|
pduType = pdu.type;
|
||
|
switch (state) {
|
||
|
case CLOSED:
|
||
|
if (pduType.equals("ConReq")) { // ConReq primitive?
|
||
|
transmitPDU(new PDU("CR"), peer); // send connection request PDU
|
||
|
dtOrAk = false;
|
||
|
sendSeq = 0;
|
||
|
recvSeq = 0;
|
||
|
crRemaining = maxRetries;
|
||
|
state = CR_SENT;
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
}
|
||
|
else if (pduType.equals("CR")) { // connection request PDU?
|
||
|
transmitPDU(new PDU("ConInd"), user);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
dtOrAk = false;
|
||
|
sendSeq = 0;
|
||
|
recvSeq = 0;
|
||
|
state = CR_RECV;
|
||
|
}
|
||
|
else if (pduType.equals("DR")) { // got disconnect request PDU
|
||
|
transmitPDU(new PDU("DC"), peer); // send disconnect confirm PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
}
|
||
|
break;
|
||
|
case CR_SENT:
|
||
|
if (pduType.equals("CC") || // connection confirmation PDU?
|
||
|
pduType.equals("CR")) { // connection request PDU?
|
||
|
// (both stations have requested connections at the same time)
|
||
|
transmitPDU(new PDU("ConConf"), user);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
timerEnabled = false;
|
||
|
state = SEND;
|
||
|
}
|
||
|
else if (pduType.equals("DR")) { // disconnection request PDU?
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
timerEnabled = false;
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
else if (pduType.equals("DisReq")) { // disconnection request prim?
|
||
|
// transmitPDU(new PDU("DisInd"), user);
|
||
|
// events.addElement(
|
||
|
// new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
break;
|
||
|
case CR_RECV:
|
||
|
if (pduType.equals("ConResp")) {
|
||
|
transmitPDU(new PDU("CC"), peer); // send connection confirm PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
state = SEND;
|
||
|
}
|
||
|
else if (pduType.equals("DR")) {
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DC"), peer); // send disconnection confirm PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
else if (pduType.equals("ConReq")) {
|
||
|
transmitPDU(new PDU("ConConf"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("CC"), peer); // send connection confirm PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
state = SEND;
|
||
|
}
|
||
|
else if (pduType.equals("DisReq")) {
|
||
|
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
break;
|
||
|
case WAIT:
|
||
|
if (pduType.equals("AK")) {
|
||
|
if (pdu.seq == sendSeq) {
|
||
|
dtOrAk = true;
|
||
|
timerEnabled = false;
|
||
|
user.setOKToSend(true);
|
||
|
state = SEND;
|
||
|
}
|
||
|
else { // wrong AK : enter error phase
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DR"), peer); // send disconnect request PDU
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
}
|
||
|
// break intentionally omitted
|
||
|
case SEND:
|
||
|
if (state == SEND // avoid drop-through from WAIT
|
||
|
&& pduType.equals("DatReq")) { // DatReq received from user
|
||
|
transmitPDU(new PDU("DT", sendSeq, pdu.getSDU()), peer);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
user.setOKToSend(false);
|
||
|
sendSeq = inc(sendSeq);
|
||
|
dtRemaining = maxRetries;
|
||
|
state = WAIT;
|
||
|
}
|
||
|
else if (pduType.equals("DR")) { // disconnection request PDU?
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DC"), peer);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
timerEnabled = false;
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
else if (pduType.equals("DT")) { // data PDU received
|
||
|
dtOrAk = true;
|
||
|
if (pdu.seq == recvSeq) { // check sequence number correct
|
||
|
recvSeq = inc(recvSeq);
|
||
|
transmitPDU(new PDU("DatInd", pdu.getSDU()), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
}
|
||
|
transmitPDU(new PDU("AK", recvSeq), peer);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
// no state transition
|
||
|
}
|
||
|
if (pduType.equals("CC") || pduType.equals("DC")) {
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DR"), peer);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
if (pduType.equals("CR")) { // connection request PDU?
|
||
|
if (!dtOrAk) {
|
||
|
transmitPDU(new PDU("CC"), peer);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
// no state transition
|
||
|
}
|
||
|
else {
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
transmitPDU(new PDU("DR"), peer);
|
||
|
events.addElement(
|
||
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
}
|
||
|
if (pduType.equals("DisReq")) {
|
||
|
transmitPDU(new PDU("DR"), peer);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
||
|
drRemaining = maxRetries;
|
||
|
state = DR_SENT;
|
||
|
}
|
||
|
break;
|
||
|
case DR_SENT: // awaiting disconnect confirm
|
||
|
if (pduType.equals("DC") || // disconnect confirm PDU?
|
||
|
pduType.equals("DR")) { // disconnect request PDU?
|
||
|
// both stations have requested disconnection at the same time
|
||
|
timerEnabled = false;
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
if (pduType.equals("ConReq")) {
|
||
|
transmitPDU(new PDU("DisInd"), user);
|
||
|
events.addElement(new ProtocolEvent(ProtocolEvent.DELIVER, pduSent));
|
||
|
}
|
||
|
if (timerEnabled && drRemaining <= 1) {
|
||
|
drRemaining--;
|
||
|
state = CLOSED;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return(events);
|
||
|
}
|
||
|
|
||
|
public void setPeer(ProtocolEntity peer) {
|
||
|
this.peer = peer;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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 = enabled;
|
||
|
}
|
||
|
|
||
|
public void setUser(ProtocolEntity user) {
|
||
|
this.user = (ABRAService)user;
|
||
|
}
|
||
|
|
||
|
public void transmitPDU(PDU pdu, ProtocolEntity destination) {
|
||
|
pdu.setSource(this);
|
||
|
pdu.setDestination(destination);
|
||
|
if (destination == peer)
|
||
|
entityEvents = medium.receivePDU(pdu);
|
||
|
else
|
||
|
entityEvents = user.receivePDU(pdu);
|
||
|
pduSent = pdu;
|
||
|
if (pdu.type.equals("DT"))
|
||
|
lastDTpdu = pdu;
|
||
|
for (Enumeration e = entityEvents.elements(); e.hasMoreElements(); )
|
||
|
System.err.println("ABRAP transmitPDU: " + (ProtocolEvent) e.nextElement());
|
||
|
}
|
||
|
|
||
|
}
|