
      CNT4704: Analysis of Computer Communication
            Networks
      Fall
            2011
       Home                     
            Lecture notes                       
            Assignment
      
      Programming Assignment 2: Reliable Data Transfer
            via Simple Transport Layer Protocol
    
    
      Due: Oct.31st by midnight (late submission by Nov. 5th midnight
      will have 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. 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: 
    
      -  Number of messages to simulate. The simulator (and
        your routines) will stop as soon as this number of messages have
        been passed down from layer 5 to your protocol, regardless of
        whether or not all of the messages have been correctly
        delivered. Thus, you need not worry about undelivered or
        unACK'ed messages still in your sender or in the channel when
        the emulator stops.
 
      Note that if you set this value to 1, your program will terminate
      immediately, before the message is delivered to the other side.
      Thus, this value should always be greater than 1.
      - Loss. You are asked to specify a packet loss
        probability. A value of 0.1 would mean that one in ten packets
        (on average) is lost.
 
      -  Corruption. You are asked to specify a packet
        corruption probability. A value of 0.2 would mean that one in
        five packets (on average) have their bits corrupted.
 
      Note that the contents of the payload, sequence, ack, or checksum
      fields can be corrupted. You must implement a checksum mechanism
      that covers the the data, sequence, and ack fields of the message
      (see hint for checksum).
      - Tracing. Setting a tracing value of 1, 2 or 3 will
        print out useful information about what is going on inside the
        emulation (e.g., what's happening to packets and timers). A
        tracing value of 0 will turn this off. A tracing value greater
        than 2 will display all sorts of odd messages that are for the
        emulator-debugging purposes (but that could also help you debug
        your code).
 
      You should keep in mind that real implementors do not have
      underlying networks that provide such nice information about what
      is going to happen to their packets!
      - Average time between messages from sender's layer5. You
        can set this value to any non-zero, positive value. Note that
        the smaller the value you choose, the faster packets will be be
        arriving to your sender.
 
    
    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 
    
      - Submit a zip file contains: (1). A project report. (2) the
        source code simulator.c for me to test; (3) your generated
        executable code and tell me where I can run your program (on
        eustis.eecs.ucf.edu or Windows computer).
 
      - To show me that you did successfully accomplished the
        assignment, in your project report: (1) describe in your report
        your overall program design with explanations for the design
        choices you might have made; (2) define and run a set of tests,
        showing me the print out of both the sending side and receiving
        side of the protocol, and explaining what the tests
        accomplished. 
 
      - For the test case, your procedures should print out some
        information whenever an event occurs at your sender or receiver
        (a message/packet arrival, or a timer interrupt) as well as any
        action taken in response. You should hand in output for a run up
        to the point (approximately) when 10 messages have been ACK'ed
        correctly at the receiver, a loss probability of 0.1, and a
        corruption probability of 0.3, and a trace level of 2. You
        should annotate your printout with highlighted color (or bald
        text) showing how your protocol correctly recovered from packet
        loss and corruption.
 
    
    Helpful Hints 
    
      -  Checksumming. You can use whatever approach for
        checksumming you want. Remember that the sequence number and ack
        field can also be corrupted. I would suggest a TCP-like
        checksum, which consists of the sum of the (integer) sequence
        and ack field values, added to a character-by-character sum of
        the payload field of the packet (i.e., treat each character as
        if it were an 8 bit integer and just add them together).
 
      - Note that any shared ``state'' among your routines needs to be
        in the form of global variables. Note also that any information
        that your procedures need to save from one invocation to the
        next must also be a global (or static) variable. For example,
        your routines will need to keep a copy of a packet for possible
        retransmission. It would probably be a good idea for such a data
        structure to be a global variable in your code. Note, however,
        that if one of your global variables is used by your sender
        side, that variable should NOT be accessed by the
        receiving side entity, since in real life, communicating
        entities connected only by a communication channel can not share
        global variables.
 
      - There is a float global variable called time that you
        can access from within your code to help you out with your
        diagnostics msgs (specially during the debugging and test
        phases).
 
      -  START SIMPLE. Set the probabilities of loss and
        corruption to zero and test out your routines. Better yet,
        design and implement your procedures for the case of no loss and
        no corruption, and get them working first. Then handle the case
        of one of these probabilities being non-zero, and then finally
        both being non-zero.
 
      -  Debugging. I'd recommend that you set the tracing
        level to 2 and put lots of printf statements in your code while
        your debugging your procedures.
 
    
    Extra Credit Assignment 
    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.
 
    
    
    Consult the basic assignment above for a general description of what
    to turn in. Besides what is stated there, you should hand in a test
    case that is at least 20 messages long, showing the window dynamics
    of your protocol.