package datalinklayer; public class LinkLayer extends Thread { String intendedMessage; PhysicalLayer p; int currentSeqNr; long timerStart; boolean isSender; String name; String receivedSoFar = ""; public LinkLayer(PhysicalLayer p1, String m1, String nm) { name = nm; intendedMessage = m1; p = p1; currentSeqNr = 0; if (intendedMessage!=null) isSender = true; else isSender=false; } // The main action for senders and receivers public void run() { long startTime = System.currentTimeMillis(); Frame pkg = null; /** Added **/ Frame pkg2 = null; /** Added: Flag for receiver to see whether 1st package has arrived **/ boolean ack1 = false; // If peer hase something to send, start with the first frame if (isSender) { /** Changed: Now two packages at initialization **/ pkg = produceNextFrameForSending(); currentSeqNr++; pkg2 = produceNextFrameForSending(); linkToPhysical(pkg); linkToPhysical(pkg2); startTimer(); } // Loop forever if you are receiver, or loop until you have nothing left to say as sender while (!isSender || intendedMessage.length()-1>=Simulation.packageSize) { // Sleep a little try {Thread.sleep(Simulation.protocolDelay);} catch (InterruptedException e) {} // Check whether a frame has arrived Frame received = physicalToLink(); if (received!=null) { // If we are a sender and get an acknowledgement we can continue if (isSender && received.ackBit && (received.seqNr==currentSeqNr)) { /** Changed: Now two packages are produced **/ currentSeqNr++; pkg = produceNextFrameForSending(); currentSeqNr++; pkg2 = produceNextFrameForSending(); linkToPhysical(pkg); linkToPhysical(pkg2); startTimer(); } // If we are the receiver and get the message we expect (or an older one) we send back an acknowledgement if (!isSender && received.seqNr<=currentSeqNr) { boolean calculatedParity = received.calculateParity(); if (calculatedParity == received.parityBit) { // Create acknowledgement package (no data) // Is it the message we were waiting for? /** Changed: Check whether it is the first or the second package for our window **/ if (received.seqNr==currentSeqNr && ack1==false) { ack1 = true; currentSeqNr++; receivedSoFar = receivedSoFar + received.data; } if (received.seqNr==currentSeqNr && ack1) { pkg = new Frame(received.seqNr,null,true); linkToPhysical(pkg); currentSeqNr++; receivedSoFar = receivedSoFar + received.data; System.out.println(" " + receivedSoFar); ack1 = false; } } // Else the message was garbled, so we forget about it (doing nothing but waiting for retransmission) else { System.out.println(this.name + ": Parity of message " + received.seqNr + " does not match"); } } } // If we are sender, we check whether the timer went off and retransmit if (isSender && timerExpired()) { System.out.println(this.name + " timed out waiting for ACK of package " + currentSeqNr); linkToPhysical(pkg); linkToPhysical(pkg2); startTimer(); } } // end of looping System.out.println("Finished transmission after " + (System.currentTimeMillis()-startTime) + " milliseconds."); } // Prepares the next frame that can be sent private Frame produceNextFrameForSending() { Frame msg = new Frame(currentSeqNr,intendedMessage.substring(0, Simulation.packageSize), false); intendedMessage = intendedMessage.substring(Simulation.packageSize,intendedMessage.length()); return msg; } // Starts the retransmission timer private void startTimer() { timerStart = System.currentTimeMillis(); } // Checks if the retransmission timer is expired private boolean timerExpired() { if (System.currentTimeMillis()-timerStart>Simulation.retransmissionTimeOut) return true; else return false; } // Give a frame to the physical layer private void linkToPhysical(Frame f) { p.queueOut.add(f); System.out.println(name + " just handed a message with ID " + f.seqNr + " and ACK=" + f.ackBit + " to its physical layer "); } // Get a frame from the physical layer public Frame physicalToLink() { if (p.queueIn.size()>0) return p.queueIn.poll(); else return null; } }