This repository has been archived on 2021-10-31. You can view files and clone it, but cannot push or open issues or pull requests.
NTW/hw2/src/impl/GBNTReceiver.java

101 lines
3.4 KiB
Java
Raw Normal View History

2020-05-08 12:29:08 +00:00
/*
* GBNTReceiver - Claudio Maggioni (2020)
* NTW2020 HW2
*
* No external source was used to create this file, other than regular course material.
*
* Note on implementation: change value of constant RECEIVER_TIMEOUT_MS to change the
* value of the receiver disconnection timeout.
*/
2020-05-06 17:39:56 +00:00
import transport.Receiver;
import transport.TimeoutAction;
public class GBNTReceiver extends Receiver implements TimeoutAction {
2020-05-07 15:08:12 +00:00
private char sequence;
2020-05-13 16:15:24 +00:00
private boolean firstPacket = true;
private static final int RECEIVER_TIMEOUT_MS = 15000;
2020-05-07 15:08:12 +00:00
private State state = State.SETUP;
enum State {
SETUP,
2020-05-08 12:25:09 +00:00
RECEIVING,
CLOSED,
2020-05-07 15:08:12 +00:00
}
private static byte[] generateACK(char sequence) {
byte[] dest = new byte[2];
dest[0] = (byte) ((sequence >> 8) & 0xFF);
dest[1] = (byte) (sequence & 0xFF);
return dest;
}
private static char readBigEndianChar(byte[] src, int offset) {
2020-05-08 12:25:09 +00:00
return (char) (((src[offset] << 8) & 0xFF00) | (src[offset + 1] & 0xFF));
2020-05-07 15:08:12 +00:00
}
private static char incrementAndRollover(char c) {
return (char) ((c + 1) % 65536);
2020-05-06 17:39:56 +00:00
}
@Override
2020-05-07 15:08:12 +00:00
public void timeoutAction() {
2020-05-08 12:25:09 +00:00
System.out.println("Disconnect timeout triggered");
2020-05-07 15:08:12 +00:00
try {
disconnect();
2020-05-08 12:25:09 +00:00
deliver(null, 0, END_OF_STREAM);
state = State.CLOSED;
2020-05-07 15:08:12 +00:00
} catch (java.lang.InterruptedException ex) {
System.out.println("Thread interrupted. Exiting directly.");
System.exit(0);
}
}
2020-05-06 17:39:56 +00:00
2020-05-07 15:08:12 +00:00
@Override
protected void unreliableReceive(byte[] bytes, int offset, int length) {
2020-05-08 12:25:09 +00:00
if (state == State.CLOSED) return;
cancelTimeout(this);
setTimeout(RECEIVER_TIMEOUT_MS, this);
2020-05-07 15:08:12 +00:00
switch(this.state) {
case SETUP:
if (length != 2) {
2020-05-08 12:25:09 +00:00
if (!firstPacket) {
2020-05-07 15:08:12 +00:00
state = State.RECEIVING;
this.unreliableReceive(bytes, offset, length);
2020-05-08 12:25:09 +00:00
return;
2020-05-07 15:08:12 +00:00
}
2020-05-08 12:25:09 +00:00
return;
2020-05-07 15:08:12 +00:00
}
2020-05-08 12:25:09 +00:00
sequence = readBigEndianChar(bytes, offset);
System.out.println("Synchronization ACK: " + (int) sequence);
2020-05-07 15:08:12 +00:00
unreliableSend(bytes, offset, 2);
firstPacket = false;
break;
case RECEIVING:
if (length == 2) { // if packet is a close packet
2020-05-08 12:25:09 +00:00
char a = readBigEndianChar(bytes, offset);
if (incrementAndRollover(this.sequence) != a) return; // ignore if not synchronized
2020-05-07 15:08:12 +00:00
this.unreliableSend(bytes, offset, 2);
2020-05-08 12:25:09 +00:00
System.out.println("Received valid FIN packet");
2020-05-07 15:08:12 +00:00
timeoutAction();
}
if (length < 3) return;
2020-05-08 12:25:09 +00:00
char seq = readBigEndianChar(bytes, offset);
2020-05-13 16:15:24 +00:00
System.out.print("Read sequence: " + (int) seq + " Exp: " + (int) incrementAndRollover(sequence)+ " -> ");
2020-05-08 12:25:09 +00:00
2020-05-13 16:15:24 +00:00
if (seq == incrementAndRollover(sequence)) {
2020-05-08 12:25:09 +00:00
this.deliver(bytes, offset + 2, length - 2);
2020-05-07 15:08:12 +00:00
sequence = incrementAndRollover(sequence);
2020-05-13 16:15:24 +00:00
System.out.print("OK! ");
} else {
System.out.print("Drop ");
2020-05-07 15:08:12 +00:00
}
2020-05-13 16:15:24 +00:00
System.out.println("Sending ack: "+ (int) sequence);
this.unreliableSend(generateACK(sequence), 0, 2);
2020-05-07 15:08:12 +00:00
break;
}
2020-05-06 17:39:56 +00:00
}
}