CNT4704: Analysis of Computer Communication Networks

Fall 2013

Home                      Lecture notes                        Assignment


Programming Assignment 2: Reliable Data Transfer via Simple Transport Layer Protocol
(Due: Oct. 16th midnight via webcourse, late submission by Oct. 21st midnight with 20 points off)


Overview

In this second programming assignment, you will be writing the sending and receiving transport-level code for implementing a simple reliable data transfer protocol. The basic assignment will be to implement the Alternating Bit Protocol (rdt3.0); the extra credit assignment will be to implement a Go-Back-N protocol. You should enjoy this assignment, as your implementation will differ very little from what would be required in a real-world situation.

Since we do not have standalone machines (with an Operating System that you can modify), your code will have to execute in a simulated environment provided by the textbook. However, the programming interface provided to your routines (i.e., the calls to/from your code from/to the layer above - passing/receiving data to/from the application layer; and the calls to/from your code from/to the layer below - passing/receiving data to/from the layer below) is very close to what is done in an actual UNIX environment. Starting/stopping of timers are also simulated, and timer interrupts will cause your timer handling routine to be activated.

The routines you will write

The procedures you will write are for the sending entity (node A) and the receiving entity (node B). Only unidirectional transfer of data (from A to B) is required. Of course, the B side will have to send packets to A to acknowledge (positively or negatively) receipt of data. Your routines are to be implemented in the form of the procedures as described below. These procedures will be called by (and will also make calls to) procedures that the textbook authors have written which emulate a network environment which can cause packet error and packet loss. The overall structure of the environment is shown in the following:

The unit of data passed between the upper layer and your protocol is a message, which is declared as:

struct msg {
  char data[20];
  };
Your sending entity will thus receive data in 20-byte chunks from layer 5; your receiving entity should deliver 20-byte chunks of correctly received data to layer 5 at the receiving side.

The unit of data passed between your routines and the network layer is the packet, which is declared as:

struct pkt {
   int seqnum;
   int acknum;
   int checksum;
   char payload[20];
    };
Your routines will fill in the payload field from the message data passed down from layer 5. The other packet fields will be used by your protocol to insure reliable delivery, as we've seen in class.

The routines you will write are detailed below. As noted above, such procedures in real-life would be part of the operating system, and would be called by other procedures in the operating system.

A_output(message),
where message is a structure of type msg, containing data to be sent to the B-side.
     This routine will be called whenever the upper layer at the sending side (node A) has a message to send. It is the job of your protocol to insure that the data in such a message is delivered in-order, and correctly, to the receiving side upper layer. You should return a value of 1 if this data packet was accepted for transmission and -1 otherwise.
A_input(packet),
where packet is a structure of type pkt.
      This routine will be called whenever a packet sent from the B-side (i.e., as a result of a tolayer3()being done by a B-side procedure) arrives at the A-side. packetis the (possibly corrupted) packet sent from the B-side.
A_timerinterrupt()
This routine will be called when A's timer expires (thus generating a timer interrupt). You'll probably want to use this routine to control the retransmission of packets. See starttimer() and stoptimer() below for how the timer is started and stopped.

A_init()
This routine will be called once, before any of your other A-side routines are called. It can be used to do any required initialization.

B_input(packet),
where packet is a structure of type pkt.
        This routine will be called whenever a packet sent from the A-side (i.e., as a result of a tolayer3()being done by a A-side procedure) arrives at the B-side. packetis the (possibly corrupted) packet sent from the A-side.
B_init()
This routine will be called once, before any of your other B-side routines are called. It can be used to do any required initialization.

Software Interfaces

The procedures described above are the ones that you will write. The textbook authors have written the following routines which can (and should) be called by your routines:

starttimer(calling_entity,increment),
where calling_entity is either 0 (for starting the A-side timer) or 1 (for starting the B side timer), and increment is a float value indicating the amount of time that will pass before the timer interrupts. A's timer should only be started (or stopped) by A-side routines, and similarly for the B-side timer.      To give you an idea of the appropriate increment value to use: a packet sent into the network takes an average of 5 time units to arrive at the other side when there are no other messages in the medium.
stoptimer(calling_entity),
where calling_entity is either 0 (for stopping the A-side timer) or 1 (for stopping the B side timer).
tolayer3(calling_entity,packet),
where calling_entity is either 0 (for the A-side send) or 1 (for the B side send), and packet is a structure of type pkt. Calling this routine will cause the packet to be sent into the network, destined for the other entity.
tolayer5(calling_entity,message),
where calling_entity is either 0 (for A-side delivery to layer 5) or 1 (for B-side delivery to layer 5), and message is a structure of type msg.  Calling this routine will cause data to be passed up to layer 5. With unidirectional data transfer (which is what you have to implement), you would only be calling this routine with calling_entity equal to 1 (delivery to the B-side).
The simulated network environment

A call to procedure tolayer3() sends packets into the medium (i.e., into the network layer). Your procedures A_input() and B_input() are called when a packet is to be delivered from the medium to your protocol layer.

The medium is capable of corrupting and losing packets. However, it will not reorder packets. When you compile your procedures and with the rest of the simulator and run the resulting program, you will be asked to specify values regarding the simulated network environment:

The Basic Assignment

You are to write code for the procedures, A_output(), A_input(), A_timerinterrupt(), A_init(), B_input(), B_init() which together will implement a stop-and-wait (i.e., the Alternating Bit protocol, which we referred to as rdt3.0 on the textbook and class notes), for a unidirectional transfer of data from the node A to node B. Node B should only send back ACK message.

You should choose a somewhat large value for the average time between messages from sender's layer 5, so that your sender is seldom called while it still has an outstanding, unacknowledged message it is trying to send to the receiver. If this occurs, your procedure should return a value of -1 and ignore (drop) that chunk of data, which will inform layer 5 that your protocol is busy trying to send previous data. In this case, layer 5 will reattempt to send this data at a later point in time. If your protocol has space in its window, you should accept the data chunk and return a value of 1.

You should put your procedures inside the file called simulator.c, which contains the simulation engine. You will need the initial version of this file (simulator.c), containing the emulation routines, and the stubs for your procedures.

This assignment can be completed on any machine supporting C, whether Unix or Windows.

What to turn in

Helpful Hints

Extra Credit Assignment (10 points)

You are to write the procedures, A_output(),A_input(),A_timerinterrupt(),A_init(),B_input(), and B_init() which together will implement a Go-Back-N unidirectional transfer of data from the A-side to the B-side, with a window size of 8 (or some other larger fixed number). Your protocol can use cumulative ACK messages.

Some new considerations for your Go-Back-N code (which do not apply to the Alternating Bit protocol) are:

A_output(message),
Your A_output() routine will now sometimes be called when there are outstanding, unacknowledged messages in the medium - implying that you will have to buffer multiple messages in your sender. Also, you'll need buffering in your sender because of the nature of Go-Back-N: sometimes your sender will be called but it won't be able to send the new message because the new message falls outside of the window.

Your sender should buffer only one window worth of packets and use the signaling mechanism (returning a -1 from this procedure) to indicate that the window is full. In order to fill up the sender's window, you should set the average time between messages from sender's layer 5 to a small value, like 2.
 

A_timerinterrupt()
This routine will be called when A's timer expires (thus generating a timer interrupt). Remember that you've only got one timer, and may have many outstanding, unacknowledged packets in the medium, so you'll have to think a bit about how to use this single timer.

  For this Go-Back-N task, you should hand in a test case that has successfully transmitted 15 messages, showing the window dynamics of your protocol.