// 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 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 getServices() { // System.err.println("CSMAProtocol.getServices - " + protocolName + // ": protocolState <" + protocolState + "> protocolOut <" + protocolOut + // "> protocolSending <" + protocolSending + ">"); String peerName = protocolPeer.getName(); // get peer name Vector list = new Vector(); // 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();// 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 performService(String service) { protocolEvents = new Vector(); // 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 receivePDU(PDU pdu) { protocolEvents = new Vector(); // 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 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)); } }