Assignment 7 2020 Problem
Assignment 7 2020 Problem
Objective:
The objective of this assignment is to build support for reliable communication over an
unreliable link. The unreliable link will be implemented with a UDP socket. You will have
to give APIs to the user that will do reliable send/receive over this unreliable link by
appropriate implementation of the APIs.
Problem Statement:
In this assignment, you will be building support for reliable communication over an
unreliable link. In particular, you will build a message-oriented, reliable, exactly-once
delivery communication layer (you can think of it as TCP without byte-orientation and
in-order delivery, or UDP with reliable delivery). Message ordering is not needed, so
messages with higher ids can be delivered earlier.
You have been introduced to the function calls socket, bind, sendto, and recvfrom to
work with UDP sockets. Assume that the TCP sockets are not there. We know that UDP
sockets are not reliable, meaning that there is no guarantee that a message sent using a
UDP socket will reach the receiver. We want to implement our own socket type, called
MRP (My Reliable Protocol) socket, that will guarantee that any message sent using a
MRP socket is always delivered to the receiver exactly once. However, unlike TCP
sockets, MRP sockets may not guarantee in-order delivery of messages. Thus
messages may be delivered out of order (later message delivered earlier). However, a
message should be delivered to the user exactly once.
Sending an application message for the first time: The user calls an API function
r_sendto() to send its message. The send API adds a unique id (use a counter starting
from 0) to the application message and adds it to the send buffer with its id and IP-port.
Handling message received (application and ACK) from the socket and
Retransmission of messages: The signal handler will be called in regular intervals.
Whenever the handler gets invoked, it needs to do the following tasks one-by-one:
● It first calls the function HandleReceive() :- Here the program will try to receive
the next message from the udp socket by calling recvfrom() function with flag
MSG_DONTWAIT. MSG_DONTWAIT makes the recvfrom() call non-blocking,
so the program will not wait if there is no message available. The
HandleReceive() function calls recvfrom() function till there is some message
available and performs actions accordingly. Once a message is received by this
function, it does the following:
○ Check if it is an application message or an ACK message.
○ If it is an application message, call a function HandleAppMsgRecv(),
which does the following:
■ check the received-message-id table if the id has already been
received (duplicate message). If it is a duplicate message, the
message is dropped, but an ACK is still sent. If it is not a duplicate
message, the message is added to the receive buffer (without the
id) including source IP-port, and an ACK is sent. The function
returns after that.
○ If it is an ACK message, call a function HandleACKMsgRecv(), which
does the following:
■ If the message is found in the unacknowledged-message table,
it is removed from the table. If not (duplicate ACK), it is ignored.
The function returns after that.
After handling the message, the HandleReceive() function returns.
Receiving a message by the user: The user calls an API function r_recvfrom(),
which either finds a message in the receive buffer or not. If there is a message in the
receive buffer, the first message is removed and given to the user, and the function
returns the no. of bytes in the message returned. If there is no message in the receive
buffer, the user process is (spin) blocked. The function will return when there is a
message in the receive buffer (if a message comes, it will be put in the buffer by the
signal handler).
You can assume there will be exactly one MRP socket created by a process for send
and receive, so only one set of the variables are needed.
You will be implementing an API with a set of function calls r_socket(), r_bind(),
r_sendto(), r_recvfrom(), and r_close() that implement MRP sockets. The
parameters to these functions and their return values are exactly the same as the
corresponding functions of the UDP socket, except for r _socket. The functions will
be implemented as a static library. Any user wishing to use MRP sockets will write a
C/C++ program that will call these functions in the same sequence as when using UDP
sockets. The library will be linked with the user program during compilation.
A brief description of the functions is given below. All calls should return 0 on success
(except r_recvfrom() which should return the no. of bytes in the message) and -1 on
error.
● r_socket – This function opens an UDP socket with the socket call. It also
dynamically allocates space for all the tables, and initializes them. It sets the timer by
calling the setitimer() function. The parameters to these are the same as the
normal socket( ) call, except that it will take only SOCK_MRP as the socket type.
● r_bind – Binds the UDP socket with the specified address-port using the bind call.
● r_sendto – Adds a message id at the beginning of the message and puts it to the
send buffer if it is not full. If the send buffer is full, this function will (spin) block the
process until there is some space available to put this message.
● r_recvfrom – Looks up the received-message table to see if any message is
already received in the underlying UDP socket or not. If yes, it returns the first
message and deletes that message from the table. If not, it blocks the call. To block
the r_recvfrom call, you can use a sleep call to wait for some time and then see
again if a message is received. r_recvfrom, similar to recvfrom, is a blocking call by
default and returns to the user only when a message is available.
● r_close – closes the socket; remove the timer and frees all memory associated with
the socket. If any data is there in the received-message table, it is discarded.
Design the message formats and the u nacknowledged-message table and the
received-message tables properly. Note that, sometimes sendto and recvfrom behave
differently during interrupt (i.e. signal). Consult the man pages and handle them
accordingly.
dropMessage() function:
As the actual number of drops in the lab environment will be near 0, you will need to
simulate an unreliable link. To do this, in the library, add a function called
dropMessage() with the following prototype in your library:
int dropMessage(float p)
where p is a probability between 0 and 1. This function first generates a random number
between 0 and 1. If the generated number is < p, then the function returns 1, else it
returns 0. Now, in the signal handler code, after a message is received (by the
recv_from() call on the UDP socket), first make a call to dropMessage(). If it returns 1, do
not take any action on the message (irrespective of whether it is data or ack) and just
return to wait to receive the next message. If it returns 0, continue with the normal
processing in the signal handler. Thus, if dropMessage() returns 1, the message
received is not processed and hence can be thought about as lost. Submit your code
with the dropMessage() calls in the signal handler, do NOT remove these calls
from your code before you submit.
The value of T should be 2 seconds (#define in rsocket.h). The value of the parameter p
(the probability) should also be specified in the rsocket.h file with a #define. When you
test your program, vary p from 0.05 to 0.5 in steps of 0.05 (0.05, 0.1, 0.15, 0.2….,0.45,
0.5). For each p value, for the same string, count the average number of transmissions
made to send each character (total number of transmissions that are made to send the
string /no. of characters in the string) . You can do this by adding a counter in the
appropriate part of the signal handler code. Report this in a table in the beginning of the
file documentation.txt (see below).
What to submit:
You should submit the following files in a single zip file:
1. rsocket.h
2. rsocket.c
3. Makefile (this should include all commands to create a library named librsocket.a
from your source files.)
4. A file called documentation.txt containing description of the different files. This file
should include:
a. The table described above for the no. of retransmissions
b. A list of all messages and their formats, with a brief description of the use
of each field
c. A list of all data structures used and a brief description of their fields
Do not include any other file in your submission, and upload the submission only
in zip format.