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/SAWSender2.java

227 lines
7.4 KiB
Java

import transport.*;
public class SAWSender2 extends Sender implements TimeoutAction {
private static final int S0 = 0;
private static final int ACK0 = 1;
private static final int S1 = 2;
private static final int ACK1 = 3;
private static final int ACK0FIN = 4; // waiting for ack0, then go to FIN
private static final int ACK1FIN = 5; // waiting for ack1, then go to FIN
private static final int FIN = 6; // waiting for final ack, then go to CLOSE
private static final int CLOSED = 7;
private static final int SENDER_TIMEOUT_MS = 5000;
private int state;
private byte[] data_pkt;
private int data_pkt_len;
public SAWSender2() {
state = S0;
data_pkt = new byte[MAX_PACKET_SIZE];
data_pkt_len = 0;
}
private void make_packet(int seq, byte[] buffer, int offset, int length) {
if (length + 1 > MAX_PACKET_SIZE) {
data_pkt_len = MAX_PACKET_SIZE;
} else {
data_pkt_len = length + 1;
}
data_pkt[0] = (byte) seq;
for (int i = 1; i < data_pkt_len; ++i)
data_pkt[i] = buffer[offset++];
}
private static void print_packet(byte[] buffer, int offset, int length) {
int end = offset + length;
System.out.print("\n[");
while (offset < end)
System.out.print(buffer[offset++] + " ");
System.out.print("]");
}
public void unreliableReceive(byte[] buffer, int offset, int length) {
// print_packet(buffer, offset, length);
switch (state) {
case S0:
System.err.println("SAWSender.unreliableReceive: received packet in S0. Ignoring.");
return;
case S1:
System.err.println("SAWSender.unreliableReceive: received packet in S1. Ignoring.");
return;
case ACK0:
System.out.print("ACK0:");
if (length > 0 && buffer[offset] == 0) {
System.out.print("->S1 ");
state = S1;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->ACK0 ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK0FIN:
System.out.print("ACK0FIN:");
if (length > 0 && buffer[offset] == 0) {
cancelTimeout(this);
goToFinState();
} else {
System.out.print("!->ACK1FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK1:
System.out.print("ACK1:");
if (length > 0 && buffer[offset] == 1) {
System.out.print("->S0 ");
state = S0;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->ACK1 ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK1FIN:
System.out.print("ACK1FIN:");
if (length > 0 && buffer[offset] == 1) {
cancelTimeout(this);
goToFinState();
} else {
System.out.print("!->ACK1FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case FIN:
System.out.print("FIN:");
if (length > 0 && buffer[offset] == 2) {
System.out.print("->CLOSED ");
state = CLOSED;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
}
}
public void timeoutAction() {
switch (state) {
case S0:
System.err.println("SAWSender.timeoutAction: timeout in S0. Ignoring timeout.");
return;
case S1:
System.err.println("SAWSender.timeoutAction: timeout in S1. Ignoring timeout.");
return;
case FIN:
case ACK0:
case ACK1:
case ACK0FIN:
case ACK1FIN:
System.out.print("T! ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
}
public int reliableSend(byte[] buffer, int offset, int length) {
switch (state) {
case S0:
System.out.print("S0:->ACK0 ");
blockSender();
blockDisconnect();
make_packet(0, buffer, offset, length);
state = ACK0;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
return data_pkt_len - 1;
case S1:
System.out.print("S1:->ACK1 ");
blockSender();
blockDisconnect();
make_packet(1, buffer, offset, length);
state = ACK1;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
return data_pkt_len - 1;
case ACK0:
case ACK1:
case ACK0FIN:
case ACK1FIN:
case FIN:
default:
System.err.println("SAWSender.reliableSend: sender should be blocked. Ignoring request");
return 0;
}
}
private void goToFinState() {
System.out.print("->FIN ");
blockSender();
blockDisconnect();
make_packet(2, null, 0, 0);
state = FIN;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
public void close() {
switch (state) {
case S0:
System.out.print("S0:");
goToFinState();
return;
case S1:
System.out.print("S1:");
goToFinState();
return;
case ACK0:
System.out.print("ACK0:->ACK0FIN ");
state = ACK0FIN;
return;
case ACK1:
System.out.print("ACK1:->ACK1FIN ");
state = ACK1FIN;
return;
case FIN:
case CLOSED:
default:
System.err.println("SAWSender.closeConnection: connection already closed or in closing state. Ignoring request");
return;
}
}
}