Project 3: TCP
Deadlines
- Milestone 1: Friday, March 20 (by meeting scheduled with mentor TA, details announced toward end of the week)
- SRC component - Traffic filtering: Friday, April 3
- Milestone 2: Wednesday, April 8 (by meeting scheduled with mentor TA)
- Final submission: Friday, April 17 by 11:59pm EDT
Introduction
In this project, you will implement an RFC-compliant version TCP on top of your virtual IP layer from the previous assignment. In doing so, you will extend your virtual network stack to implement sockets, the key networking abstraction at the transport layer that allows hosts to keep track of multiple, simultaneous connections. Thus, you will not only learn about how TCP works, but you’ll learn about the OS infrastructure involved to support a networking stack.
Students report that this project is very challenging, but also very rewarding. When you are done here, you will really understand TCP, and the challenges involved in building a real-world network protocol.
Teams: You may work on this project on the same team you used for IP, or you may switch teams. At this point, you should have already filled out the TCP team form to tell us your team preferences. If you have any further concerns about your team or collaborating on this project, please contact the instructor ASAP.
Warning: You have roughly 5 weeks to complete this assignment, with two intermediate milestone deadlines for you to implement part of the functionality and check in with the course staff. We strongly recommend that you start early and take full advantage of this time–you will need it!
During this time, we remind you that we are here to help at all stages of the process! If you have questions at the design or implementation stage, we implore you to ask for help early so that we can make sure you are on the right track.
What you will build
In the IP project, you implemented handling to deliver virtual IP packets between nodes. To implement TCP, you will extend your vhost to use TCP to reliably send data between hosts. Ultimately, our goal will be to reliably send whole files between hosts, even under a lossy network that intentionally drops packets.
Your TCP implementation will have four major components:
- An abstraction for sockets which maps packets to individual connections. To work with sockets, you will build your own Socket API, similar to a real networking API, that allows “applications” to use your sockets to interact with the virtual network
- An implementation of the TCP state machine that implements connection setup and teardown
- The sliding window protocol that determines when to send and receive data, acknowledges received data, and retransmits data as necessary
- A new set of REPL commands that will allow you (and us) to test your API and send/receive files
The first three items make up what we call the TCP stack, which is another “layer” in your node that implements TCP. You can think about how your TCP stack fits into your existing IP implementation based on the figure below:

