RFC 761

DoD standard Transmission Control Protocol

๐Ÿ“… published January 1980, from ietf

RFC 761 and IEN 129 โœจ

  • Title: DOD STANDARD TRANSMISSION CONTROL PROTOCOL ๐Ÿ’–
  • Date: January 1980 ๐Ÿ“…
  • Editor: Jon Postel ๐ŸŽ€
  • Prepared for: Defense Advanced Research Projects Agency, Information Processing Techniques Office, 1400 Wilson Boulevard, Arlington, Virginia 22209 ๐Ÿ‡บ๐Ÿ‡ธ
  • Prepared by: Information Sciences Institute, University of Southern California, 4676 Admiralty Way, Marina del Rey, California 90291 ๐ŸŒŠ
  • Category or status: not stated in this document ๐Ÿคทโ€โ™€๏ธ
  • Replaces: IENs 124, 112, 81, 55, 44, 40, 27, 21, 5 ๐Ÿ”

The original doesn't say it obsoletes or updates any RFC, so I'm not going to invent one. ๐Ÿ™…โ€โ™€๏ธ


TABLE OF CONTENTS

    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 ....................................... 10
  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 .................................... 29
  3.5  Closing a Connection ......................................... 35
  3.6  Precedence and Security ...................................... 38
  3.7  Data Communication ........................................... 38
  3.8  Interfaces ................................................... 42
  3.9  Event Processing ............................................. 52

GLOSSARY ............................................................ 75

REFERENCES .......................................................... 83

PREFACE ๐ŸŽ€

This document describes the DoD Standard Transmission Control Protocol (TCP). There have been eight earlier editions of the ARPA TCP specification on which this standard is based, and the present text draws heavily from them. There have been many contributors to this work both in terms of concepts and in terms of text. This edition incorporates the addition of security, compartmentation, and precedence concepts into the TCP specification.

Jon Postel

Editor


1. INTRODUCTION ๐Ÿฆ‹

Okay so, the Transmission Control Protocol (TCP) is basically meant to be a super reliable host-to-host protocol. It's for hosts talking to each other over packet-switched computer networks, and especially when a bunch of those networks are hooked up together. ๐Ÿ”—โœจ

This document spells out what the Transmission Control Protocol has to do, the program that actually implements it, and the interface that programs or users use to call on its services. ๐Ÿ’…

1.1. Motivation

Computer communication systems are becoming a huge deal in military, government, and civilian settings. This document mostly focuses on military computer communication needs, especially being robust when communication is unreliable and staying available when there's congestion. Still, lots of these problems show up in civilian and government work too. ๐Ÿซถ

As strategic and tactical computer networks get built and deployed, it's essential to connect them together and to have standard interprocess communication protocols that can support a wide range of applications. ๐ŸŒ To get ahead of that need, the Deputy Undersecretary of Defense for Research and Engineering declared the Transmission Control Protocol (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 stack of protocols that support applications spanning multiple networks. TCP gives reliable interprocess communication between pairs of processes on hosts attached to different but interconnected computer networks. ๐Ÿ’– It doesn't assume much about how reliable the protocols below it 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 over a wide range of communication systems, from hard-wired connections to packet-switched or circuit-switched networks. ๐ŸŒˆ

TCP is based on concepts first described by Cerf and Kahn in [1]. It sits right above a basic Internet Protocol [2], which lets TCP send and receive variable-length segments of information wrapped in internet datagram "envelopes." The internet datagram is how source and destination TCPs get addressed even when they're in different networks. ๐Ÿ“ฎ 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 information about the precedence, security classification, and compartmentation of the TCP segments, so that info can travel end-to-end across multiple networks. ๐Ÿ”

Here's the layering picture: ๐ŸŽ€

                           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 as the higher-level protocols. Realistically though, lots of computer systems will hook up to networks through front-end computers that house the TCP and internet protocol layers, along with network-specific software. ๐Ÿ–ฅ๏ธ The TCP specification describes an interface to the higher-level protocols that still seems implementable for the front-end case, as long as there's a suitable host-to-front-end protocol in place. ๐Ÿงš

1.2. Scope

TCP is meant to give a reliable process-to-process communication service in a multinetwork environment. ๐ŸŒธ It's also intended to be a host-to-host protocol that's commonly used across multiple networks. ๐Ÿฆ‹

1.3. About this Document

This document is a specification of the behavior required of any TCP implementation, both when it talks to higher-level protocols and when it talks to other TCPs. ๐Ÿ“œ The rest of this section gives a quick overview of the protocol interfaces and how things operate. Section 2 covers the philosophy behind the TCP design. Section 3 goes deep: it describes the actions TCP has to take when different events happen (new segments arriving, user calls, errors, and so on), and it lays out the exact formats of TCP segments. ๐Ÿ”

1.4. Interfaces

TCP has two sides. On one side it talks to user or application processes, and on the other side it talks to a lower-level protocol like Internet Protocol. ๐Ÿ”Œ

The interface between an application process and TCP is described in reasonable detail. It's made up of 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, but there's a minimum level of functionality that's required at the TCP/user interface for any valid implementation. ๐Ÿ’…

The interface between TCP and the lower-level protocol is mostly left unspecified. The one thing assumed is that some mechanism exists that lets the two layers pass information to each other asynchronously. Usually the lower-level protocol is the one that defines that 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]. ๐ŸŒโœจ

1.5. Operation โœจ

okay so, the main job of TCP is to give processes a reliable, securable logical circuit or connection between pairs of processes ๐Ÿ”—๐Ÿ’– and it has to do that on top of an internet communication system that is less reliable. so it needs help 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 packing some number of octets into segments for transmission through the internet system. in this stream mode, the TCPs decide when to block and forward data at their own convenience ๐Ÿฆ‹.

if a user wants a record-oriented service, TCP lets them submit records, called letters ๐Ÿ’Œ. when the sending user marks a record boundary (end-of-letter), the TCPs promptly forward and deliver the data up to that point to the receiver. no waiting around, it's giving efficiency ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ.

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 transmitted a sequence number and requiring a positive acknowledgment (ACK) from the receiving TCP โœ…. if the ACK doesn't show up within a timeout interval, the data gets retransmitted ๐Ÿ”. on the receiving end, the sequence numbers help put segments that arrive out of order back in the right order and get rid of duplicates ๐Ÿงฉ. damage is handled by adding a checksum to each segment, checking it at the receiver, and discarding any damaged segments ๐Ÿ—‘๏ธ.

as long as the TCPs keep functioning properly and the internet system doesn't get completely partitioned, no transmission errors will affect the users ๐Ÿ’…. TCP recovers from internet communication system errors, and that is so iconic ๐Ÿ‘‘.

Flow Control:

TCP gives the receiver a way to control how much data the sender can send ๐Ÿšฆ. this happens by returning a "window" with every ACK. the window indicates a range of acceptable sequence numbers beyond the last segment successfully received ๐ŸชŸ. in stream mode, the window is the allowed number of octets the sender may transmit before getting further permission. in record mode, the window is the allowed amount of buffer space the sender may use. this can be more than the number of data octets actually transmitted if the letter size and buffer size don't match ๐Ÿคทโ€โ™€๏ธ.

Multiplexing:

so many processes inside a single Host need to use TCP at the same time, right? ๐Ÿ™ƒ so TCP gives each host a set of addresses called ports. when you put a port together with the network and host addresses from the internet communication layer, you get a socket ๐Ÿ”Œ. a pair of sockets uniquely identifies each connection ๐Ÿ’œ. and a single socket can be used in multiple connections at once. main character energy ๐ŸŽ€.

each Host handles binding ports to processes on its own ๐Ÿ . still, it's useful to attach frequently used processes (e.g., a "logger" or timesharing service) to fixed sockets that are made known to the public ๐Ÿ“ข. then people can reach these services through the known addresses ๐ŸŒธ. figuring out and learning the port addresses of other processes can involve more dynamic mechanisms โœจ.

Connections:

the reliability and flow control mechanisms need TCPs to set up and keep track of certain status information for each data stream ๐Ÿ“‹. all of that information together (sockets, sequence numbers, and window sizes) is called a connection ๐Ÿงถ. every connection is uniquely specified by a pair of sockets, one for each of its two sides ๐Ÿ‘ฏโ€โ™€๏ธ.

when two processes want to talk, their TCP's must first establish a connection, which means setting up the status information on each side ๐Ÿค. once the communication is done, the connection gets terminated or closed, freeing up the resources for other things ๐Ÿงน.

because connections have to be set up between unreliable hosts and over an unreliable internet communication system, TCP uses a handshake mechanism with clock-based sequence numbers ๐Ÿ•ฐ๏ธ. this helps avoid connections getting initialized in the wrong way ๐Ÿ™…โ€โ™€๏ธ.

Precedence and Security:

TCP users can indicate the security and precedence of their communication ๐Ÿ”. if those features aren't needed, default values are provided ๐Ÿซง.


2. PHILOSOPHY ๐Ÿ’…

2.1. Elements of the Internetwork System ๐ŸŒ

the internetwork environment is made up of hosts connected to networks, and those networks are connected to each other through gateways ๐Ÿ•ธ๏ธ. it's assumed here that the networks could be local networks (e.g., the ETHERNET) or large networks (e.g., the ARPANET), but either way they're based on packet switching technology ๐Ÿ“ฆ. the active agents that produce and consume messages are processes ๐Ÿงš. different levels of protocols in the networks, the gateways, and the hosts support an interprocess communication system. that system gives two-way data flow on logical connections between process ports ๐Ÿ”„.

we specifically assume that data is sent from host to host through a set of networks ๐Ÿ›ฃ๏ธ. when we say network, we mean a packet switched network (PSN) ๐Ÿ“ฎ. this assumption probably isn't strictly necessary, since a circuit switched network or a hybrid of the two could also work. but to keep things concrete, we explicitly assume that the hosts are connected to one or more packet switches of a PSN ๐ŸŽฏ.

the term packet is used generically here to mean the data of one transaction between a host and a packet switch ๐Ÿ“ฌ. the format of data blocks exchanged between packet switches in a network generally won't be our concern ๐Ÿ™ˆ.

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 (following the fairly common definition of a process as a program in execution) ๐Ÿƒโ€โ™€๏ธ. even terminals and files or other I/O devices are viewed as communicating with each other through processes. so basically all communication is inter-process communication ๐Ÿ’ฌ.

since a process might need to tell apart several communication streams between itself and another process (or processes), we imagine that each process may have a number of ports. those ports are how it communicates with the ports of other processes ๐Ÿšชโœจ.

2.2. Model of Operation ๐Ÿงฉ

processes send data by calling on TCP and passing buffers of data as arguments ๐Ÿ“ค. TCP packages the data from these 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 notifies that user ๐Ÿ””. the TCPs include control information in the segments, which they use to make sure data gets transmitted reliably and in order ๐Ÿซถ.

the model of internet communication has an internet protocol module associated with each TCP. this module provides an interface to the local network ๐Ÿ”Œ. the 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 do 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 go through next ๐Ÿ”. then it's "wrapped" in a local packet that suits the next network and routed to the next gateway, or to the final destination ๐ŸŽ€.

a gateway is permitted to break an internet datagram up into smaller internet datagram fragments if that's necessary for transmission through the next network โœ‚๏ธ. to do this, the gateway produces a set of internet datagrams, each carrying a fragment ๐Ÿงท. fragments may be broken into smaller ones at intermediate gateways too ๐Ÿช†. 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 (after reassembling the datagram, if needed) and passes it to the destination TCP ๐ŸŽฏ.

this simple model glosses over a lot of details, which is totally fine for now ๐Ÿ™ƒ. one important feature is the type of service. it gives information to the gateway (or internet module) to help it pick the service parameters to use when crossing the next network ๐Ÿงญ. the type of service information includes the precedence of the datagram ๐Ÿ‘‘. datagrams may also carry security information, so that hosts and gateways operating in multilevel secure environments can properly separate datagrams for security reasons ๐Ÿ”.

2.3. The Host Environment ๐Ÿก

TCP is assumed to be a module in a time sharing 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 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 ๐Ÿ“ž.

even though processes are assumed to be supported by the host operating system, TCP's mechanisms don't rule out implementing TCP in a front-end processor ๐Ÿ—๏ธ. but in that kind of implementation, a host-to-front-end protocol has to provide the functionality needed to support the type of TCP-user interface described above ๐Ÿ’œ.

2.4. Interfaces ๐Ÿ”Œ

the TCP/user interface handles calls the user makes on 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 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 take parameters for passing the address, type of service, precedence, security, and other control information ๐ŸŽ€.

2.5. Relation to Other Protocols ๐Ÿงฉ

okay so, here's where TCP sits in the protocol hierarchy ๐Ÿงš it's the middle layer, bestie, and Figure 2 shows the whole stack:

       +------+ +-----+ +-----+       +-----+
       |Telnet| | FTP | |Voice|  ...  |     |  Application Level
       +------+ +-----+ +-----+       +-----+
             |   |         |             |
            +-----+     +-----+       +-----+
            | TCP |     | RTP |  ...  |     |  Host Level
            +-----+     +-----+       +-----+
               |           |             |
            +-------------------------------+
            |      Internet Protocol        |  Gateway Level
            +-------------------------------+
                           |
              +---------------------------+
              |   Local Network Protocol  |    Network Level
              +---------------------------+
                           |



                         Protocol Relationships

                               Figure 2.

TCP is expected to support higher level protocols efficiently ๐Ÿ’– and it should be easy to plug things like the ARPANET Telnet [3] or AUTODIN II THP into TCP โœจ that's giving main character energy ๐Ÿ‘‘

2.6. Reliable Communication ๐Ÿ’Œ

a stream of data sent on a TCP connection gets delivered reliably and in order at the destination ๐Ÿซถ the secret sauce is 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 is the one sent with that segment, and it's 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 from the other direction ๐Ÿ“ฌ

here's the vibe: when TCP sends a segment, it keeps a copy on a retransmission queue and starts a timer โฑ๏ธ when the ack for that data shows up, the segment gets deleted from the queue. if the ack doesn't arrive before the timer runs out, the segment gets sent again ๐Ÿ”

ngl, an ack from TCP does not mean the data reached the end user ๐Ÿ’€ it only means the receiving TCP has taken on the responsibility to deliver it ๐Ÿซก

to control how much data flows into a TCP, there's a flow control mechanism ๐Ÿšฐ the data receiving TCP reports a window to the sending TCP. that window says how many octets, starting from the acknowledgment number, the receiver is currently ready to take ๐ŸŒธ

2.7. Connection Establishment and Clearing ๐Ÿฆ‹

so TCP needs a way to tell apart all the data streams it handles, and that's the port identifier ๐ŸŽ€ but ports get picked independently by each operating system, TCP, or user, so they might not be unique ๐Ÿ™ˆ to fix that, TCP glues an internet address (identifying the TCP) onto a port identifier to make a socket, and that socket is unique across all the networks connected together ๐ŸŒˆ

a connection is fully specified by the pair of sockets at its two ends ๐Ÿ’œ one local socket can join many connections to different foreign sockets, and a connection can carry data in both directions, which is "full duplex" ๐Ÿ”ฅ

TCPs are free to link ports to processes however they like ๐Ÿ’… still, a few basic concepts seem necessary in any implementation:

There must be well-known sockets that TCP only associates with the "appropriate" processes, by some means. we picture processes "owning" ports, and processes can only start connections on the ports they own. (How ownership actually gets implemented is a local issue, but we're imagining a Request Port user command, or a way to uniquely hand a group of ports to one process, e.g., by using the high order bits of a port name to point at a given process ๐Ÿง)

a connection is set up in the OPEN call using the local port and foreign socket arguments. in return, TCP gives back a (short) local connection name that the user uses in later calls ๐ŸŽŸ๏ธ there's a bunch of stuff a connection needs to remember, so imagine a data structure called a Transmission Control Block (TCB) ๐Ÿ—‚๏ธ one way to build it would be to make the local connection name a pointer to that TCB. the OPEN call also says whether to actively pursue the connection or passively wait for one ๐Ÿซถ

a passive OPEN means the process wants to accept incoming connection requests instead of starting one itself ๐Ÿฅน often it'll accept a request from anyone, and then a foreign socket of all zeros is used to mean "unspecified socket." unspecified foreign sockets are allowed only on passive OPENs ๐Ÿ™…โ€โ™€๏ธ

a service process that wants to serve unknown processes could issue a passive OPEN with an unspecified foreign socket. then it can connect with any process that asks for a connection to that local socket. it'd help a lot if everyone knew that this local socket belongs to that service ๐Ÿ“ฃ

well-known sockets are a super handy way to link a socket address to a standard service ahead of time ๐Ÿ“š for example, the "Telnet-Server" process might be permanently assigned to one socket, while other sockets get reserved for File Transfer, Remote Job Entry, Text Generator, Echoer, and Sink processes (the last three are just for test purposes ๐Ÿงช). a socket address might even be reserved for a "Look-Up" service that returns the specific socket where a newly created service is running ๐Ÿ” the concept of well-known sockets is part of the TCP spec, but which socket goes with which service is outside this spec ๐Ÿคทโ€โ™€๏ธ

processes can issue passive OPENs, wait for matching calls from other processes, and get told by TCP when connections are established โณ two processes that call each other at the exact same time still connect correctly ๐Ÿคฏ this flexibility is critical for distributed computing, where components act asynchronously with respect to each other ๐ŸŒŸ

there are two ways to match the sockets in a local request against an incoming segment ๐Ÿ” in the first, the local request fully specified the foreign socket, so the match must be exact. in the second, the local request left the foreign socket unspecified, so any foreign socket is fine as long as the local sockets match โœ…

if there are several pending passive OPENs (recorded in TCBs) with the same local socket, an incoming segment should be matched to a request with the specific foreign socket from that segment, if one exists, before anything gets matched to a request with an unspecified foreign socket ๐Ÿ’…

the procedures for setting up and clearing connections use the synchronize (SYN) and finis (FIN) control flags, and they involve swapping three messages. this is called a three-way hand shake [4] ๐Ÿค

a connection starts when an arriving segment with a SYN meets a waiting TCB entry that a user OPEN command created ๐Ÿ’˜ matching the local and foreign sockets is what decides when a connection has started. it becomes "established" once sequence numbers are synchronized in both directions ๐ŸŽ‰

clearing a connection also means exchanging segments, and in this case they carry the FIN control flag ๐Ÿ‘‹

2.8. Data Communication ๐Ÿ“ฆ

the data flowing on a connection can be thought of as a stream of octets, or as a sequence of records. in TCP, the records are called letters, and they're variable length ๐Ÿ’Œ in each SEND call, the sending user says whether that data finishes a letter by setting the end-of-letter parameter โœ๏ธ

a letter might be too big to send in one go, so it has to be broken into segments first ๐Ÿงฉ we assume the segments get put back together into a letter before the receiving process sees it ๐Ÿงท a segment can hold all or part of a letter, but it never holds parts of more than one letter ๐Ÿ™…โ€โ™€๏ธ the end of a letter is marked by an EOL control flag showing up in a segment ๐Ÿ

a sending TCP is allowed to gather data from the sending user and send it in segments whenever it's convenient, but once the end of letter is signaled, it must send all unsent data ๐Ÿš€ and when a receiving TCP has a complete letter, it must not wait for more data from the sending TCP before passing the letter up to the receiving process ๐Ÿ™Œ

there's a connection between letters as sent and the buffers of data that cross the TCP/user interface ๐Ÿงบ every time an end-of-letter (EOL) flag is attached to data placed into the receiving user's buffer, that buffer goes back to the user for processing, even if it isn't full ๐Ÿซ  if a letter is longer than the user's buffer, it gets passed along in buffer-size units, and the last unit might only be partly full ๐Ÿ“ the receiving TCP's buffer size can be shared with the sending TCP when the connection is being set up ๐Ÿค“

TCP keeps the flow of segments under control so it doesn't get saturated or overloaded with traffic ๐Ÿšฆ it does this with window flow control: the data receiving TCP reports a window to the data sending TCP, and that window is the range of sequence numbers of data octets the receiver is currently ready to accept ๐ŸชŸ

TCP also has a way to tell the receiver that, further along in the data stream than the receiver is currently reading, there's urgent data ๐Ÿšจ TCP doesn't spell out what the user should do after getting that news, but the general idea is that the receiving process should act to read through to the end of the urgent data quickly ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

2.9. Precedence and Security ๐Ÿ”

TCP uses the internet protocol type of service field and the security option to give TCP users precedence and security on a per connection basis ๐Ÿ›ก๏ธ not every TCP module will work in a multilevel secure environment. some might be limited to unclassified use only, and others might only operate at one security level and compartment ๐Ÿ™ˆ so some TCP implementations and services for users might be limited to a subset of the multilevel secure case ๐Ÿซค

TCP modules that operate in a multilevel secure environment should properly mark outgoing segments with the security, compartment, and precedence ๐Ÿท๏ธ those modules should also give their users, or higher level protocols like Telnet or THP, an interface to specify the security level, compartment, and precedence they want for connections ๐ŸŽ›๏ธ

2.10. Robustness Principle ๐Ÿ›ก๏ธ

TCP implementations should follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others ๐Ÿซถ๐Ÿ’–


3. FUNCTIONAL SPECIFICATION โœจ

3.1. Header Format โœจ

Okay bestie, so TCP segments get sent as internet datagrams ๐Ÿ“ฆ. The Internet Protocol header carries a bunch of info fields, including the source and destination host addresses [2]. Then a TCP header comes right after the internet header and supplies all the TCP-specific stuff ๐Ÿ’…. This split is iconic because it leaves room for host-level protocols other than TCP ๐ŸŒˆ.

    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|E|R|S|F|                               |
   | Offset| Reserved  |R|C|O|S|Y|I|            Window             |
   |       |           |G|K|L|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

TCP Header Format ๐Ÿงš

Heads up, 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).

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 including options is an integral number of 32 bits long.

Reserved: 6 bits

Reserved for future use. Must be zero. ๐Ÿ™ˆ

Control Bits: 8 bits (from left to right): ๐Ÿ”ฅ

  • URG: Urgent Pointer field significant
  • ACK: Acknowledgment field significant
  • EOL: End of Letter
  • 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 plus the data length in octets (this is not an explicitly transmitted quantity, but is computed from the total length, and the header length). ๐Ÿง 

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 should 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 should 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.
   100        -       Reserved.
   105        4       Buffer 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. ๐Ÿงš

Buffer Size ๐Ÿช„

   +--------+--------+---------+--------+
   |01000101|00000100|    buffer size   |
   +--------+--------+---------+--------+
    Kind=105 Length=4

Buffer Size Option Data: 16 bits

If this option is present, then it communicates the receive buffer size at the TCP which sends this segment. This field should only be sent in the initial connection request (i.e., in segments with the SYN control bit set). If this option is not used, the default buffer size of one octet is assumed. ๐Ÿ’–

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 even talk about how TCP works, we need some vocab ๐Ÿค“๐ŸŽ€. keeping a TCP connection alive means remembering a bunch of variables, and TCP keeps them all in one connection record called a Transmission Control Block (TCB). ๐Ÿ“‹ The TCB holds the local and remote socket numbers, the connection's security and precedence, pointers to the user's send and receive buffers, pointers to the retransmit queue and to the current segment, and a whole pile of send and receive sequence number variables. it's giving organized chaos but make it efficient ๐Ÿ’…

Send Sequence Variables

SND.UNA - send unacknowledged
SND.NXT - send sequence
SND.WND - send window
SND.BS  - send buffer size
SND.UP  - send urgent pointer
SND.WL  - send sequence number used for last window update
SND.LBB - send last buffer beginning
ISS     - initial send sequence number

Receive Sequence Variables

RCV.NXT - receive sequence
RCV.WND - receive window
RCV.BS  - receive buffer size
RCV.UP  - receive urgent pointer
RCV.LBB - receive last buffer beginning
IRS     - initial receive sequence number

these diagrams are gonna help you picture how those variables sit on the sequence space ๐Ÿฆ‹ (it's honestly so pretty when it clicks)

  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.
  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.

Current Segment Variables

there's also a set of variables that get their values straight from the fields of whatever segment is currently being handled. they show up a LOT in the discussion, so get cozy with them ๐Ÿงš

SEG.SEQ - segment sequence number
SEG.ACK - segment acknowledgment number
SEG.LEN - segment length
SEG.WND - segment window
SEG.UP  - segment urgent pointer
SEG.PRC - segment precedence value

Connection States

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, TIME-WAIT, CLOSE-WAIT, CLOSING, and the fictional state CLOSED. CLOSED is fictional because it's basically the vibe where there's no TCB at all, which means no connection at all ๐Ÿ’€. here's a quick rundown of what each one means:

  • LISTEN - waiting for a connection request from any remote TCP and port.
  • SYN-SENT - waiting for a matching connection request after you've already sent one.
  • SYN-RECEIVED - waiting for the confirming acknowledgment of a connection request, after having both received and sent one.
  • ESTABLISHED - an open connection, ready to send and receive data segments. the main character moment โœจ๐Ÿ‘‘
  • FIN-WAIT-1 - waiting for a connection termination request from the remote TCP, or for an acknowledgment of the termination request you already sent.
  • FIN-WAIT-2 - waiting for a connection termination request from the remote TCP.
  • TIME-WAIT - waiting long enough to be sure the remote TCP got the acknowledgment of its termination request.
  • CLOSE-WAIT - waiting for a connection termination request from the local user.
  • CLOSING - waiting for the remote TCP to acknowledge a termination request.
  • CLOSED - no connection state at all ๐Ÿซถ

Events

a connection changes state in response to events ๐Ÿฆ‹. the events are: the user calls OPEN, SEND, RECEIVE, CLOSE, ABORT, and STATUS; incoming segments, especially the ones carrying the SYN and FIN flags; and timeouts. the Glossary has a much more complete list of terms and definitions if you ever need it ๐Ÿ“š

the state diagram in figure 6 is a bit of a minimalist ๐Ÿ’…. it only shows state changes, plus the events that cause them and the actions that result. it doesn't cover error conditions or actions that don't change state. a later section goes into way more detail on how TCP reacts to events, so don't panic if something's missing here ๐Ÿ™ˆ
                              +---------+ ---------\      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  \       /   CLOSE            +---------+
   | rcv ACK of FIN   -------   |     |   -------
   | --------------   snd ACK   |     |   snd FIN
   V        x                   V     V
 +---------+                  +---------+
 |FINWAIT-2|                  | CLOSING |
 +---------+                  +---------+
   | rcv FIN                          | rcv ACK of FIN
   | -------    Timeout=2MSL          | --------------
   V snd ACK    ------------          V   delete TCB
 +---------+     delete TCB   +---------+
 |TIME WAIT|----------------->| CLOSED  |
 +---------+                  +---------+

                      TCP Connection State Diagram
                               Figure 6.

3.3. Sequence Numbers ๐Ÿฆ‹

okay bestie, this is the core idea of TCP ๐Ÿ’… every single octet of data sent over a TCP connection gets its own sequence number. Since every octet is sequenced, each one can be acknowledged. The acknowledgment is cumulative, so an ack of sequence number X means that all octets up to but not including X were received โœจ That makes duplicate detection straightforward even when retransmission happens ๐Ÿ™ˆ Numbering works inside a segment too: the first data octet right after the header is the lowest numbered, and the octets that follow are numbered consecutively.

It is essential to remember that the sequence number space is finite, though very large ๐ŸŒˆ It runs from 0 to 2**32 - 1. Because it's finite, all arithmetic on sequence numbers has to be done modulo 2**32. This unsigned arithmetic keeps the relationships between sequence numbers intact as they wrap from 2**32 - 1 back to 0. Computer modulo math has some tricky subtleties, so be extra careful when you program these comparisons ๐Ÿ˜ญ The typical sequence number comparisons TCP needs to make are:

  • (a) Determining that an acknowledgment refers to some sequence number sent but not yet acknowledged.
  • (b) Determining that all sequence numbers occupied by a segment have been acknowledged (e.g., to remove the segment from a retransmission queue).
  • (c) Determining that an incoming segment contains sequence numbers which are expected (i.e., that the segment "overlaps" the receive window).

On send connections, these comparisons are needed:

    older sequence numbers                        newer sequence numbers


        SND.UNA                SEG.ACK                 SND.NXT
           |                      |                       |
       ----|----XXXXXXX------XXXXXXXXXX---------XXXXXX----|----
           |    |            |    |             |         |
                |            |                  |
             Segment 1    Segment 2          Segment 3

                      <----- sequence space ----->

                   Sending Sequence Space Information

                               Figure 7.
  • SND.UNA = oldest unacknowledged sequence number
  • SND.NXT = next sequence number to be sent
  • SEG.ACK = acknowledgment (next sequence number expected by the acknowledging TCP)
  • SEG.SEQ = first sequence number of a segment
  • SEG.SEQ+SEG.LEN-1 = last sequence number of a segment

A new acknowledgment (called an "acceptable ack") is one for which this inequality holds ๐ŸŽ€

SND.UNA < SEG.ACK =< SND.NXT

All arithmetic is modulo 2**32, and comparisons are unsigned. =< means "less than or equal" โœจ

A segment on the retransmission queue is fully acknowledged if the sum of its sequence number and length is less than the acknowledgment value in the incoming segment ๐Ÿ’œ

SEG.LEN is the number of octets occupied by the data in the segment. It's really important that SEG.LEN be non-zero ๐Ÿซถ Segments that don't occupy any sequence space (like empty acknowledgment segments) are never placed on the retransmission queue, so they wouldn't go through this particular test.

On receive connections, these comparisons are needed:

    older sequence numbers                        newer sequence numbers


                RCV.NXT                         RCV.NXT+RCV.WND
                   |                               |
       ---------XXX|XXX------XXXXXXXXXX---------XXX|XX---------
                |  |         |                  |  |
                |            |                  |
             Segment 1    Segment 2          Segment 3

                      <----- sequence space ----->

                  Receiving Sequence Space Information

                                Figure 8.
  • RCV.NXT = next sequence number expected on incoming segments
  • RCV.NXT+RCV.WND = last sequence number expected on incoming segments, plus one
  • 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 is judged to occupy a portion of valid receive sequence space if:

 0 =< (SEG.SEQ+SEG.LEN-1 - RCV.NXT) < (RCV.NXT+RCV.WND - RCV.NXT)

SEG.SEQ+SEG.LEN-1 is the last sequence number the segment occupies. RCV.NXT is the next sequence number expected on an incoming segment, and RCV.NXT+RCV.WND is the right edge of the receive window ๐Ÿฆ‹

Okay, 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+SEG.LEN =< RCV.NXT+RCV.WND

Note that the acceptance test requires the end of a segment to lie inside the window, which is a bit stricter than it absolutely has to be. If at least the first sequence number of the segment lies in the receive window, or if some part of the segment does, the segment might be judged acceptable. So in Figure 8, at least segments 1 and 2 are acceptable by the strict rule, and segment 3 may or may not be, depending on how strictly you read the rule ๐Ÿ‘‘

Note that when the receive window is zero, no segments should be acceptable except ACK segments. That means a TCP should be able to keep a zero receive window while still transmitting data and receiving ACKs โœจ

We've also used the numbering scheme to protect certain control information. Some control flags are implicitly included in the sequence space, so they can be retransmitted and acknowledged without confusion. That way one and only one copy of the control gets acted upon ๐Ÿ”ฅ Control information isn't physically carried in the segment data space, so we need rules for implicitly assigning sequence numbers to control. Only the SYN and FIN need this protection, and they're only used when a connection opens and closes. For sequence number purposes, the SYN is considered to occur before the first actual data octet of the segment it's in, and the FIN is considered to occur after the last actual data octet in the segment it's in. The segment length includes both data and the sequence space taken up by controls. When a SYN is present, SEG.SEQ is the sequence number of the SYN.

Initial Sequence Number Selection

The protocol doesn't restrict a particular connection from being used over and over again ๐ŸŒธ A connection is defined by a pair of sockets, and each new instance of a connection is called an incarnation of the connection. The problem this creates is: "how does the TCP identify duplicate segments from previous incarnations of the connection?" This gets really obvious if the connection is opened and closed in quick succession, or if the connection breaks with loss of memory and then gets re-established ๐Ÿ˜ญ

To avoid confusion, we have to stop segments from one incarnation of a connection from being used while the same sequence numbers might still be floating around the network from an earlier incarnation. We want this to hold even if a TCP crashes and loses all knowledge of the sequence numbers it's been using ๐Ÿงš When new connections are created, an initial sequence number (ISN) generator picks a new 32 bit ISN. The generator is tied to a (possibly fictitious) 32 bit clock whose low order bit increments roughly every 4 microseconds. So the ISN cycles about every 4.55 hours. Since we assume segments stay in the network for no more than tens of seconds or minutes, at worst, we can reasonably assume ISN's will be unique ๐Ÿ’–

Each connection has 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 have to synchronize on each other's initial sequence numbers. This happens in an exchange of connection establishing messages that carry a control bit called "SYN" (for synchronize) along with the initial sequence numbers. As a shorthand, messages 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 ISN's. A "three way handshake" is necessary because sequence numbers aren't tied to a global clock in the network, and TCPs may use different mechanisms for picking ISN's. The receiver of the first SYN has no way of knowing whether the segment was an old delayed one, unless it remembers the last sequence number used on the connection (which isn't always possible). So it has to ask the sender to verify this SYN ๐Ÿซถ

The "three way handshake" and the advantages of a "clock-driven" scheme are discussed in [4]. ๐Ÿ“š

Knowing When to Keep Quiet

To be sure a TCP doesn't create a segment with 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 when starting up or recovering from a crash in which memory of sequence numbers in use was lost โณ For this specification, the MSL is taken to be 2 minutes. That's an engineering choice and may be changed if experience shows it's desirable ๐ŸŒˆ Note that if a TCP is reinitialized in some sense but keeps its memory of sequence numbers in use, it doesn't need to wait at all. It just has to be sure to use sequence numbers larger than those it used recently โœจ

It should be noted that this strategy does not protect against spoofing or other replay type duplicate message problems. ๐Ÿ™ˆ


3.4. Establishing a connection ๐ŸŽ€

The "three-way handshake" is the procedure used to establish a connection ๐Ÿ’œ It's normally started by one TCP and answered by another TCP. The procedure also works if two TCPs start it at the same time. In a simultaneous attempt, a TCP receives a "SYN" segment that carries no acknowledgment after it has sent a "SYN" itself. Of course, an old duplicate "SYN" segment arriving can make it look to the recipient like a simultaneous connection initiation is happening. Proper use of "reset" segments can sort out those cases ๐Ÿ‘‘ Several examples of connection initiation follow. These examples don't show connection synchronization using data-carrying segments, but that's perfectly legit, as long as the receiving TCP doesn't deliver the data to the user until it's clear the data is valid. In other words, the data must be buffered at the receiver until the connection reaches the ESTABLISHED state ๐Ÿซถ The three-way handshake reduces the chance of false connections. It's a trade-off between memory and messages, used to provide information for that checking ๐Ÿ’…

The simplest three-way handshake is shown in figure 9 below. ๐ŸŽ€ Here's how to read the figures: each line is numbered so we can point at it. Right arrows (-->) mean a TCP segment is leaving TCP A for TCP B, or arriving at B from A. Left arrows (<--) are the reverse. An ellipsis (...) means a segment is still floating around in the network (delayed) ๐Ÿซ  An "XXX" means a segment got lost or rejected ๐Ÿ’€ Comments go in parentheses. The TCP states show where things stand AFTER the segment departs or arrives, and the segment contents sit in the middle of each line. Those contents are abbreviated to the sequence number, control flags, and ACK field. Window, addresses, lengths, and text are left out so it stays clean ๐Ÿ’…

    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 9.

In line 2 of figure 9, TCP A starts things off by sending a SYN segment that says it'll use sequence numbers beginning with 100. โœจ In line 3, TCP B sends its own SYN and acknowledges the SYN it got from TCP A. Notice that the acknowledgment field means TCP B is now expecting to hear sequence 101, which acknowledges the SYN that occupied sequence 100. Iconic. ๐Ÿ‘‘

At line 4, TCP A replies with an empty segment carrying an ACK for TCP B's SYN. Then in line 5, TCP A sends some data. The segment in line 5 has the same sequence number as the one in line 4, and that's because the ACK doesn't take up any sequence number space. (If it did, we'd end up ACKing ACKs, and nobody wants that ๐Ÿ˜ญ)

Simultaneous initiation is only slightly more complicated, as figure 10 shows. Each TCP cycles from CLOSED to SYN-SENT to SYN-RECEIVED to ESTABLISHED. ๐ŸŒˆ

The main reason for the three-way handshake is to stop old duplicate connection initiations from causing confusion. ๐Ÿฆ‹ To handle this, there's a special control message called reset, which was devised for exactly this job. If the receiving TCP is in a non-synchronized state (that's SYN-SENT or SYN-RECEIVED), it goes back to LISTEN when it receives an acceptable reset. If the TCP is in one of the synchronized states (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, TIME-WAIT, CLOSE-WAIT, CLOSING), it aborts the connection and tells its user. We'll talk about that second case under "half-open" connections below. ๐Ÿ™ˆ

    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=101><ACK=301><CTL=ACK> ...

6.  ESTABLISHED  <-- <SEQ=301><ACK=101><CTL=ACK> <-- SYN-RECEIVED

7.               ... <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED

          Simultaneous Connection Synchronization

                         Figure 10.
    TCP A                                                TCP B

1.  CLOSED                                               LISTEN

2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               ...

3.  (duplicate) ... <SEQ=1000><CTL=SYN>              --> SYN-RECEIVED

4.  SYN-SENT    <-- <SEQ=300><ACK=1001><CTL=SYN,ACK> <-- SYN-RECEIVED

5.  SYN-SENT    --> <SEQ=1001><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 11.

Let's look at figure 11 as an example of how recovery from old duplicates works. ๐Ÿงš At line 3, an old duplicate SYN shows up at TCP B. TCP B can't tell it's an old duplicate, 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 is 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 carries on normally. If the SYN at line 6 had shown up before the RST, a more complicated exchange might have happened, with RSTs sent in both directions.

Half-Open Connections and Other Anomalies

An established connection is "half-open" if one of the TCPs has closed or aborted the connection on its end without the other one knowing. It's also half-open if the two ends have become desynchronized because a crash wiped out memory. ๐Ÿ“ Connections like this will automatically reset if someone tries to send data in either direction. The thing is, half-open connections are supposed to be unusual, and the recovery procedure is a little involved. ๐Ÿ˜…

If the connection no longer exists at site A, then when the user at site B tries to send any data on it, the site B TCP gets a reset control message. That message should tell the site B TCP that something is wrong, and it's expected to abort the connection. ๐Ÿ’œ

Now picture two user processes, A and B, talking to each other when a crash makes TCP A lose its memory. Depending on the operating system running A's TCP, there's a good chance some error recovery mechanism exists. Once 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 that second case, it gets the error message "connection not open" from its own local TCP. To establish the connection, A's TCP will send a segment containing a SYN. This leads to the scenario in figure 12. After TCP A crashes, the user tries to re-open the connection, while TCP B, meanwhile, 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.                                                   CLOSED

7.  SYN-SENT --> <SEQ=400><CTL=SYN>              -->

                 Half-Open Connection Discovery

                           Figure 12.

When the SYN arrives at line 3, TCP B, which is in a synchronized state, responds with an acknowledgment saying what sequence number it expects next (ACK 100). TCP A sees that this segment doesn't acknowledge anything it sent. Since TCP A is unsynchronized, it sends a reset (RST) because it has 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 9. ๐ŸŽ€

Another interesting case happens when TCP A crashes and TCP B tries to send data on what it thinks is a synchronized connection. Figure 13 shows this. Here, the data that reaches TCP A from TCP B (line 2) is unacceptable, because no such connection exists. So TCP A sends a RST. TCP B finds that RST acceptable, 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 13.

In figure 14, TCPs A and B both have passive connections waiting for a SYN. An old duplicate arriving at TCP B (line 2) stirs B into action. B returns a SYN-ACK (line 3), which causes TCP A to generate a RST, because 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 14.

There are a bunch of other cases too, and they're all covered by the following rules for RST generation and processing. โœจ

Reset Generation

As a general rule, a reset (RST) should be sent whenever a segment arrives that apparently isn't meant for the current incarnation of the connection or a future one. A reset should not be sent if it isn't clear that this is the case. So if any segment arrives for a nonexistent connection, a reset should be sent. If a segment ACKs something that has never been sent on the current connection, then one of the following two cases applies. ๐Ÿฆ‹

  1. If the connection is in any non-synchronized state (LISTEN, SYN-SENT, SYN-RECEIVED), or if the connection doesn't exist, a reset (RST) should be formed and sent for any segment that acknowledges something not yet sent. The RST should take its SEQ field from the ACK field of the offending segment (if the ACK control bit was set), and its ACK bit should be reset (zero), except to refuse a initial SYN. A reset is also sent if an incoming segment has a security level or compartment that doesn't exactly match the level and compartment requested for the connection. And if the precedence of the incoming segment is less than the precedence level requested, a reset is sent. ๐Ÿ”ฅ
  2. If the connection is in a synchronized state (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, TIME-WAIT, CLOSE-WAIT, CLOSING), any unacceptable segment should only get an empty acknowledgment segment back. That segment contains the current send-sequence number and an acknowledgment saying which sequence number is expected next. ๐ŸŒˆ

Reset Processing

Every reset (RST) segment gets validated by checking its SEQ fields. A reset is valid if its sequence number is in the window. For a RST received in response to an initial SYN, any sequence number is acceptable as long as the ACK field acknowledges the SYN. ๐Ÿงš

The receiver of a RST validates it first, and only then changes state. If the receiver was in the LISTEN state, it ignores the reset. If the receiver was in the SYN-RECEIVED state and had previously been in the LISTEN state, it goes back to LISTEN. Otherwise, the receiver aborts the connection and goes to the CLOSED state. And if the receiver was in any other state, it aborts the connection, advises the user, and goes to the CLOSED state. ๐Ÿ’–

3.5. Closing a Connection โœจ

okay so CLOSE basically means "I'm done sending, bestie" ๐Ÿ’… Closing a full-duplex connection is kinda messy, ngl, because it's not obvious what happens to the receiving side. So TCP treats CLOSE in a simplex way ๐Ÿฆ‹ The user who CLOSEs can keep RECEIVEing until they're told the other side has CLOSED too. So a program can do a bunch of SENDs, then a CLOSE, then keep listening until a RECEIVE fails because the other side closed. It's giving clean exit energy ๐ŸŽ€

We assume TCP will tell the user that the other side closed, even if no RECEIVEs are pending, so the user can wrap up gracefully ๐Ÿซถ TCP also reliably delivers every buffer that was SENT before the connection was CLOSED. So if you don't expect any data back, you just wait until the connection is CLOSED successfully, and then you know all your data reached the destination TCP. No cap, that's iconic โœจ

There are basically three cases ๐Ÿ‘‘

  1. The user tells the TCP to CLOSE the connection.
  2. The remote TCP starts the close by sending a FIN control signal.
  3. Both users CLOSE at the same time.

Case 1: Local user initiates the close ๐ŸŒธ

Here, a FIN segment gets built and put on the outgoing segment queue. TCP won't accept any more SENDs from the user, and it moves into the FIN-WAIT-1 state. RECEIVEs are still allowed in this state ๐Ÿ’œ Every segment up to and including the FIN gets retransmitted until it's acknowledged. Once the other TCP has both ACKed the FIN and sent a FIN of its own, the first TCP can ACK that FIN. Also, a TCP that receives a FIN will ACK it but won't send its own FIN until its user has CLOSED the connection too. Very polite, very structured ๐Ÿ™ˆ

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 its user the connection is closing. The user should respond with a CLOSE, and then the TCP can send a FIN to the other TCP. After that, it waits until its own FIN is acknowledged, and then it deletes the connection. If the ACK never comes, the connection is aborted after a timeout and the user is told ๐Ÿ’€

Case 3: Both users close simultaneously ๐ŸŒˆ

When both users CLOSE at the same time, FIN segments get exchanged. Once all the segments before the FINs have been processed and acknowledged, each TCP can ACK the FIN it received. When both get those ACKs, both delete the connection. Two besties hanging up at the exact same moment, lol ๐Ÿ˜ญ

  TCP A                                                TCP B

1.  ESTABLISHED                                          ESTABLISHED

2.  (Close)
    FIN-WAIT-1  --> <SEQ=100><CTL=FIN>               --> CLOSE-WAIT

3.  FIN-WAIT-2  <-- <SEQ=300><ACK=101><CTL=ACK>      <-- CLOSE-WAIT

4.                                                       (Close)
    TIME-WAIT   <-- <SEQ=301><CTL=FIN>               <-- CLOSING

5.  TIME-WAIT   --> <SEQ=100><ACK=301><CTL=ACK>      --> CLOSED

6.  (2 MSL)
    CLOSED

                       Normal Close Sequence

                             Figure 15.
  TCP A                                                TCP B

1.  ESTABLISHED                                          ESTABLISHED

2.  (Close)                                              (Close)
    FIN-WAIT-1  --> <SEQ=100><CTL=FIN>               ... FIN-WAIT-1
                <-- <SEQ=300><CTL=FIN>               <--
                ... <SEQ=100><CTL=FIN>               -->

3.  CLOSING     --> <SEQ=100><ACK=301><CTL=ACK>      ... CLOSING
                <-- <SEQ=300><ACK=101><CTL=ACK>      <--
                ... <SEQ=100><ACK=301><CTL=ACK>      -->

4.  CLOSED                                               CLOSED

                    Simultaneous Close Sequence

                             Figure 16.

3.6. Precedence and Security ๐Ÿ”ฅ

The idea is that a connection is only allowed between ports that have exactly the same security and compartment values, and at the higher of the two precedence levels that the two parts asked for ๐Ÿซถ

The precedence levels are ๐Ÿ‘‡

flash override - 111
flash          - 110
immediate      - 10X
priority       - 01X
routine        - 00X

The security levels are ๐Ÿ”

top secret    - 11
secret        - 10
confidential  - 01
unclassified  - 00

The compartments get assigned by the Defense Communications Agency. The defaults are precedence: routine, security: unclassified, compartment: zero ๐Ÿ“ A host that doesn't implement the precedence or security features should clear these fields to zero for the segments it sends.

A connection attempt with mismatched security/compartment values, or a lower precedence value, should be rejected by sending a reset. Not it, not the vibe ๐Ÿ™…โ€โ™€๏ธ

Also, TCP modules that only run 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. So even the chill ones gotta stay alert ๐Ÿ‘€

3.7. Data Communication ๐Ÿ’ฌโœจ

okay so once the connection is established, data gets communicated by swapping segments ๐Ÿ’Œ but segments can get lost (checksum test fails, or the network is congested ๐Ÿ˜ญ), so TCP uses retransmission (after a timeout) to make sure every single segment gets delivered ๐Ÿซถ. duplicate segments can also show up, thanks to the network or TCP's own retransmissions ๐Ÿ™ˆ. as we covered in the sequence numbers section, TCP runs certain tests on the sequence and acknowledgment numbers in each segment to verify 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 keeps track of the oldest unacknowledged sequence number in SND.UNA ๐ŸŒธ. if the data flow is momentarily idle and everything sent has been acknowledged, then all three variables will be equal โœจ.

when the sender creates 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 ๐Ÿฆ‹. the gap between these values is a measure of the delay in the communication, so it's basically a vibe check on how laggy things are ๐Ÿข.

normally, the amount each variable advances is just the length of the data in the segment. however, when letters are used there are special provisions for coordinating the sequence numbers, the letter boundaries, and the receive buffer boundaries ๐Ÿ’Œ๐ŸŽ€.

End of Letter Sequence Number Adjustments

okay this part is lowkey the most intricate bit, so buckle up ๐ŸŽข. TCP has a provision where the receiver of data can optionally tell the sender its buffer size at the time of connection synchronization ๐Ÿงš. if that happens, the receiver must use this fixed buffer size for the entire lifetime of the connection ๐Ÿ”’. and if a buffer size is communicated, then there is a coordination between receive buffers, letters, and sequence numbers ๐Ÿซง.

each time a buffer is completed, either because it got filled or because of an end of letter (EOL), the sequence number gets incremented through the end of that buffer ๐Ÿ“.

so whenever an EOL is transmitted, the sender advances its send sequence number, SND.NXT, by enough to consume all the unused space in the receiver's buffer ๐Ÿ’ซ. that consumed space gets subtracted from the send window, just like the space used by actual data does ๐Ÿ“.

and whenever an EOL is received, the receiver advances its receive sequence number, RCV.NXT, by enough to consume all the unused space in the receiver's buffer ๐ŸŒˆ. that consumed space gets subtracted from the receive window too, just like real data ๐Ÿฉท.

    older sequence numbers                        newer sequence numbers

            |           Buffer 1            |   Buffer 2
            |                               |
        ----+-------------------------------+-----------------
            XXXXXXXXXXXXXXXXXXXXX+++++++++++
            |                    |          |
            |<-----SEG.LEN------>|          |
            |                    |          |
            |                    |          |
         SEG.SEQ                 A          B

                    XXX - data octets from segment
                    +++ - phantom data

                      <----- sequence space ----->

                        End of Letter Adjustment

                               Figure 17.

look at this diagram, it's giving ๐ŸŽจ. in the case shown, if the segment doesn't carry an EOL flag, the next value of SND.NXT or RCV.NXT will be A ๐ŸŽฏ. if it does carry an EOL flag, the next value will be B ๐Ÿ’œ.

the exchange of buffer size and sequencing info is done in units of octets ๐Ÿ”ข. if no buffer size is stated, the buffer size is assumed to be 1 octet ๐Ÿค. the receiver tells the sender the size of the buffer in a SYN segment, using the 16 bit buffer size data in an option field in the TCP header ๐ŸŽ€.

each EOL advances the sequence number (SN) to the next buffer boundary, and the logic goes like this ๐Ÿงฎ:

    While LBB < SEG.SEQ+SEG.LEN
    Do LBB <- LBB + BS End
    SN <- LBB

where LBB is the Last Buffer Beginning, and BS is the buffer size ๐Ÿช„.

the CLOSE user call implies an end of letter, and so does the FIN control flag in an incoming segment ๐Ÿ”š๐Ÿ’….

The Communication of Urgent Information

the goal of the TCP urgent mechanism is to let the sending user stimulate the receiving user into accepting some urgent data ๐Ÿšจ. it also lets the receiving TCP tell the receiving user when all the currently known urgent data has been received by the user ๐Ÿ™Œ.

this mechanism lets a point in the data stream be marked as the end of "urgent" information ๐Ÿ. whenever this point is ahead of the receive sequence number (RCV.NXT) at the receiving TCP, that TCP should tell the user to go into "urgent mode" ๐Ÿšฆ. when the receive sequence number catches up to the urgent pointer, the TCP should tell the user to go into "normal mode" ๐ŸŒค๏ธ. and if the urgent pointer gets updated while the user is in "read fast" mode, the update will be invisible to the user ๐Ÿฅท.

the method uses an urgent field, which is carried in all segments transmitted ๐Ÿ“ฆ. the URG control flag says the urgent field is meaningful, and it should be added to the segment sequence number to get the urgent pointer ๐Ÿงฉ. if this flag isn't set, that means the urgent pointer hasn't changed ๐Ÿ˜Œ.

to send an urgent indication, the user must also send at least one data octet ๐Ÿซธ. if the sending user also indicates an end of letter, the timely delivery of the urgent info to the destination process gets even better ๐Ÿš€โœจ.

Managing the Window

the window sent in each segment shows the range of sequence numbers the sender of the window (the data receiver) is currently prepared to accept ๐ŸชŸ. this is assumed to be related to the data buffer space currently available for this connection ๐Ÿ›๏ธ. the window info is a guideline to aim at, not a hard rule ๐ŸŽฏ.

a large window encourages transmissions, but if more data arrives than can be accepted, it gets discarded ๐Ÿ˜ฌ. that leads to excessive retransmissions, which adds unnecessary load to the network and the TCPs ๐Ÿ“‰. a small window, on the other hand, might restrict data transmission so much that there's a round trip delay between each new segment ๐ŸŒ.

TCP does give you the tools to 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's strongly discouraged ๐Ÿšซ. the robustness principle says TCPs will not shrink the window themselves, but they should be ready for other TCPs to do it ๐Ÿ›ก๏ธ๐Ÿซถ.

the sending TCP must be prepared to accept and send at least one octet of new data even if the send window is zero ๐Ÿšง. it should also regularly retransmit to the receiving TCP, even when the window is zero. two minutes is recommended for that retransmission interval when the window is zero โฐ. this retransmission is essential, because it's what guarantees that when either TCP has a zero window, the window re-opening gets reliably reported to the other one ๐Ÿ”๐Ÿ’–.

the sending TCP packages the data it wants to transmit into segments that fit the current window, and it may repackage segments sitting on the retransmission queue ๐Ÿ“ฆ๐Ÿ”„. this repackaging is not required, but it may be helpful ๐Ÿ™.

users must keep reading connections they close for sending until the TCP says there's no more data ๐Ÿ“–.

in a connection with one-way data flow, the window info is carried in acknowledgment segments that all have the same sequence number. that means there's no way to reorder them if they arrive out of order ๐ŸŒ€. it's not a serious problem, but it does mean the window info can occasionally be temporarily based on old reports from the data receiver ๐Ÿ•ฐ๏ธ.


3.8. Interfaces ๐Ÿงฉ

there are of course two interfaces we care about: the user/TCP interface and the TCP/IP interface ๐Ÿ”Œ. we have a pretty detailed model of the user/TCP interface, but only a sketch of the interface to the lower level protocol module ๐Ÿ–๏ธ.

User/TCP Interface

ngl, the functional description of user commands to the TCP is kinda fictional, since every operating system has different facilities ๐Ÿซฃ. so we have to warn readers that different TCP implementations may have different user interfaces ๐ŸŒ. however, 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 required of all TCP implementations ๐Ÿ“œ.

TCP User Commands

the following sections functionally describe a USER/TCP interface ๐Ÿ’ป. the notation is similar to most procedure or function calls in high level languages, but this 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 ๐Ÿซฑ๐Ÿซฒ. individual implementations can define their own exact format, and they may provide 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 providing interprocess communication, the TCP must not only accept commands, but must 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
[, buffer size] [, timeout] [, precedence]
[, security/compartment]) -> local connection name

we assume the local TCP knows the identity of the processes it serves, and it will check the authority of the process to use the connection specified ๐Ÿ•ต๏ธโ€โ™€๏ธ. depending on the implementation, the local network and TCP identifiers for the source address will either be supplied by the TCP or by the processes it serves (e.g., the program that interfaces with the TCP network) ๐Ÿงพ. all of this is because of security concerns: no TCP should be able to masquerade as another one, and so on ๐ŸŽญ. likewise, 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 to wait for a particular connection, or an unspecified foreign socket to wait for any call ๐ŸŒ. a fully specified passive call can be made active by a later SEND being executed ๐Ÿ“ฃ.

a full-duplex transmission control block (TCB) is created and partially filled in with data from the OPEN command parameters ๐Ÿงฑ๐Ÿ’œ.

on an active OPEN command, the TCP will begin the procedure to synchronize (i.e., establish) the connection right away โšก.

the buffer size, if present, tells the TCP that the caller will always receive data from the connection in buffers of that size ๐Ÿ“ฆ. this buffer size measures the buffer between the user and the local TCP ๐Ÿงบ. the buffer size between the two TCPs may be different ๐Ÿซถโœจ.

The timeout, if you pass one, lets the caller set a timeout for all the buffers sent on the connection โฐ๐ŸŽ€ If a buffer doesn't get delivered to the destination before the timeout runs out, the TCP will abort the connection ๐Ÿ’€ The present global default is 30 seconds. The buffer retransmission rate can vary, but most likely it'll be tied to how long the remote TCP takes to respond ๐ŸŒธ

The TCP (or some part of the operating system) will check that the user is actually allowed to open a connection with the requested precedence or security/compartment ๐Ÿ‘‘ If you leave precedence or security/compartment out of the OPEN call, the default values should be used ๐Ÿงš

TCP will only accept an incoming request as a match if the security/compartment info is exactly the same, and only if the precedence is equal to or higher than the one requested in the OPEN call ๐Ÿ”ฅ

The precedence for the connection is the higher of the value you requested in the OPEN call and the value from the incoming request, and it stays locked at that value for the whole life of the connection ๐Ÿ’…

Depending on the TCP implementation, either the TCP gives the user back a local connection name, or the user picks their own (in which case another parameter is needed in the call) ๐Ÿฆ‹ Once you've got that local connection name, it's a super handy shorthand for the connection defined by the <local socket, foreign socket> pair โœจ

Send

Format:

SEND(local connection name, buffer address, byte count,
EOL flag, URGENT flag [, timeout])

Okay, this call causes the data in the buffer you point to be sent on the indicated connection ๐Ÿ“ฎ If the connection hasn't been opened, the SEND counts as an error ๐Ÿ™ˆ Some implementations let you SEND first, and then an automatic OPEN happens behind the scenes โœจ If the calling process isn't authorized to use this connection, an error gets returned ๐Ÿ˜ญ

If the EOL flag is set, the data is the End Of a Letter, and the EOL bit gets set in the last TCP segment made from the buffer ๐Ÿ’Œ If the EOL flag isn't set, later SENDs will look like they're part of the same letter ๐Ÿ“

If the URGENT flag is set, the segments from this call get the urgent pointer set to show that some of the data is urgent ๐Ÿšจ This is how you can simulate "break" signals from terminals, or error or completion codes from I/O devices, for example ๐Ÿ–ฅ๏ธ What the urgent signal means to the receiving process is unspecified ๐Ÿคทโ€โ™€๏ธ The receiving TCP will signal the urgent condition to the receiving process as long as the urgent pointer says the data before it hasn't been consumed yet ๐Ÿซถ The whole point of urgent is to nudge the receiver into accepting some urgent data, and to tell them when all the urgent data they currently know about 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 (say, because a LISTENing connection got specific after a foreign segment arrived for the local socket), then the buffer you designated gets sent to the implied foreign socket ๐Ÿฆ‹ Generally, if you OPEN with an unspecified foreign socket, you can SEND without ever explicitly knowing the foreign socket address ๐Ÿงš

BUT, if a SEND is attempted before the foreign socket is specified, an error will be returned ๐Ÿ’€ You can use the STATUS call to check the status of the connection ๐Ÿ” In some implementations, the TCP may notify the user when an unspecified socket gets bound ๐Ÿ””

If a timeout is specified, the current timeout for this connection changes to the new one โฐ

In the simplest implementation, SEND wouldn't give control back to the sending process until either the transmission was complete or the timeout was exceeded ๐Ÿ˜ด But honestly, this approach is prone to deadlocks (for example, both sides might try to do SENDs before doing any RECEIVEs) and gives poor performance, so it is not recommended ๐Ÿ™…โ€โ™€๏ธ A more sophisticated implementation returns immediately so the process can keep running alongside network I/O, and so that multiple SENDs can be in progress at once ๐Ÿš€

Multiple SENDs get served first come, first served, so the TCP will queue up the ones it can't service right away ๐ŸŽŸ๏ธ

We've been implicitly 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 ๐Ÿคž You could optimistically assume eventual success, and if you're wrong, the connection will close anyway due to the timeout ๐Ÿ’€ In implementations like this (synchronous), there will still be some asynchronous signals, but those deal with the connection itself, not with specific segments or letters ๐Ÿง

NOTA BENE: In order for the process to tell apart the error or success indications for different SENDs, it might be a good idea for the buffer address to come back along with the coded response to the SEND request ๐ŸŽ€ TCP-to-user signals are discussed below, and they cover what information should be returned to the calling process ๐Ÿ‘€

Receive

Format: RECEIVE (local connection name, buffer address, byte count)

This command allocates a receiving buffer for the specified connection ๐Ÿ›๏ธ If no OPEN came before this command, or the calling process isn't authorized to use this connection, an error is returned ๐Ÿšซ

In the simplest implementation, control wouldn't return to the calling program until either the buffer was filled or some error happened, but this approach is super prone to deadlocks ๐Ÿ˜ฌ A more sophisticated implementation lets several RECEIVEs be outstanding at once ๐Ÿ™Œ Those get filled as segments arrive ๐Ÿ“ฆ This gets you more throughput, at the cost of a fancier (possibly asynchronous) way to tell the calling program that a letter has been received or a buffer has been filled ๐Ÿ’…

If there isn't enough buffer space to reassemble a complete letter, the EOL flag won't be set in the response to the RECEIVE ๐Ÿ™…โ€โ™€๏ธ The buffer gets filled with as much data as it can hold ๐Ÿงบ The last buffer needed to hold the letter comes back with EOL signaled ๐Ÿ’Œ

The remaining parts of a partly delivered letter get placed into buffers as they become available through successive RECEIVEs ๐Ÿงฉ If several RECEIVEs are outstanding, they might be filled with parts of one single long letter, or with at most one letter each ๐Ÿ“š The return codes for each RECEIVE tell you what's in the buffer ๐Ÿท๏ธ

If a buffer size was given in the OPEN call, then every buffer presented in RECEIVE calls must be of exactly that size, or an error indication will be returned ๐Ÿ“

The URGENT flag only gets set if the receiving user was previously told, through a TCP-to-user signal, that urgent data is waiting ๐Ÿšจ So the receiving user should be in "read-fast" mode ๐ŸŽ๏ธ If the URGENT flag is on, more urgent data is still hanging around ๐Ÿ‘€ If the URGENT flag is off, this RECEIVE call has returned all the urgent data, and the user can now leave "read-fast" mode ๐Ÿฅณ

To tell apart several outstanding RECEIVEs, and to handle the case where a letter is smaller than the buffer supplied, the return code comes with both a buffer pointer and a byte count showing the actual length of the letter received ๐Ÿ“

Other implementations of RECEIVE might have the TCP allocate the buffer storage, or the TCP might share a ring buffer with the user ๐Ÿ”„ Variations like these will cause obvious differences in the user interface to the TCP ๐ŸŽจ

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 ๐Ÿ™…โ€โ™€๏ธ CLOSE is meant to be a graceful operation, meaning outstanding SENDs get 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 ๐Ÿ“ฆโœจ Also, users should keep RECEIVEing on CLOSING connections, since the other side might still be sending the last of its data ๐Ÿ‘‚ Basically, CLOSE means "I have no more to send," but it does NOT mean "I will not receive any more" ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’œ If the user-level protocol isn't well thought out, the closing side might be unable to get rid of all its data before timing out ๐Ÿ˜ฉ When that happens, CLOSE turns into ABORT, and the closing TCP gives up ๐Ÿ’€

The user can CLOSE the connection at any time on their own initiative, or in response to various prompts from the TCP (like a remote close executed, a transmission timeout exceeded, or the destination being inaccessible) ๐Ÿซ 

Because closing a connection requires talking to the foreign TCP, connections may stay in the closing state for a short time โณ If you try to reopen the connection before the TCP replies to the CLOSE command, you'll get error responses ๐Ÿ™ˆ

Close also implies end of letter ๐Ÿ’Œ

Status

Format: STATUS(local connection name)

This is an implementation dependent user command, and it could be excluded without adverse effect ๐Ÿคทโ€โ™€๏ธ The information returned would typically come from the TCB associated with the connection ๐Ÿ—‚๏ธ

This command returns a data block containing the following information:

  local socket,
  foreign socket,
  local connection name,
  receive window,
  send window,
  connection state,
  number of buffers awaiting acknowledgment,
  number of buffers pending receipt (including partial ones),
  receive buffer size,
  urgent state,
  precedence,
  security/compartment,
  and default transmission timeout.

Depending on the connection's state, or on the implementation itself, some of this info might not be available or meaningful ๐Ÿซฃ If the calling process isn't authorized to use this connection, an error is returned ๐Ÿ” This keeps unauthorized processes from snooping around and gaining info about a connection ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿšซ

Abort โœจ

Format:  ABORT (local connection name)

okay so ABORT is the big red button ๐Ÿ”ด๐Ÿ’…. It makes every pending SEND and RECEIVE get aborted, deletes the TCB (the connection's state record), and sends a special RESET message to the TCP on the other side. 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 dramatic exit ๐ŸŽ€โœจ

TCP-to-User Messages

so the operating system is assumed to give the TCP a way to asynchronously poke the user program ๐Ÿ‘€ When the TCP does poke a user program, it passes along some info. A lot of the time that info is an error message. Other times it's about how a SEND or RECEIVE (or some other user call) finished up ๐ŸŒธ

Here's what gets passed along:

  Local Connection Name                    Always
  Response String                          Always
  Buffer Address                           Send & Receive
  Byte count (counts bytes received)       Receive
  End-of-Letter flag                       Receive
  End-of-Urgent flag                       Receive

TCP/Network Interface

the TCP leans on a lower level protocol module to actually send and receive stuff over a network ๐ŸŒ One example is the ARPA internetwork system, where that lower module is the Internet Protocol [2]. In most cases the simple interface below is perfectly adequate ๐Ÿฆ‹

The following two calls cover what the TCP needs when it talks to the internet protocol module ๐Ÿ’–

  SEND (dest, TOS, TTL, BufPTR, len, Id, DF, options => result)

    where:

      dest = destination address
      TOS = type of service
      TTL = time to live
      BufPTR = buffer pointer
      len = length of buffer
      Id  = Identifier
      DF = Don't Fragment
      options = internet option data
      result = response
        OK = datagram sent ok
        Error = error in arguments or local network error

    Note that the precedence is included in the TOS and the
    security/compartment is passed as an option.

  RECV (BufPTR => result, source, dest, prot, TOS, len)

    where:

      BufPTR = buffer pointer
      result = response
        OK = datagram received ok
        Error = error in arguments
      source = source address
      dest = destination address
      prot = protocol
      TOS = type of service
      options = internet option data
      len = length of buffer

    Note that the precedence is in the TOS, and the
    security/compartment is an option.

so when the TCP sends a segment, it runs the SEND call and supplies all the arguments ๐Ÿ“ฆ The internet protocol module checks the arguments when it gets the call, then prepares and sends the message. If the arguments are good and the local network accepts the segment, the call returns successfully โœ… If the arguments are bad, or the local network doesn't accept the segment, the call returns unsuccessfully โŒ On unsuccessful returns, a reasonable report should be made about what caused the problem, but the details of those reports are up to each implementation ๐Ÿคทโ€โ™€๏ธ

when a segment shows up at the internet protocol module from the local network, there's either a RECV call already pending from the TCP, or there isn't ๐Ÿซฃ If there is, that pending call gets satisfied by handing the segment's info over to the TCP. If there isn't, the TCP just gets notified that a segment is waiting ๐Ÿ””

The notification to the TCP can come through a pseudo interrupt or something similar, whatever fits the operating system environment of the implementation โšก

A TCP's RECV call can either be satisfied right away by a pending segment, or it can just hang out until a segment arrives ๐Ÿ•ฐ๏ธ

Now, the Internet Protocol gives us arguments for type of service and time to live. TCP uses these settings for those parameters ๐Ÿ’…

  Type of Service = Precedence:  none, Package:  stream,
  Reliability:  higher, Preference:  speed, Speed:  higher; or
  00011111.

  Time to Live    = one minute, or 00111100.
Note that the assumed maximum segment lifetime is two minutes. TCP is explicitly asking that a segment be destroyed if it can't be delivered by the internet system within one minute. That's a lot of intention in one line ๐Ÿ˜ญ

3.9. Event Processing

okay this is the heart of the whole TCP state machine ๐Ÿง โœจ The TCP basically responds to events. There are three categories of events: user calls, arriving segments, and timeouts. This section explains what the TCP does for each event. A lot of the time, the processing depends on what state the connection is in ๐ŸŽ€

Events that occur:

  • User Calls
    • OPEN
    • SEND
    • RECEIVE
    • CLOSE
    • ABORT
    • STATUS
  • Arriving Segments
    • SEGMENT ARRIVES
  • Timeouts
    • USER TIMEOUT
    • RETRANSMISSION TIMEOUT

The model for the TCP/user interface is that user commands get an immediate return, and possibly a delayed response through an event or pseudo interrupt ๐Ÿ’ซ In the descriptions below, the word "signal" means cause a delayed response ๐Ÿ“ฃ

Error responses come back as character strings. For example, user commands that reference connections that don't exist get "error: connection not open" ๐Ÿ™ƒ

Please note that everything below uses arithmetic on sequence numbers, acknowledgment numbers, windows, et cetera, all modulo 2**32, the size of the sequence number space ๐Ÿ”ข Also, "=<" means less than or equal to ๐Ÿ“

A natural way to think about processing incoming segments is to imagine they get tested first for proper sequence number (so, their contents lie in the range of the expected "receive window" in the sequence number space). After that, they're generally queued and processed in sequence number order ๐Ÿฆ‹

When a segment overlaps other segments that were already received, we reconstruct the segment so it contains just the new data, and we adjust the header fields so everything stays consistent ๐Ÿงฉ

OPEN Call

CLOSED STATE (i.e., TCB does not exist)

Create a new transmission control block (TCB) to hold connection state information. Fill in the local socket identifier, foreign socket, precedence, security/compartment, and user timeout information. 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 it's active and the foreign socket is unspecified, return "error: foreign socket unspecified". If it's active and the foreign socket is specified, issue a SYN segment. An initial send sequence number (ISS) is selected, and the TCP receive buffer size is selected (if applicable). A SYN segment of the form <SEQ=ISS><CTL=SYN> is sent (this may include the buffer size option if applicable). Set SND.UNA to ISS, SND.NXT to ISS+1, SND.LBB 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 SYN-SENT STATE SYN-RECEIVED STATE ESTABLISHED STATE FIN-WAIT-1 STATE FIN-WAIT-2 STATE TIME-WAIT STATE CLOSE-WAIT STATE CLOSING STATE

Return "error: connection already exists". Already in the club, bestie ๐Ÿ™„

SEND Call

CLOSED STATE (i.e., TCB does not exist)

If the user should no 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, change the connection from passive to active, select an ISS, and select the receive buffer size. Send a SYN segment, set SND.UNA to ISS, SND.NXT to ISS+1, and SND.LBB to ISS+1. Enter SYN-SENT state. Data associated with the SEND may be sent with the SYN segment, or queued for transmission after entering ESTABLISHED state. The urgent bit, if requested in the command, should be sent with the first data segment 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 was not specified, return "error: foreign socket unspecified". ๐ŸŒท

SYN-SENT STATE

Queue it for processing after the connection is ESTABLISHED. Typically nothing can be sent yet anyway, because the send window hasn't been set by the other side yet ๐Ÿซ  If there's no space, return "error: insufficient resources".

SYN-RECEIVED STATE

Queue it for later processing after entering ESTABLISHED state. If there's no space to queue, respond with "error: insufficient resources". ๐ŸŽŸ๏ธ

ESTABLISHED STATE

Segmentize the buffer, then send it or queue it for output, with a piggybacked acknowledgment (acknowledgment value = RCV.NXT) riding along with the data ๐Ÿ’Œ If there's insufficient space to remember this buffer, simply return "error: insufficient resources".

If the remote buffer size is not one octet, and this is the end of a letter, do the following end-of-letter/buffer-size adjustment processing โœจ

  if EOL = 0 then

    SND.NXT <- SEG.SEQ + SEG.LEN

  if EOL = 1 then

    While SND.LBB < SEG.SEQ + SEG.LEN
    Do SND.LBB <- SND.LBB + SND.BS End
    SND.NXT <- SND.LBB

If the urgent flag is set, then SND.UP <- SND.NXT-1, and set the urgent pointer in the outgoing segment ๐Ÿšจ

FIN-WAIT-1 STATE FIN-WAIT-2 STATE TIME-WAIT STATE

Return "error: connection closing" and don't service the request. ๐Ÿšซ

CLOSE-WAIT STATE

Segmentize any text to be sent and queue it for output. If there's insufficient space to remember the SEND, return "error: insufficient resources" ๐Ÿซ™

CLOSING STATE

Respond with "error: connection closing" ๐Ÿฅบ

RECEIVE Call

CLOSED STATE (i.e., TCB does not exist)

If the user should no 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

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 "end of letter" (EOL) if this is the case ๐Ÿ“ฌ

If RCV.UP is in advance 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 ๐Ÿค

FIN-WAIT-1 STATE FIN-WAIT-2 STATE

Reassemble and return a letter, or as much as will fit, in the user buffer. Queue the request if it can't be serviced immediately. ๐Ÿงบ

TIME-WAIT STATE CLOSE-WAIT STATE

Okay bestie, the other side already sent its FIN ๐Ÿ’Œ, so any RECEIVE has to be served from text that's been put back together but hasn't reached the user yet. If there's no reassembled text waiting, the RECEIVE gets "error: connection closing" ๐Ÿ’€. If there is some, use it to satisfy the RECEIVE. Slay ๐Ÿ’…

CLOSING STATE

Return "error: connection closing" ๐Ÿ™ˆ

CLOSE Call

CLOSED STATE (i.e., TCB does not exist)

If the user isn't allowed to have access to this connection, return "error: connection illegal for this process". ๐Ÿšซ

Otherwise, return "error: connection does not exist". ๐ŸŒธ

LISTEN STATE

Any outstanding RECEIVEs should get "error: closing" responses. Then delete the TCB and return "ok" โœจ

SYN-SENT STATE

Delete the TCB, and send "error: closing" responses to any queued SENDs or RECEIVEs. Gone, no cap ๐Ÿฆ‹

SYN-RECEIVED STATE

Either queue this for processing after entering the ESTABLISHED state, or segmentize and send a FIN segment. If you go with the latter, enter FIN-WAIT-1 state. Main character decisions only ๐Ÿ‘‘

ESTABLISHED STATE

Queue this until all the preceding SENDs have been segmentized. Then form a FIN segment and send it. Either way, enter FIN-WAIT-1 state. ๐Ÿงš

FIN-WAIT-1 STATE FIN-WAIT-2 STATE

Ngl, strictly speaking this is an error, and it should get a "error: connection closing" response. An "ok" response would also be acceptable, as long as a second FIN isn't emitted. (The first FIN is allowed to be retransmitted though ๐Ÿ”)

TIME-WAIT STATE

Strictly speaking this is also an error, and it should get "error: connection closing". An "ok" response would be acceptable too. However, the FIN has already been sent and acknowledged, so nothing should be sent or retransmitted. Quiet vibes only ๐Ÿคซ

CLOSE-WAIT STATE

Queue this request until all the preceding SENDs have been segmentized. Then send a FIN segment and enter CLOSING state. ๐ŸŽ€

CLOSING STATE

Respond with "error: connection closing" ๐Ÿ’œ

ABORT Call

CLOSED STATE (i.e., TCB does not exist)

If the user isn't allowed to have access to this connection, return "error: connection illegal for this process".

Otherwise, return "error: connection does not exist".

LISTEN STATE

Any outstanding RECEIVEs should get "error: connection reset" responses. Then delete the TCB and return "ok". Bye bye ๐Ÿ‘‹

SYN-SENT STATE

Delete the TCB, and return "reset" responses to any queued SENDs or RECEIVEs. ๐Ÿ“

SYN-RECEIVED STATE

Send a RST of this form:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=RST,ACK>

Then return any unprocessed SENDs or RECEIVEs with the "reset" code, and delete the TCB. ๐Ÿ’ซ

ESTABLISHED STATE

Send a reset segment:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=RST,ACK>

All queued SENDs and RECEIVEs should get "reset" responses. Every segment queued for transmission (except the RST formed above) or retransmission should be flushed. Then delete the TCB. Full chaos mode ๐Ÿ”ฅ

FIN-WAIT-1 STATE FIN-WAIT-2 STATE

A reset segment (RST) should be formed and sent:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=RST,ACK>

Outstanding SENDs, RECEIVEs, CLOSEs, and any segments queued for retransmission or segmentizing should be flushed, with a "connection reset" notification to the user. Then delete the TCB. ๐Ÿ’”

TIME-WAIT STATE

Respond with "ok" and delete the TCB. Done and dusted โœจ

CLOSE-WAIT STATE

Flush any pending SENDs and RECEIVEs, returning "connection reset" responses for them. Form and send a RST segment:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=RST,ACK>

Then flush all the segment queues and delete the TCB. ๐Ÿงน

CLOSING STATE

Respond with "ok" and delete the TCB. Flush any remaining segment queues too. If a CLOSE command is still pending, respond "error: connection reset". ๐ŸŒˆ

STATUS Call

CLOSED STATE (i.e., TCB does not exist)

If the user isn't allowed to have access to this 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. Literally the healthiest state ๐Ÿซถ

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.

TIME-WAIT STATE

Return "state = TIME-WAIT and the TCB pointer.

CLOSE-WAIT STATE

Return "state = CLOSE-WAIT", and the TCB pointer.

CLOSING STATE

Return "state = CLOSING", and the TCB pointer.

SEGMENT ARRIVES

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 that doesn't contain a RST causes a RST to be sent in response. The acknowledgment and sequence field values are picked so the reset sequence will be 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 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, except another RST. The RST should be formatted like this:

<SEQ=SEG.ACK><CTL=RST>

Return.

An incoming RST should be ignored. Return. ๐Ÿ™ƒ

If there was no ACK, then check for a SYN.

If the SYN bit is set, check the security. If the security/compartment on the incoming segment doesn't exactly match the security/compartment in the TCB, send a reset and return. If SEG.PRC is less than TCB.PRC, send a reset and return. If SEG.PRC is greater than TCB.PRC, then set TCB.PRC<-SEG.PRC. Now RCV.NXT and RCV.LBB are set 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 this form:

<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>

SND.NXT and SND.LBB are set to ISS+1, and SND.UNA is set to ISS. The connection state should change 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 wasn't fully specified (i.e., the foreign socket wasn't fully specified), then the unspecified fields should be filled in now. ๐ŸŽ‰

If there was no SYN but there was other text or control:

Any other control or text-bearing segment (one not containing SYN) must have an ACK, so it would be discarded by the ACK processing. An incoming RST segment couldn't be valid, since it couldn't have been sent in response to anything sent by this incarnation of the connection. So you're unlikely to get here, but if you do, drop the segment and return. ๐Ÿ˜ฌ

If the state is SYN-SENT, then

First, check for an ACK.

If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, or the security/compartment in the segment doesn't exactly match the security/compartment in the TCB, or the precedence in the segment is less than the precedence in the TCB, send a reset:

<SEQ=SEG.ACK><CTL=RST>

Then discard the segment and return. ๐Ÿšซ

If SND.UNA =< SEG.ACK =< SND.NXT, and the security/compartment and precedence are acceptable, then the ACK is acceptable. SND.UNA should be advanced to equal SEG.ACK, and any segments on the retransmission queue that are thereby acknowledged should be removed. โœ…

If the ACK is ok (or there is no ACK), check the RST bit.

If the RST bit is set, signal the user "error: connection reset", enter CLOSED state, drop the segment, delete the TCB, and return. ๐Ÿ’ฅ

If the ACK is ok (or there is no ACK) and it wasn't a RST, check the SYN bit.

If the SYN bit is on and the security/compartment and precedence are acceptable, then RCV.NXT and RCV.LBB are set to SEG.SEQ+1, and IRS is set to SEG.SEQ. If SND.UNA > ISS (our SYN has been ACKed), change the connection state to ESTABLISHED. Otherwise, enter SYN-RECEIVED. In any case, form an ACK segment:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>

and send it. Data or controls that were queued for transmission may be included. ๐Ÿ“ฌ

If SEG.PRC is greater than TCB.PRC, set TCB.PRC<-SEG.PRC.

If there are other controls or text in the segment, continue processing at the fifth step below, where the URG bit is checked. Otherwise, return. ๐Ÿงต

Otherwise,

First, check the sequence number.

SYN-RECEIVED STATE ESTABLISHED STATE FIN-WAIT-1 STATE FIN-WAIT-2 STATE TIME-WAIT STATE CLOSE-WAIT STATE CLOSING 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+SEG.LEN =< RCV.NXT+RCV.WND

Note that the test above guarantees that the last sequence number used by the segment lies in the receive window. If 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 isn't acceptable, an acknowledgment should be sent in reply:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>

If the incoming segment is unacceptable, drop it and return. ๐Ÿ™…โ€โ™€๏ธ

Second, check security and precedence.

If the security/compartment and precedence in the segment don't exactly match the security/compartment and precedence in the TCB, form a reset and return.

Note this check is placed after the sequence check, to stop a segment from an old connection between these parts (with a different security or precedence) from aborting the current connection. Smart, right? ๐Ÿง 

Third, check the ACK field.

SYN-RECEIVED STATE

If the RST bit is off and SND.UNA < SEG.ACK =< SND.NXT, then set SND.UNA <- SEG.ACK, remove any acknowledged segments from the retransmission queue, and enter ESTABLISHED state. ๐ŸŽ€

If the segment acknowledgment isn't acceptable, form a reset segment:

<SEQ=SEG.ACK><CTL=RST>

and send it, unless the incoming segment is an RST (or there's no ACK). In that case, discard it and return. ๐Ÿซง

ESTABLISHED STATE

FIN-WAIT-1 STATE and FIN-WAIT-2 STATE: in addition to the processing for the ESTABLISHED state, if the retransmission queue is empty, the user's CLOSE can be acknowledged ("ok") but do not delete the TCB. ๐ŸŽ€

TIME-WAIT STATE: the only thing that can arrive in this state is a retransmission of the remote FIN. Acknowledge it, and restart the 2 MSL timeout. โณ

CLOSE-WAIT STATE: do the same processing as for the ESTABLISHED state. ๐Ÿฆ‹

CLOSING STATE: if the ACK acknowledges our FIN then delete the TCB (enter the CLOSED state), otherwise ignore the segment. ๐Ÿ’…


fourth, check the RST bit,

SYN-RECEIVED STATE: if the RST bit is set then, if the segment has passed sequence and acknowledgment tests, it is valid. If this connection was initiated with a passive OPEN (i.e., came from the LISTEN state), then return this connection to LISTEN state. 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, signal the user "connection refused". In either case, all segments on the retransmission queue should be removed. ๐Ÿ™ˆ

ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING STATE: 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. ๐Ÿ’€

TIME-WAIT: enter the CLOSED state, delete the TCB, and return. ๐ŸŒธ


fifth, check the SYN bit,

SYN-RECEIVED, ESTABLISHED STATE: if the SYN bit is set, check the segment sequence number against the receive window. The segment sequence number must be in the receive window; if not, ignore the segment. If the SYN is on and SEG.SEQ = IRS then everything is ok and no action is needed; but if they are not equal, there is an error and a reset must be sent.

If a reset must be sent it is formed as follows:

<SEQ=SEG.ACK><CTL=RST>

The connection must be aborted as if a RST had been received. ๐Ÿšจ

FIN-WAIT STATE-1, FIN-WAIT STATE-2, TIME-WAIT STATE, CLOSE-WAIT STATE, CLOSING STATE: this case should not occur, since a duplicate of the SYN which started the current connection incarnation will have been filtered in the SEG.SEQ processing. Other SYN's will have been rejected by this test as well (see SYN processing for ESTABLISHED state). ๐Ÿงš


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), and signal the user that the remote side has urgent data if the urgent pointer (RCV.UP) is in advance of the data consumed. If the user has already been signaled (or is still in the "urgent mode") for this continuous sequence of urgent data, do not signal the user again. ๐Ÿ“ฃ

TIME-WAIT STATE, CLOSE-WAIT STATE, CLOSING: this should not occur, since a FIN has been received from the remote side. Ignore the URG. ๐Ÿ™ƒ


seventh, process the segment text,

ESTABLISHED STATE: once in the ESTABLISHED state, it is possible to deliver segment text to user RECEIVE buffers. Text from segments can be moved into buffers until either the buffer is full or the segment is empty. If the segment empties and carries an EOL flag, then the user is informed, when the buffer is returned, that an EOL has been received. โœจ

If buffer size is not one octet, then do the following end-of-letter/buffer-size adjustment processing:

if EOL = 0 then

  RCV.NXT <- SEG.SEQ + SEG.LEN

if EOL = 1 then

  While RCV.LBB < SEG.SEQ+SEG.LEN
  Do RCV.LBB <- RCV.LBB + RCV.BS End
  RCV.NXT <- RCV.LBB

When the TCP takes responsibility for delivering the data to the user it must also acknowledge the receipt of the data. Send an acknowledgment of the form:

<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>

This acknowledgment should be piggybacked on a segment being transmitted if possible without incurring undue delay. ๐Ÿซถ

FIN-WAIT-1 STATE, FIN-WAIT-2 STATE: if there are outstanding RECEIVEs, they should be satisfied, if possible, with the text of this segment; remaining text should be queued for further processing. If a RECEIVE is satisfied, the user should be notified, with "end-of-letter" (EOL) signal, if appropriate. ๐Ÿ’Œ

TIME-WAIT STATE, CLOSE-WAIT STATE: this should not occur, since a FIN has been received from the remote side. Ignore the segment text. ๐Ÿ™…


eighth, check the FIN bit,

Send an acknowledgment for the FIN. Signal the user "connection closing", and return any pending RECEIVEs with same message. Note that FIN implies EOL for any segment text not yet delivered to the user. If the current state is ESTABLISHED, enter the CLOSE-WAIT state. If the current state is FIN-WAIT-1, enter the CLOSING state. If the current state is FIN-WAIT-2, enter the TIME-WAIT state. ๐Ÿ‘‹

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, delete the TCB, and return. โฐ

RETRANSMISSION TIMEOUT

For any state if the retransmission timeout expires on a segment in the retransmission queue, send the segment at the front of the retransmission queue again, reinitialize the retransmission timer, and return. ๐Ÿ”


GLOSSARY ๐Ÿ“–

1822 BBN Report 1822, "The Specification of the Interconnection of a Host and an IMP". The specification of interface between a host and the ARPANET.

ACK A control bit (acknowledge) occupying no sequence space, which indicates that the acknowledgment field of this segment specifies the next sequence number the sender of this segment is expecting to receive, hence acknowledging receipt of all previous sequence numbers. ๐Ÿ’–

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 internally in the ARPANET between IMPs. The maximum size is about 126 octets (1008 bits).

buffer size An option (buffer size) used to state the receive data buffer size of the sender of this option. May only be sent in a segment that also carries a SYN.

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.

EOL A control bit (End of Letter) occupying no sequence space, indicating that this segment ends a logical letter with the last data octet in the segment. If this end of letter causes a less than full buffer to be released to the user and the connection buffer size is not one octet then the end-of-letter/buffer-size adjustment to the receive sequence number must be made. ๐Ÿ“

FIN A control bit (finis) occupying one sequence number, which indicates that the sender will send no more data or control occupying sequence space.

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. This identifying value assigned by the sender aids in assembling the fragments of a datagram.

IMP The Interface Message Processor, 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). Selected on 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, the control information on an ARPANET message at the host-IMP interface.

left sequence This is the next sequence number to be acknowledged by the data receiving TCP (or the lowest currently unacknowledged sequence number) and is sometimes referred to as the left edge of the send window.

letter A logical unit of data, in particular the logical unit of data transmitted between processes via TCP.

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. Arbitrarily defined to be 2 minutes. โฑ๏ธ

octet An eight bit byte.

Options An Option field may contain several options, and each option may be several octets in length. The options are used primarily in testing situations; for example, to carry timestamps. Both the Internet Protocol and TCP provide for options fields. ๐ŸŒˆ

packet ๐Ÿ“ฆ okay so a packet is a package of data with a header, and that header may or may not be logically complete โœจ It's more of a physical packaging than a logical packaging of data, bestie ๐Ÿ’…

port ๐Ÿšช the portion of a socket that says which logical input or output channel of a process the data is tied to ๐ŸŽ€

process ๐Ÿงš a program in execution! From the point of view of TCP or any other host-to-host protocol, it's the source or destination of data ๐Ÿ’–

PSN ๐Ÿ›ฐ๏ธ a Packet Switched Network, like the ARPANET ๐ŸŒˆ

RCV.BS ๐Ÿชฃ receive buffer size, which is the remote buffer size ๐Ÿ™ˆ

RCV.LBB ๐Ÿงบ receive last buffer beginning

RCV.NXT โญ๏ธ receive next sequence number

RCV.UP ๐Ÿšจ receive urgent pointer

RCV.WND ๐ŸชŸ receive window

receive last buffer beginning ๐Ÿงบ this is the sequence number of the first octet of the most recent buffer. The value is use in calculating the next sequence number when a segment contains an end of letter indication ๐Ÿ’…

receive next sequence number โญ๏ธ this is the next sequence number the local TCP is expecting to receive. Literally waiting on it ๐Ÿซถ

receive window ๐ŸชŸ this represents the sequence numbers the local (receiving) TCP is willing to receive. So the local TCP considers segments overlapping the range RCV.NXT to RCV.NXT + RCV.WND - 1 to carry acceptable data or control โœจ Segments with sequence numbers entirely outside this range are considered duplicates and get discarded ๐Ÿ—‘๏ธ not me discarding them, but the rules say so ๐Ÿ’€

RST ๐Ÿ›‘ a control bit (reset), occupying no sequence space, that tells the receiver to delete the connection without any further interaction ๐Ÿ˜ญ The receiver can figure out, based on the sequence number and acknowledgment fields of the incoming segment, whether it should honor the reset command or ignore it. In no case does receipt of a segment containing RST give rise to a RST in response. Periodt ๐Ÿ’œ

RTP ๐ŸŽต Real Time Protocol: a host-to-host protocol for communication of time critical information โฐ

Rubber EOL ๐Ÿงฝ an end of letter (EOL) that needs a sequence number adjustment so the beginning of the next letter lines up on a buffer boundary. Stretchy, iykyk ๐ŸŒธ

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. A TCP segment is the unit of data transfered between a pair of TCP modules, so it's basically the main character of the transfer ๐ŸŽ€

segment acknowledgment โœ… the sequence number in the acknowledgment field of the arriving segment

segment length ๐Ÿ“ the amount of sequence number space occupied by a segment, including any controls which occupy sequence space

segment sequence ๐Ÿ”ข the number in the sequence field of the arriving segment

send last buffer beginning ๐Ÿงบ this is the sequence number of the first octet of the most recent buffer. This value is used in calculating the next sequence number when a segment contains an end of letter indication ๐Ÿ’–

send sequence ๐Ÿ“ค this is the next sequence number the local (sending) TCP will use on the connection. It's initially selected from an initial sequence number curve (ISN) and gets incremented for each octet of data or sequenced control transmitted ๐Ÿฆ‹

send window ๐ŸชŸ this represents the sequence numbers which the remote (receiving) TCP is willing to receive. It's the value of the window field specified in segments from the remote (data receiving) TCP. The range of sequence numbers that a TCP may emit lies between SND.NXT and SND.UNA + SND.WND - 1 ๐ŸŒˆ

SND.BS ๐Ÿชฃ send buffer size, the local buffer size

SND.LBB ๐Ÿงบ send last buffer beginning

SND.NXT โญ๏ธ send sequence

SND.UNA ๐Ÿซง left sequence

SND.UP ๐Ÿšจ send urgent pointer

SND.WL ๐Ÿ•ฐ๏ธ send sequence number at last window update

SND.WND ๐ŸชŸ send window

socket ๐Ÿ”Œ an address that specifically includes a port identifier, meaning 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, used at the initiation of a connection to indicate where the sequence numbering will start. Every story has a beginning ๐Ÿฅน

TCB ๐Ÿ—‚๏ธ Transmission control block, the data structure that records the state of a connection ๐Ÿ“’

TCB.PRC ๐Ÿ‘‘ the precedence of the connection

TCP ๐Ÿ’Ž Transmission Control Protocol: a host-to-host protocol for reliable communication in internetwork environments. The most reliable friend in the group chat ๐Ÿซถ

TOS ๐Ÿ“ Type of Service, an Internet Protocol field

Type of Service ๐Ÿ“ an Internet Protocol field which indicates the type of service for this internet fragment

URG ๐Ÿ“ฃ a control bit (urgent), occupying no sequence space, used to indicate that the receiving user should be notified to do urgent processing as long as there is data to be consumed with sequence numbers less than the value indicated in the urgent pointer ๐Ÿšจ bestie, this one is a whole vibe

urgent pointer ๐Ÿ‘‰ a control field meaningful only when the URG bit is on. It communicates the value of the urgent pointer, which indicates 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.), "DOD Standard Internet Protocol," Defense Advanced Research Projects Agency, Information Processing Techniques Office, RFC 760, IEN 128, January 1980. ๐ŸŒŸ

[3] Feinler, E. and J. Postel, ARPANET Protocol Handbook, Network Information Center, SRI International, Menlo Park, CA, January 1978. ๐Ÿ“–

[4] Dalal, Y. and C. Sunshine, "Connection Management in Transport Protocols," Computer Networks, Vol. 2, No. 6, pp. 454-473, December 1978. ๐Ÿ’ซ

๐Ÿ“ฆ where this page comes from