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.
415 lines
14 KiB
Java
415 lines
14 KiB
Java
// CSMAProtocol.java
|
|
|
|
package protocol; // protocol package
|
|
|
|
import java.util.*; // import Java utility classes
|
|
|
|
import support.*; // import Jasper support classes
|
|
|
|
/**
|
|
This is the class that supports the CSMA/CD MAC layer.
|
|
|
|
@author Kenneth J. Turner
|
|
@version 1.0 (24th July 2010, KJT): initial version
|
|
*/
|
|
|
|
public class CSMAProtocol implements ProtocolEntity {
|
|
|
|
////////////////////////// User Interface Messages ///////////////////////////
|
|
|
|
/** Protocol deliver offer */
|
|
private final static String DELIVER = "Deliver data to ";
|
|
|
|
/** Protocol finish transmission offer */
|
|
private final static String FINISH = "Finish sending data to ";
|
|
|
|
/** Protocol jam offer */
|
|
private final static String JAM = "Jam transmission to ";
|
|
|
|
/** Protocol retry limit report */
|
|
private final static String RETRIES =
|
|
"Report failure due to excessive retries";
|
|
|
|
/** Protocol start transmission offer */
|
|
private final static String START = "Start sending data to ";
|
|
|
|
////////////////////////////// Protocol States ///////////////////////////////
|
|
|
|
/** Protocol state - collision */
|
|
protected final static int NORMAL = 0;
|
|
|
|
/** Protocol state - collision detected */
|
|
protected final static int COLLISION = 1;
|
|
|
|
/** Protocol state - jam received following collision */
|
|
protected final static int JAM_IN = 2;
|
|
|
|
/** Protocol state - jam sent following collision */
|
|
protected final static int JAM_OUT = 3;
|
|
|
|
/** Protocol state - backing off following jam */
|
|
protected final static int BACKOFF = 4;
|
|
|
|
///////////////////////////// Protocol Variables /////////////////////////////
|
|
|
|
/** Protocol backoff count */
|
|
protected int protocolBackoff;
|
|
|
|
/** Protocol deferring to an incoming transmission */
|
|
private boolean protocolDeferring;
|
|
|
|
/** Protocol events */
|
|
private Vector<ProtocolEvent> protocolEvents;
|
|
|
|
/** Protocol PDU received */
|
|
protected CSMAPdu protocolIn;
|
|
|
|
/** Protocol channel */
|
|
protected CSMAMedium protocolMedium;
|
|
|
|
/** Protocol name */
|
|
protected String protocolName;
|
|
|
|
/** Protocol PDU sent */
|
|
protected CSMAPdu protocolOut;
|
|
|
|
/** Protocol peer */
|
|
protected CSMAProtocol protocolPeer;
|
|
|
|
/** Protocol in the process of receiving a message */
|
|
protected boolean protocolReceiving;
|
|
|
|
/** Protocol retry count */
|
|
protected int protocolRetries;
|
|
|
|
/** Protocol in the process of sending a message */
|
|
protected boolean protocolSending;
|
|
|
|
/** Protocol collision state */
|
|
protected int protocolState;
|
|
|
|
/** Protocol user */
|
|
protected CSMAService protocolUser;
|
|
|
|
////////////////////////////// Protocol Methods //////////////////////////////
|
|
|
|
/**
|
|
Constructor for a (de)multiplexer.
|
|
|
|
@param protocolMedium channel
|
|
@param protocolName protocol name
|
|
*/
|
|
public CSMAProtocol(Medium protocolMedium, String protocolName) {
|
|
this.protocolName = protocolName; // set protocol name
|
|
this.protocolMedium = // set protocol medium
|
|
(CSMAMedium) protocolMedium;
|
|
initialise(); // initialise protocol
|
|
}
|
|
|
|
/**
|
|
Return the backoff count as a random integer in the range (0, 2^retries].
|
|
This is 0..1 if there have been no retries, 0..2 if there has been one
|
|
retry, etc. Technically this is the number of slot times, but actual time is
|
|
irrelevant in the simulation approach.
|
|
|
|
@return backoff interval
|
|
*/
|
|
public int backoffCount() {
|
|
float backoff = // get random in (0, 2^retries]
|
|
(float) (CSMA.getRandom() * Math.pow(2.0, protocolRetries));
|
|
return(Math.round(backoff)); // return nearest integer
|
|
}
|
|
|
|
/**
|
|
Return a protocol event with the given comment.
|
|
|
|
@param comment protocol comment
|
|
@return protocol event
|
|
*/
|
|
public ProtocolEvent comment(String comment) {
|
|
return(new ProtocolEvent(ProtocolEvent.COMMENT, this, comment));
|
|
}
|
|
|
|
/**
|
|
Get the protocol name.
|
|
|
|
@return protocol name
|
|
*/
|
|
public String getName() {
|
|
return(protocolName); // return protocol name
|
|
}
|
|
|
|
/**
|
|
Get the protocol peer.
|
|
|
|
@return protocol peer
|
|
*/
|
|
public CSMAProtocol getPeer() {
|
|
return(protocolPeer); // return protocol peer
|
|
}
|
|
|
|
/**
|
|
Return services currently offered.
|
|
|
|
@return list of protocol services
|
|
*/
|
|
public Vector<String> getServices() {
|
|
// System.err.println("CSMAProtocol.getServices - " + protocolName +
|
|
// ": protocolState <" + protocolState + "> protocolOut <" + protocolOut +
|
|
// "> protocolSending <" + protocolSending + ">");
|
|
String peerName = protocolPeer.getName(); // get peer name
|
|
Vector<String> list = new Vector<String>(); // initialise protocol services
|
|
if (protocolState != NORMAL) { // handling collision?
|
|
if (protocolState == COLLISION || // collision detected or
|
|
protocolState == JAM_IN) { // jam received?
|
|
list.add(JAM + peerName); // append jam sending offer
|
|
}
|
|
else if (protocolState == BACKOFF) { // backing off?
|
|
// System.err.println("CSMAProtocol.getServices - " + protocolName +
|
|
// ": state local <" + protocolState + "> remote <" +
|
|
// protocolPeer.protocolState + ">, backoff local <" +
|
|
// protocolBackoff + "> remote <" + protocolPeer.protocolBackoff +
|
|
// ">, protocolRetries local <" + protocolRetries + "> remote <" +
|
|
// protocolPeer.protocolRetries + ">\n");
|
|
int peerState = protocolPeer.protocolState; // get peer state
|
|
if (peerState == BACKOFF || // peer also backing off or
|
|
peerState == NORMAL) { // peer recovered from backoff?
|
|
if (protocolBackoff <= // local protocol can retry?
|
|
protocolPeer.protocolBackoff) {
|
|
protocolRetries++; // increment retry count
|
|
if (protocolRetries > CSMA.retryLimit) { // retry limit reached?
|
|
list.add(RETRIES); // add retry limit report
|
|
}
|
|
else { // retry limit not reached
|
|
protocolState = NORMAL; // set collision state to normal
|
|
protocolOut.type = CSMAPdu.START; // set PDU back to start
|
|
initialise_part(); // partly re-initialise protocol
|
|
list.add(START+ peerName + // append retry sending offer
|
|
" (retry " + protocolRetries + ")");
|
|
}
|
|
}
|
|
else { // local entity must wait
|
|
initialise_part(); // partly re-initialise protocol
|
|
protocolDeferring = true; // note deferring
|
|
}
|
|
}
|
|
}
|
|
} // not handling collision hereon
|
|
else if (protocolOut != null) { // outgoing PDU available?
|
|
if (protocolSending) { // already sending?
|
|
if (protocolMedium.isEmpty(protocolName)) { // no local PDUs sent?
|
|
list.add(FINISH + peerName); // append finish sending offer
|
|
}
|
|
}
|
|
else if ((protocolMedium.isEmpty() || // nothing in medium or
|
|
CSMA.retryLimit > 0) && // retries allowed, and
|
|
protocolPeer.protocolState == // peer not in collision and
|
|
NORMAL &&
|
|
!protocolDeferring) { // not deferring?
|
|
list.add(START + peerName); // append start sending offer
|
|
}
|
|
}
|
|
if (protocolIn != null && // incoming PDU available and
|
|
protocolState == NORMAL) { // not in collision?
|
|
String serviceName = protocolUser.getName(); // get service name
|
|
list.add(DELIVER + serviceName); // append deliver offer
|
|
}
|
|
return (list); // return protocol service list
|
|
}
|
|
|
|
/**
|
|
Initialise the protocol entity.
|
|
*/
|
|
public void initialise() {
|
|
initialise_part(); // partly initialise protocol
|
|
protocolIn = null; // initialise incoming PDU
|
|
protocolOut = null; // initialise outgoing PDu
|
|
protocolRetries = 0; // initialise no retries
|
|
CSMA.randomIndex = 0; // initialise random index
|
|
}
|
|
|
|
/**
|
|
Partly initialise the protocol entity in the event of backoff and retry.
|
|
*/
|
|
public void initialise_part() {
|
|
protocolDeferring = false; // initialise not deferring
|
|
protocolEvents = new Vector<ProtocolEvent>();// initialise protocol events
|
|
protocolReceiving = false; // initialise not receiving
|
|
protocolSending = false; // initialise not sending
|
|
protocolState = NORMAL; // initialise no collision
|
|
}
|
|
|
|
/**
|
|
Perform service.
|
|
|
|
@param service service request
|
|
@return resulting protocol events
|
|
*/
|
|
public Vector<ProtocolEvent> performService(String service) {
|
|
protocolEvents = new Vector<ProtocolEvent>(); // initialise protocol events
|
|
if (service.startsWith(DELIVER)) { // deliver request?
|
|
CSMASdu sdu = // create SDU from PDU
|
|
new CSMASdu(CSMASdu.DATA, protocolIn.sdu);
|
|
transmitPDU(sdu, protocolUser); // deliver SDU to service user
|
|
protocolIn = null; // re-initialise incoming PDU
|
|
}
|
|
else if (service.startsWith(FINISH)) { // finish sending request?
|
|
String message = protocolOut.sdu; // get current SDU
|
|
protocolOut = // create finish PDU
|
|
new CSMAPdu(CSMAPdu.FINISH, message);
|
|
protocolSending = false; // note not sending
|
|
protocolEvents.addElement( // add send event
|
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, protocolOut));
|
|
transmitPDU(protocolOut, protocolPeer); // send protocol PDU
|
|
if (protocolPeer.protocolState == NORMAL) // peer is in normal state?
|
|
protocolOut = null; // re-initialise outgoing PDU
|
|
}
|
|
else if (service.startsWith(JAM)) { // jamming request?
|
|
if (protocolState == JAM_IN) { // jam received?
|
|
protocolState = BACKOFF; // note backing off
|
|
protocolBackoff = backoffCount(); // compute backoff "time"
|
|
protocolEvents.addElement( // add backoff event
|
|
comment("backoff " + protocolBackoff));
|
|
}
|
|
else // jam not received
|
|
protocolState = JAM_OUT; // note jam sent
|
|
CSMAPdu pdu = new CSMAPdu(CSMAPdu.JAM, ""); // set jam PDU
|
|
protocolEvents.addElement( // add send event
|
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pdu));
|
|
transmitPDU(pdu, protocolPeer); // send protocol PDU
|
|
}
|
|
else if (service.startsWith(RETRIES)) { // retries response?
|
|
initialise(); // re-initialise whole protocol
|
|
CSMASdu sdu = // construct failure SDU
|
|
new CSMASdu(CSMASdu.FAIL, "Retry Limit");
|
|
transmitPDU(sdu, protocolUser); // deliver SDU to service user
|
|
}
|
|
else if (service.startsWith(START)) { // start sending request?
|
|
String message = protocolOut.sdu; // get current SDU
|
|
protocolOut = // create start PDU
|
|
new CSMAPdu(CSMAPdu.START, message);
|
|
protocolSending = true; // note sending
|
|
if (protocolReceiving) { // already receiving?
|
|
protocolState = COLLISION; // note collision
|
|
protocolEvents.addElement( // add collision event
|
|
comment("collision"));
|
|
}
|
|
protocolEvents.addElement( // add send event
|
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, protocolOut));
|
|
transmitPDU(protocolOut, protocolPeer); // send protocol PDU
|
|
}
|
|
return(protocolEvents); // return protocol events
|
|
}
|
|
|
|
/**
|
|
Receive PDU.
|
|
|
|
@param pdu PDU
|
|
@return resulting protocol events
|
|
*/
|
|
public Vector<ProtocolEvent> receivePDU(PDU pdu) {
|
|
protocolEvents = new Vector<ProtocolEvent>(); // initialise event list
|
|
if (pdu != null) { // non-empty PDU?
|
|
String type = pdu.type; // get PDU type
|
|
String data = pdu.sdu; // get SDU
|
|
if (type.equals(CSMASdu.DATA)) { // service user message?
|
|
protocolOut = // store outgoing PDU
|
|
new CSMAPdu(CSMAPdu.START, data);
|
|
if (protocolReceiving) { // already receiving
|
|
protocolDeferring = true; // note deferring
|
|
protocolEvents.addElement( // add defer event
|
|
comment("defer"));
|
|
}
|
|
}
|
|
else if (type.equals(CSMAPdu.FINISH)) { // finish receiving message?
|
|
protocolReceiving = false; // note not receiving
|
|
if (protocolState == NORMAL) // normal state?
|
|
protocolIn = (CSMAPdu) pdu; // store incoming PDU
|
|
if (protocolDeferring) { // deferring?
|
|
protocolDeferring = false; // not deferring
|
|
protocolEvents.addElement( // add resume event
|
|
comment("resume"));
|
|
}
|
|
}
|
|
else if (type.equals(CSMAPdu.JAM)) { // jam message?
|
|
if (protocolState == JAM_OUT) { // jam sent?
|
|
protocolState = BACKOFF; // note backing off
|
|
protocolBackoff = backoffCount(); // compute backoff "time"
|
|
protocolEvents.addElement( // add backoff event
|
|
comment("backoff " + protocolBackoff));
|
|
}
|
|
else { // jam not sent
|
|
if (protocolState == NORMAL) { // normal state?
|
|
protocolEvents.addElement( // add collision event
|
|
comment("collision"));
|
|
}
|
|
protocolState = JAM_IN; // note jam received
|
|
}
|
|
}
|
|
else if (type.equals(CSMAPdu.START)) { // start receiving message?
|
|
protocolReceiving = true; // note receiving
|
|
if (protocolSending) { // already sending?
|
|
protocolState = COLLISION; // note collision
|
|
protocolEvents.addElement( // add collision event
|
|
comment("collision"));
|
|
}
|
|
else if (protocolOut != null) { // PDU to be sent?
|
|
protocolDeferring = true; // note deferring
|
|
if (protocolPeer.protocolState == NORMAL) // peer in normal state?
|
|
protocolEvents.addElement( // add defer event
|
|
comment("defer"));
|
|
}
|
|
if (protocolState == NORMAL && // normal state and
|
|
protocolDeferring) { // deferring to peer?
|
|
protocolPeer.protocolRetries = 0; // reset its retry count
|
|
}
|
|
}
|
|
}
|
|
return(protocolEvents); // return protocol events
|
|
}
|
|
|
|
/**
|
|
Set the protocol peer.
|
|
|
|
@param protocolPeer protocol peer
|
|
*/
|
|
public void setPeer(ProtocolEntity protocolPeer) {
|
|
this.protocolPeer = // set protocol peer
|
|
(CSMAProtocol) protocolPeer;
|
|
}
|
|
|
|
/**
|
|
Set the protocol service.
|
|
|
|
@param protocolUser protocol service user
|
|
*/
|
|
public void setUser(ProtocolEntity protocolUser) {
|
|
this.protocolUser = // set service user
|
|
(CSMAService) protocolUser;
|
|
}
|
|
|
|
/**
|
|
Send PDU.
|
|
|
|
@param pdu PDU
|
|
@param destination protocol destination
|
|
*/
|
|
public void transmitPDU(PDU pdu, ProtocolEntity destination) {
|
|
pdu.setSource(this); // set protocol entity as source
|
|
pdu.setDestination(destination); // set message destination
|
|
Vector<ProtocolEvent> receiveEvents; // declare receive events
|
|
if (destination == protocolPeer) { // for protocol peer?
|
|
receiveEvents = // receive PDU at medium
|
|
protocolMedium.receivePDU(pdu);
|
|
}
|
|
else // for service user?
|
|
receiveEvents = // receive PDU at user
|
|
protocolUser.receivePDU(pdu);
|
|
for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
|
|
protocolEvents.addElement( // append receive event
|
|
receiveEvents.get(i));
|
|
}
|
|
|
|
}
|
|
|