Fundamentally, your TCP stack will be another component in your host that receives packets from the IP layer, similar to how you handled RIP and test packets in the IP project. TCP uses IP protocol number 6—to receive packets, you will start by adding another protocol handler for TCP packets, and then your handler will map them to sockets.
In keeping with our emphasis on building good abstractions similar to a real networking stack, you should think of your socket API as the interface between your REPL commands and the rest of your TCP stack. This API should be similar to the socket API for the language you are using, though you are welcome to draw ideas from other languages as well. Even though your TCP stack will only be used by your vhost program, we recommend building your TCP implementation in a library/module/packge/etc, similar to your IP stack, which will help you keep your code organized.
How to navigate the docs
The remainder of this page outlines the major components of the implementation and points to relevant specifications—both in this document, and in RFC standards—and then provides information on grading and the project timeline.
Sockets and a Socket API
To interface with your TCP stack, you will create a representation for sockets within your node and an API to interact with them. Just like in a real OS, our virtual sockets will allow your node to maintain multiple simultaneous connections with other nodes on which you can send and receive data.
To do this, you will build your own API for creating and operating on virtual sockets, similar to the socket functions you have been using all semester, such as Listen, Dial/Connect, Read, Write, Close). You will add commands in your driver program that will interact with your sockets using your API, similar to how applications interact with the OS.
See the Socket API specification for a description of the main API features you will need and an example of what an API could look like. You don’t need to exactly implement the API shown here, but yours should have similar components.
TCP protocol
The core of your implementation will be what happens inside your TCP stack on each API call, and each time a socket receives a packet. In general, your implementation should follow RFC9293, the now-primary Internet standard for TCP—however, we have made some modifications to the standard to simplify certain elements and remove certain features that are not required. Thus, your implementation will be a minimal form of TCP that implements the most important features, with a few exceptions to help reduce the complexity.
See the TCP Implementation notes for a detailed description of the major features, our modifications, pointers to relevant RFCs, and other implementation-specific notes.
TCP REPL commands
To work with sockets and your socket API, you will add several new REPL commands that can create and send/receive on sockets, as well as send files.
For full details, see the REPL Commands specification.
Congestion Control (Extra credit)
Coming soon! We’ll release details about this after spring break.
SRC component: Navigating contexts traffic filtering
(NEW in Spring 2026) This project also contains a short [SRC component that you’ll complete independently of the rest of your TCP implementation. In this part, you’ll modify your vrouter to filter packets based on certain header info to block or limit certain types of content.
This part won’t require a lot of code, but should be an insightful look at how network devices can filter traffic, the power this can have over users, and the kinds of decisions that need to be made to implement it.
For more details see the SRC section.
The SRC component has a separate deadline in between Milestones I and II. To submit, simply push your work to your github repository and fill out the required form. For more details. see this section.
Getting Started
To get started, see the TCP getting started guide guide for information on how to start your new repository, pull our updated reference code, and how to run it. This document also lists the most important conceptual resources you should review before starting.
Gearups
We will have three gearups for TCP, one for each phase of your implementation:
- Gearup I (overview, prep for Milestone I): Thursday, March 12
- Gearup II (prep for Milestone II): TBA (details after spring break)
- Gearup III (everything else): TBA (details after spring break)
We’ve also posted the notes/recordings from last year’s gearups if you want to read ahead–for the latest links, see the getting started guide.
Reference implementation and interoperation
Like with IP, your implementation MUST be able to interoperate with the reference version, so please make sure you use it to test your work.
We will primarily grade your work by watching packets in Wireshark, so it is important that you build and format your packets correctly. For details on how to do this, see the getting started guide and this list of testing resources.
Note: We are using a new reference implementation this year. We have done our best to test it, but it is still likely that we will notice bugs. If you notice the reference behaving in a way that does not comply with the specification, please let us know by posting on EdStem–we’ll aggregate any known issues in our FAQ/reading list post. You are not responsible for replicating any buggy behavior, or altering your implementation to make thing work with a buggy reference (which is not a good design practice).
If you encounter issues forwarding packets with the reference vrouter, you should aim to fix these issues at the start of the project. If you have questions on how to do this, please contact the course staff–we can help!
Reference vhost (by request only)
If you do not feel confident in extending your work from the previous assignment to support TCP, please talk to us. We can advise you on critical areas of your IP implementation to prioritize. For example, your TCP implementation will not require RIP, so don’t worry if you had issues with this part.
If necessary, we may be to provide a reference implementation for a vhost that you can use as a starting point instead of your own implementation. If you are interested in this, please contact the instructor.
Roadmap and Grading
To help provide a framework for your work, this project is divided into three implementation phases with two intermediate milestone deadlines. At each milestone deadline, you’ll schedule a meeting with your mentor TA to check in on your implementation and ask questions.
Each phase will also have its own gearup, which will demonstrate the required functionality and provide an overview of the most important implementation details.
Milestone I
Similar to the IP milestone, you will complete this part by scheduling a meeting with the course staff (preferably your mentor TA) by Friday, March 20. We will release details on scheduling toward the end of this week.
For this meeting, your implementation should be able to demonstrate the following:
- Establishing new connections by properly following the TCP state diagram under ideal conditions. Sending data, handling error cases, or connection teardown are not required.
- When creating new connections, you should allocate a data structure pertaining to the socket—be prepared to discuss what you need to include in this data structure for the rest of your implementation
- To test establishing new connections, you should implement the
a,c, and (partially)lscommands to listen for, create, and list connections, respectively. - You should be able to view your TCP traffic in Wireshark to confirm you are using the packet header correctly. However, computing the TCP checksum is not required.
- For this milestone, you
SHOULD NOTattempt to implement retransmissions for dropped handshake packets. Instead, we recommend leaving this for the final stage, when you’ll build a generic implementation for retransmissions that works with data packets too.
In addition, you should consider how you will tackle the following:
- What data structures/state variables would you need to represent each TCP socket?
- How do you map incoming packets to sockets?
- How does the connection’s state (eg.
SYN_RECEIVED,ESTABLISHED, etc.) affect how you handle a packet?
Milestone II
You should schedule a subsequent milestone checkin with the course staff on or before Wednesday April 8. We will release scheduling details after spring break.
For this meeting, you should be able to implement the following:
- Aim to have the send and receive commands working over non-lossy links, based on our specifications for
VReadandVWrite. To do this, your send and receive should each be utilizing the sliding window, ACKing the data received, and updating the window. Implementing your sliding window will require an implementation for your send and receive buffers, including handling sequence numbers. - Retransmission, connection teardown, and handling out-of-order packets are NOT required yet. However, you should be able to talk about a plan for for how you will implement these (this is a great time to ask questions!).
- You should write an implementation for your REPL commands to send and receive files (
sfandrf) using your socket API. These commands do NOT need to work (nor is it expected that you’ll even run them yet!), but we recommend implementing them (to the point that your code compiles), so you can start planning how you’ll use your socket API to implement them, and so we can give you feedback on this. For any API functions you need that aren’t implemented yet (eg.VClose), just define empty functions so your code compiles.
Like the other milestone meetings, don’t worry too much about having a perfectly working implementation–the goal of this meeting is to give you time to check in with the course staff about your understanding and your design and so you have feedback for the remainder of the project. If you are stuck or are having issues, just bring what you have—you’ll receive credit so long as it’s clear you’ve been working on the problem.
Final deadline: Sending and receiving files
After Milestone II, you should implement the remaining components required to send and receive files using the sf and rf commands. Broadly, this will entail the following additional components:
- Retransmissions based on a computed RTO interval (from a measurement of SRTT)
- Receiving out-of-order packets
- Connection teardown
- Adhering to the receiver’s flow control window (including zero-window probing)
- A README and performance measurement (described in the next section)
To test your implementation, you should attempt to send files using the reference router under ideal conditions, and using a 2% loss rate. We will not test loss rates higher than 2%.
This final stage is where you should be spending the most time consulting the RFC. If you have questions on whether you need to handle a certain edge case not mentioned in our specifications, just ask! We don’t want you to be bogged down handling more edge cases than necessary to have a working implementation that can tolerate lossy links.
Documentation and Performance Measurement
In addition to your implementation, we want you to understand how your design decisions affect your TCP’s behavior and performance. For your final submission, you should include a README that documents your major design decisions and your reasoning for using them, including:
- What are the key data structures that represent a connection? (No need to list every field of every struct—just focus on what’s most critical for the major features, e.g., “to handle retransmissions, we use a queue that contains Y and Z”)
- At a high level, how does your TCP logic (sending, receiving, retransmissions, etc.) use threads, and how do they interact with each other (and your data structures)? (eg. “thread X is responsible for …, it waits for events Y and Z, and then sends Q”)
- If you could do this assignment again, what would you change? Any ideas for how you might improve performance?
- If you have any other major bugs or limitations not mentioned in the previous question, please describe the bug and how you have tried to debug the problem
In addition to your readme, we ask that you submit two other documentation components: a post-project form (similar to IP), and a measurement/discussion of your implementation’s performance.
Post-project forms
Before your grading meeting, you should complete two post-project forms (links and details will be available once the Gradescope submission is open):
-
TCP design survey (complete as a group): a super-quick survey about your major design decisions. We’ll use this info to help understand common ways to implement the project, which will help us calibrate recommendations for future years.
-
Post-project form (complete individually): a survey about your feedback on the project, and how your team collaborated (similar to IP)
Measuring performance
When you submit, we also ask that you investigate your implementation’s performance, but you are not required to highly optimize your implementation to meet a certain performance goal. While performance is key in all systems design, spending many iterations on optimizing your design is beyond the scope of this project. Instead, we only ask that you measure your implementation’s performance relative to the reference node and comment on it in your README.
To do this, measure the time to send a file of at least 1MB for both your node and the reference node using the linear-r1h2 network with no packet loss and compare the times. Ideally, your implementation should have performance on the same order of magnitude as the reference under the same test conditions.
Note Since our network runs exclusively on the loopback interface, your implementation’s performance is limited by CPU speed, so it’s not valid to compare measurements made on different systems. When taking measurements, you should always try with the reference first to establish a baseline, and then compare the relative times.
Packet capture: Finally, you should include a packet capture of a 1 MB file transmission between two of your nodes. To do this, send a file on the linear-r1h2 network with a 2% drop rate.
When submitting, you should “annotate” the following items in your capture file:
- The 3-way handshake
- One segment sent and acknowledged
- One segment that is retransmitted
- Connection teardown
To do this, list the frame numbers for each item in your README. For each annotation, you should evaluate if your implementation is responding appropriately per the specification–If you notice any issues, please document them.
For a demonstration of how to create a packet capture, see the Gearup III video.
Handing In and Interactive Grading
Before each milestone and the final deadline, you should submit your work by pushing to your git repository. Before the final deadline, we will also release instructions on how to submit your work to Gradescope.
After the Thanksgiving break, your mentor TA will arrange to meet with you for an interactive grading session to demonstrate the functionality of your program and grade the majority of it.
Similar to IP, you may continue to make minor tweaks/bugfixes and updates to your documentation (Readme, SRC, code cleanup) before grading meeting without incurring late days, but you should not be implementing major features or “fixing” code you have not previously tested. We may ask you about you original version when grading, and any changes you have made since that time.
Final Thoughts
Once again, we highly recommend getting started on this assignment soon—don’t wait to start until a few days before the deadlines! If you have questions, or need help with your implementation, always feel free ask for help or clarification or debugging. This is a hard assignment, but we are here to help you and provide resources, and we will be most effective at doing so if you ask early!
Although we expect compatibility between your TCP implementation and our own, do not get bogged down in the RFC from the start. It is much more important that you understand how TCP works on an algorithmic/abstract level and design the interface to your buffers from your TCP stack and from the virtual socket layer. For any corner cases or small details, the RFC will be your best friend, and our reference implementation should provide a useful example. Always feel free to ask if you have any questions about what you are required to do, or how to handle corner cases. We are here to help! You got this!