You are to implement routines coded in C to perform transport layer functions (much like socket code in a real operating system would). The functions you write will be called by (and will call) procedures that are provided for you which emulate a network environment.
The functions you will write are for the sending entity (Client also known as A) and the receiving entity (Server also known as B). Transfer of data (from client to server) and acknowledgements from server to client are required.
All of the data passed between the layers is encoded in one of two opaque data types: a message_t or a packet_t. You cannot access these types directly. You access parts of these types by using the routines declared in the message.h file and the packet.h file.
Variables of these types are created dynamically. You must call their
new_
functions to create instances of them before you can
use them.
Documentation about the routines that you must use to access those
data types are in the packet_t
documentation and the message_t
documentation.
All of the emulator routines you will need to access are declared in the file KRnet.h. Those function are described in the KRNet documentation. How the emulator works is described below.
Your routines will fill in the payload field from the message data passed down from the application layer (#5). The other packet fields will be used by your protocols to ensure reliable delivery, as we've seen in class. Stubs for all of the routines you are to complete are in the files, client.c and server.c. The purpose of those routines are described in the stucode documentation.
The code that you are given simulates a network with two hosts (A the client, and B the server). You are writing the transport layer code for each of the hosts. We are interested in four things that the simulation provides:
At the heart of the simulation is an event queue used for discrete time simulation. Every entry in the queue contains two things: (1) a time and (2) an event scheduled to occur at that time. Events are inserted into the queue in order of time and are normally removed from the head of the queue, but cancelling timers is the exception.
When you start a timer an event is inserted into the queue for the timer to go off. When you cancel a timer, the timer event is removed from the queue and so the queue is as if the timer had not been set.
The simulation could maintain a clock that advances every time unit and checks to see if any events are in the queue for the current time. But instead it uses a different method: when an event is removed from the head of the queue, the clock is updated to the time of that event. When there are no more events in the queue, the simulation stops.
The simulation code begins by generating events for the delivery of
messages from the client's application layer to the transport layer.
When your code calls sendToNWSlayer()
, the simulation
either buffers the packet to be sent later or inserts an event to
deliver the packet to the other host, depending on the return value of
your xCanSendMorePkt()
function.
If your code does not insert any events into the queue then, after generating the messages from the application layer, there will be nothing in the queue and the simulation will stop without any data having been delivered.
Here is an example of how you can use the simulation to deal with messages that come into the client's transport layer from above.
When the event queue finds an entry to generate a message from the
client, the simulation code passes the message to the clientOutput()
function
in your code.
Your clientOutput()
function should create a correct
packet from the message, simulate sending it to the server (using the
sendToNWSlayer()
function), and set a timer (using the
startTimer()
function).
Functions to get data into and out of messages and packets are described in the message_t and packet_t documentation.
If you are implementing the alternating bit protocol then remember
that your code should only be able to have one unacknowledged packet
at a time. The simulation will call your
clientCanSendMorePkt()
function to make sure that there
is only one packet in transit at a time.