Skip to content

Library implementing a reliable data transfer protocol (similar in certain ways to TCP) using UDP

Notifications You must be signed in to change notification settings

Khouderchah-Alex/libRDT

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Overview

This project is an implementation of a reliable data transfer protocol that was originally written for a networking course at UCLA. Most often, reliable data transfer over the Internet uses TCP, the implementation of which is generally in kernel space. This implementation is of a protocol somewhat different from TCP (a large difference being that TCP uses cumulative ACKs, whereas this protocol uses selective repeat), and the implementation itself is in user-space rather than kernel-space.

As an aside, this protocol is not the same as the Remote Desktop Protocol (commonly known as RDP). When "RDP" is used in the source code, it is meant as an abbreviation for Reliable Data Protocol, which is the name given to the protocol implemented here.

Implementation

The fundamental concept of our reliability protocol is the RdpConnection class, which contains all of the state necessary to perform the needed reliability functions---such as keeping track of unacked packets and their resend times---as well as providing all of the needed network-reliability functionality.

The structure of a packet is quite simple. Every packet consists of 64-bit header followed by some amount (between 0 and 1020 bytes) of data. The packet header contains the packet's sequence number (or ACK number if the packet is an ACK), the size of the packet including the header size, and any flags. The available flags are:

  • ACK -- for an acknowledgement
  • SYN -- for connection initialization
  • FIN -- for connection termination
  • RQST -- for a file request
  • FIRST -- for the first packet in a file transmission
  • LAST -- for the last packet in a file transmission

Unacked packets are kept track of by the use of a circular buffer. Every element of the circular buffer contains a pointer to its respective packet (or nullptr if the packet has been acked), a resend time, and a pointer to the unacked packet that has the next greatest resend time. That is, while the unacked packets are consecutive in memory by virtue of being placed in a circular buffer, they also form a linked list that is sorted based on earliest resend time. Note that the first unacked packet to be added to the circular buffer is not necessarily always the first to be resent (immediately after being resent, the first packet in the circular buffer will have the latest resend time). Every time a previously-unACKed packet is ACKed, its corresponding circular buffer element will be removed from the linked list. Furthermore, if the ACKed packet is the first element in the circular buffer, it will be removed from the circular buffer, along with any following elements that have already been ACKed. Whenever a packet is sent for the first time, it will be added to the circular buffer, placed at the end of the resend linked list, and a hash table mapping sequence numbers to circular buffer indices will be updated.

The private method RdpConnection::Update() performs much of the heavy-lifting for this protocol's implementation. This method gets the current time and resends any packets that need to be resent, updating the previously-described resend linked list while doing so. If a UDP datagram is waiting at the underlying UDP socket, the datagram will be read in, and the appropriate action will be performed depending on the flags. This method returns a different value depending on what type of packet, if any, was read in, as well as allowing the caller to optionally have the packet read into a local buffer, for further examining after Update() is called.

When the client requests a certain file from the server, it sends a packet containing the file name and sets the RQST flag in the message header. Note that the current implementation sends file requests in a single packet, and thus the file name cannot be more than 1020 characters. While this can be changed in future implementations, it was deemed unnecessary for this project, as most files are under 1020 characters to begin with (the skeptical reader can be referred to the Windows API, which often places a limit of 256 characters on file paths).

When the server sends file data to a client, it sets the FIRST flag for the first data packet and the LAST flag for the final data packet. The LAST flag is used so that there is no ambiguity on the client-side about when all of a file's data has been received. The FIRST flag is not entirely necessary, as the client is already aware of the next expected sequence number, but is useful for certain debugging situations (if, for example, there happens to be a bug in the code that sets the next expected sequence number).

With regards to connection initiation, the client-side implementation is quite simple, as clients are not expected to connect to an unknown number of hosts. The API for clients is thus very similar to the Unix Sockets API, where a client need only call RdpConnection::Connect() to connect to a server. On the server-side, a call to RdpConnection::Listen() creates a circular buffer of the specified backlog size, where each circular buffer is of a pending connection (which is simply a host address and the received sequence number). After this call, any received SYN packets from clients will result in a new element being added to the circular buffer---assuming there is still room in the circular buffer. A call to RdpConnection::Accept() will remove the first pending connection from this circular buffer---or block until a pending connection is available---and will complete the connection handshake with the corresponding client. At this point the server will be connected solely to that client until the connection is terminated, at which point RdpConnection::Accept() could be called again to service the next client. Future versions could be modified so that concurrent server applications could be written more easily.

About

Library implementing a reliable data transfer protocol (similar in certain ways to TCP) using UDP

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published