X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=README;h=0f91f871c9eef353439f57f6dc21af9846ffe649;hb=e5db16f2c3e5debdc60b129f8f271faa1c482959;hp=d5edf564fb93533662533529eba3da378f1fcd21;hpb=6934880365c13cfebe5806be0f40c4c45a5dcf84;p=utcp diff --git a/README b/README index d5edf56..0f91f87 100644 --- a/README +++ b/README @@ -21,10 +21,11 @@ TODO v1.0: * Implement send buffer * Window scaling * Handle retransmission + - Proper timeout handling TODO v2.0: -* Nagle +* Nagle (add PSH back to signal receiver that now we want an immediate ACK?) * NAK and SACK * Congestion window scaling * Timestamps? @@ -43,3 +44,150 @@ Fast transaction: ACK -> Does this need special care or can we rely on higher level MACs? + +RFCs +---- + +793 Transmission Control Protocol (Functional Specification) +2581 TCP Congestion Control +2988 Computing TCP's Retransmission Timer + + + +INVARIANTS +---------- + +- snd.una: the sequence number of the first byte we did not receive an ACK for +- snd.nxt: the sequence number of the first byte after the last one we ever sent +- snd.wnd: the number of bytes we have left in our (UTCP/application?) input buffer + +- rcv.nxt: the sequence number of the first byte after the last one we passed up to the application +- rcv.wnd: the number of bytes the receives has left in its input buffer (may be more/less than our send buffer size) + +- The only packets that do not have ACK set must either have SYN or RST set +- Only packets received with rcv.nxt <= hdr.seq <= rcv.nxt + rcv.wnd are valid, drop others. +- If it has ACK set, and it's higher than snd.una, update snd.una. + But don't update it past c->snd.next. (RST in that case?) + +- SYN and FIN each count as one byte for the sequence numbering, but no actual byte is transferred in the payload. + +CONNECTION TIMEOUT +------------------ + +This timer is intended to catch the case when we are waiting very long for a response but nothing happens. +The timeout is in the order of minutes. + +- The conn timeout is set whenever there is unacknowledged data, or when we are in the TIME_WAIT status. +- If snd.una is advanced while the timeout is set, we re-set the timeout. +- If the conn timeout expires, close the connection immediately. + +RETRANSMIT TIMEOUT +------------------ + +(See RFC 2988, 3366) + +This timer is intended to catch the case where we didn't get an ACK from the peer. +In principle, the timeout should be slightly longer than the maximum latency along the path. + + +- The rtrx timeout is set whenever snd.nxt is advanced. +- If the rtrx timeout expires, retransmit at least one packet, and re-set the timeout. + +STATES +------ + +CLOSED: this connection is closed, all packets received will result in RST. + RX: RST + TX: return error + RT: clear timers + RST: ignore + +LISTEN: (= no connection yet): only allow SYN packets, it application does not accept, return RST|ACK, else SYN|ACK. + RX: on accept, send SYNACK, go to SYN_RECEIVED + TX: cannot happen + RT: cannot happen + RST: ignore + +SYN_SENT: we sent a SYN, now expecting SYN|ACK + RX: must be valid SYNACK, send ACK, go to ESTABLISHED + TX: put in send buffer (TODO: send SYN again with data?) + RT: send SYN again + +SYN_RECEIVED: we received a SYN, sent back a SYN|ACK, now expecting an ACK + RX: must be valid ACK, go to ESTABLISHED + TX: put in send buffer (TODO: send SYNACK again with data?) + RT: send SYNACK again + +ESTABLISHED: SYN is acked, we can now send/receive normal data. + RX: process data, return ACK. If FIN set, go to CLOSE_WAIT + TX: put in send buffer, segmentize and send + RT: send unACKed data again + +FIN_WAIT_1: we want to close the connection, and just sent a FIN, waiting for it to be ACKed. + RX: process data, return ACK. If our FIN is acked, go to FIN_WAIT_2, if a FIN was also received, go to CLOSING + TX: return error + RT: send unACKed data or else FIN again + +FIN_WAIT_2: our FIN is ACKed, just waiting for more data or FIN from the peer. + RX: process data, return ACK. If a FIN was also received, go to CLOSING + TX: return error + RT: should not happen, clear timeouts + +CLOSE_WAIT: we received a FIN, we sent back an ACK + RX: only return an ACK. + TX: put in send buffer, segmentize and send + RT: send unACKed data again + +CLOSING: we had already sent a FIN, and we received a FIN back, now waiting for it to be ACKed. + RX: if it's ACKed, set conn timeout, go to TIME_WAIT + TX: return an error + RT: send unACKed data or else FIN again + +LAST_ACK: we are waiting for the last ACK before we can CLOSE + RX: if it's ACKed, go to CLOSED + TX: return an error + RT: send FIN again + +TIME_WAIT: connection is in princple closed, but our last ACK might not have been received, so just wait a while to see if a FIN gets retransmitted so we can resend the ACK. + RX: if we receive anything, reset conn timeout. + TX: return an error + RT: should not happen, clear rtrx timeout + +SEND PACKET +----------- + +- Put the packet in the send buffer. +- Decide how much to send: + - Not more than receive window allows + - Not more that congestion window allows +- Segmentize and send the packets +- At the end, snd.nxt is advanced with the number of bytes sent +- Set the rtrx and conn timers if they have not been set + +RETRANSMIT +---------- + +- Decide how much to send: + - Not more than we have in the send buffer + - Not more than receive window allows + - Not more that congestion window allows +- Segmentize and send packets +- No advancement of sequence numbers happen +- Reset the rtrx timers + +RECEIVE PACKET +-------------- + +- Drop invalid packets: + - Invalid flags or state + - ACK always set + - hdr.seq not within our receive window + - hdr.ack ahead of snd.nxt +- Handle RST packets +- Advance snd.una? + - reset conn timer if so + - remove ACKed data from send buffer +- If snd.una == snd.nxt, clear rtrx and conn timer +- Process state changes due to SYN +- Send new data to application +- Process state changes due to FIN