-
Notifications
You must be signed in to change notification settings - Fork 0
Protocol specification
PTC Wiki ▸ Protocol specification
The segment header has a fixed length of 16 bytes:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| #SEQ (sequence number) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| #ACK (acknowledge number) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |A|N|R|S|F| |
| Reserved |C|D|S|Y|I| Window |
| |K|T|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Below we briefly discuss each of these fields:
-
Source port(16 bits): port number used by the sender of the packet. -
Destination port(16 bits): port number used by the receiver of the packet. -
#SEQ(32 bits): indicates the first byte of data contained in the packet. Regarding this, note that theSYNandFINcontrol bits (explained soon) must be sequenced. -
#ACK(32 bits): indicates the value of the next byte that the sender expects to receive. Once a connection is successfully established, this value must be sent. -
Reserved(11 bits): reserved for future use; must be zero. - Control bits (5 bits):
-
ACKmust be always set. Indicates that the#ACKfield is significant. -
SYNshould be only set when attempting to establish a connection or when replying to a previously receivedSYNpacket. Used to synchronize sequence numbers. - Similarly,
FINshould be set only when the sender is willing to close its write stream. Note that the receiver might continue to send data, which implies that the sender must continue to correctly process the payload contained in every incoming packet. - At the moment, the other flags (i.e.,
RSTandNDT) have no use. -
Window(16 bits): the number of bytes starting with#ACKthat the sender is willing to accept. -
Payload(variable length): data provided by upper-layer protocols.
Just like a TCP segment travels inside an IP datagram, our PTC packets will do so as well. In order for hosts to be aware of this, the proto field of the IP header must be set to 202, a value typically not assigned to any other known protocol.
Before being able to send data, PTC instances must establish a connection. For this, a three-way handshake algorithm is used:
- First, the active instance (client) must send a
SYNsegment having an arbitrary#SEQnumber (the initial sequence number). Moreover,Windowmust contain the allocated size in bytes for the receive buffer. The remaining fields may have any value; they will be ignored by the interlocutor. - The passive instance (server) will respond with a
SYN+ACKpacket whose purpose is to not only acknowledge the connection establishment request but also to inform its initial sequence number. Thus,#ACKmust be set to the received#SEQplus one. - Finally, the client will acknowledge the
SYNsent by the server by sending anACKpacket on which the#ACKfield must be set to the received#SEQplus one as well.
Once this is done, both parts will consider that the connection is established.
In order to release the connection, an asymmetric, four-way handshake algorithm is used. When a PTC is willing to close the connection, it will no longer be able to send further data (i.e., its write stream will be closed). However, it will be able to keep receiving data sent by its peer (i.e., its read stream remains open). The FIN control bit is used to accomplish this half-closing. The States section below covers every possible scenario regarding connection release.
PTC flow control is essentially analogous to that of TCP (without options). It uses cumulative acknowledgements and provides a variable-sized receive window whose actual size is usually determined by the space allocated for the incoming buffer. Every aspect of the sliding window is encapsulated in a structure called control block, which is instantiated by a PTC once it has made contact with a remote interlocutor. The control block manages both the send and receive windows and also the incoming and outgoing data buffers. Regarding the send side, the following variables are defined:
-
SND_UNA, which contains the smallest sequence number still not acknowledged. -
SND_NXT, which represents the next sequence number to be used in an outgoing segment. -
SND_WND, which is the maximum number of bytes that can be sent at the moment, conforming to the information provided by the interlocutor. -
SND_WL1, which indicates the sequence number of the last incoming packet used to updateSND_WND. -
SND_WL2, which, similarly, indicates the acknowledge number of the last incoming packet used to updateSND_WND.
The next diagram shows the sequence space as defined by these variables:
1 2 3 4
----------|----------|----------|----------
SND_UNA SND_NXT SND_UNA + SND_WND
Each fragment may be understood as follows:
- Sequence numbers already acknowledged.
- Sequence numbers used in outgoing segments still not acknowledged.
- Sequence numbers currently available to dispatch new data segments.
- Sequence numbers that will be available in the future, as acknowledges arrive.
The receive window is managed by keeping track of these variables:
-
RCV_NXT, whose value corresponds to the next sequence number that PTC expects to receive. -
RCV_WND, which is the number of bytes that PTC is able to accept at the moment.
In a similar fashion, the sequence space might be pictured like so:
1 2 3
----------|----------|----------
RCV_NXT RCV_NXT + RCV_WND
Here, the first portion contains every sequence number already received and acknowledged, while portion 2 represents the sequence numbers that PTC is now willing to accept. Finally, portion 3 has every sequence number which will be acceptable in the future. These will move to portion 2 when data arrives and RCV_NXT moves right.
After sending a data segment, PTC will also enqueue it in the retransmission queue. This packet will remain there until it is eventually acknowledged. Moreover, the protocol specifies a timeout for this acknowledge, RETRANSMISSION_TIMEOUT. Should this time be exceeded, PTC must assume that its packet did not reach destination and thus will have to be retransmitted.
A maximum number of retransmissions is defined as well (MAX_RETRANSMISSION_ATTEMPTS). If any segment happens to be retransmitted more times than this value, PTC must assume that the connection died and will proceed to close it without sending FIN, freeing instead every resource allocated.
A PTC connection lifetime might traverse several states:
-
LISTEN, which represents waiting for an incoming connection from a remote PTC. -
SYN_SENT, on which the PTC is waiting for a reply for the connection request previously issued. -
SYN_RCVD, where the PTC has already received a connection request and replied it positively, and is waiting for this last message to be confirmed. -
ESTABLISHED, which indicates an open and active connection. It is the standard data exchange state. -
FIN_WAIT1, where the PTC started to close its write stream and is waiting for an acknowledgement of its interlocutor. -
FIN_WAIT2, where the PTC has successfully closed its write stream and still waits for its peer to close theirs. -
CLOSE_WAIT, which indicates that the peer closed its write stream and the PTC is waiting for the user to close the connection. -
CLOSING, which represents a simultaneous close of both parts. -
LAST_ACK, on which the PTC is just waiting for its peer to send and acknowledgement to theFINpreviously sent (the peer has already closed its write stream). -
CLOSED, which is the absence of connection.
State transitions are triggered by three kinds of events: user actions (close/shutdown, listen and connect), segment arrival and excessive retransmissions. The following diagram summarizes the valid transitions along with their associated events and the actions taken by the protocol in response.
+---------+ -------- connect
| CLOSED | \ ----------
+---------+ \ SYN
| ^ \
listen | | close \
---------- | | ---------- \
| | \
V | \
+---------+ \
| LISTEN | |
+---------+ |
SYN | |
--------- | V
+---------+ SYN+ACK / +----------+
| |<------------------ | |
|SYN_RCVD | | SYN_SENT |
| |------------------- ------------------| |
+---------+ ACK \ / SYN+ACK +----------+
--------- | | -----------
| | ACK
V V
+---------------+
| ESTABLISHED |
+---------------+
close | | FIN
------- | | -------
+-----------+ FIN / \ ACK +-------------+
| FIN_WAIT1 |<---------------- ------------------->| CLOSE_WAIT |
| |-------------------- +-------------+
+-----------+ FIN \ close |
| ACK ------- | ------- |
| -------- ACK | FIN |
V V V
+---------+ +---------+ +----------+
|FIN_WAIT2| | CLOSING | | LAST_ACK |
+---------+ +---------+ +----------+
| ACK | ACK |
| FIN ------- | ------- |
| ------- V |
\ ACK +---------+ /
------------------------>| CLOSED |<--------------------
+---------+
In order to improve simplicity, the transitions to CLOSED after surpassing the maximum allowed number of retransmissions were omitted. Note that this transition might occur not only in ESTABLISHED but also in any other synchronized state on which a data segment or a FIN segment might be sent.
Upon receiving a packet, PTC will process it according to its underlying state. In what follows, we will note SEG_SEQ, SEG_ACK, SEG_LEN and SEG_WND the incoming packet sequence number, its acknowledge number, its payload length and its window size, respectively. In addition, recall that every packet whose ACK flag is off must be automatically discarded no matter what state PTC is on (with the sole exception of LISTEN).
Only SYN packets should be accepted. When doing so, PTC should initialize the control block after the information provided by such packet and a random initial sequence number ISS. After switching to SYN_RCVD, PTC must send a SYN/ACK packet in response and finally increment SND_NXT.
Only SYN/ACK packets should be accepted. Besides, SEG_ACK must be equal to SND_NXT (i.e., the sequence number previously sent plus one). If this holds, the control block should be initialized, the state should be set to ESTABLISHED and a proper acknowledgement should be sent.
If SEG_ACK is acceptable (i.e., its value equals SND_NXT), PTC should move to ESTABLISHED and also increment SND_UNA (since a SYN must be sequenced too).
If the FIN flag is on, PTC should check that SEQ_SEQ equals RCV_NXT, in which case it should change the connection state to CLOSE_WAIT, increment RCV_NXT (since the FIN flag must be sequenced) and finally send an acknowledgement. If SEG_SEQ has an unexpected value, simply send and ACK informing current RCV_NXT value.
If, on the contrary, the FIN flag is off, make the control block validate whether the packet should be accepted. SEG_ACK is acceptable if its value lies within the expected sequence numbers:
SND_UNA < SEG_ACK <= SND_NXT
If this holds, update SND_UNA setting it to SEG_ACK. On the other hand, the payload is acceptable only if the sequence numbers consumed by the segment have non-null intersection with the receive window:
RCV_NXT <= SEG_SEQ < RCV_NXT + RCV_WND or
RCV_NXT <= SEG_SEQ + SEG_LEN - 1 < RCV_NXT + RCV_WND
If so, PTC should put in the incoming buffer that portion of the payload contained in the receive window. If this portion starts in RCV_NXT, this value must be also updated by adding the length in bytes of the accepted data. In addition, RCV_WND must be decremented (as the buffer is now consuming more memory).
The control block must also analyze whether SND_WND should be updated using this packet. This has to be done in case that the packet is acknowledging expected sequence numbers:
SND_UNA <= SEG_ACK <= SND_NXT
Notice that the leftmost <= is required in order to properly process potential window updates with duplicate ACK values (RFC 1122).
Besides SND_WND, PTC must update SND_WL1 and SND_WL2 only if the packet received is "new":
SND_WL1 < SEG_SEQ or
SND_WL1 = SEG_SEQ y SND_WL2 <= SEG_ACK
In this scenario, the variables will be effectively updated:
-
SND_WNDwill be set toSEG_WND, -
SND_WL1, toSEG_SEQ, and -
SND_WL2toSEG_ACK.
Finally, if the segment has a non-null payload, an acknowledgement must be sent even if this packet was not accepted. This could be accomplished by piggybacking if the output buffer happens to have any data waiting to be transmitted. If not, an ad-hoc acknowledgement must be sent.
If the control block accepts SEG_ACK, this packet is acknowledging the FIN previously sent. Thus, PTC must change its connection state to FIN_WAIT2. If a FIN arrives as well, it must be processed exactly like it is in ESTABLISHED, but instead moving to CLOSED after doing so.
If SEG_ACK is not accepted and the packet has the FIN flag on, PTC should do the same but the next state must be CLOSING (since the peer started a simultaneous close).
In any case, the control block must validate the packet and eventually send an ACK as explained above. This is because the packet might contain valid data. Note that in this case PTC will not be able to piggyback the acknowledgement since a FIN was already sent.
If the FIN flag is on, proceed as in ESTABLISHED, but move to CLOSED after doing so. If not, make the control block process the packet and send an ACK if the payload is not null.
In this case, PTC should only wait for an acceptable SEG_ACK. If this happens, it means that the FIN is effectively ackwowledged and thus the connection state must be changed to CLOSED.
Given that the remote PTC successfully closed its write stream, PTC should be only expecting acknowledgements in this state. Therefore, the control block must process the packet in order to adjust the send window and its related variables.
Proceed as in CLOSING.