I'm working on a programming assignment which simulates network traffic between two hosts. My task is to implement the transport layer, the code for the other layers, GUI etc. is already provided. I have managed to do this and the code works according to the specifications listed below. My concern is that the code feels badly structured and could be improved significantly both in regards of structure and functionality.
Video demonstration of a working implementation from our instructors.
Requirements:
- Uses the constructors values for timer and window size.
- Sends packets that arrive from the applicationlayer if there's space in the window.
- Buffers packets which arrives from the application layer if there's no space in the window.
- Resends all packets that has been sent but not ACK:ed in case of a timer interrupt.
- Responds to correct packets that arrive in order with an ACK.
- Responds to correct packets that has been previously received with an ACK.
- Ignores packets that are incorrect and/or arrives in the wrong order.
- Sends packets from the buffer if an ACK has been received and there's space in the window.
Below is my code for the transport layer. I'm not sure if the rest of the simulator's code (which is not written by me and should not be reviewed) is needed to do a review but I will include a link to it anyway.
TransportLayer.java:
package protocolsimulator;
import java.util.HashMap;
import protocolsimulator.Segment;
public class TransportLayer
{
private LayerSimulator mLayerSimulator = null;
private String mId;
private int mTimerValue, mWindowSize;
private int seqNumber = -1;
private int ackNumber = -1;
private int expected = 0;
private HashMap<Integer, Segment> sentSegments = new HashMap<Integer, Segment>();
private HashMap<Integer, Segment> receivedACKS = new HashMap<Integer, Segment>();
private HashMap<Integer, Segment> recvBuffer = new HashMap<Integer, Segment>();
private HashMap<Integer, Segment> sendBuffer = new HashMap<Integer, Segment>();
/**
* Consructs a TransportLayer
*
* @param id Id for the host
* @param layers Class that simulates layers arount the Transport Layer
*/
/**
* Constructs a TransportLayer
*
* @param id Id for the host (A or B)
* @param layers Simulates the layes above and below the Transport Layer
* @param timerValue Timer value in ms (1000 ms = 1 sec)
* @param windowSize The amount of unACK:ed packets we can transmit
*/
public TransportLayer(String id, LayerSimulator layers, int timerValue, int windowSize){
mLayerSimulator = layers;
mId = id;
mTimerValue = timerValue;
mWindowSize = windowSize;
}
/**
* Called from the Application Layer when a message is sent to an other host
*
* @param message Message from the Application Layer
*/
public void toTransportLayer(String message){
if(mId.equals("A")){
seqNumber++;
}
else if(mId.equals("B")){
ackNumber++;
}
System.out.println("Received: " + message + " from the application layer");
Segment seg = new Segment (mId,seqNumber,ackNumber,message);
if(mWindowSize > 0){
mWindowSize--;
if(!sendBuffer.containsValue(seg)){
sendBuffer.put(seg.seqNumber, seg);
}
send(seg);
}
else{
System.out.println("Window full. Adding " + seg.payload + " to buffer.");
if(!sendBuffer.containsValue(seg)){
sendBuffer.put(seg.seqNumber, seg);
}
}
}
/**
* Called from the Network Layer when a segment arrives
*
* @param segment Segment that arrives from the Network Layer
*/
public void toTransportLayer(Segment segment)
{
// Checks if the segment is corrupted..
if(segment.isCorrect()){
// Receiving from B..
if(mId.equals("A")){
System.out.println(mId +" received ACK: " + segment.payload);
System.out.println("Timer stopped..");
mLayerSimulator.resetTimer();
mWindowSize++;
System.out.println("Sendbuffer size: " + sendBuffer.size());
if(!receivedACKS.containsValue(segment)){
receivedACKS.put(segment.ackNumber, segment);
expected = receivedACKS.size();
System.out.println("Received ACKS: " + receivedACKS.size());
}
if(receivedACKS.size() == sendBuffer.size()){
System.out.println("All packets received!");
}
if(sendBuffer.size() > receivedACKS.size() && mWindowSize > 0){
Segment next = sendBuffer.get(segment.ackNumber+1);
send(next);
}
}
// Receiving segments from A and sending acks.
else if(mId.equals("B")){
System.out.println( mId + " received: " + segment.toString());
// Check if segment has been received before.
if(recvBuffer.containsKey(segment.seqNumber)){
System.out.println("Already in buffer: " + segment.payload);
sendACK(segment);
}
else if(segment.seqNumber <= expected){
System.out.println("Not in recvbuffer, adding to recvBuffer and sends to application layer.");
mLayerSimulator.toApplicationLayer(segment.payload);
recvBuffer.put(segment.seqNumber, segment);
expected = recvBuffer.size();
sendACK(segment);
}
else{
System.out.println("Wrong sequence number: " + segment.seqNumber + ", expected " + expected + ", ignoring..");
}
}
}
else{
System.out.println(mId + " received a corrupt packet: " + segment.toString());
}
}
/**
* Function for sending acks
*/
public void sendACK(Segment s){
Segment ack = new Segment();
ack.seqNumber = -1;
ack.from = "B";
ack.ackNumber = s.seqNumber;
ack.payload = "ACK " + s.payload.charAt(0);
System.out.println( mId + " sent ACK: " + s.payload);
mLayerSimulator.toNetworkLayer(ack);
}
/**
* Called by the simulator when the specified time for the timer has passed
*/
public void timerInterrupt(){
System.out.println("TimerInterrupt: Clearing window and resending unacked segments..");
Segment segment;
mWindowSize = 2;
for(int i = 0; i < sentSegments.size(); i++){
segment = sentSegments.get(i);
if(segment != null && !checkACK(segment) && mWindowSize > 0){
mWindowSize--;
send(segment);
}
}
}
/**
* Checks if segment has been acked before.
*/
private boolean checkACK(Segment s){
if(receivedACKS.containsKey(s.seqNumber)){
return true;
}
else{
return false;
}
}
/**
* Sends a segment to the network layer. Stores the segment in sentSegments.
*/
private void send(Segment s){
System.out.println(mId + " sends " + s.toString());
if(!sentSegments.containsValue(s)){
sentSegments.put(s.seqNumber,s);
}
mLayerSimulator.toNetworkLayer(s);
mLayerSimulator.startTimer(mTimerValue);
}
}