227 lines
7.4 KiB
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;
|
|
}
|
|
}
|
|
}
|