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

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