RFC 793
Transmission Control Protocol
RFC 793: Transmission Control Protocol ๐
Okay bestie, welcome to the legendary TCP spec ๐ Let's start with the title block tea โโจ
The title is Transmission Control Protocol, part of the DARPA Internet Program Protocol Specification, and it's dated September 1981 ๐ . It was prepared for the Defense Advanced Research Projects Agency's Information Processing Techniques Office at 1400 Wilson Boulevard in Arlington, Virginia 22209, and the actual writing was done by the Information Sciences Institute at the University of Southern California, 4676 Admiralty Way, Marina del Rey, California 90291 ๐๏ธ. The editor is Jon Postel ๐. This is the DoD Standard TCP, and it replaces RFC 761 ๐. The IEN documents numbered 129, 124, 112, 81, 55, 44, 40, 27, 21, and 5 are listed with it too ๐.
Here's the table of contents, exactly as the original lays it out ๐บ๏ธ
PREFACE ........................................................ iii
1. INTRODUCTION ..................................................... 1
1.1 Motivation .................................................... 1
1.2 Scope ......................................................... 2
1.3 About This Document ........................................... 2
1.4 Interfaces .................................................... 3
1.5 Operation ..................................................... 3
2. PHILOSOPHY ....................................................... 7
2.1 Elements of the Internetwork System ........................... 7
2.2 Model of Operation ............................................ 7
2.3 The Host Environment .......................................... 8
2.4 Interfaces .................................................... 9
2.5 Relation to Other Protocols ................................... 9
2.6 Reliable Communication ........................................ 9
2.7 Connection Establishment and Clearing ........................ 10
2.8 Data Communication ........................................... 12
2.9 Precedence and Security ...................................... 13
2.10 Robustness Principle ......................................... 13
3. FUNCTIONAL SPECIFICATION ........................................ 15
3.1 Header Format ................................................ 15
3.2 Terminology .................................................. 19
3.3 Sequence Numbers ............................................. 24
3.4 Establishing a connection .................................... 30
3.5 Closing a Connection ......................................... 37
3.6 Precedence and Security ...................................... 40
3.7 Data Communication ........................................... 40
3.8 Interfaces ................................................... 44
3.9 Event Processing ............................................. 52
GLOSSARY ............................................................ 79
REFERENCES .......................................................... 85
PREFACE ๐
This document describes the DoD Standard Transmission Control Protocol (TCP) ๐ . There were nine earlier editions of the ARPA TCP spec, and this standard is built on them and borrows heavily from them ๐. So many people contributed, both to the ideas and to the wording, which is honestly iconic. This edition clears up several details, gets rid of the end-of-letter buffer-size adjustments, and redescribes the letter mechanism as a push function โจ.
Jon Postel Editor
1. INTRODUCTION ๐ฆ
Okay, so TCP is meant to be a highly reliable host-to-host protocol ๐ช. It's for hosts talking to each other across packet-switched computer communication networks, and across interconnected systems made of those networks.
This doc explains the functions TCP performs, the program that implements it, and its interface to the programs or users that need its services ๐งฉ.
1.1. Motivation
Computer communication systems are playing a bigger and bigger role in military, government, and civilian settings ๐. This document focuses mostly on military computer communication needs, especially robustness when communication is unreliable and availability when there's congestion ๐ก๏ธ. But plenty of these problems show up in the civilian and government sectors too, so it's not just a military thing.
As strategic and tactical computer communication networks get developed and deployed, it's essential to connect them and to have standard interprocess communication protocols that can support a wide range of applications ๐. Anticipating the need for those standards, the Deputy Undersecretary of Defense for Research and Engineering declared the TCP described here to be a basis for DoD-wide interprocess communication protocol standardization ๐.
TCP is a connection-oriented, end-to-end reliable protocol ๐. It's designed to sit in a layered hierarchy of protocols that support applications spanning multiple networks ๐ฅ. It gives reliable interprocess communication between pairs of processes on host computers attached to separate but interconnected networks. Very few assumptions are made about how reliable the protocols below TCP are. TCP just assumes it can get a simple, potentially unreliable datagram service from the lower-level protocols ๐คทโโ๏ธ. In principle, TCP should be able to run on a wide range of communication systems, from hard-wired connections all the way up to packet-switched or circuit-switched networks ๐.
TCP is based on concepts first described by Cerf and Kahn in [1] ๐ง . It fits into a layered protocol architecture just above the basic Internet Protocol [2] ๐ฐ. That lower layer gives TCP a way to send and receive variable-length segments of information wrapped in internet datagram "envelopes" โ๏ธ. The internet datagram is how source and destination TCPs in different networks get addressed. The internet protocol also handles any fragmentation or reassembly of TCP segments needed to get them through multiple networks and interconnecting gateways ๐. On top of that, it carries precedence, security classification, and compartmentation info for the TCP segments, so that information can travel end-to-end across multiple networks ๐.
Protocol Layering
+---------------------+
| higher-level |
+---------------------+
| TCP |
+---------------------+
| internet protocol |
+---------------------+
|communication network|
+---------------------+
Figure 1
Most of this document is written with TCP implementations in mind that live on the same host computer as the higher-level protocols ๐ . Some computer systems hook up to networks through front-end computers, which house the TCP and internet protocol layers along with network-specific software ๐ฅ๏ธ. The TCP spec describes an interface to the higher-level protocols that still seems implementable for the front-end case, as long as a suitable host-to-front-end protocol is in place ๐ฏ.
1.2. Scope
TCP is meant to provide a reliable process-to-process communication service in a multinetwork environment ๐ซ. It's also meant to be a host-to-host protocol in common use across multiple networks ๐.
1.3. About This Document
This document is the specification of the behavior required of any TCP implementation ๐. That covers both how it interacts with higher-level protocols and how it interacts with other TCPs ๐ค. The rest of this section gives a very quick look at the protocol interfaces and how things operate. Section 2 sums up the philosophy behind the TCP design ๐งโโ๏ธ. Section 3 is the deep dive: a detailed description of what TCP has to do when different events happen (new segments arriving, user calls, errors, and so on), plus the exact formats of TCP segments ๐.
1.4. Interfaces
TCP talks to user or application processes on one side, and to a lower-level protocol like Internet Protocol on the other side ๐.
The interface between an application process and TCP is shown in pretty good detail ๐ธ. It's a set of calls that feel a lot like the calls an operating system gives an application for handling files ๐. For example, there are calls to open and close connections, and calls to send and receive data on established connections. TCP is also expected to be able to talk to application programs asynchronously ๐ฌ. Implementors get a lot of freedom to design interfaces that suit their particular operating system environment, but a minimum level of functionality is required at the TCP/user interface for any valid implementation ๐ซถ.
The interface between TCP and the lower-level protocol is basically unspecified, except that it's assumed some mechanism exists that lets the two layers pass information to each other asynchronously โก. Usually the lower-level protocol is the one that specifies this interface. TCP is designed to work in a very general environment of interconnected networks, and the lower-level protocol assumed throughout this document is the Internet Protocol [2] ๐ธ.
Bestie, that's the end of part 1! ๐ More parts are coming, starting with 1.5 Operation, so stay tuned ๐ง
1.5. Operation โจ
okay so the main job of TCP is giving processes a reliable, securable logical circuit (aka a connection) with each other. ๐ Doing that on top of a less reliable internet system takes facilities in these areas:
- Basic Data Transfer
- Reliability
- Flow Control
- Multiplexing
- Connections
- Precedence and Security
Here's how TCP handles each one, bestie ๐
Basic Data Transfer
TCP can move a continuous stream of octets in each direction between its users. It does this by packaging some octets into segments for transit through the internet system. Generally, the TCPs decide for themselves when to block up data and send it on, whatever works best for them ๐ซถ
Sometimes users need to be sure that everything they handed to TCP actually got sent ๐ญ That's what the push function is for. The sending user indicates that data should be pushed through to the receiving user, and a push makes the TCPs promptly forward and deliver the data up to that point. The exact push point might not be visible to the receiving user, and push doesn't add any record boundary marker either ๐
Reliability
TCP must recover from data that is damaged, lost, duplicated, or delivered out of order by the internet communication system. ๐ฅ The way it does this is by giving every octet a sequence number and requiring a positive acknowledgment (ACK) from the receiving TCP. If the ACK doesn't arrive within a timeout interval, the data gets retransmitted. At the receiver, sequence numbers put segments that showed up out of order back in the right order and get rid of duplicates. Damage gets handled with a checksum on each segment, which the receiver checks, and damaged segments get discarded ๐ง
As long as the TCPs keep functioning properly and the internet system doesn't become completely partitioned, no transmission errors will mess with the correct delivery of data. TCP recovers from errors in the internet communication system, so it's giving resilient ๐
Flow Control
TCP gives the receiver a way to control how much data the sender sends ๐ธ It does this by returning a "window" with every ACK. The window is a range of acceptable sequence numbers beyond the last segment successfully received. It tells the sender how many octets it may transmit before getting further permission. Main character energy for the receiver, honestly โจ
Multiplexing
Lots of processes inside a single Host need to use TCP at the same time, so TCP provides a set of addresses called ports within each host ๐ฆ Put a port together with the network and host addresses from the internet communication layer and you get a socket. A pair of sockets uniquely identifies each connection. A single socket can be used in multiple connections at once, which is so iconic ๐
Each Host handles binding ports to processes on its own. It's useful, though, to attach commonly used processes (like a "logger" or a timesharing service) to fixed sockets that are published to the public. Then people can reach those services through the known addresses. Finding out about other processes' ports can involve more dynamic mechanisms ๐
Connections
The reliability and flow control mechanisms we just talked about need TCPs to set up and keep track of certain status information for each data stream. That whole bundle, which includes sockets, sequence numbers, and window sizes, is called a connection ๐ Each connection is uniquely specified by a pair of sockets identifying its two sides.
When two processes want to talk, their TCPs must first set up a connection (initializing the status information on each side) ๐ซถ When they're done, the connection gets terminated or closed so the resources can be freed up for other stuff.
Connections have to be set up between unreliable hosts over an unreliable internet communication system, so TCP uses a handshake mechanism with clock-based sequence numbers. This avoids erroneous initialization of connections. It's giving security guard energy ๐
Precedence and Security
TCP users can indicate the security and precedence of their communication ๐ Default values are provided for when these features aren't needed, so you're never stuck picking โจ
2. PHILOSOPHY ๐ง
2.1. Elements of the Internetwork System
The internetwork environment is made of hosts connected to networks, and those networks are interconnected via gateways ๐ Here it's assumed the networks could be local networks (like the ETHERNET) or large networks (like the ARPANET), but either way they're based on packet switching technology. The active agents that produce and consume messages are processes. Various levels of protocols in the networks, the gateways, and the hosts work together to support an interprocess communication system. That system gives two-way data flow on logical connections between process ports ๐
The word packet is used generically to mean the data of one transaction between a host and its network. We're generally not going to worry about the format of the data blocks exchanged within a network, since that's not our problem ๐
Hosts are computers attached to a network. From the communication network's point of view, they're the sources and destinations of packets. Processes are the active elements in host computers (a process being a program in execution, which is the pretty common definition). Even terminals, files, and other I/O devices communicate with each other through processes. So all communication is really inter-process communication ๐ฆ
Since a process might need to tell apart several communication streams between itself and another process (or several processes), we picture each process as having a number of ports it uses to talk to other processes' ports ๐ง
2.2. Model of Operation
Processes send data by calling on TCP and passing it buffers of data as arguments ๐ TCP packages the data from those buffers into segments and calls on the internet module to transmit each segment to the destination TCP. The receiving TCP puts the data from a segment into the receiving user's buffer and then notifies that user. The TCPs put control information in the segments, which they use to make sure data is transmitted reliably and in order ๐ฅ
The model of internet communication has an internet protocol module tied to each TCP, and it provides an interface to the local network. This internet module packages TCP segments inside internet datagrams and routes those datagrams to a destination internet module or an intermediate gateway. To send the datagram through the local network, it gets embedded in a local network packet ๐ฆ
The packet switches may perform further packaging, fragmentation, or other operations to get the local packet delivered to the destination internet module ๐ธ
At a gateway between networks, the internet datagram gets "unwrapped" from its local packet and examined to figure out which network it should travel through next. Then it gets "wrapped" in a local packet that suits the next network and routed onward, either to the next gateway or to the final destination โจ
A gateway is permitted to break an internet datagram into smaller internet datagram fragments when that's needed for transmission through the next network. To do this, the gateway produces a set of internet datagrams, each carrying one fragment. Fragments can be broken down even further at later gateways. The internet datagram fragment format is designed so the destination internet module can reassemble the fragments into internet datagrams ๐งฉ
A destination internet module unwraps the segment from the datagram (reassembling the datagram first, if necessary) and passes the segment to the destination TCP ๐
This simple model glosses over a lot of details ๐ One important feature is the type of service. It gives the gateway (or internet module) information to guide it in choosing the service parameters for traversing the next network. The type of service information includes the precedence of the datagram. Datagrams can also carry security information, so hosts and gateways operating in multilevel secure environments can properly segregate datagrams for security reasons ๐
2.3. The Host Environment
TCP is assumed to be a module inside an operating system ๐ฅ๏ธ Users access TCP pretty much the way they'd access the file system. TCP may call on other operating system functions, for example to manage its data structures. The actual interface to the network is assumed to be controlled by a device driver module. TCP doesn't call the network device driver directly. Instead, it calls the internet datagram protocol module, which may in turn call the device driver ๐ซถ
The TCP mechanisms don't rule out implementing TCP in a front-end processor. However, in that kind of implementation, a host-to-front-end protocol must provide the functionality needed to support the type of TCP-user interface described in this document ๐
2.4. Interfaces
The TCP/user interface lets the user call TCP to OPEN or CLOSE a connection, to SEND or RECEIVE data, or to get STATUS about a connection ๐ These calls work like other calls from user programs on the operating system, like the calls to open, read from, and close a file ๐
The TCP/internet interface provides calls to send and receive datagrams addressed to TCP modules in hosts anywhere in the internet system. These calls have parameters for passing the address, type of service, precedence, security, and other control information ๐
2.5. Relation to Other Protocols
Here's a diagram showing where TCP sits in the protocol hierarchy ๐ฆ
+------+ +-----+ +-----+ +-----+
|Telnet| | FTP | |Voice| ... | | Application Level
+------+ +-----+ +-----+ +-----+
| | | |
+-----+ +-----+ +-----+
| TCP | | RTP | ... | | Host Level
+-----+ +-----+ +-----+
| | |
+-------------------------------+
| Internet Protocol & ICMP | Gateway Level
+-------------------------------+
|
+---------------------------+
| Local Network Protocol | Network Level
+---------------------------+
Protocol Relationships
Figure 2.
TCP is expected to be able to support higher level protocols efficiently ๐ช It should be easy to interface higher level protocols like the ARPANET Telnet or AUTODIN II THP to TCP ๐
2.6. Reliable Communication ๐
okay so the big promise here is that a stream of data sent on a TCP connection gets delivered reliably and in order at the destination ๐ซถโจ no lost puzzle pieces, no shuffled pages, periodt.
the way TCP pulls this off is with sequence numbers and acknowledgments. Conceptually, every single octet of data gets its own sequence number ๐ข The sequence number of the first octet in a segment rides along with that segment and gets called the segment sequence number. Segments also carry an acknowledgment number, which is the sequence number of the next data octet the sender is expecting to receive in the reverse direction. so it's basically a little "got everything up to here, send me the next one" note ๐
here's the retransmission dance ๐ When TCP sends a segment with data, it puts a copy on a retransmission queue and starts a timer โฐ Once the acknowledgment for that data shows up, the segment gets deleted from the queue. But if the timer runs out before the ack arrives, the segment gets sent again ๐ iconic persistence honestly.
ngl this part is easy to misread: an acknowledgment from TCP does not mean the data reached the end user ๐ It only means the receiving TCP has taken responsibility for delivering it. big difference, bestie!
now for flow control ๐ธ To keep the data flowing at a sane pace between TCPs, the receiving TCP reports a "window" to the sending TCP. That window tells the sender how many octets, counting from the acknowledgment number, the receiver is currently ready to take. it's giving "here's how much room I have right now" energy ๐๏ธ๐
2.7. Connection Establishment and Clearing ๐ฆ
so TCP needs a way to keep all its separate data streams apart, and that's where the port identifier comes in ๐ Each TCP picks its ports independently, which means two TCPs might pick the same port number. Not unique! So to make things unique across the whole thing, we glue an internet address (the one identifying the TCP) onto a port identifier. That combo is called a socket, and it's unique across every network connected together ๐๐
a connection is fully defined by the pair of sockets at its two ends. One local socket can be part of a bunch of connections, each going to a different foreign socket ๐ง And connections are full duplex, which just means data can flow in both directions at once โ๏ธโจ
TCPs get to decide how they link ports to processes ๐ That said, every implementation needs a few basic ideas. There have to be well-known sockets that the TCP only hands out to the "appropriate" processes, somehow. The vibe is that processes can own ports, and a process can only start connections on ports it owns ๐ (How you do the ownership bit is a local business, but the spec imagines a Request Port user command, or a way to hand out a whole group of ports to one process, like using the high-order bits of a port name to mark which process owns it.)
when a connection gets opened, the OPEN call takes a local port and a foreign socket. In return, the TCP gives back a short local connection name that the user can use in later calls ๐ Plenty of info about each connection has to be remembered, so we imagine a data structure called a Transmission Control Block (TCB) ๐๏ธ One way to build it is to make the local connection name just a pointer to that connection's TCB. The OPEN call also says whether the connection should be actively pursued or passively waited for ๐
a passive OPEN means the process wants to accept incoming connection requests instead of starting one itself ๐ช A lot of the time, a passive OPEN will take a connection from anybody ๐ For that case, a foreign socket of all zeros stands for "unspecified." Unspecified foreign sockets are only allowed on passive OPENs, so no sneaking them into active ones ๐ โโ๏ธ
picture a service process that wants to help unknown processes ๐ค It would issue a passive OPEN with an unspecified foreign socket, and then any process that asks to connect to that local socket can get in. it helps a lot if everyone knows that local socket belongs to this service ๐ฃ
well-known sockets are a neat shortcut for tying a socket address to a standard service ๐ For example, the "Telnet-Server" process is permanently pinned to one particular socket. Other sockets are set aside for File Transfer, Remote Job Entry, Text Generator, Echoer, and Sink processes (the last three are just for testing ๐งช). There could even be a socket reserved for a "Look-Up" service, which would tell you which specific socket a newly created service is available on ๐ The well-known socket idea is part of TCP, but which services get which sockets is outside this spec (see [4]).
processes can issue passive OPENs, sit there waiting for matching active OPENs, and get told by TCP when a connection is established ๐ Two processes that issue active OPENs to each other at the same time still get connected correctly ๐คฏ That flexibility is a big deal for distributed computing, where components do their own thing asynchronously ๐
there are two main ways a local passive OPEN can match a foreign active OPEN. In the first, the passive OPEN fully specified the foreign socket, so the match has to be exact ๐ฏ In the second, the passive OPEN left the foreign socket unspecified, so any foreign socket works as long as the local sockets match โ Partially restricted matches are possible too, so there's wiggle room ๐
now, if several pending passive OPENs (saved in TCBs) share the same local socket, a foreign active OPEN gets matched first to a TCB that names that exact foreign socket, if one exists ๐ฅ Only after that does it look at a TCB with an unspecified foreign socket ๐ฅ
establishing a connection uses the synchronize (SYN) control flag and a three-message exchange ๐ค People call this the three-way handshake [3] ๐
a connection starts when an arriving segment with a SYN meets a waiting TCB entry, and both came from user OPEN commands ๐ซ When the local and foreign sockets match, that's when the connection counts as initiated. It becomes "established" once sequence numbers have been synchronized in both directions ๐
clearing a connection also takes a few segments, but this time they carry the FIN control flag ๐
2.8. Data Communication ๐ฎ
the data on a connection can be pictured as a stream of octets ๐ With each SEND call, the sending user says whether that data (and any earlier data) should be pushed straight through to the receiving user, by setting the PUSH flag ๐
the sending TCP is allowed to collect data from the sending user and send it in segments whenever it's convenient for it ๐ฐ๏ธ But once the push function gets signaled, it must send all the unsent data. And when a receiving TCP sees the PUSH flag, it must not wait for more data from the sending TCP before handing the data to the receiving process ๐โโ๏ธ๐จ
heads up, bestie: there's no required link between push and segment boundaries ๐ A segment's data might come from one SEND call (all of it or just part of it), or it might come from several SEND calls mashed together.
the whole point of the push function and PUSH flag is to get data through from the sending user to the receiving user ๐ It is not a record service. Don't go looking for message boundaries here ๐ โโ๏ธ
there's also a link between the push function and the buffers that cross the TCP/user interface ๐งบ Every time a PUSH flag goes with data placed into the receiving user's buffer, that buffer gets handed back to the user for processing, even if it isn't full yet ๐ค And if data fills up the user's buffer before a PUSH shows up, the data gets passed along in buffer-size chunks ๐ฆ
TCP also has a way to tell the receiver that, further along in the data stream than what the receiver is currently reading, there's urgent data ๐จ TCP doesn't dictate what the user does once it hears about pending urgent data. The general idea is that the receiving process takes action to process that urgent data quickly โก
2.9. Precedence and Security ๐
TCP uses the internet protocol type of service field and the security option to offer precedence and security on a per-connection basis to TCP users ๐ Not every TCP module will work in a multilevel secure environment. Some might be limited to unclassified use only, and others might only run at one security level and compartment ๐ง So some TCP implementations, and the services they offer users, may only cover a subset of the multilevel secure case ๐ซง
TCP modules that do operate in a multilevel secure environment must properly mark outgoing segments with the security, compartment, and precedence ๐ท๏ธ Those modules also must give their users, or higher level protocols like Telnet or THP, an interface for specifying the security level, compartment, and precedence they want for connections ๐
2.10. Robustness Principle ๐ก๏ธ
TCP implementations follow a general principle of robustness, and it's the iconic one: be conservative in what you do, be liberal in what you accept from others ๐ โจ Send carefully, receive generously, always. that's the energy ๐ซถ
3. FUNCTIONAL SPECIFICATION โจ
3.1. Header Format โจ
okay so TCP segments get sent as internet datagrams ๐ฆ the IP header carries a bunch of info, including the source and destination host addresses [2]. then the TCP header comes right after the internet header and holds all the TCP-specific stuff ๐ this split is lowkey genius bc it means other host-level protocols can exist alongside TCP ๐ซถ
TCP Header Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TCP Header Format
Note that one tick mark represents one bit position. ๐
Figure 3. ๐ฆ
Source Port: 16 bits ๐ธ
The source port number. ๐
Destination Port: 16 bits ๐ธ
The destination port number. ๐
Sequence Number: 32 bits ๐ง
The sequence number of the first data octet in this segment (except when SYN is present). If SYN is present the sequence number is the initial sequence number (ISN) and the first data octet is ISN+1. ๐ซถ
Acknowledgment Number: 32 bits ๐ง
If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive. Once a connection is established this is always sent. ๐
Data Offset: 4 bits ๐
The number of 32 bit words in the TCP Header. This indicates where the data begins. The TCP header (even one including options) is an integral number of 32 bits long. โจ
Reserved: 6 bits ๐
Reserved for future use. MUST be zero. ๐ซ
Control Bits: 6 bits (from left to right): ๐๏ธ
- URG: Urgent Pointer field significant ๐ฅ
- ACK: Acknowledgment field significant ๐
- PSH: Push Function ๐
- RST: Reset the connection ๐
- SYN: Synchronize sequence numbers ๐
- FIN: No more data from sender ๐
Window: 16 bits ๐ช
The number of data octets beginning with the one indicated in the acknowledgment field which the sender of this segment is willing to accept. ๐ท
Checksum: 16 bits ๐งฎ
The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header and text. If a segment contains an odd number of header and text octets to be checksummed, the last octet is padded on the right with zeros to form a 16 bit word for checksum purposes. The pad is not transmitted as part of the segment. While computing the checksum, the checksum field itself is replaced with zeros. ๐ค
The checksum also covers a 96 bit pseudo header conceptually prefixed to the TCP header. This pseudo header contains the Source Address, the Destination Address, the Protocol, and TCP length. This gives the TCP protection against misrouted segments. This information is carried in the Internet Protocol and is transferred across the TCP/Network interface in the arguments or results of calls by the TCP on the IP. ๐บ๏ธ
+--------+--------+--------+--------+
| Source Address |
+--------+--------+--------+--------+
| Destination Address |
+--------+--------+--------+--------+
| zero | PTCL | TCP Length |
+--------+--------+--------+--------+
The TCP Length is the TCP header length plus the data length in octets (this is not an explicitly transmitted quantity, but is computed), and it does not count the 12 octets of the pseudo header. ๐ง
Urgent Pointer: 16 bits ๐จ
This field communicates the current value of the urgent pointer as a positive offset from the sequence number in this segment. The urgent pointer points to the sequence number of the octet following the urgent data. This field is only be interpreted in segments with the URG control bit set. ๐ฏ
Options: variable โ๏ธ
Options may occupy space at the end of the TCP header and are a multiple of 8 bits in length. All options are included in the checksum. An option may begin on any octet boundary. There are two cases for the format of an option: ๐
- Case 1: A single octet of option-kind.
- Case 2: An octet of option-kind, an octet of option-length, and the actual option-data octets.
The option-length counts the two octets of option-kind and option-length as well as the option-data octets. ๐ข
Note that the list of options may be shorter than the data offset field might imply. The content of the header beyond the End-of-Option option MUST be header padding (i.e., zero). ๐ซง
A TCP MUST implement all options. ๐ฅ๐ฅ
Currently defined options include (kind indicated in octal): ๐
Kind Length Meaning
---- ------ -------
0 - End of option list.
1 - No-Operation.
2 4 Maximum Segment Size.
Specific Option Definitions ๐ญ
End of Option List ๐
+--------+
|00000000|
+--------+
Kind=0
This option code indicates the end of the option list. This might not coincide with the end of the TCP header according to the Data Offset field. This is used at the end of all options, not the end of each option, and need only be used if the end of the options would not otherwise coincide with the end of the TCP header. ๐งฉ
No-Operation ๐ถโ๐ซ๏ธ
+--------+
|00000001|
+--------+
Kind=1
This option code MAY be used between options, for example, to align the beginning of a subsequent option on a word boundary. There is no guarantee that senders will use this option, so receivers MUST be prepared to process options even if they do not begin on a word boundary. ๐คทโโ๏ธ
Maximum Segment Size ๐
+--------+--------+---------+--------+
|00000010|00000100| max seg size |
+--------+--------+---------+--------+
Kind=2 Length=4
Maximum Segment Size Option Data: 16 bits ๐
If this option is present, then it communicates the maximum receive segment size at the TCP which sends this segment. This field MUST only be sent in the initial connection request (i.e., in segments with the SYN control bit set). If this option is not used, any segment size is allowed. ๐
Padding: variable ๐ซง
The TCP header padding is used to ensure that the TCP header ends and data begins on a 32 bit boundary. The padding is composed of zeros. ๐ค
3.2. Terminology โจ
okay bestie, before we can talk about how TCP actually works ๐ง we need some vocab, no cap. TCP has to remember a bunch of stuff about each connection, so we put all of it in one record called a Transmission Control Block, or TCB ๐ฆ ๐. Inside the TCB you'll find the local and remote socket numbers, the security and precedence of the connection, pointers to the user's send and receive buffers, pointers to the retransmit queue and to the current segment. On top of that, a bunch of sequence number variables live in there too, and they're the main characters of this whole section ๐
Send Sequence Variables
Here's the send side crew ๐
SND.UNA- send unacknowledgedSND.NXT- send nextSND.WND- send windowSND.UP- send urgent pointerSND.WL1- segment sequence number used for last window updateSND.WL2- segment acknowledgment number used for last window updateISS- initial send sequence number
Receive Sequence Variables
And now the receive side ๐ฆ
RCV.NXT- receive nextRCV.WND- receive windowRCV.UP- receive urgent pointerIRS- initial receive sequence number
These diagrams help you picture how those variables map onto the sequence space, and honestly they're iconic ๐คฉ
Send Sequence Space
1 2 3 4
----------|----------|----------|----------
SND.UNA SND.NXT SND.UNA
+SND.WND
1 - old sequence numbers which have been acknowledged
2 - sequence numbers of unacknowledged data
3 - sequence numbers allowed for new data transmission
4 - future sequence numbers which are not yet allowed
Send Sequence Space
Figure 4.
The send window is the portion of the sequence space labeled 3 in figure 4 ๐
Receive Sequence Space
1 2 3
----------|----------|----------
RCV.NXT RCV.NXT
+RCV.WND
1 - old sequence numbers which have been acknowledged
2 - sequence numbers allowed for new reception
3 - future sequence numbers which are not yet allowed
Receive Sequence Space
Figure 5.
The receive window is the portion of the sequence space labeled 2 in figure 5 ๐ธ
There are also some variables that get their values from the fields of the current segment, so they're basically the segment's own little ID card ๐ชช
Current Segment Variables
SEG.SEQ- segment sequence numberSEG.ACK- segment acknowledgment numberSEG.LEN- segment lengthSEG.WND- segment windowSEG.UP- segment urgent pointerSEG.PRC- segment precedence value
A connection moves through a series of states over its whole lifetime ๐ The states are: LISTEN, SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT, and the fictional state CLOSED. ๐ CLOSED is fictional because it means there's no TCB, and therefore no connection at all. Here's the quick tea on each one:
LISTEN- waiting for a connection request from any remote TCP and port ๐SYN-SENT- waiting for a matching connection request after having sent a connection request ๐คSYN-RECEIVED- waiting for a confirming connection request acknowledgment, after having both received and sent a connection request ๐คESTABLISHED- an open connection where data received can be delivered to the user. This is the normal state for the data transfer phase of the connection โจFIN-WAIT-1- waiting for a connection termination request from the remote TCP, or an acknowledgment of the termination request you already sent ๐FIN-WAIT-2- waiting for a connection termination request from the remote TCP ๐ฅฑCLOSE-WAIT- waiting for a connection termination request from the local user ๐CLOSING- waiting for a connection termination request acknowledgment from the remote TCP ๐ฌLAST-ACK- waiting for an acknowledgment of the connection termination request you previously sent to the remote TCP (which includes an acknowledgment of its connection termination request) ๐ซTIME-WAIT- waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request โณCLOSED- no connection state at all ๐ซฅ
A TCP connection hops from one state to another in response to events โก The events are the user calls OPEN, SEND, RECEIVE, CLOSE, ABORT, and STATUS; the incoming segments, especially the ones carrying the SYN, ACK, RST and FIN flags; and timeouts โฐ
Figure 6 is the state diagram. It only shows state changes, plus the events that cause them and the resulting actions. It doesn't cover error conditions or actions that aren't tied to a state change, but we get more into that later ๐
NOTE BENE: this diagram is only a summary and must not be taken as the total specification. Don't treat it like the full rulebook, bestie ๐ซ๐
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+
TCP Connection State Diagram
Figure 6.
3.3. Sequence Numbers ๐ข๐
okay this is the big one, so get comfy ๐๏ธ A fundamental idea in TCP's design is that every octet of data sent over a TCP connection gets its own sequence number ๐ฏ Since every octet is numbered, each one can be acknowledged. The acknowledgment mechanism is cumulative: an acknowledgment of sequence number X means that all octets up to but not including X have been received โ This makes duplicate detection straightforward when retransmissions happen, which is so smart ๐ง โจ Within a segment, the first data octet right after the header is the lowest numbered, and the octets after it are numbered consecutively ๐
Now the sequence number space is finite, even though it's super huge ๐ It goes from 0 to 2**32 - 1. Since it's finite, all arithmetic on sequence numbers MUST be done modulo 2**32. This unsigned arithmetic keeps the relationships between sequence numbers intact as they wrap around from 2**32 - 1 back to 0 ๐ There are some subtleties to modular arithmetic, so take great care when you program comparisons of these values ๐ The symbol "=<" means "less than or equal" (modulo 2**32) ๐งฎ
The typical kinds of sequence number comparisons TCP has to do include:
- Determining that an acknowledgment refers to some sequence number that was sent but not yet acknowledged ๐
- Determining that all sequence numbers occupied by a segment have been acknowledged (for example, to remove the segment from a retransmission queue) ๐๏ธ
- Determining that an incoming segment contains sequence numbers that are expected (in other words, the segment "overlaps" the receive window) ๐ช
When you send data, TCP is going to receive acknowledgments back. These comparisons are needed to process those acknowledgments ๐ฌ
SND.UNA = oldest unacknowledged sequence number
SND.NXT = next sequence number to be sent
SEG.ACK = acknowledgment from the receiving TCP (next sequence
number expected by the receiving TCP)
SEG.SEQ = first sequence number of a segment
SEG.LEN = the number of octets occupied by the data in the segment
(counting SYN and FIN)
SEG.SEQ+SEG.LEN-1 = last sequence number of a segment
A new acknowledgment (called an "acceptable ack") is one where this inequality holds:
SND.UNA < SEG.ACK =< SND.NXT
A segment on the retransmission queue is fully acknowledged if the sum of its sequence number and length is less than or equal to the acknowledgment value in the incoming segment ๐
When data comes in, these comparisons are needed too ๐ฅ
RCV.NXT = next sequence number expected on an incoming segments, and
is the left or lower edge of the receive window
RCV.NXT+RCV.WND-1 = last sequence number expected on an incoming
segment, and is the right or upper edge of the receive window
SEG.SEQ = first sequence number occupied by the incoming segment
SEG.SEQ+SEG.LEN-1 = last sequence number occupied by the incoming
segment
A segment counts as occupying a portion of valid receive sequence space if either of these is true ๐ฆ
RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
or
RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
The first part of this test checks whether the start of the segment falls in the window, and the second part checks whether the end of the segment falls in the window. If the segment passes either part, it contains data in the window ๐
Actually, it's a little more complicated than that ๐ Because of zero windows and zero length segments, there are four cases for whether an incoming segment is acceptable ๐ฆ
Segment Receive Test
Length Window
------- ------- -------------------------------------------
0 0 SEG.SEQ = RCV.NXT
0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
>0 0 not acceptable
>0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
Note that when the receive window is zero, no segments should be acceptable except ACK segments. So it is possible for a TCP to maintain a zero receive window while transmitting data and receiving ACKs ๐ธ However, even when the receive window is zero, a TCP must process the RST and URG fields of all incoming segments ๐ซถ
We also used the numbering scheme to protect certain control information โจ The trick is that some control flags get implicitly included in the sequence space, so they can be retransmitted and acknowledged without confusion. (Basically, one and only one copy of the control gets acted upon. Iconic.) Control information is not physically carried in the segment data space, so we need rules for implicitly assigning sequence numbers to control ๐ The SYN and FIN are the only controls that need this protection, and they're only used at connection opening and closing ๐ฅ
For sequence number purposes, the SYN is considered to occur before the first actual data octet of the segment it's in, while the FIN is considered to occur after the last actual data octet in the segment it's in. The segment length (SEG.LEN) includes both data and sequence space occupying controls. When a SYN is present, SEG.SEQ is the sequence number of the SYN ๐ง
Initial Sequence Number Selection โจ
The protocol places no restriction on a particular connection being used over and over again ๐ A connection is defined by a pair of sockets, and new instances of a connection are called incarnations of the connection. The problem is: "how does the TCP identify duplicate segments from previous incarnations of the connection?" ๐ This gets very real if the connection is opened and closed in quick succession, or if the connection breaks with loss of memory and is then reestablished ๐ญ
To avoid confusion, we must prevent segments from one incarnation of a connection from being used while the same sequence numbers may still be floating around the network from an earlier incarnation. We want to make sure of this even if a TCP crashes and loses all knowledge of the sequence numbers it has been using ๐ When new connections are created, an initial sequence number (ISN) generator is employed, and it selects a new 32 bit ISN. The generator is bound to a (possibly fictitious) 32 bit clock whose low order bit is incremented roughly every 4 microseconds. So the ISN cycles approximately every 4.55 hours. Since we assume segments will stay in the network no more than the Maximum Segment Lifetime (MSL), and the MSL is less than 4.55 hours, we can reasonably assume ISNs will be unique ๐
For each connection there's a send sequence number and a receive sequence number. The initial send sequence number (ISS) is chosen by the data sending TCP, and the initial receive sequence number (IRS) is learned during the connection establishing procedure ๐
For a connection to be established or initialized, the two TCPs must synchronize on each other's initial sequence numbers. This happens in an exchange of connection establishing segments carrying a control bit called "SYN" (for synchronize) along with the initial sequence numbers. As a shorthand, segments carrying the SYN bit are also called "SYNs". So the solution needs a suitable mechanism for picking an initial sequence number, plus a slightly involved handshake to exchange the ISNs ๐ฆ
The synchronization requires each side to send its own initial sequence number and to receive a confirmation of it in an acknowledgment from the other side. Each side must also receive the other side's initial sequence number and send a confirming acknowledgment ๐ซถ
1) A --> B SYN my sequence number is X
2) A <-- B ACK your sequence number is X
3) A <-- B SYN my sequence number is Y
4) A --> B ACK your sequence number is Y
Because steps 2 and 3 can be combined in a single message, this is called the three way (or three message) handshake ๐
A three way handshake is necessary because sequence numbers are not tied to a global clock in the network, and TCPs may have different mechanisms for picking the ISNs ๐ The receiver of the first SYN has no way of knowing whether the segment was an old delayed one or not, unless it remembers the last sequence number used on the connection (which is not always possible). So it must ask the sender to verify this SYN. The three way handshake and the advantages of a clock-driven scheme are discussed in [3] ๐
Knowing When to Keep Quiet ๐คซ
To be sure that a TCP doesn't create a segment carrying a sequence number that an old segment still in the network might duplicate, the TCP must keep quiet for a maximum segment lifetime (MSL) before assigning any sequence numbers. This applies upon starting up or recovering from a crash in which memory of the sequence numbers in use was lost ๐ญ For this specification, the MSL is taken to be 2 minutes. This is an engineering choice, and it may be changed if experience indicates it's desirable to do so ๐
Note that if a TCP is reinitialized in some sense, yet retains its memory of sequence numbers in use, then it need not wait at all. It only has to be sure to use sequence numbers larger than those recently used โจ
The TCP Quiet Time Concept ๐ง
This specification provides that hosts which "crash" without retaining any knowledge of the last sequence numbers transmitted on each active (i.e., not closed) connection shall delay emitting any TCP segments for at least the agreed Maximum Segment Lifetime (MSL) in the internet system of which the host is a part. In the paragraphs below, an explanation for this specification is given. TCP implementors may violate the "quiet time" restriction, but only at the risk of causing some old data to be accepted as new, or new data to be rejected as old, duplicated by some receivers in the internet system ๐
TCPs consume sequence number space each time a segment is formed and entered into the network output queue at a source host. The duplicate detection and sequencing algorithm in the TCP protocol relies on the unique binding of segment data to sequence space, to the extent that sequence numbers will not cycle through all 2**32 values before the segment data bound to those sequence numbers has been delivered and acknowledged by the receiver, and all duplicate copies of the segments have "drained" from the internet ๐ Without such an assumption, two distinct TCP segments could conceivably be assigned the same or overlapping sequence numbers, causing confusion at the receiver as to which data is new and which is old. Remember that each segment is bound to as many consecutive sequence numbers as there are octets of data in the segment ๐
Under normal conditions, TCPs keep track of the next sequence number to emit and the oldest sequence number awaiting acknowledgment, so they don't accidentally reuse a sequence number before its first use has been acknowledged ๐ธ This alone does not guarantee that old duplicate data drains from the net, so the sequence space has been made very large to reduce the probability that a wandering duplicate causes trouble when it arrives. At 2 megabits/sec, it takes 4.5 hours to use up 2**32 octets of sequence space. Since the maximum segment lifetime in the net is not likely to exceed a few tens of seconds, this is deemed ample protection for foreseeable nets, even if data rates escalate to tens of megabits/sec. At 100 megabits/sec, the cycle time is 5.4 minutes, which may be a little short, but it's still within reason ๐ฅ
The basic duplicate detection and sequencing algorithm in TCP can be defeated, however, if a source TCP doesn't have any memory of the sequence numbers it last used on a given connection. For example, if the TCP were to start all connections with sequence number 0, then upon crashing and restarting, a TCP might re-form an earlier connection (possibly after half-open connection resolution) and emit packets with sequence numbers identical to or overlapping with packets still in the network, which were emitted on an earlier incarnation of the same connection ๐ฑ In the absence of knowledge about the sequence numbers used on a particular connection, the TCP specification recommends that the source delay for MSL seconds before emitting segments on the connection, to allow time for segments from the earlier connection incarnation to drain from the system โญ
Even hosts that can remember the time of day and use it to select initial sequence number values are not immune from this problem (i.e., even if time of day is used to select an initial sequence number for each new connection incarnation) ๐
Suppose, for example, that a connection is opened starting with sequence number S. Suppose this connection isn't used much, and eventually the initial sequence number function (ISN(t)) takes on a value equal to the sequence number, say S1, of the last segment sent by this TCP on a particular connection. Now suppose that at this instant the host crashes, recovers, and establishes a new incarnation of the connection. The initial sequence number chosen is S1 = ISN(t), which is the last used sequence number on the old incarnation of the connection! ๐ If the recovery happens quickly enough, any old duplicates in the net bearing sequence numbers in the neighborhood of S1 may arrive and be treated as new packets by the receiver of the new incarnation of the connection ๐ญ
The problem is that the recovering host may not know how long it crashed, nor does it know whether there are still old duplicates in the system from earlier connection incarnations ๐ฅบ
One way to deal with this problem is to deliberately delay emitting segments for one MSL after recovery from a crash. This is the "quiet time" specification. Hosts that prefer to avoid waiting, and are willing to risk possible confusion of old and new packets at a given destination, may choose not to wait for the "quiet time" ๐โโ๏ธ Implementors may provide TCP users with the ability to select, on a connection by connection basis, whether to wait after a crash, or may informally implement the "quiet time" for all connections. Obviously, even where a user selects to "wait," this is not necessary after the host has been "up" for at least MSL seconds ๐
okay so to sum it all up ๐ : every segment that gets sent takes up one or more sequence numbers in the sequence space, and those numbers stay "busy" or "in use" until MSL seconds have passed. ๐ฐ๏ธ If a crash happens, there's a block of space-time that the octets of the last segment sent are sitting in. And if a new connection starts too soon and uses any of the sequence numbers in that footprint from the previous connection incarnation, there's a potential sequence number overlap that could confuse the receiver ๐ญ๐ซถ
3.4. Establishing a connection โจ
The "three-way handshake" is the procedure used to establish a connection ๐ค Usually one TCP starts it and another TCP responds. It also works if two TCPs start it at the same time ๐ฏโโ๏ธ In that simultaneous case, each TCP gets a "SYN" segment with no acknowledgment after it has already sent its own "SYN". Of course, an old duplicate "SYN" segment showing up can make it look like a simultaneous connection initiation is happening ๐ Using "reset" segments properly is how you tell these cases apart ๐
Here are a few examples of connection initiation ๐ฆ These examples don't show connection synchronization with data-carrying segments, but that's perfectly legit, as long as the receiving TCP doesn't hand the data to the user until it's clear the data is valid. (So the data has to be buffered at the receiver until the connection reaches the ESTABLISHED state.) The three-way handshake cuts down on false connections ๐ก๏ธ It's a trade-off between memory and messages, since you need some info to do that checking โจ
The simplest three-way handshake is shown in figure 7 below ๐ Read the figures like this: each line is numbered so we can reference it. Right arrows (-->) mean a TCP segment is leaving TCP A for TCP B, or arriving at B from A. Left arrows (<--) mean the reverse. An ellipsis (...) means a segment is still in the network (delayed) ๐ข An "XXX" means a segment got lost or rejected ๐ Comments go in parentheses. TCP states show the state AFTER the segment departs or arrives (the segment's contents are in the middle of each line). The segment contents are abbreviated to sequence number, control flags, and ACK field. Other fields like window, addresses, lengths, and text are left out to keep things clear ๐ง
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED
3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
Basic 3-Way Handshake for Connection Synchronization
Figure 7.
In line 2 of figure 7, TCP A kicks things off by sending a SYN segment saying it'll use sequence numbers starting at 100 ๐ธ In line 3, TCP B sends its own SYN and acknowledges the SYN it got from TCP A. Notice the acknowledgment field says TCP B is now expecting to hear sequence 101, which acknowledges the SYN that used up sequence 100 ๐คโจ
At line 4, TCP A replies with an empty segment containing an ACK for TCP B's SYN. Then at line 5, TCP A finally sends some data ๐ The sequence number in line 5 is the same as in line 4, because the ACK doesn't take up any sequence number space. (If it did, we'd end up ACKing ACKs, and that's a whole mess ๐ญ)
Simultaneous initiation is only a little more complicated, as figure 8 shows ๐ฅ Each TCP goes from CLOSED to SYN-SENT to SYN-RECEIVED to ESTABLISHED.
TCP A TCP B
1. CLOSED CLOSED
2. SYN-SENT --> <SEQ=100><CTL=SYN> ...
3. SYN-RECEIVED <-- <SEQ=300><CTL=SYN> <-- SYN-SENT
4. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED
5. SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...
6. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
7. ... <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
Simultaneous Connection Synchronization
Figure 8.
The main reason for the three-way handshake is to stop old duplicate connection initiations from causing chaos ๐ To handle that, there's a special control message called reset ๐งน If the receiving TCP is in a non-synchronized state (SYN-SENT or SYN-RECEIVED), it goes back to LISTEN when it gets an acceptable reset. If the TCP is in one of the synchronized states (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT), it aborts the connection and tells its user ๐ณ We'll talk about that latter case under "half-open" connections below ๐
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> ...
3. (duplicate) ... <SEQ=90><CTL=SYN> --> SYN-RECEIVED
4. SYN-SENT <-- <SEQ=300><ACK=91><CTL=SYN,ACK> <-- SYN-RECEIVED
5. SYN-SENT --> <SEQ=91><CTL=RST> --> LISTEN
6. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED
7. SYN-SENT <-- <SEQ=400><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
8. ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK> --> ESTABLISHED
Recovery from Old Duplicate SYN
Figure 9.
As a simple example of recovering from old duplicates, check out figure 9 ๐ต๏ธโโ๏ธ At line 3, an old duplicate SYN shows up at TCP B. TCP B can't tell it's old, so it responds normally (line 4). TCP A notices the ACK field is wrong and sends back a RST (reset), with its SEQ field picked so the segment looks believable ๐ญ When TCP B gets that RST, it goes back to LISTEN. Then the original SYN (pun intended) finally arrives at line 6, and the synchronization goes through normally โจ If the SYN at line 6 had arrived before the RST, things would've gotten more complicated, with RSTs being sent in both directions ๐
Half-Open Connections and Other Anomalies
An established connection is "half-open" if one of the TCPs closed or aborted the connection on its end without the other one knowing, or if the two ends got desynchronized because a crash wiped out memory ๐ฅบ These connections automatically get reset if someone tries to send data in either direction. That said, half-open connections are expected to be unusual, and the recovery procedure is kinda involved ๐ซ
If site A no longer has the connection, then when the user at site B tries to send data on it, the site B TCP gets a reset control message ๐จ That message tells the site B TCP that something is wrong, and it's expected to abort the connection.
Okay, picture two user processes, A and B, communicating when a crash happens and A's TCP loses its memory ๐ Depending on the operating system running A's TCP, some error recovery mechanism might exist. When TCP is back up, A will probably start over from the beginning or from a recovery point. So A will likely try to OPEN the connection again, or try to SEND on the connection it still thinks is open. In the latter case, it gets the error message "connection not open" from its own local TCP ๐ To establish the connection, A's TCP sends a segment containing SYN. This leads to the example in figure 10 ๐ After TCP A crashes, the user tries to re-open the connection. Meanwhile, TCP B still thinks the connection is open ๐ฅน
TCP A TCP B
1. (CRASH) (send 300,receive 100)
2. CLOSED ESTABLISHED
3. SYN-SENT --> <SEQ=400><CTL=SYN> --> (??)
4. (!!) <-- <SEQ=300><ACK=100><CTL=ACK> <-- ESTABLISHED
5. SYN-SENT --> <SEQ=100><CTL=RST> --> (Abort!!)
6. SYN-SENT CLOSED
7. SYN-SENT --> <SEQ=400><CTL=SYN> -->
Half-Open Connection Discovery
Figure 10.
When the SYN arrives at line 3, TCP B is in a synchronized state and the incoming segment is outside the window, so it responds with an acknowledgment saying what sequence it expects next (ACK 100) ๐ TCP A sees that this segment doesn't acknowledge anything it sent. Since it's unsynchronized, it sends a reset (RST) because it's detected a half-open connection ๐ TCP B aborts at line 5. TCP A keeps trying to establish the connection, and the problem is now just the basic 3-way handshake from figure 7 ๐
Another interesting case happens when TCP A crashes and TCP B tries to send data on what it thinks is a synchronized connection ๐คฏ That's shown in figure 11. The data arriving at TCP A from TCP B (line 2) is unacceptable because no such connection exists, so TCP A sends a RST. The RST is acceptable, so TCP B processes it and aborts the connection ๐ซฃ
TCP A TCP B
1. (CRASH) (send 300,receive 100)
2. (??) <-- <SEQ=300><ACK=100><DATA=10><CTL=ACK> <-- ESTABLISHED
3. --> <SEQ=100><CTL=RST> --> (ABORT!!)
Active Side Causes Half-Open Connection Discovery
Figure 11.
In figure 12, TCP A and TCP B both have passive connections waiting for a SYN ๐งโโ๏ธ An old duplicate arriving at TCP B (line 2) stirs B into action. A SYN-ACK goes back (line 3), and that makes TCP A generate a RST, since the ACK in line 3 isn't acceptable. TCP B accepts the reset and goes back to its passive LISTEN state ๐
TCP A TCP B
1. LISTEN LISTEN
2. ... <SEQ=Z><CTL=SYN> --> SYN-RECEIVED
3. (??) <-- <SEQ=X><ACK=Z+1><CTL=SYN,ACK> <-- SYN-RECEIVED
4. --> <SEQ=Z+1><CTL=RST> --> (return to LISTEN!)
5. LISTEN LISTEN
Old Duplicate SYN Initiates a Reset on two Passive Sockets
Figure 12.
A bunch of other cases are possible too, and they're all covered by the following rules for RST generation and processing ๐
Reset Generation
As a general rule, reset (RST) must be sent whenever a segment arrives that apparently isn't meant for the current connection ๐ A reset must not be sent if it isn't clear that this is the case ๐ โโ๏ธ
There are three groups of states:
- If the connection does not exist (CLOSED) then a reset is sent in response to any incoming segment except another reset. In particular, SYNs addressed to a non-existent connection are rejected by this means. ๐ซถ
If the incoming segment has an ACK field, the reset takes its sequence number from that ACK field ๐ Otherwise the reset gets sequence number zero, and its ACK field is the sum of the incoming segment's sequence number and segment length ๐งฎ Either way, the connection stays in the CLOSED state ๐
- If the connection is in any non-synchronized state (LISTEN, SYN-SENT, SYN-RECEIVED) and the incoming segment acknowledges something that hasn't been sent yet (the segment carries an unacceptable ACK), a reset is sent. The same goes if an incoming segment has a security level or compartment that doesn't exactly match the level and compartment requested for the connection ๐ซ
If our SYN hasn't been acknowledged and the precedence level of the incoming segment is higher than the one we requested, then either raise the local precedence level (if the user and the system allow it) or send a reset ๐ If the incoming segment's precedence level is lower than the one we requested, keep going as if the precedence matched exactly. If the remote TCP can't raise its precedence level to match ours, that will show up in the next segment it sends, and the connection will be terminated then ๐ซถ If our SYN has been acknowledged (maybe in this very incoming segment), the precedence level of the incoming segment has to match the local precedence level exactly. If it doesn't, a reset must be sent ๐
If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment. Otherwise, the reset has sequence number zero and the ACK field is set to the sum of the sequence number and segment length of the incoming segment. Either way, the connection remains in the same state ๐
- If the connection is in a synchronized state (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT), any unacceptable segment (one with an out-of-window sequence number or an unacceptable acknowledgment number) must only get an empty acknowledgment segment back. That ACK carries the current send-sequence number and an acknowledgment of the next sequence number expected to be received. The connection stays in the same state ๐ง
If an incoming segment has a security level, compartment, or precedence that doesn't exactly match the level, compartment, and precedence requested for the connection, a reset is sent and the connection goes to the CLOSED state. The reset takes its sequence number from the ACK field of the incoming segment ๐
Reset Processing ๐ธ
In all states except SYN-SENT, every reset (RST) segment gets validated by checking its SEQ fields. A reset is valid if its sequence number is in the window. In the SYN-SENT state (an RST received in response to an initial SYN), the RST is acceptable if its ACK field acknowledges the SYN ๐
The receiver of an RST validates it first, then changes state. If the receiver was in the LISTEN state, it ignores the RST. If the receiver was in SYN-RECEIVED and had previously been in the LISTEN state, it goes back to LISTEN. Otherwise, the receiver aborts the connection and goes to CLOSED. If the receiver was in any other state, it aborts the connection, tells the user, and goes to CLOSED ๐ญ
3.5. Closing a Connection ๐ฆ
CLOSE means "I have no more data to send." Closing a full-duplex connection is kind of ambiguous, obviously, because it isn't clear how to treat the receiving side. We chose to treat CLOSE in a simplex fashion. The user who CLOSEs can keep RECEIVING until they're told the other side has CLOSED too. So a program could start several SENDs, then a CLOSE, then keep RECEIVING until it's signaled that a RECEIVE failed because the other side has CLOSED ๐
We assume the TCP will signal the user that the other side has closed, even if no RECEIVEs are outstanding, so the user can wrap up their side gracefully โจ A TCP will reliably deliver every buffer SENT before the connection was CLOSED. So a user who doesn't expect any data back only needs to wait until they hear the connection was CLOSED successfully to know all their data reached the destination TCP ๐ Users must keep reading the connections they close for sending until the TCP says there's no more data ๐
There are basically three cases:
- The user starts by telling the TCP to CLOSE the connection.
- The remote TCP starts by sending a FIN control signal.
- Both users CLOSE at the same time.
Case 1: Local user initiates the close ๐ท
In this case, a FIN segment can be built and placed on the outgoing segment queue. The TCP won't accept any more SENDs from the user, and it enters the FIN-WAIT-1 state. RECEIVEs are still allowed in this state. All segments up to and including the FIN get retransmitted until they're acknowledged. Once the other TCP has both acknowledged the FIN and sent a FIN of its own, the first TCP can ACK that FIN. Note that a TCP receiving a FIN will ACK it, but won't send its own FIN until its user has also CLOSED the connection ๐ซง
Case 2: TCP receives a FIN from the network ๐ง
If an unsolicited FIN shows up from the network, the receiving TCP can ACK it and tell the user the connection is closing. The user responds with a CLOSE, and then the TCP can send a FIN to the other TCP after sending any remaining data. The TCP then waits until its own FIN is acknowledged, and then it deletes the connection. If no ACK shows up, the connection is aborted after the user timeout and the user is told ๐ฌ
Case 3: Both users close simultaneously ๐ฏ
A simultaneous CLOSE by the users at both ends causes FIN segments to be exchanged. Once all segments before the FINs have been processed and acknowledged, each TCP can ACK the FIN it received. When each one gets those ACKs, both will delete the connection ๐ฅ
TCP A TCP B
1. ESTABLISHED ESTABLISHED
2. (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. (Close)
TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED
6. (2 MSL)
CLOSED
Normal Close Sequence
Figure 13.
TCP A TCP B
1. ESTABLISHED ESTABLISHED
2. (Close) (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> ... FIN-WAIT-1
<-- <SEQ=300><ACK=100><CTL=FIN,ACK> <--
... <SEQ=100><ACK=300><CTL=FIN,ACK> -->
3. CLOSING --> <SEQ=101><ACK=301><CTL=ACK> ... CLOSING
<-- <SEQ=301><ACK=101><CTL=ACK> <--
... <SEQ=101><ACK=301><CTL=ACK> -->
4. TIME-WAIT TIME-WAIT
(2 MSL) (2 MSL)
CLOSED CLOSED
Simultaneous Close Sequence
Figure 14.
3.6. Precedence and Security ๐
The idea is that a connection is only allowed between ports running with exactly the same security and compartment values, and at the higher of the precedence levels the two ports requested ๐ก๏ธ
The precedence and security parameters used in TCP are exactly the ones defined in the Internet Protocol (IP) [2]. Throughout this TCP specification, the term "security/compartment" means the security parameters used in IP, including security, compartment, user group, and handling restriction ๐ง
A connection attempt with mismatched security/compartment values, or a lower precedence value, must be rejected by sending a reset. A connection gets rejected for too low a precedence only after an acknowledgment of the SYN has been received ๐ซ
Heads up: TCP modules that only operate at the default precedence value still have to check the precedence of incoming segments, and they might need to raise the precedence level they use on the connection ๐
The security parameters may be used even in a non-secure environment (where the values would indicate unclassified data). So hosts in non-secure environments must be prepared to receive the security parameters, even though they don't need to send them ๐ธ
3.7. Data Communication โจ
okay so once the connection is established, data gets moved around by swapping segments ๐. Segments can get lost because of errors (the checksum test fails) or because the network is congested ๐ญ, so TCP uses retransmission after a timeout to make sure every single segment arrives. Duplicate segments can also show up, thanks to the network or TCP's own retransmissions. Like we talked about in the sequence numbers section, TCP runs certain tests on the sequence and acknowledgment numbers in each segment to check that they're acceptable ๐.
The sender keeps track of the next sequence number to use in SND.NXT. The receiver keeps track of the next sequence number it expects in RCV.NXT. The sender also tracks the oldest unacknowledged sequence number in SND.UNA. If the data flow is momentarily idle and everything sent has been acknowledged, all three variables are equal ๐ซถ.
When the sender builds a segment and transmits it, the sender advances SND.NXT. When the receiver accepts a segment, it advances RCV.NXT and sends an acknowledgment. When the data sender gets an acknowledgment, it advances SND.UNA. How far apart these values are is a measure of the delay in the communication ๐ข. The amount each variable moves is the length of the data in the segment. Also, once you're in the ESTABLISHED state, every segment must carry current acknowledgment information, no exceptions ๐
.
The CLOSE user call implies a push function, and so does the FIN control flag in an incoming segment ๐.
Retransmission Timeout
literally the network is so unpredictable (it's an internetwork, it's a whole mess ๐), and TCP connections get used for so many different things, so the retransmission timeout has to be figured out dynamically ๐ง . The spec gives one procedure as an example, just to show how it could work.
An Example Retransmission Timeout Procedure
Here's the vibe. You measure the time between sending a data octet with a particular sequence number and receiving an acknowledgment that covers that sequence number. (The segments you send don't have to match the segments you receive.) That measured time is the Round Trip Time (RTT) โฑ๏ธ. Next you compute a Smoothed Round Trip Time (SRTT) like this:
SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
Then, based on that, you compute the retransmission timeout (RTO):
RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]
where UBOUND is an upper bound on the timeout (e.g., 1 minute), LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is a smoothing factor (e.g., .8 to .9), and BETA is a delay variance factor (e.g., 1.3 to 2.0) ๐ฆ.
The Communication of Urgent Information
The whole point of the TCP urgent mechanism is to let the sending user poke the receiving user into accepting some urgent data ๐จ. It also lets the receiving TCP tell its user when all the urgent data it currently knows about has been received ๐.
This mechanism lets a point in the data stream be marked as the end of the urgent information. Whenever that point is ahead of the receive sequence number (RCV.NXT) at the receiving TCP, that TCP must tell the user to go into "urgent mode". When the receive sequence number catches up to the urgent pointer, the TCP must tell the user to go into "normal mode" ๐. If the urgent pointer gets updated while the user is in "urgent mode", the user won't see the update at all ๐.
The method uses an urgent field that's carried in every segment that gets transmitted. The URG control flag says the urgent field is meaningful, and that its value has to be added to the segment sequence number to get the urgent pointer. If the flag isn't there, there's no urgent data outstanding ๐ธ.
To send an urgent indication, the user also must send at least one data octet โ๏ธ. If the sending user also indicates a push, the urgent information gets to the destination process faster โก.
Managing the Window
The window in each segment tells you the range of sequence numbers that the sender of the window (the data receiver) is ready to accept right now ๐ช. The assumption is that this is tied to how much data buffer space is available for the connection.
A big window encourages transmissions. If more data shows up than can be accepted, it gets thrown away ๐๏ธ, which causes a ton of retransmissions, adding pointless load to the network and the TCPs ๐ฉ. A small window can choke off data so badly that you end up with a round trip delay between every new segment ๐.
The mechanisms let a TCP advertise a large window and then later advertise a much smaller one, without having accepted that much data. This is called "shrinking the window," and it is strongly discouraged ๐ โโ๏ธ. The robustness principle says TCPs will not shrink the window themselves, but they will be ready for other TCPs to do it ๐ซถ.
The sending TCP must be ready to accept new data from the user and send at least one octet of it, even when the send window is zero. The sending TCP must also keep retransmitting to the receiving TCP regularly, even when the window is zero. Two minutes is recommended for the retransmission interval while the window is zero โฐ. This retransmission is essential, because it guarantees that when either TCP has a zero window, the window reopening gets reliably reported to the other side ๐.
When the receiving TCP has a zero window and a segment arrives, it must still send an acknowledgment showing its next expected sequence number and its current window, which is zero 0๏ธโฃ.
The sending TCP packages the data it's sending into segments that fit the current window, and it may repackage the segments on the retransmission queue. Repackaging is not required, but it may be helpful ๐ฆ.
In a connection with one-way data flow, the window information rides in acknowledgment segments that all share the same sequence number. That means there's no way to reorder them if they arrive out of order ๐ตโ๐ซ. It's not a huge deal, but it means the window info can occasionally be based on old reports from the data receiver. The fix is to act on window information only from segments that carry the highest acknowledgment number, meaning segments whose acknowledgment number is equal to or greater than the highest one received before ๐.
Window management has a big impact on performance, so here are some suggestions for implementers ๐.
Window Management Suggestions
Allocating a very small window makes data get sent in lots of tiny segments, when fewer big segments would actually perform better ๐.
One way to dodge small windows is for the receiver to hold off on updating a window until the new allocation is at least X percent of the maximum allocation possible for the connection (where X might be 20 to 40) ๐ง.
Another idea is for the sender to avoid sending small segments by waiting until the window is big enough before sending data. If the user signals a push function, though, the data must be sent even if it's a small segment ๐.
Heads up that acknowledgments should not be delayed, or you'll get unnecessary retransmissions ๐ . One strategy is to send an acknowledgment as soon as a small segment arrives (without updating the window information), and then send another acknowledgment with the new window information once the window is larger ๐ก.
The segment that probes a zero window can also kick off a slide into smaller and smaller segments ๐. If a segment with a single data octet, sent to probe a zero window, gets accepted, it uses up one octet of the window that just opened. If the sending TCP just sends as much as it can whenever the window is non-zero, the data ends up split into alternating big and small segments ๐ข. Over time, occasional pauses where the receiver frees up window space break the big segments into a small and a not-quite-so-big pair. After a while, the transmission is mostly small segments ๐ฅฒ.
The takeaway is that TCP implementations need to actively try to combine small window allocations into larger windows ๐งฉ, since the window management mechanisms tend to create lots of small windows in the simplest implementations.
3.8. Interfaces
There are, of course, two interfaces to care about: the user/TCP interface and the TCP/lower-level interface ๐. We have a pretty detailed model of the user/TCP interface, but the interface to the lower level protocol module is left unspecified here, since the lower level protocol's own specification will cover it in detail. For the case where the lower level is IP, we do note some of the parameter values TCPs might use ๐.
User/TCP Interface
The functional description of user commands to TCP below is, at best, fictional ๐ง, because every operating system has different facilities. So readers should be warned that different TCP implementations may have different user interfaces. Even so, all TCPs must provide a certain minimum set of services, so that every TCP implementation can support the same protocol hierarchy ๐๏ธ. This section specifies the functional interfaces that are required of all TCP implementations ๐.
TCP User Commands
The following sections functionally describe a USER/TCP interface. The notation looks like most procedure or function calls in high-level languages, but that doesn't rule out trap-type service calls (e.g., SVCs, UUOs, EMTs) ๐งพ.
The user commands below specify the basic functions the TCP must perform to support interprocess communication. Each implementation has to define its own exact format, and it may offer combinations or subsets of the basic functions in single calls. In particular, some implementations may want to automatically OPEN a connection on the first SEND or RECEIVE the user issues for a given connection ๐ฏ.
When it's providing interprocess communication, the TCP must not only accept commands, but also return information to the processes it serves. That information consists of:
- (a) general information about a connection (e.g., interrupts, remote close, binding of unspecified foreign socket).
- (b) replies to specific user commands indicating success or various types of failure.
Open
Format:
OPEN (local port, foreign socket, active/passive
[, timeout] [, precedence] [, security/compartment] [, options])
-> local connection name
We assume the local TCP knows the identity of the processes it serves, and it will check that the process is authorized to use the connection specified ๐. Depending on the TCP implementation, the local network and TCP identifiers for the source address will be supplied either by the TCP or by the lower level protocol (e.g., IP) ๐ชช. These considerations come from concern about security, to the extent that no TCP should be able to masquerade as another one, and so on ๐ต๏ธโโ๏ธ. Similarly, no process can masquerade as another without the collusion of the TCP ๐ซฃ.
If the active/passive flag is set to passive, then this is a call to LISTEN for an incoming connection ๐โจ. A passive open MAY have either a fully specified foreign socket, so it waits for one particular connection, or an unspecified foreign socket, so it waits for any call at all ๐ฆ. A fully specified passive call can be turned active later by running a SEND ๐ .
A transmission control block (TCB) gets created and partly filled in with the data from the OPEN command parameters ๐.
On an active OPEN command, TCP starts the procedure to synchronize (aka establish) the connection right away ๐.
The timeout, if there is one, lets the caller set a timeout for all the data submitted to TCP โฐ. If the data isn't delivered to the destination within that timeout period, TCP aborts the connection ๐. The present global default is five minutes ๐.
TCP, or some part of the operating system, checks that the user is allowed to open a connection with the specified precedence or security/compartment ๐. If the OPEN call doesn't specify precedence or security/compartment, the default values MUST be used ๐.
TCP only accepts incoming requests as a match if the security/compartment information is exactly the same, AND the precedence is equal to or higher than the precedence requested in the OPEN call ๐.
The precedence for the connection is the higher of the values requested in the OPEN call and received from the incoming request, and it stays fixed at that value for the life of the connection ๐. Implementers MAY want to give the user control over this precedence negotiation ๐๏ธ. For example, the user might be allowed to specify that precedence must be matched exactly, or that any attempt to raise it gets confirmed by the user first ๐.
TCP gives the user a local connection name ๐ท๏ธ. That name can then be used as a shorthand for the connection defined by the <local socket, foreign socket> pair ๐ซถ.
Send ๐
Format:
SEND (local connection name, buffer address, byte
count, PUSH flag, URGENT flag [,timeout])
This call sends the data in the indicated user buffer over the indicated connection ๐จ. If the connection hasn't been opened, the SEND counts as an error ๐ฌ. Some implementations MAY let users SEND first, and then an automatic OPEN happens ๐ช. If the calling process isn't authorized to use this connection, an error comes back ๐ซ.
If the PUSH flag is set, the data MUST be transmitted promptly to the receiver, and the PUSH bit gets set in the last TCP segment made from the buffer ๐โโ๏ธ๐จ. If the PUSH flag is not set, the data MAY be combined with data from later SENDs so transmission is more efficient โก.
If the URGENT flag is set, the segments sent to the destination TCP will have the urgent pointer set ๐จ. The receiving TCP signals the urgent condition to the receiving process if the urgent pointer shows that data before it hasn't been consumed yet ๐ฃ. The whole point of urgent is to hype the receiver up to process the urgent data, and to tell the receiver when all the currently known urgent data has arrived ๐ข. The number of times the sending user's TCP signals urgent won't necessarily match the number of times the receiving user gets told about urgent data ๐คทโโ๏ธ.
If no foreign socket was specified in the OPEN, but the connection is established anyway (for example, because a LISTENing connection got specific after a foreign segment arrived for the local socket), then the designated buffer is sent to the implied foreign socket ๐ฏ. People who use OPEN with an unspecified foreign socket can still use SEND without ever explicitly knowing the foreign socket address ๐ง .
BUT, if a SEND is tried before the foreign socket gets specified, an error is returned ๐ โโ๏ธ. Users can use the STATUS call to check the status of the connection ๐. In some implementations, TCP MAY tell the user when an unspecified socket gets bound ๐.
If a timeout is specified, the current user timeout for this connection changes to the new one โฑ๏ธ.
In the simplest implementation, SEND wouldn't return control to the sending process until either the transmission was complete or the timeout was exceeded ๐ด. But that simple method can deadlock (for example, both sides might try to do SENDs before doing any RECEIVEs) AND it performs poorly, so it is NOT RECOMMENDED ๐ โโ๏ธ๐. A more sophisticated implementation returns immediately, so the process can run at the same time as network I/O, and it also lets multiple SENDs be in progress at once ๐๏ธ. Multiple SENDs get served first come, first served, so TCP queues the ones it can't service right away ๐งพ.
We've been assuming an asynchronous user interface, where a SEND later gets some kind of SIGNAL or pseudo-interrupt from the serving TCP ๐ฌ. The other option is to return a response right away ๐. For instance, SENDs might return an immediate local acknowledgment, even if the distant TCP hasn't acknowledged the segment yet ๐ค. We could optimistically assume eventual success, and if we're wrong, the connection closes anyway due to the timeout โ. In implementations like that (synchronous), there are still some asynchronous signals, but they deal with the connection itself, not with specific segments or buffers ๐งฉ.
So the process can tell apart the error and success indications for different SENDs, it might be appropriate for the buffer address to come back along with the coded response to the SEND request ๐๏ธ. TCP-to-user signals get discussed below, and they show what information SHOULD be returned to the calling process ๐.
Receive ๐ฅ
Format:
RECEIVE (local connection name, buffer address, byte
count) -> byte count, urgent flag, push flag
This command allocates a receiving buffer for the specified connection ๐๏ธ. If no OPEN came before it, or the calling process isn't authorized to use this connection, an error is returned ๐ โโ๏ธ.
In the simplest implementation, control wouldn't go back to the calling program until either the buffer was full or some error happened, but this scheme is super prone to deadlocks ๐ตโ๐ซ. A more sophisticated implementation lets several RECEIVEs be outstanding at once ๐ช. They get filled as segments arrive ๐ฆ. This strategy gives more throughput, but the cost is a fancier (possibly asynchronous) scheme to tell the calling program that a PUSH was seen or a buffer got filled ๐.
If enough data arrives to fill the buffer before a PUSH is seen, the PUSH flag won't be set in the response to the RECEIVE ๐ซ. The buffer gets filled with as much data as it can hold ๐ฏ. If a PUSH is seen before the buffer is full, the buffer comes back partially filled with PUSH indicated ๐ซธ.
If there's urgent data, the user was informed as soon as it arrived, through a TCP-to-user signal ๐จ. The receiving user SHOULD therefore be in "urgent mode" ๐ซจ. If the URGENT flag is on, more urgent data is still on the way ๐ฃ๏ธ. If the URGENT flag is off, this RECEIVE call has returned all the urgent data, and the user MAY now leave "urgent mode" ๐ฅณ. Heads up: data after the urgent pointer (non-urgent data) can't be delivered to the user in the same buffer as preceding urgent data, unless the boundary is clearly marked for the user ๐ง.
To tell apart several outstanding RECEIVEs, and to handle the case where a buffer isn't completely filled, the return code comes with both a buffer pointer and a byte count showing the actual length of the data received ๐ข.
Other ways to do RECEIVE could have TCP allocate the buffer storage, or TCP could share a ring buffer with the user ๐.
Close ๐ช
Format:
CLOSE (local connection name)
This command closes the specified connection ๐. If the connection isn't open, or the calling process isn't authorized to use this connection, an error is returned โ. Closing is meant to be graceful ๐ซง: outstanding SENDs keep getting transmitted (and retransmitted) as flow control allows, until they've all been serviced ๐ท. So it should be fine to make several SEND calls, then a CLOSE, and expect all the data to reach the destination ๐ . Users SHOULD also keep RECEIVEing on CLOSING connections, because the other side might still be sending the last of its data ๐ญ. So CLOSE means "I have no more to send," but it does NOT mean "I will not receive any more" ๐ โโ๏ธ๐. It can happen (if the user-level protocol isn't well thought out) that the closing side can't get rid of all its data before timing out ๐ฉ. When that happens, CLOSE turns into ABORT, and the closing TCP gives up ๐ณ๏ธ.
The user MAY CLOSE the connection at any time on their own initiative, or in response to various prompts from TCP (for example, a remote close was executed, the transmission timeout was exceeded, or the destination is inaccessible) ๐ฌ.
Closing needs to talk to the foreign TCP, so connections MAY remain in the closing state for a short time โณ. Trying to reopen the connection before TCP replies to the CLOSE command will get you error responses ๐ซ.
Close also implies the push function ๐ซธ.
Status ๐
Format:
STATUS (local connection name) -> status data
This is an implementation-dependent user command, and it could be left out without any bad effects ๐คทโโ๏ธ. The information returned would typically come from the TCB tied to the connection ๐๏ธ.
This command returns a data block with the following info ๐:
local socket,
foreign socket,
local connection name,
receive window,
send window,
connection state,
number of buffers awaiting acknowledgment,
number of buffers pending receipt,
urgent state,
precedence,
security/compartment,
and transmission timeout.
Depending on the state of the connection, or on the implementation itself, some of this info may not be available or meaningful ๐. If the calling process isn't authorized to use this connection, an error is returned ๐. That's the point: it stops unauthorized processes from snooping on a connection ๐ต๏ธโโ๏ธ๐.
Abort ๐
Format:
ABORT (local connection name)
3.8. Interfaces (continued) ๐
Okay so ABORT is basically the dramatic exit ๐. It causes all pending SENDs and RECEIVES to get aborted ๐ โโ๏ธ, the TCB gets removed ๐๏ธ, and a special RESET message gets sent to the TCP on the other side of the connection ๐. Depending on the implementation, users might get an abort indication for each outstanding SEND or RECEIVE, or they might just get an ABORT-acknowledgment. Either way it's giving main character exit ๐
TCP-to-User Messages
Okay so the operating system is assumed to give the TCP a way to asynchronously tap the user program on the shoulder ๐. When the TCP does signal a user program, certain info gets passed along. Often that info is an error message ๐ญ. Other times it's info about finishing a SEND or RECEIVE or some other user call โจ. Here's what gets passed along:
Local Connection Name Always
Response String Always
Buffer Address Send & Receive
Byte count (counts bytes received) Receive
Push flag Receive
Urgent flag Receive
TCP/Lower-Level Interface
The TCP calls on a lower level protocol module to actually send and receive info over a network ๐. One case is the ARPA internetwork system, where the lower level module is the Internet Protocol (IP) [2] ๐ฆ.
If the lower level protocol is IP, it provides arguments for a type of service and for a time to live. TCP uses these settings for those parameters ๐ง:
Type of Service = Precedence: routine, Delay: normal, Throughput:
normal, Reliability: normal; or 00000000.
Time to Live = one minute, or 00111100.
Note that the assumed maximum segment lifetime is two minutes ๐. Here we explicitly ask that a segment be destroyed if it cannot be delivered by the internet system within one minute. That's a very firm boundary, bestie ๐ โโ๏ธ.
If the lower level is IP (or another protocol that provides this feature) and source routing is used, the interface must allow the route information to be communicated ๐บ๏ธ. This is especially important so that the source and destination addresses used in the TCP checksum are the originating source and ultimate destination ๐. It's also important to preserve the return route so connection requests can be answered ๐ซถ.
Any lower level protocol will have to provide the source address, destination address, and protocol fields, plus some way to determine the "TCP length". It has to do this both to provide the functional equivlent service of IP and to be used in the TCP checksum ๐ธ.
3.9. Event Processing โจ
The processing in this section is an example of one possible implementation ๐ฅ. Other implementations may have slightly different processing sequences, but they should differ from those in this section only in detail, not in substance ๐.
The TCP is basically a responder, bestie ๐ง. It reacts to events, and the events fall into three categories: user calls, arriving segments, and timeouts. This section describes what the TCP does for each event ๐ . A lot of the time, the processing depends on the state of the connection ๐.
Here are the events that can happen:
User Calls
OPEN
SEND
RECEIVE
CLOSE
ABORT
STATUS
Arriving Segments
SEGMENT ARRIVES
Timeouts
USER TIMEOUT
RETRANSMISSION TIMEOUT
TIME-WAIT TIMEOUT
The model for the TCP/user interface is that user commands get an immediate return, and possibly a delayed response via an event or pseudo interrupt โญ. In the descriptions below, the term "signal" means cause a delayed response ๐ฆ.
Error responses are given as character strings ๐. For example, user commands that reference connections that don't exist get "error: connection not open" ๐.
Please note that all arithmetic on sequence numbers, acknowledgment numbers, windows, et cetera, is modulo 2**32, the size of the sequence number space ๐ข. Also note that "=<" means less than or equal to (modulo 2**32) ๐.
A natural way to think about processing incoming segments is to imagine they're first tested for proper sequence number. That means checking that their contents lie in the range of the expected "receive window" in the sequence number space ๐. Then they're generally queued and processed in sequence number order ๐ซถ.
When a segment overlaps other already received segments, we reconstruct the segment to contain just the new data, and adjust the header fields so everything stays consistent ๐.
Note that if no state change is mentioned, the TCP stays in the same state ๐ธ.
OPEN Call
CLOSED STATE (i.e., TCB does not exist)
Create a new transmission control block (TCB) to hold connection state info ๐. Fill in the local socket identifier, foreign socket, precedence, security/compartment, and user timeout info. Note that some parts of the foreign socket may be unspecified in a passive OPEN, and they're filled in by the parameters of the incoming SYN segment ๐ง. Verify that the security and precedence requested are allowed for this user. If they aren't, return "error: precedence not allowed" or "error: security/compartment not allowed." ๐
โโ๏ธ If passive, enter the LISTEN state and return. If active and the foreign socket is unspecified, return "error: foreign socket unspecified". If active and the foreign socket is specified, issue a SYN segment ๐. An initial send sequence number (ISS) is selected. A SYN segment of the form <SEQ=ISS><CTL=SYN> is sent. Set SND.UNA to ISS, SND.NXT to ISS+1, enter SYN-SENT state, and return ๐.
If the caller doesn't have access to the local socket specified, return "error: connection illegal for this process" ๐ญ. If there's no room to create a new connection, return "error: insufficient resources" ๐.
LISTEN STATE
If active and the foreign socket is specified, then change the connection from passive to active, and select an ISS ๐ฆ. Send a SYN segment, set SND.UNA to ISS, and SND.NXT to ISS+1. Enter SYN-SENT state. Data associated with SEND may be sent with the SYN segment or queued for transmission after entering ESTABLISHED state โจ. The urgent bit, if requested in the command, must be sent with the data segments sent as a result of this command ๐ฅ. If there's no room to queue the request, respond with "error: insufficient resources". If the foreign socket wasn't specified, then return "error: foreign socket unspecified" ๐.
SYN-SENT STATE, SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE
Return "error: connection already exists" ๐ .
SEND Call
CLOSED STATE (i.e., TCB does not exist)
If the user doesn't have access to such a connection, then return "error: connection illegal for this process" ๐ โโ๏ธ.
Otherwise, return "error: connection does not exist" ๐ญ.
LISTEN STATE
If the foreign socket is specified, then change the connection from passive to active, and select an ISS ๐. Send a SYN segment, set SND.UNA to ISS, and SND.NXT to ISS+1. Enter SYN-SENT state. Data associated with SEND may be sent with the SYN segment or queued for transmission after entering ESTABLISHED state ๐ธ. The urgent bit, if requested in the command, must be sent with the data segments sent as a result of this command ๐ซถ. If there's no room to queue the request, respond with "error: insufficient resources". If the foreign socket wasn't specified, then return "error: foreign socket unspecified" ๐.
SYN-SENT STATE, SYN-RECEIVED STATE
Queue the data for transmission after entering ESTABLISHED state ๐ง. If there's no space to queue, respond with "error: insufficient resources" ๐.
ESTABLISHED STATE, CLOSE-WAIT STATE
Segmentize the buffer and send it with a piggybacked acknowledgment (acknowledgment value = RCV.NXT) ๐ฆ. If there's insufficient space to remember this buffer, simply return "error: insufficient resources" ๐ญ.
If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the urgent pointer in the outgoing segments ๐ฅ.
FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE
Return "error: connection closing" and do not service the request ๐ โโ๏ธ.
RECEIVE Call
CLOSED STATE (i.e., TCB does not exist)
If the user doesn't have access to such a connection, return "error: connection illegal for this process" ๐.
Otherwise, return "error: connection does not exist" ๐ .
LISTEN STATE, SYN-SENT STATE, SYN-RECEIVED STATE
Queue it for processing after entering ESTABLISHED state โจ. If there's no room to queue this request, respond with "error: insufficient resources" ๐.
ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE
If insufficient incoming segments are queued to satisfy the request, queue the request ๐. If there's no queue space to remember the RECEIVE, respond with "error: insufficient resources" ๐ญ.
Reassemble the queued incoming segments into the receive buffer and return to the user. Mark "push seen" (PUSH) if this is the case ๐.
If RCV.UP is ahead of the data currently being passed to the user, notify the user of the presence of urgent data ๐.
When the TCP takes responsibility for delivering data to the user, that fact must be communicated to the sender via an acknowledgment ๐ซถ. The formation of such an acknowledgment is described below, in the discussion of processing an incoming segment ๐ฆ.
CLOSE-WAIT STATE
Since the remote side has already sent a FIN, RECEIVEs must be satisfied by text that's already on hand but not yet delivered to the user ๐ง. If no text is waiting to be delivered, the RECEIVE will get an "error: connection closing" response ๐ญ. Otherwise, any remaining text can be used to satisfy the RECEIVE ๐ธ.
CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE
Return "error: connection closing" ๐ โโ๏ธ.
CLOSE Call
CLOSED STATE (i.e., TCB does not exist)
If the user doesn't have access to such a connection, return "error: connection illegal for this process" ๐.
Otherwise, return "error: connection does not exist" ๐.
LISTEN STATE
Any outstanding RECEIVEs are returned with "error: closing" responses ๐ฅ. Delete the TCB, enter CLOSED state, and return ๐ฆ.
SYN-SENT STATE
Delete the TCB and return "error: closing" responses to any queued SENDs or RECEIVEs ๐ญ.
SYN-RECEIVED STATE
If no SENDs have been issued and there's no pending data to send, then form a FIN segment, send it, and enter FIN-WAIT-1 state ๐. Otherwise, queue it for processing after entering ESTABLISHED state ๐ซถ.
ESTABLISHED STATE
Queue this until all preceding SENDs have been segmentized, then form a FIN segment and send it โจ. In any case, enter FIN-WAIT-1 state ๐ .
FIN-WAIT-1 STATE, FIN-WAIT-2 STATE
Strictly speaking, this is an error and should receive an "error: connection closing" response ๐. An "ok" response would be acceptable too, as long as a second FIN isn't emitted (the first FIN may be retransmitted, though) ๐.
CLOSE-WAIT STATE
Queue this request until all preceding SENDs have been segmentized. Then send a FIN segment and enter CLOSING state ๐.
CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE
Respond with "error: connection closing" ๐.
ABORT Call
CLOSED STATE (i.e., TCB does not exist) is where the connection doesn't even exist yet, so the answer depends on who's asking ๐
- If the user should not have access to such a connection, return
"error: connection illegal for this process"๐ซ - Otherwise return
"error: connection does not exist"๐ซ
LISTEN STATE ๐ง
- Any outstanding RECEIVEs should be returned with
"error: connection reset"responses. Delete the TCB, enter CLOSED state, and return. Bye bye, listener ๐
SYN-SENT STATE ๐ค
- All queued SENDs and RECEIVEs should be given
"connection reset"notification, the TCB gets deleted, enter CLOSED state, and return. The handshake got ghosted ๐
SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, and CLOSE-WAIT STATE ๐
- Send a reset segment:
<SEQ=SND.NXT><CTL=RST>
- All queued SENDs and RECEIVEs should be given
"connection reset"notification. All segments queued for transmission (except for the RST formed above) or retransmission should be flushed, the TCB gets deleted, enter CLOSED state, and return. Everything gets cleaned up, periodt โจ
CLOSING STATE, LAST-ACK STATE, and TIME-WAIT STATE ๐ฆ
- Respond with
"ok", delete the TCB, enter CLOSED state, and return. Calm exit, very iconic ๐ธ
STATUS Call ๐
CLOSED STATE (i.e., TCB does not exist) ๐
- If the user should not have access to such a connection, return
"error: connection illegal for this process"๐ซ - Otherwise return
"error: connection does not exist"๐ซ
LISTEN STATE ๐ง
- Return
"state = LISTEN", and the TCB pointer.
SYN-SENT STATE ๐ค
- Return
"state = SYN-SENT", and the TCB pointer.
SYN-RECEIVED STATE ๐ฅ
- Return
"state = SYN-RECEIVED", and the TCB pointer.
ESTABLISHED STATE ๐
- Return
"state = ESTABLISHED", and the TCB pointer. The connection is thriving ๐
FIN-WAIT-1 STATE ๐
- Return
"state = FIN-WAIT-1", and the TCB pointer.
FIN-WAIT-2 STATE ๐
- Return
"state = FIN-WAIT-2", and the TCB pointer.
CLOSE-WAIT STATE ๐ช
- Return
"state = CLOSE-WAIT", and the TCB pointer.
CLOSING STATE ๐ซ
- Return
"state = CLOSING", and the TCB pointer.
LAST-ACK STATE ๐ฅ
- Return
"state = LAST-ACK", and the TCB pointer.
TIME-WAIT STATE โณ
- Return
"state = TIME-WAIT", and the TCB pointer.
SEGMENT ARRIVES ๐
Okay so this is where incoming segments get sorted out, and it's a whole thing ๐ง
If the state is CLOSED (i.e., TCB does not exist) then ๐
- All data in the incoming segment is discarded. An incoming segment containing a RST is discarded. An incoming segment not containing a RST causes a RST to be sent in response. The acknowledgment and sequence field values are selected to make the reset sequence acceptable to the TCP that sent the offending segment ๐
- If the ACK bit is off, sequence number zero is used:
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
- If the ACK bit is on:
<SEQ=SEG.ACK><CTL=RST>
- Return.
If the state is LISTEN then ๐ง
- First, check for an RST. An incoming RST should be ignored. Return. Not your drama, not your problem ๐ซถ
- Second, check for an ACK. Any acknowledgment is bad if it arrives on a connection still in the LISTEN state. An acceptable reset segment should be formed for any arriving ACK-bearing segment. The RST should be formatted as follows:
<SEQ=SEG.ACK><CTL=RST>
- Return.
- Third, check for a SYN. If the SYN bit is set, check the security. If the security/compartment on the incoming segment does not exactly match the security/compartment in the TCB, then send a reset and return:
<SEQ=SEG.ACK><CTL=RST>
- If the SEG.PRC is greater than the TCB.PRC, then if allowed by the user and the system, set TCB.PRC<-SEG.PRC. If not allowed, send a reset and return:
<SEQ=SEG.ACK><CTL=RST>
- If the SEG.PRC is less than the TCB.PRC, then continue.
- Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ, and any other control or text should be queued for processing later. ISS should be selected and a SYN segment sent of the form:
<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
- SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection state should be changed to SYN-RECEIVED. Note that any other incoming control or data (combined with SYN) will be processed in the SYN-RECEIVED state, but processing of SYN and ACK should not be repeated. If the listen was not fully specified (i.e., the foreign socket was not fully specified), then the unspecified fields should be filled in now. ๐คฉ
- Fourth, other text or control. Any other control or text-bearing segment (not containing SYN) must have an ACK and thus would be discarded by the ACK processing. An incoming RST segment could not be valid, since it could not have been sent in response to anything sent by this incarnation of the connection. So you are unlikely to get here, but if you do, drop the segment, and return. ๐ซ
If the state is SYN-SENT then ๐ค
- First, check the ACK bit.
- If the ACK bit is set:
- If
SEG.ACK =< ISS, orSEG.ACK > SND.NXT, send a reset (unless the RST bit is set, in which case drop the segment and return):
- If
- If the ACK bit is set:
<SEQ=SEG.ACK><CTL=RST>
- and discard the segment. Return.
- If
SND.UNA =< SEG.ACK =< SND.NXTthen the ACK is acceptable. โ
- Second, check the RST bit.
- If the RST bit is set:
- If the ACK was acceptable, then signal the user
"error: connection reset", drop the segment, enter CLOSED state, delete the TCB, and return. Otherwise (no ACK) drop the segment and return.
- If the ACK was acceptable, then signal the user
- If the RST bit is set:
- Third, check the security and precedence.
- If the security/compartment in the segment does not exactly match the security/compartment in the TCB, send a reset:
- If there is an ACK:
- If the security/compartment in the segment does not exactly match the security/compartment in the TCB, send a reset:
<SEQ=SEG.ACK><CTL=RST>
- Otherwise:
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
- If there is an ACK, the precedence in the segment must match the precedence in the TCB. If not, send a reset:
<SEQ=SEG.ACK><CTL=RST>
- If there is no ACK:
- If the precedence in the segment is higher than the precedence in the TCB, then if allowed by the user and the system, raise the precedence in the TCB to that in the segment. If not allowed to raise the prec, then send a reset:
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
- If the precedence in the segment is lower than the precedence in the TCB, continue.
- If a reset was sent, discard the segment and return.
- Fourth, check the SYN bit. This step should be reached only if the ACK is ok, or there is no ACK, and if the segment did not contain a RST.
- If the SYN bit is on and the security/compartment and precedence are acceptable, then RCV.NXT is set to SEG.SEQ+1, and IRS is set to SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there is an ACK), and any segments on the retransmission queue which are thereby acknowledged should be removed.
- If SND.UNA > ISS (our SYN has been ACKed), change the connection state to ESTABLISHED, form an ACK segment:
<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
- and send it. Data or controls which were queued for transmission may be included. If there are other controls or text in the segment, then continue processing at the sixth step below, where the URG bit is checked. Otherwise return.
- Otherwise, enter SYN-RECEIVED, form a SYN,ACK segment:
<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
- and send it. If there are other controls or text in the segment, queue them for processing after the ESTABLISHED state has been reached, return.
- Fifth, if neither of the SYN or RST bits is set, then drop the segment and return. ๐๏ธ
Otherwise, ๐
First, check the sequence number. ๐ข
- For the following states: SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, and TIME-WAIT STATE:
- Segments are processed in sequence. Initial tests on arrival are used to discard old duplicates, but further processing is done in SEG.SEQ order. If a segment's contents straddle the boundary between old and new, only the new parts should be processed.
- There are four cases for the acceptability test for an incoming segment:
Segment Receive Test
Length Window
------- ------- -------------------------------------------
0 0 SEG.SEQ = RCV.NXT
0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
>0 0 not acceptable
>0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
- If the RCV.WND is zero, no segments will be acceptable, but special allowance should be made to accept valid ACKs, URGs and RSTs.
- If an incoming segment is not acceptable, an acknowledgment should be sent in reply (unless the RST bit is set, in which case drop the segment and return):
<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
- After sending the acknowledgment, drop the unacceptable segment and return.
- In the following, it is assumed that the segment is the idealized segment that begins at RCV.NXT and does not exceed the window. One could tailor actual segments to fit this assumption by trimming off any portions that lie outside the window (including SYN and FIN), and only processing further if the segment then begins at RCV.NXT. Segments with higher beginning sequence numbers may be held for later processing. ๐งฉ
Second, check the RST bit. ๐จ
- SYN-RECEIVED STATE
- If the RST bit is set:
- If this connection was initiated with a passive OPEN (i.e., came from the LISTEN state), then return this connection to LISTEN state and return. The user need not be informed. If this connection was initiated with an active OPEN (i.e., came from SYN-SENT state), then the connection was refused, so signal the user
"connection refused". In either case, all segments on the retransmission queue should be removed. And in the active OPEN case, enter the CLOSED state, delete the TCB, and return.
- If this connection was initiated with a passive OPEN (i.e., came from the LISTEN state), then return this connection to LISTEN state and return. The user need not be informed. If this connection was initiated with an active OPEN (i.e., came from SYN-SENT state), then the connection was refused, so signal the user
- If the RST bit is set:
- ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, and CLOSE-WAIT
- If the RST bit is set, then any outstanding RECEIVEs and SEND should receive
"reset"responses. All segment queues should be flushed. Users should also receive an unsolicited general"connection reset"signal. Enter the CLOSED state, delete the TCB, and return. Yikes, that's a full reset ๐ญ
- If the RST bit is set, then any outstanding RECEIVEs and SEND should receive
- CLOSING STATE, LAST-ACK STATE, and TIME-WAIT
- If the RST bit is set, then enter the CLOSED state, delete the TCB, and return.
Third, check security and precedence. ๐
- SYN-RECEIVED
- If the security/compartment and precedence in the segment do not exactly match the security/compartment and precedence in the TCB, then send a reset, and return.
- ESTABLISHED STATE
- If the security/compartment and precedence in the segment do not exactly match the security/compartment and precedence in the TCB, then send a reset. Any outstanding RECEIVEs and SEND should receive
"reset"responses. All segment queues should be flushed. Users should also receive an unsolicited general"connection reset"signal. Enter the CLOSED state, delete the TCB, and return. Security mismatch = full stop ๐
- If the security/compartment and precedence in the segment do not exactly match the security/compartment and precedence in the TCB, then send a reset. Any outstanding RECEIVEs and SEND should receive
Okay so this check sits right after the sequence check, and that's giving intention ๐ It stops a segment from an old connection between these same ports (but with a different security or precedence) from knocking out the current connection. Iconic protection, no notes ๐ก๏ธ
Fourth, check the SYN bit. ๐ฆ
This happens in these states:
SYN-RECEIVEDESTABLISHED STATEFIN-WAIT STATE-1FIN-WAIT STATE-2CLOSE-WAIT STATECLOSING STATELAST-ACK STATETIME-WAIT STATE
If the SYN is in the window, it's an error ๐จ So we send a reset, any outstanding RECEIVEs and SENDs get reset responses, every segment queue gets flushed, and the user gets an unsolicited general connection reset signal too. Then we enter CLOSED, delete the TCB, and return. Bye bye ๐
If the SYN is not in the window, this step never gets reached, because an ack already went out back in the first step (the sequence number check) ๐ง
Fifth, check the ACK field. ๐
If the ACK bit is off, drop the segment and return. Done and dusted ๐
If the ACK bit is on, it depends on the state:
SYN-RECEIVED STATE โจ
If SND.UNA =< SEG.ACK =< SND.NXT, then enter the ESTABLISHED state and keep processing.
If the segment's acknowledgment isn't acceptable, form a reset segment:
<SEQ=SEG.ACK><CTL=RST>
and send it. ๐
ESTABLISHED STATE ๐ธ
If SND.UNA < SEG.ACK =< SND.NXT, then set SND.UNA <- SEG.ACK. Any segments on the retransmission queue that are now fully acknowledged get removed. Users should get positive acknowledgments for buffers that were SENT and fully acknowledged, so the SEND buffer comes back with an "ok" response. If the ACK is a duplicate (SEG.ACK < SND.UNA), you can ignore it. If the ACK is for something not yet sent (SEG.ACK > SND.NXT), then send an ACK, drop the segment, and return. Not it, bestie ๐
โโ๏ธ
If SND.UNA < SEG.ACK =< SND.NXT, the send window should be updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and SND.WL2 =< SEG.ACK)), then set SND.WND <- SEG.WND, set SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. ๐
Quick note: SND.WND is an offset from SND.UNA. SND.WL1 records the sequence number of the last segment used to update SND.WND, and SND.WL2 records the acknowledgment number of that same segment. The check is what stops old segments from messing with the window. Protected, obsessed ๐ญ
FIN-WAIT-1 STATE ๐ฆ
Do everything the ESTABLISHED state does, and then, if our FIN is now acknowledged, enter FIN-WAIT-2 and keep processing there โจ
FIN-WAIT-2 STATE ๐
Do everything the ESTABLISHED state does, plus this: if the retransmission queue is empty, the user's CLOSE can be acknowledged with "ok", but don't delete the TCB yet ๐ซถ
CLOSE-WAIT STATE ๐
Same processing as the ESTABLISHED state. Easy ๐
CLOSING STATE ๐ฅ
Do everything the ESTABLISHED state does, and if the ACK acknowledges our FIN, enter the TIME-WAIT state. Otherwise, ignore the segment. Literally no drama ๐
LAST-ACK STATE ๐
The only thing that can show up in this state is an acknowledgment of our FIN. If our FIN is now acknowledged, delete the TCB, enter the CLOSED state, and return. Goodbye, TCB ๐ฅ
TIME-WAIT STATE โญ
The only thing that can show up here is a retransmission of the remote FIN. Acknowledge it and restart the 2 MSL timeout. โณ
Sixth, check the URG bit. ๐
ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ๐ธ
If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP). Signal the user that the remote side has urgent data if the urgent pointer (RCV.UP) is ahead of the data already consumed. If the user has already been signaled (or is still in "urgent mode") for this continuous run of urgent data, don't signal them again. Nobody likes being pinged twice ๐
CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT ๐
This shouldn't happen, since a FIN has already come in from the remote side. Ignore the URG.
Seventh, process the segment text. ๐ง
ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ๐
Once we're in the ESTABLISHED state, segment text can be delivered into the user's RECEIVE buffers. Text can be moved into buffers until the buffer is full or the segment is empty. If the segment empties and carries a PUSH flag, the user gets told, when the buffer comes back, that a PUSH was received ๐ฃ
When TCP takes responsibility for delivering the data to the user, it must also acknowledge that it received the data. โ
Once TCP takes responsibility for the data, it advances RCV.NXT over the data it accepted and adjusts RCV.WND to match the current buffer availability. The total of RCV.NXT and RCV.WND should not go down. ๐โ
Please check out the window management suggestions in section 3.7. Trust me, they're worth it ๐
Send an acknowledgment that looks like this:
<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
This ack should get piggybacked on a segment that's being transmitted, as long as that doesn't cause undue delay ๐ฆ
CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE ๐
This shouldn't happen, since a FIN has already come in from the remote side. Ignore the segment text.
Eighth, check the FIN bit. ๐
Don't process the FIN if the state is CLOSED, LISTEN, or SYN-SENT, because SEG.SEQ can't be validated there. Drop the segment and return. Not today ๐ซ
If the FIN bit is set, signal the user connection closing and return any pending RECEIVEs with that same message. Advance RCV.NXT over the FIN and send an acknowledgment for it. FIN implies PUSH for any segment text the user hasn't received yet, so that stuff is getting delivered ๐
SYN-RECEIVED STATE, ESTABLISHED STATE ๐
Enter the CLOSE-WAIT state. ๐
FIN-WAIT-1 STATE ๐
If our FIN has been ACKed (maybe even in this very segment), enter TIME-WAIT, start the time-wait timer, and turn off the other timers. If not, enter the CLOSING state. โฐ
FIN-WAIT-2 STATE โญ
Enter the TIME-WAIT state. Start the time-wait timer and turn off the other timers. ๐ง
CLOSE-WAIT STATE ๐ซถ
Stay in the CLOSE-WAIT state. ๐ธ
CLOSING STATE ๐ฅ
Stay in the CLOSING state. ๐
LAST-ACK STATE ๐
Stay in the LAST-ACK state. ๐ค
TIME-WAIT STATE โณ
Stay in the TIME-WAIT state, and restart the 2 MSL time-wait timeout. โจ
And return. ๐
USER TIMEOUT โฐ
For any state, if the user timeout expires, flush all queues. Signal the user error: connection aborted due to user timeout in general, and for any outstanding calls too. Then delete the TCB, enter the CLOSED state, and return. Oof ๐ญ
RETRANSMISSION TIMEOUT ๐
For any state, if the retransmission timeout expires on a segment in the retransmission queue, send the segment at the front of that queue again, reinitialize the retransmission timer, and return. Second chances are everything ๐ซถ
TIME-WAIT TIMEOUT ๐
If the time-wait timeout expires on a connection, delete the TCB, enter the CLOSED state, and return. And that's the tea โ
GLOSSARY ๐
1822 ๐งพ
BBN Report 1822, "The Specification of the Interconnection of a Host and an IMP". The specification of the interface between a host and the ARPANET.
ACK ๐ฆ
A control bit (acknowledge) that takes up no sequence space. It shows that this segment's acknowledgment field holds the next sequence number the sender expects to receive, which means it's acknowledging receipt of all the earlier sequence numbers. Simple, but so important ๐
ARPANET message ๐
The unit of transmission between a host and an IMP in the ARPANET. The maximum size is about 1012 octets (8096 bits).
ARPANET packet ๐ฆ
A unit of transmission used inside the ARPANET between IMPs. The maximum size is about 126 octets (1008 bits).
connection ๐
A logical communication path identified by a pair of sockets. โจ
datagram ๐จ
A message sent in a packet switched computer communications network.
Destination Address ๐
The destination address, usually the network and host identifiers.
FIN ๐
A control bit (finis) that takes up one sequence number. It shows that the sender won't send any more data or control that uses sequence space. Bye for real ๐
fragment ๐งฉ
A portion of a logical unit of data. In particular, an internet fragment is a portion of an internet datagram.
FTP ๐
A file transfer protocol.
header ๐
Control information at the beginning of a message, segment, fragment, packet, or block of data.
host ๐ฅ๏ธ
A computer. In particular, a source or destination of messages from the point of view of the communication network. ๐ป
Identification ๐ชช
An Internet Protocol field. The sender assigns this value, and it helps put the fragments of a datagram back together ๐งท
IMP ๐
The Interface Message Processor, which is the packet switch of the ARPANET.
internet address ๐
A source or destination address specific to the host level.
internet datagram ๐ฌ
The unit of data exchanged between an internet module and the higher level protocol, together with the internet header.
internet fragment ๐งฉ
A portion of the data of an internet datagram, with an internet header.
IP ๐
Internet Protocol.
IRS ๐ฑ
The Initial Receive Sequence number. The first sequence number used by the sender on a connection.
ISN ๐
The Initial Sequence Number. The first sequence number used on a connection (either ISS or IRS). It's selected using a clock-based procedure. โฐ
ISS ๐ธ
The Initial Send Sequence number. The first sequence number used by the sender on a connection.
leader ๐ฉ
Control information at the beginning of a message or block of data. In particular, in the ARPANET, it's the control information on an ARPANET message at the host-IMP interface.
left sequence โฌ ๏ธ
The next sequence number to be acknowledged by the data receiving TCP (or the lowest currently unacknowledged sequence number). It's sometimes called the left edge of the send window. ๐ช
local packet ๐๏ธ
The unit of transmission within a local network.
module ๐งฑ
An implementation, usually in software, of a protocol or other procedure. ๐ ๏ธ
MSL โณ
Maximum Segment Lifetime: the time a TCP segment can exist in the internetwork system. It's arbitrarily defined to be 2 minutes. Long enough to be a whole era ๐ญ
octet ๐ข
An eight bit byte.
Options โ๏ธ
An Option field may contain several options, and each option may be several octets long. The options are mainly used in testing situations, for example, to carry timestamps. Both the Internet Protocol and TCP provide for options fields. ๐งช
packet ๐ฆ
A package of data with a header that may or may not be logically complete. It's more often a physical packaging than a logical one. ๐
port ๐ช
The part of a socket that specifies which logical input or output channel of a process is associated with the data. Basically the door the data walks through ๐ชโจ
process ๐ธ A program in execution! It's a source or destination of data from the point of view of the TCP or other host-to-host protocol. โจ
PUSH ๐ A control bit occupying no sequence space, indicating that this segment contains data that must be pushed through to the receiving user. ๐ซถ
RCV.NXT ๐ฆ receive next sequence number RCV.UP ๐ receive urgent pointer RCV.WND ๐ receive window
receive next sequence number ๐ง This is the next sequence number the local TCP is expecting to receive. Literally the number it's waiting for, bestie. ๐
receive window ๐ This is the range of sequence numbers the local (receiving) TCP is willing to receive. So the local TCP treats any segment overlapping RCV.NXT to RCV.NXT + RCV.WND - 1 as carrying acceptable data or control. Anything with sequence numbers entirely outside that range is considered a duplicate and gets discarded. Bye, bye ๐
RST ๐ A control bit (reset) that occupies no sequence space. It tells the receiver to delete the connection without any further interaction. The receiver can look at the sequence number and acknowledgment fields of the incoming segment to decide whether to honor the reset or ignore it. ngl this is a big decision. In no case does receiving a segment containing RST trigger a RST in response, so nobody's starting a reset war here ๐ โโ๏ธ
RTP ๐ Real Time Protocol: a host-to-host protocol for communicating time critical information. โฐ
SEG.ACK ๐ธ segment acknowledgment SEG.LEN ๐ฆ segment length SEG.PRC ๐ segment precedence value SEG.SEQ โจ segment sequence SEG.UP ๐ฅ segment urgent pointer field SEG.WND ๐ segment window field
segment ๐ A logical unit of data. In particular, a TCP segment is the unit of data transferred between a pair of TCP modules. Main character energy ๐
segment acknowledgment ๐ซถ The sequence number in the acknowledgment field of the arriving segment.
segment length ๐ The amount of sequence number space a segment occupies, including any controls that take up sequence space.
segment sequence ๐ง The number in the sequence field of the arriving segment.
send sequence ๐ This is the next sequence number the local (sending) TCP will use on the connection. It starts out selected from an initial sequence number curve (ISN) and goes up by one for each octet of data or sequenced control it transmits. Iykyk ๐
send window ๐ธ This is the range of sequence numbers the remote (receiving) TCP is willing to receive. It's the value of the window field in segments from that remote (data receiving) TCP. A TCP can emit new sequence numbers from SND.NXT up to SND.UNA + SND.WND - 1. (Retransmissions of sequence numbers between SND.UNA and SND.NXT are expected, of course. Obviously ๐)
SND.NXT ๐ฆ send sequence SND.UNA ๐ left sequence SND.UP ๐ send urgent pointer SND.WL1 โจ segment sequence number at last window update SND.WL2 ๐ segment acknowledgment number at last window update SND.WND ๐ send window
socket ๐ง An address that specifically includes a port identifier. In other words, it's the concatenation of an Internet Address with a TCP port. ๐
Source Address ๐ The source address, usually the network and host identifiers. ๐
SYN ๐ฅ A control bit in the incoming segment, occupying one sequence number. It's used at the initiation of a connection to indicate where the sequence numbering will start. Big first impression energy ๐
TCB ๐ Transmission control block: the data structure that records the state of a connection. It's the connection's whole diary ๐
TCB.PRC ๐ The precedence of the connection.
TCP ๐ Transmission Control Protocol: a host-to-host protocol for reliable communication in internetwork environments. The queen of reliability ๐๐ซถ
TOS ๐ฆ Type of Service, an Internet Protocol field.
Type of Service ๐ An Internet Protocol field that indicates the type of service for this internet fragment.
URG ๐ A control bit (urgent) occupying no sequence space. It's used to tell the receiving user to do urgent processing, as long as there's data to be consumed with sequence numbers less than the value in the urgent pointer. Emergency mode, bestie ๐จ
urgent pointer ๐ธ A control field that's only meaningful when the URG bit is on. It communicates the value of the urgent pointer, which points at the data octet associated with the sending user's urgent call. ๐ฃ
REFERENCES ๐โจ
- [1] Cerf, V., and R. Kahn, "A Protocol for Packet Network Intercommunication", IEEE Transactions on Communications, Vol. COM-22, No. 5, pp 637-648, May 1974.
- [2] Postel, J. (ed.), "Internet Protocol - DARPA Internet Program Protocol Specification", RFC 791, USC/Information Sciences Institute, September 1981.
- [3] Dalal, Y. and C. Sunshine, "Connection Management in Transport Protocols", Computer Networks, Vol. 2, No. 6, pp. 454-473, December 1978.
- [4] Postel, J., "Assigned Numbers", RFC 790, USC/Information Sciences Institute, September 1981.
๐ฆ where this page comes from
- ietf: rfc793 1981-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms