CS 60 Computer Networks
Lab4
Simple Reliable Transport (SRT) - Implementing Signalling (SIG)
In this lab, you will implement the signaling protocol for the Simple Reliable Transport (SRT), which is
part of DartNet. Lab4 does not deal with the transfer of SRT data segments. Rather, SYN, SYNACK, and
FIN, FINACK are implemented. Lab5 will deal with data transfer and specifically the implementation of a
“sliding window” protocol for efficient data transfer between the client and server (unidirectional reliable
byte stream).
At the end of this lab you will have really good sense for how protocols such as TCP establish connections
between hosts and how the internal mechanisms resolve issue such as lost or corrupt signaling packets
(e.g., SYN is lost).
We have already discussed the design of SRT and how it fits into DartNet.
Before you read another line of this programming assignment please read or re-read the
Lecture 11’s notes on SRT design .
While quite a lot of information is given on APIs, data structures, connection management, and FSMs
you will need to think about how to implement the SRT function calls as part of the SRT
layer.
Submitting assignment:
Use svn as normal.
Please make sure that the lab4 directory contains a simple text file, named README, describing anything
“unusual” about how your solutions should be located, executed, and considered; and a Makefile to build
the source.
Your lab4 should have the following structure and files.
[atc@dhcp-212-223 lab4] ls *
Makefile ReadMe
client:
app_client.c srt_client.c srt_client.h
common:
constants.h seg.c seg.h
server:
app_server.c srt_server.c srt_server.h
____________________________________________________________________________
Important source and header files - read them
OK, now you have read the design notes, look at these important files - browse them for now, we will be
back.
Note, all the files listed below plus other files (e.g., makefile, README, etc.) needed for this
lab can be found in this tarball file: lab4handout.tar.gz . Save this and work from this
tarball for your assignment.
There are a number of files that show examples of the app_client.c and app_server.c that show the SRT
Socket API. In addition, we provide a number of header files that define constants used by SRT that you
should include in your code.
The challenge of this lab is to implement the function calls used by app_client.c and app_server.c. So take
a look at those example application files. This is very similar to the C socket programming we have done
alreay. The functions will be implemented in the srt_client.c and srt_server.c code;
the skeleton code for these two files is given below (but use the tarball above, as
source).
So, let’s look at the files now:
Clients application - examples of client using SRT Socket API.
app_client.c.
Client side data structures and prototypes needed to implement the client side SRT protocol
srt_client.h.
srt_client.c.
Server application - examples of server side SRT Socket API.
app_server.c.
Server side data structures and prototypes needed to implement the server side SRT protocol
srt_server.h.
srt_server.c.
SNP APIs - header file. SRT header and segement data structure, SNP prototypes.
seg.h.
Constants
constants.h.
Coding FSMs
Please familiarize yourself with the following in the SRT design document: .
1) Connection set up and tear down diagrams.
2) The SRT client and server side FSMs.
You will need to make sure that in all the code that you write (which is essentially all the SRT function
calls in Fig. 1) you drive the code as a state machine. For example, consider the following code
snippet:
int srt_client_disconnect(int sockfd) {
client_tcb_t *tp;
tp=gettcb(sockfd);
if (tp == NULL)
return -1;
switch(tp->state) {
case CLOSED:
......;
break;
case SYNSENT:
......;
break;
case CONNECTED:
......;
break;
case FINWAIT:
......;
break;
default:
}
}
This gives a simple and clean way to write code that is state machine driven. Try and use this style
consistently in your solution. Many of the SRT functions you have to write can have a structure
like this. There are some exceptions. The snp_sendseg() and snp_recvseg() do not have to
embedd SRT FSM information. However, snp_recvseg() is complicated by the fact that it
has to parse bytes streams in search of the special start “!&” and end “!#” characters as
delimiters of a segment (SYN, SYNACK, FIN, FINACK). A good way to implement this parser
of bytes to find the start of a segment and then end - is to design a little FSM for handing
incoming bytes and keeping state on the stream in snp_recvseg(). Just an idea - many ways to do
this.
SRT Functions to Implement
Fig.1) shows that the SRT runs directly on the overlay and not over SNP which will be our final goal in a
future lab. You assignment revolves around implementing all the functions shown in the diagram. When
you look at the client and server FSMs you will see TIMEOUTs for retransmitting packets. How are you
going to implement timers? How does your client side and server side break down into threads. Ask
yourself what is the minimal number of threads needed to implement the client and server
side.
Note, that the SRT sits directly on the “thin” overlay layer for Lab4. The overlay in this case simply
implements a TCP connection between the client and server SRT transport protocols. The overlay just
contains a direct TCP connection between the client and the server. The overlay_start() and
overlay_stop() functions create the drect TCP connection between the client and the server.
overlay_start() should return the TCP socket descriptor. overlay_stop() closes the TCP connection. The
code needed to do this is essentially the C code we developed for the socket programming
assignment. Therefore, you already have 90% of the code for the overlay. For lab4, the API
functions need to implement are shown in Fig. 1. These are a subset of the DartNet API function
calls.
You will need to implement SNP_sendseg() and SNP_recvseg() function calls to send and
receive segments using the overlay’s TCP connection. In the case of TCP data is sent as byte
stream. Note, in order to send data segments over the overlay TCP connection, we need to add
delimiters in the byte stream. In SRT uses the special characters “!&” to indicate the start of
a segment and the special characters “!#” to indicate the end of a segment. Two notes on
these delimiters. First, these characters should not occur in the data sent between the client
and the service. This is a restriction (and the protocol would operate incorrectly if “!&” or
“!#” were to occur in the byte stream from the client. So you should make sure your data
does not include these pairs of special control characters. Second, delimiters are necessary
because the receiving side of a STR packet (i.e., STR header + STR segment) needs to know
when it successfully receives an SRT packet. This is one way to do it. Probably the simplest
approach.
Because the overlay is built from TCP rather than say UDP we do not have any loss. To allow the
overlay to look as if it runs across lossy links and that packets can be lost in the Internet we
implement loss() function invoked in SNP_recvseg() when an SRT packet is received to discard
the segment with probability PKT_LOSS_RATE to simulate the packet loss to force SRT
to recover the missing segments which can be SRT DATA packets, SYN, SYNACK, FIN,
and FINACK. The SRT protocol must be able to recover correctly from loss of any of these
packets.
See the design document for more details on all the function calls. We do go into this below with more
specifics than the design notes.
SRT client-side prototypes
In what follows, we provide more details on each of the client-side prototypes you will implement. These
are just guidelines you are free to implement the protocol as you like.
//
//
// SRT socket API for the client side application.
// ===================================
//
// In what follows, we provide the prototype definition for each call and limited pseudo code representation
// of the function. This is not meant to be comprehensive - more a guideline.
//
// You are free to design the code as you wish.
//
// NOTE: When designing all functions you should consider all possible states of the FSM using
// a switch statement (see the Lab4 assignment for an example). Typically, the FSM has to be
// in a certain state determined by the design of the FSM to carry out a certain action.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void srt_client_init(int conn);
// This function initializes the TCB table marking all entries NULL. It also initializes
// a global variable for the overlay TCP socket descriptor ‘‘conn’’ used as input parameter
// for snp_sendseg and snp_recvseg. Finally, the function starts the seghandler thread to
// handle the incoming segments. There is only one seghandler for the client side which
// handles call connections for the client.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_client_sock(unsigned int client_port);
// This function looks up the client TCB table to find the first NULL entry, and creates
// a new TCB entry using malloc() for that entry. All fields in the TCB are initialized
// e.g., TCB state is set to CLOSED and the client port set to the function call parameter
// client port. The TCB table entry index should be returned as the new socket ID to the client
// and be used to identify the connection on the client side. If no entry in the TC table
// is available the function returns -1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_client_connect(int socked, unsigned int server_port);
// This function is used to connect to the server. It takes the socket ID and the
// server’s port number as input parameters. The socket ID is used to find the TCB entry.
// This function sets up the TCB’s server port number and a SYN segment to send to
// the server using snp_sendseg(). After the SYN segment is sent, a timer is started.
// If no SYNACK is received after SYNSEG_TIMEOUT timeout, then the SYN is
// retransmitted. If SYNACK is received, return 1. Otherwise, if the number of SYNs
// sent > SYN_MAX_RETRY, transition to CLOSED state and return -1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_client_send(int sockfd, void* data, unsigned int length);
// Send data to a srt server. You do not need to implement this for Lab4.
// We will use this in Lab5 when we implement a Go-Back-N sliding window.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_client_disconnect(int sockfd);
// This function is used to disconnect from the server. It takes the socket ID as
// an input parameter. The socket ID is used to find the TCB entry in the TCB table.
// This function sends a FIN segment to the server. After the FIN segment is sent
// the state should transition to FINWAIT and a timer started. If the
// state == CLOSED after the timeout the FINACK was successfully received. Else,
// if after a number of retries FIN_MAX_RETRY the state is still FINWAIT then
// the state transitions to CLOSED and -1 is returned.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_client_close(int sockfd);
// This function calls free() to free the TCB entry. It marks that entry in TCB as NULL
// and returns 1 if succeeded (i.e., was in the right state to complete a close) and -1
// if fails (i.e., in the wrong state).
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void *seghandler(void* arg);
// This is a thread started by srt_client_init(). It handles all the incoming
// segments from the server. The design of seghanlder is an infinite loop that calls snp_recvseg(). If
// snp_recvseg() fails then the overlay connection is closed and the thread is terminated. Depending
// on the state of the connection when a segment is received (based on the incoming segment) various
// actions are taken. See the client FSM for more details.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SRT server-side prototypes
In what follow we provide more details on each of the server-side prototypes you will implement. These are
just guidelines you are free to implement the protocol as you like.
//
//
// SRT socket API for the server side application.
// ===================================
//
// In what follows, we provide the prototype definition for each call and limited pseudo code representation
// of the function. This is not meant to be comprehensive - more a guideline.
//
// You are free to design the code as you wish.
//
// NOTE: When designing all functions you should consider all possible states of the FSM using
// a switch statement (see the Lab4 assignment for an example). Typically, the FSM has to be
// in a certain state determined by the design of the FSM to carry out a certain action.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void srt_server_init(int conn);
// This function initializes the TCB table marking all entries NULL. It also initializes
// a global variable for the overlay TCP socket descriptor ‘‘conn’’ used as input parameter
// for snp_sendseg and snp_recvseg. Finally, the function starts the seghandler thread to
// handle the incoming segments. There is only one seghandler for the server side which
// handles call connections for the client.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_server_sock(unsigned int port);
// This function looks up the client TCB table to find the first NULL entry, and creates
// a new TCB entry using malloc() for that entry. All fields in the TCB are initialized
// e.g., TCB state is set to CLOSED and the server port set to the function call parameter
// server port. The TCB table entry index should be returned as the new socket ID to the server
// and be used to identify the connection on the server side. If no entry in the TCB table
// is available the function returns -1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_server_accept(int sockfd);
// This function gets the TCB pointer using the sockfd and changes the state of the connetion to
// LISTENING. It then starts a timer to ‘‘busy wait’’ until the TCB’s state changes to CONNECTED
// (seghandler does this when a SYN is received). It waits in an infinite loop for the state
// transition before proceeding and to return 1 when the state change happens, dropping out of
// the busy wait loop. You can implement this blocking wait in different ways, if you wish.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_server_recv(int sockfd, void* buf, unsigned int length);
// Receive data to a srt client. Recall this is a unidirectional transport
// where DATA flows from the client to the server. Signaling/control messages
// such as SYN, SYNACK, etc.flow in both directions. You do not need to implement
// this for Lab4. We will use this in Lab5 when we implement a Go-Back-N sliding window.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int srt_server_close(int sockfd);
// This function calls free() to free the TCB entry. It marks that entry in TCB as NULL
// and returns 1 if succeeded (i.e., was in the right state to complete a close) and -1
// if fails (i.e., in the wrong state).
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void *seghandler(void* arg);
// This is a thread started by srt_server_init(). It handles all the incoming
// segments from the client. The design of seghanlder is an infinite loop that calls snp_recvseg(). If
// snp_recvseg() fails then the overlay connection is closed and the thread is terminated. Depending
// on the state of the connection when a segment is received (based on the incoming segment) various
// actions are taken. See the client FSM for more details.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
SNP prototypes
In what follows, we provide more details on each of the snp prototypes you will implement. These are just
guidelines you are free to implement the protocol as you like.
//
// SNP API for the client and server sides
// =======================================
//
// In what follows, we provide the prototype definition for each call and limited pseudo code representation
// of the function. This is not meant to be comprehensive - more a guideline.
//
// You are free to design the code as you wish.
//
// NOTE: snp_sendseg() and snp_recvseg() are services provided by the networking layer
// i.e., simple network protocol to the transport layer.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int snp_sendseg(int connection, seg_t* segPtr);
// Send a SRT segment over the overlay network (this is simply a single TCP connection in the
// case of Lab4). TCP sends data as a byte stream. In order to send segments over the overlay TCP connection,
// delimiters for the start and end of the packet must be added to the transmission.
// That is, first send the characters ‘‘!&’’ to indicate the start of a segment; then
// send the segment seg_t; and finally, send end of packet markers ‘‘!#’’ to indicate the end of a segment.
// Return 1 in case of success, and -1 in case of failure. snp_sendseg() uses
// send() to first send two chars, then send() again but for the seg_t, and, then
// send() two chars for the end of packet.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int snp_recvseg(int connection, seg_t* segPtr);
// Receive a segment over overlay network (this is a single TCP connection in the case of
// Lab4). We recommend that you recieve one byte at a time usin recv(). Here you are looking for
// ‘‘!&’’ characters then seg_t and then ‘‘!#’’. This is a FSM of sorts and you
// should code it that way. Make sure that you cover cases such as ‘‘#&bbb!b!bn#bbb!#’’
// The assumption here (fairly limiting but simplistic) is that !& and !# will not
// be seen in the data in the segment. You should read in one byte as a char at
// a time and copy the data part into a buffer to be returned to the caller.
//
// IMPORTANT: once you have parsed a segment you should call seglost(). Here is the code
// for seglost():
//
// if segment is lost (we emulate that the packet is lost on the network) the return 1;
// otherwise we assume that the packet is received OK and return 0
//
// int seglost() {
// int random = rand()%100;
// if(random<LOSS_RATE*100)
// return 1;
// else
// return 0;
//}
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++