Computer Network: Project
Introduction
This project is divided into two checkpoints. You will implement a tiny FTP client and server in the first checkpoint based on TCP. in the second checkpoint, you will go one step further and implement a simple but amazing TCP protocol.
It is important to note that this project is a group task done by 3-4 students. If you have difficulty finding your team members, don't hesitate to contact the TAs. This is a hard project, so start early and feel more than welcome to ask questions, both TAs and the teacher will be more than welcome to help you debug, design, and provide hints in working on this project. Hope you enjoy your journey on this project!
1 Checkpoint 1
The purpose of checkpoint 1 is to give you experience in developing File Transfer Protocol(FTP). You will write a simple client and server using a subset of the File Transfer Protocol (FTP) [RFC 959] .
Why are we doing this? As we know, software school has a tradition, that is, we have to submit our labs and projects to our school FTP server. So it's a good way to commemorate FTP, as it is gradually drowning in history(Just a joke ^_^). Actually, FTP plays an important role in the early stage of the Internet because of its convenience for transmission. Implementing such a protocol strictly following the RFC can make you have a deeper understanding of the Internet.
1.1 Overview
During this project, you will implement an FTP client/server to download/upload files based on TCP protocol in C language.
The File Transfer Protocol (FTP) is a standard communication protocol to transmit computer files from a server to a client through a computer network. FTP is built on a client-server model architecture using separate control and data connections between the client and the server. FTP users may authenticate themselves with a clear-text sign-in protocol, normally in the form of a username and password, but can connect anonymously if the server is configured to allow it.
1.2 Tiny FTP Client / Server
You will implement an FTP server and an FTP client using C language. Among them, the FTP server stores files, and users can use the FTP client to access file resources located on the FTP server through your FTP protocol.
You don't have to implement all FTP commands. To make this project easier, the following minimum implementation is required for your server, the syntax of the command is indicated in the parenthesis.
get (get [remote_filename]) -- Copy file with the name [remote_filename] from remote directory to local directory. put (put [local_filename]) -- Copy file with the name [local_filename] from local directory to remote directory. delete (delete [remote_filename]) – Delete the file with the name [remote_filename] from the remote directory.
ls (ls) -- List the files and subdirectories in the remote directory.
pwd (pwd) – Print the current working directory on the remote machine. quit (quit) – End the FTP session.
1.3 Notice
You should implement two FTP transmission methods: ASCII code and binary. Suppose the client copies a file that contains simple ASCII text. In that case, FTP will usually automatically adjust the file's contents to facilitate the interpretation of the file into the file format stored on the server.
It would help if you implemented a reasonable exception-handling scheme. For example, when the user has illegal input, provide proper error prompts to ensure the program's robustness.
You can design the details that are not clear in the experimental requirements as long as they are reasonable.
2 Checkpoint 2
TCP is a transport layer protocol that enables processes on different devices to communicate reliably. TCP’s beauty stems from its ability to give applications a simple abstraction with strong guarantees, even though the underlying network only provides best-effort delivery. Best effort delivery means that packets can be lost, duplicated, reordered, and that there is no guarantee that the bandwidth available will remain the same (due to changes in the network itself or interference from other traffic).
2.1 Overview
In this checkpoint, your goal is to implement the underlying mechanisms that are the basis of TCP’s strong guarantees. You will focus on implementing an algorithm that is very similar to TCP Reno. However, TCP has evolved since Reno, which is now just one of many congestion control algorithms (CCAs) in use. Companies use different CCAs depending on their context.
In this checkpoint, you will implement the TCP three-way handshake, RTT estimation, as well as TCP’s sliding window algorithm.
2.2 CMU-TCP
Figure1: CMU-TCP header format.
You will implement CMU-TCP, a simple reliable transport protocol. Different from a traditional TCP implementation, CMU-TCP segments are carried inside UDP payloads, this allows you to implement CMU-TCP from user space using UDP sockets and benefit from UDP’s existing multiplexing/demultiplexing capabilities. As in traditional TCP, CMU-TCP connects two end points, an initiator and a listener. While a CMU-TCP header shares many fields with traditional TCP, its structure is different. Figure 1 shows the
You will build CMU-TCP using UDP sockets, crafting packets and transmitting them yourself. UDP will not re-transmit lost packets, and UDP has no control over when a packet is sent (i.e., the sending throughput). You must augment UDP with these features yourself. As both sides (initiator and listener) can send and receive, you will need to track a lot of data and information.
2.2.1 Starter Code and Implementation Details
The starter code is hosted on GitHub: https://github.com/17ssDP/cmu-tcp . See README.md for a description of the files in the starter code and instructions on how to run it.
The API exposed to applications is defined in cmu_tcp.h and consists of four core functions whose signatures should not be changed (cmu_socket, cmu_close, cmu_read, and cmu_write). An application requests a new CMU- TCP socket by calling the cmu_socket function. The application specifies whether it is a listener (e.g., a server) or an initiator (e.g., a client). For listener sockets, the application specifies the port to listen on. For initiator sockets, the application specifies the IP and port number of the listener socket. After initializing the socket, the application can use cmu_write to transmit data and cmu_read to receive data.
All multi-byte integer fields must be transmitted in network byte order. ntoh(), hton(), and similar functions are important. We also provide many helper functions to get and set different packet fields, automatically dealing with endianness. Refer to cmu_packet.h for their signatures and cmu_packet.c for their implementation. You must also be careful when comparing sequence number as they might wrap around. When comparing sequence numbers you may use one of the provided helper functions (before, after, between) in cmu_packet.h.
You can verify that your headers are sent correctly using Wireshark or tcpdump (Section 2.4.3), which allow you to inspect packet data, including the full Ethernet frame. When viewing a packet, you should see something similar to the image below; in this case the payload starts at 0x0020. The IDENTIFIER (15441) shows up in hexadecimal as 0x00003C51.
2.3.1.2 Experimental Component
For the experimental component, you will measure the ‘flow completion time’ (or ‘FCT’: how long it takes to finish transferring a file) under different loss rates (0%, 0.1% and 0.01%). You should fix the base rate at 10 Mbps and set the delay to 20 ms. Apply these settings to both the server and the client. For each one of the different loss rates, you will transfer files of a range of sizes: 512 bytes, 4 KiB, 32 KiB, 256 KiB, and 2 MiB. Hence, you will measure 15 total scenarios: five different file sizes × three loss rates.
Hypothesis. Given the implementation in the starting code (baseline) and your complete CP2 implementation, before running any experiment, we ask that you hypothesize about your expected results.
(1) Derive an equation to predict how long (in number of RTTs) it will take for the initial implementation to transfer a file of size with loss rate . Recall that the throughput is fixed (10 Mbps) and the RTT is also fixed at 40 ms (20 ms delay on each end).
(2) Derive an equation to predict how long (in number of RTTs) it will take for your CP2 implementation to transfer a file of size with loss rate . (Don’t forget the handshake and, if you implemented it, teardown time!)
(3) Using these two equations, predict in which scenarios your CP2 implementation would outperform the baseline. 5
Similarly, predict when the baseline implementation would outperform your CP2 implementation. Provide a chart or table with an entry for every testing scenario predicting how many RTTs it will take to complete the file transfer using either the baseline or your new implementation.
2.4 Resources
This section describes some of the recommended tools for developing and testing CMU-TCP.
2.4.1 Development Environment
For this checkpoint, you can do all of your development on your own machine using containers. You are also welcomed to keep using AWS for your development if that is more convenient. You should install Docker [12] and Vagrant [11] on the machine you plan to develop on. We have provided a Vagrantfile specifying two containers, a client and a server.
The following sections describe the tools that are already installed on the containers to help you test your code. You can also install any additional tools you need.
2.4.2 Control network characteristics with tcconfig
tcconfig [6] is installed on the containers to let you artificially control the characteristics of the virtual network that interconnects the containers. The initial default settings on the containers are a 20 ms delay on both containers (so the total RTT is 40 ms), and 100 Mbps bidirectional bandwidth with no loss.
Refer to the references for more information on how to use tcconfig to simulate different network characteristics that will be useful for testing your code, including packet loss, reordering, and corruption.
2.4.3 Capture and analyze packets with tcpdump and tshark
tcpdump [7] and Wireshark (and its equivalent command line program: tshark [8]) are installed on the containers to allow you to capture packets sent between the containers and analyze them later. We provide the following files in the directory project-2_15-441-2/utils/ to help with packet analysis (feel free to modify these if you want):
tcp.lua: This ia a Lua plugin so that Wireshark can dissect our custom CMU-TCP packet format [9]. capture_packets.sh shows how you can pass this file to tshark to parse packets. To use the plugin with the Wireshark GUI on your machine, you should add this file to Wireshark’s plugin folder [10].
2.4.4 Analyzing a large file transfer
The starter code client.c and server.c will transmit a small file, cmu_tcp.c between the client and server. You should also test your code by transmitting a large file, capturing the packets, and plotting the congestion window over time. You can use the utilities described in Section 2.4.3 to create capture.pcap and graph.pdf by running the following commands:
vagrant@client:/vagrant/project-2_15-441-2$ ./client
(In the server container) When the transfer finishes, stop the packet capture and generate a graph:
vagrant@server:/vagrant/project-2_15-441-2$ make vagrant@server:/vagrant/project-2_15-441-2$ ./utils/capture_packets.sh start capture.pcap vagrant@server:/vagrant/project-2_15-441-2$ ./server
vagrant@server:/vagrant/project-2_15-441-2$ ./utils/capture_packets.sh stop capture.pcap vagrant@server:/vagrant/project-2_15-441-2$ ./gen_graph.py
2.4.5 Running tests with pytest
There are many ways that you can write tests for your code. To help get you started, pytest [14] is installed on the containers and we provide some examples of basic tests in test/test_cp1.py. Running make test will run these tests automatically. You should expand these tests or use a different tool to test your code. However, be sure to update the Makefile so that make test must still runs your tests. As in checkpoint 1, you should also use standard C debugging tools including gdb and Valgrind, which are also installed on the containers.
2.4.6 Automatic code formatting and analysis
We provided a pre-commit [15] configuration file that you can use to automatically format and statically check your code whenever you run make format inside one of the containers. You can check .pre-commit-config.yaml to see all the hooks that we run. You can optionally also install it in your development machine. This will ensure that it always runs all the hooks whenever you create a new commit. If you want to install pre-commit in your local machine, run pip3 install pre-commit. Then run pre-commit install in the root directory of the cmu-tcp repository to install the pre- commit hooks.