Skip to content

Instantly share code, notes, and snippets.

@wudaown
Created March 11, 2018 15:30
Show Gist options
  • Save wudaown/baed8684d47e15d4acdf74535b030ddb to your computer and use it in GitHub Desktop.
Save wudaown/baed8684d47e15d4acdf74535b030ddb to your computer and use it in GitHub Desktop.
/*===============================================================*
* File: SWP.java *
* *
* This class implements the sliding window protocol *
* Used by VMach class *
* Uses the following classes: SWE, Packet, PFrame, PEvent, *
* *
* Author: Professor SUN Chengzheng *
* School of Computer Engineering *
* Nanyang Technological University *
* Singapore 639798 *
*===============================================================*/
import java.util.Timer;
import java.util.TimerTask;
public class SWP {
/*========================================================================*
the following are provided, do not change them!!
*========================================================================*/
//the following are protocol constants.
public static final int MAX_SEQ = 7;
public static final int NR_BUFS = (MAX_SEQ + 1) / 2;
// the following are protocol variables
private int oldest_frame = 0;
private PEvent event = new PEvent();
private Packet out_buf[] = new Packet[NR_BUFS];
//the following are used for simulation purpose only
private SWE swe = null;
private String sid = null;
//Constructor
public SWP(SWE sw, String s) {
swe = sw;
sid = s;
}
//the following methods are all protocol related
private void init() {
for (int i = 0; i < NR_BUFS; i++) {
out_buf[i] = new Packet();
}
}
/**
* @param e Packet Event
*/
private void wait_for_event(PEvent e) {
swe.wait_for_event(e); //may be blocked
oldest_frame = e.seq; //set timeout frame seq
}
private void enable_network_layer(int nr_of_bufs) {
//network layer is permitted to send if credit is available
swe.grant_credit(nr_of_bufs);
}
private void from_network_layer(Packet p) {
swe.from_network_layer(p);
}
private void to_network_layer(Packet packet) {
swe.to_network_layer(packet);
}
private void to_physical_layer(PFrame fm) {
System.out.println("SWP: Sending frame: seq = " + fm.seq +
" ack = " + fm.ack + " kind = " +
PFrame.KIND[fm.kind] + " info = " + fm.info.data);
System.out.flush();
swe.to_physical_layer(fm);
}
private void from_physical_layer(PFrame fm) {
PFrame fm1 = swe.from_physical_layer();
fm.kind = fm1.kind;
fm.seq = fm1.seq;
fm.ack = fm1.ack;
fm.info = fm1.info;
}
/*===========================================================================*
implement your Protocol Variables and Methods below:
*==========================================================================*/
// Input buffer
private boolean no_ack = true;
private boolean between(int a, int b, int c) {
return ((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a));
}
private void send_frame(int fk, int frame_nr, int frame_expected, Packet buffer[]) {
PFrame s = new PFrame(); // temporary variable to hold the frame
s.kind = fk; // Assign the Event type to outgoing frame
if (fk == PFrame.DATA) {
s.info = buffer[frame_nr % NR_BUFS]; // encapsulate packet if it is data frame
}
s.seq = frame_nr; // assign frame number
s.ack = (frame_expected + MAX_SEQ) % (MAX_SEQ + 1); // piggybacking the acknowledge number for frame receive
if (fk == PFrame.NAK) {
no_ack = false; // generate NAK
}
to_physical_layer(s); // push to physical layer
if (fk == PFrame.DATA) {
start_timer(frame_nr); // start timer for retransmission
}
stop_ack_timer(); // stop ack timer if any
}
public void protocol6() {
init();
Packet in_buff[] = new Packet[NR_BUFS]; // Inbound Buffer
int ack_expected = 0; // Acknowledgement Number expected from other party
int next_frame_to_send = 0; // Frame Number to be send
int frame_expected = 0;
int too_far = NR_BUFS;
int i = 0;
PFrame frame = new PFrame();
boolean arrived[] = new boolean[NR_BUFS];
Timer timeout[] = new Timer[NR_BUFS];
for (int j = 0; j < NR_BUFS; j++) {
arrived[j] = false;
in_buff[j] = new Packet();
}
// attach timer to each frame or rather buffer
for (int k=0; k<=NR_BUFS; k++) {
frameTimer[k] = new Timer();
}
enable_network_layer(NR_BUFS);
while (true) {
wait_for_event(event);
switch (event.type) {
case (PEvent.NETWORK_LAYER_READY):
// When network layer is ready
// retrieve packet from upper network layer
from_network_layer(out_buf[next_frame_to_send % NR_BUFS]);
// encapsulate the packet into data frame and push to physical layer
send_frame(PFrame.DATA, next_frame_to_send, frame_expected, out_buf);
// increment counter for next frame to be send
next_frame_to_send = inc(next_frame_to_send);
break;
case (PEvent.FRAME_ARRIVAL):
// Frame arrival event trigger the virtual machine
// to retrieve frame from physical layer
// if it is a data frame check the sequence number
// and NAK flag from here either start a ACK timer
// or issue a NAK packet
from_physical_layer(frame);
if (frame.kind == PFrame.DATA) {
// NAK frame send if frame is not expected
if ((frame.seq != frame_expected) && no_ack) {
send_frame(PFrame.NAK, 0, frame_expected, out_buf);
} else {
// else start timer
start_ack_timer();
}
if (between(frame_expected, frame.seq, too_far) && (!arrived[frame.seq % NR_BUFS])) {
arrived[frame.seq % NR_BUFS] = true;
in_buff[frame.seq % NR_BUFS] = frame.info;
while (arrived[frame_expected % NR_BUFS]) {
// handle piggybacked ack frame
// pass frame and advance in window
to_network_layer(in_buff[frame_expected % NR_BUFS]);
no_ack = true;
arrived[frame_expected % NR_BUFS] = false;
// advance lower bound of receiver window
frame_expected = inc(frame_expected);
// advance upper bound of receiver window
too_far = inc(too_far);
// start ack timer to check whether ack is needed
start_ack_timer();
}
}
}
if ((frame.kind == PFrame.NAK) && between(ack_expected, (frame.ack + 1) % (MAX_SEQ + 1), next_frame_to_send)) {
send_frame(PFrame.DATA, (frame.ack + 1) % (MAX_SEQ + 1), frame_expected, out_buf);
}
while (between(ack_expected, frame.ack, next_frame_to_send)) {
// stop timer since frame arrive correctly
stop_timer(ack_expected % NR_BUFS);
// increment the next ack number expected
ack_expected = inc(ack_expected);
// granted credit
enable_network_layer(1);
}
break;
case (PEvent.CKSUM_ERR):
if (no_ack) {
send_frame(PFrame.NAK, 0, frame_expected, out_buf);
}
break;
case (PEvent.TIMEOUT):
send_frame(PFrame.DATA, oldest_frame, frame_expected, out_buf);
break;
case (PEvent.ACK_TIMEOUT):
send_frame(PFrame.ACK, 0, frame_expected, out_buf);
break;
default:
System.out.println("SWP: undefined event type = "
+ event.type);
System.out.flush();
}
}
}
/* Note: when start_timer() and stop_timer() are called,
the "seq" parameter must be the sequence number, rather
than the index of the timer array,
of the frame associated with this timer,
*/
private static final int TIMER_DURATION = 600;
private static final int ACK_DURATION = 300;
private Timer[] frameTimer = new Timer [NR_BUFS + 1]; //+1 is for the final buffer for frame timer
private class EventTimerTask extends TimerTask {
private int seq;
public EventTimerTask(int seq) {
this.seq = seq;
}
@Override
public void run(){
swe.generate_timeout_event(seq);
}
}
private class Ack_TimerTask extends TimerTask {
@Override
public void run(){
swe.generate_acktimeout_event();
}
}
private void start_timer(int seq) {
//frameTimer starts with seq
stop_timer(seq); //cancel timer if it is still on
frameTimer[seq%NR_BUFS] = new Timer();
frameTimer[seq%NR_BUFS].schedule(new EventTimerTask(seq), TIMER_DURATION); //scheduling of time task
}
private void stop_timer(int seq) {
// Stop the timer attach to the frame
frameTimer[seq%NR_BUFS].cancel();
}
private void start_ack_timer() {
// Only one timer exists at any point of time
// stop the current first
// ACK_DURATION has to be shorted than TIMER_DURATION
// so that frame retransmission timer does not expired
// and retransmit.
stop_ack_timer();
frameTimer[NR_BUFS] = new Timer();
frameTimer[NR_BUFS].schedule(new Ack_TimerTask(), ACK_DURATION);
}
private void stop_ack_timer() {
// Stop the timer attach to the frame
frameTimer[NR_BUFS].cancel();
}
private int inc(int frame_nr) {
frame_nr = (frame_nr + 1) % 8;
return frame_nr;
}
}//End of class
/* Note: In class SWE, the following two public methods are available:
. generate_acktimeout_event() and
. generate_timeout_event(seqnr).
To call these two methods (for implementing timers),
the "swe" object should be referred as follows:
swe.generate_acktimeout_event(), or
swe.generate_timeout_event(seqnr).
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment