Tech-invite3GPPspaceIETFspace
959493929190898887868584838281807978777675747372717069686766656463626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100
in Index   Prev   Next

RFC 7016

Adobe's Secure Real-Time Media Flow Protocol

Pages: 113
Informational
Part 4 of 4 – Pages 75 to 113
First   Prev   None

Top   ToC   RFC7016 - Page 75   prevText

3.6. Flows

A flow is a unidirectional communication channel in a session for transporting a correlated series of user messages from a sender to a receiver. Each end of a session may have zero or more sending flows to the other end. Each sending flow at one end has a corresponding receiving flow at the other end.

3.6.1. Overview

3.6.1.1. Identity
Flows are multiplexed in a session by a flow identifier. Each end of a session chooses its sending flow identifiers independently of the other end. The choice of similar flow identifiers by both ends does not imply an association. A sender MAY choose any identifier for any flow; therefore, a flow receiver MUST NOT ascribe any semantic meaning, role, or name to a flow based only on its identifier. There are no "well known" or reserved flow identifiers. Bidirectional flow association is indicated at flow startup with the Return Flow Association option (Section 2.3.11.1.2). An endpoint can indicate that a new sending flow is in return (or response) to a receiving flow from the other end. A sending flow MUST NOT indicate more than one return association. A receiving flow can be specified as the return association for any number of sending flows. The return flow association, if any, is fixed for the lifetime of the sending flow. Note: Closure of one flow in an association does not automatically close other flows in the association, except as specified in Section 3.6.3.1.
Top   ToC   RFC7016 - Page 76
   Flows are named with arbitrary user metadata.  This specification
   doesn't mandate any particular encoding, syntax, or semantics for the
   user metadata, except for the encoded size (Section 2.3.11.1.1); the
   user metadata is entirely reserved for the application.  The user
   metadata is fixed for the lifetime of the flow.

3.6.1.2. Messages and Sequencing
Flows provide message-oriented framing. Large messages are fragmented for transport in the network. Receivers reassemble fragmented messages and only present complete messages to the user. A sender queues messages on a sending flow one after another. A receiver can recover the original queuing order of the messages, even when they are reordered in transit by the network or as a result of loss and retransmission, by means of the messages' fragment sequence numbers. Flows are the basic units of message sequencing; each flow is sequenced independently of all other flows; inter-flow message arrival and delivery sequencing are not guaranteed. Independent flow sequencing allows a sender to prioritize the transmission or retransmission of the messages of one flow over those of other flows in a session, allocating capacity from the transmission budget according to priority. RTMFP is designed for flows to be the basic unit of prioritization. In any flow, fragment sequence numbers are unique and monotonically increasing; that is, the fragment sequence numbers for any message MUST be greater than the fragment sequence numbers of all messages previously queued in that flow. Receipt of fragments out of sequence number order within a flow creates discontiguous gaps at the receiver, causing it to send an acknowledgement for every packet and also causing the size of the encoded acknowledgements to grow. Therefore, for any flow, the sender SHOULD send lower sequence numbers first. A sender can abandon a queued message at any time, even if some fragments of that message have been received by the other end. A receiver MUST be able to detect a gap in the flow when a message is abandoned; therefore, each message SHOULD take at least one sequence number from the sequence space even if no fragments for that message are ever sent. The sender will transmit the fragments of all messages not abandoned, and retransmit any lost fragments of all messages not abandoned, until all the fragments of all messages not abandoned are acknowledged by the receiver. A sender indicates a Forward Sequence Number (FSN) to instruct the receiver that sequence numbers less than or equal to the FSN will not be transmitted or retransmitted. This allows the receiver to move forward over gaps and continue sequenced delivery of completely received messages to the user. Any incomplete messages missing fragments with sequence
Top   ToC   RFC7016 - Page 77
   numbers less than or equal to the FSN were abandoned by the sender
   and will never be completed.  A gap indication MUST be communicated
   to the receiving user.

3.6.1.3. Lifetime
A sender begins a flow by sending user message fragments to the other end, and including the user metadata and, if any, the return flow association. The sender continues to include the user metadata and return flow association until the flow is acknowledged by the far end, at which point the sender knows that the receiver has received the user metadata and, if any, the return flow association. After that point, the flow identifier alone is sufficient. Flow receivers SHOULD acknowledge all sequence numbers received for any flow, whether the flow is accepted or rejected. Flow receivers MUST NOT acknowledge sequence numbers higher than the FSN that were not received. Acknowledgements drive the congestion control and avoidance algorithms and therefore must be accurate. An endpoint can reject a receiving flow at any time in the flow's lifetime. To reject the flow, the receiving endpoint sends a Flow Exception Report chunk (Section 2.3.16) immediately preceding every acknowledgement chunk for the rejected receiving flow. An endpoint may eventually conclude and close a sending flow. The last sequence number of the flow is marked with the Final flag. The sending flow is complete when all sequence numbers of the flow, including the final sequence number, have been cumulatively acknowledged by the receiver. The receiving flow is complete when every sequence number from the FSN to the final sequence number has been received. The sending flow and corresponding receiving flow at the respective ends hold the flow identifier of a completed flow in reserve for a time to allow delayed or duplicated fragments and acknowledgements to drain from the network without erroneously initiating a new receiving flow or erroneously acknowledging a new sending flow. If a flow sender receives a Flow Exception indication from the other end, the flow sender SHOULD close the flow and abandon all of the undelivered queued messages. The flow sender SHOULD indicate an exception to the user.
Top   ToC   RFC7016 - Page 78

3.6.2. Sender

Each sending flow comprises the flow-specific information context necessary to transfer that flow's messages to the other end. Each sending flow context includes at least: o F_FLOW_ID: this flow's identifier; o STARTUP_OPTIONS: the set of options to send to the receiver until this flow is acknowledged, including the User's Per-Flow Metadata and, if set, the Return Flow Association; o SEND_QUEUE: the unacknowledged message fragments queued in this flow, initially empty; each message fragment entry comprising the following: * SEQUENCE_NUMBER: the sequence number of this fragment; * DATA: this fragment's user data; * FRA: the fragment control value for this message fragment, having one of the values enumerated for that purpose in Section 2.3.11 ("User Data Chunk"); * ABANDONED: a boolean flag indicating whether this fragment has been abandoned; * SENT_ABANDONED: a boolean flag indicating whether this fragment was abandoned when sent; * EVER_SENT: a boolean flag indicating whether this fragment has been sent at least once, initially false; * NAK_COUNT: a count of the number of negative acknowledgements detected for this fragment, initially 0; * IN_FLIGHT: a boolean flag indicating whether this fragment is currently outstanding, or in flight, in the network, initially false; * TRANSMIT_SIZE: the size, in bytes, of the encoded User Data chunk (including the chunk header) for this fragment when it was transmitted into the network. o F_OUTSTANDING_BYTES: the sum of the TRANSMIT_SIZE of each entry in SEND_QUEUE where entry.IN_FLIGHT is true;
Top   ToC   RFC7016 - Page 79
   o  RX_BUFFER_SIZE: the most recent available buffer advertisement
      from the other end (Sections 2.3.13 and 2.3.14), initially
      65536 bytes;

   o  NEXT_SN: the next sequence number to assign to a message fragment,
      initially 1;

   o  F_FINAL_SN: the sequence number assigned to the final message
      fragment of the flow, initially having no value;

   o  EXCEPTION: a boolean flag indicating whether an exception has been
      reported by the receiver, initially false;

   o  The state, at any time being one of the following values: the open
      state F_OPEN; the closing states F_CLOSING and F_COMPLETE_LINGER;
      and the closed state F_CLOSED.

   Note: The following diagram is only a summary of state transitions
   and their causing events, and is not a complete operational
   specification.

                                 +--------+
                                 | F_OPEN |
                                 +--------+
                                      |CLOSE or
                                      |rcv Flow Exception
                                      |
                                      v
                                 +---------+
                                 |F_CLOSING|
                                 +---------+
                                      |rcv Data Ack
                                      |  0..F_FINAL_SN
                                      v
                             +-----------------+
                             |F_COMPLETE_LINGER|
                             +-----------------+
                                      | 130 seconds
                                      v
                                  +--------+
                                  |F_CLOSED|
                                  +--------+

                   Figure 19: Sending Flow State Diagram
Top   ToC   RFC7016 - Page 80
3.6.2.1. Startup
The application opens a new sending flow to the other end in an S_OPEN session. The implementation chooses a new flow ID that is not assigned to any other sending flow in that session in the F_OPEN, F_CLOSING, or F_COMPLETE_LINGER states. The flow starts in the F_OPEN state. The STARTUP_OPTIONS for the new flow is set with the User's Per-Flow Metadata (Section 2.3.11.1.1). If this flow is in return (or response) to a receiving flow from the other end, that flow's ID is encoded in a Return Flow Association (Section 2.3.11.1.2) option and added to STARTUP_OPTIONS. A new sending flow SHOULD NOT be opened in response to a receiving flow from the other end that is not in the RF_OPEN state when the sending flow is opened. At this point, the flow exists in the sender but not in the receiver. The flow begins when user data fragments are transmitted to the receiver. A sender can begin a flow in the absence of immediate user data by sending a Forward Sequence Number Update (Section 3.6.2.7.1), by queuing and transmitting a user data fragment that is already abandoned.
3.6.2.2. Queuing Data
The application queues messages in an F_OPEN sending flow for transmission to the far end. The implementation divides each message into one or more fragments for transmission in User Data chunks (Section 2.3.11). Each fragment MUST be small enough so that, if assembled into a packet (Section 2.2.4) with a maximum-size common header, User Data chunk header, and, if not empty, this flow's STARTUP_OPTIONS, the packet will not exceed the path MTU (Section 3.5.4.3). For each fragment, create a fragment entry and set fragmentEntry.SEQUENCE_NUMBER to flow.NEXT_SN, and increment flow.NEXT_SN by one. Set fragmentEntry.FRA according to the encoding in User Data chunks: 0: This fragment is a complete message. 1: This fragment is the first of a multi-fragment message. 2: This fragment is the last of a multi-fragment message. 3: This fragment is in the middle of a multi-fragment message. Append fragmentEntry to flow.SEND_QUEUE.
Top   ToC   RFC7016 - Page 81
3.6.2.3. Sending Data
A sending flow is ready to transmit if the SEND_QUEUE contains at least one entry that is eligible to send, and if either RX_BUFFER_SIZE is greater than F_OUTSTANDING_BYTES or EXCEPTION is set to true. A SEND_QUEUE entry is eligible to send if it is not IN_FLIGHT, AND at least one of the following conditions holds: o The entry is not ABANDONED; or o The entry is the first one in the SEND_QUEUE; or o The entry's SEQUENCE_NUMBER is equal to flow.F_FINAL_SN. If the session's transmission budget allows, a flow that is ready to transmit is selected for transmission according to the implementation's prioritization scheme. The manner of flow prioritization is not mandated by this specification. Trim abandoned messages from the front of the queue, and find the Forward Sequence Number (FSN): 1. While the SEND_QUEUE contains at least two entries, AND the first entry is not IN_FLIGHT, AND the first entry is ABANDONED, remove and discard the first entry from the SEND_QUEUE; 2. If the first entry in the SEND_QUEUE is not abandoned, set FSN to entry.SEQUENCE_NUMBER - 1; otherwise, 3. If the first entry in the SEND_QUEUE is IN_FLIGHT, AND entry.SENT_ABANDONED is false, set FSN to entry.SEQUENCE_NUMBER - 1; otherwise, 4. The first entry in the SEND_QUEUE is abandoned and either is not IN_FLIGHT or was already abandoned when sent; set FSN to entry.SEQUENCE_NUMBER. The FSN MUST NOT be greater than any sequence number currently outstanding. The FSN MUST NOT be equal to any sequence number currently outstanding that was not abandoned when sent.
Top   ToC   RFC7016 - Page 82
   Assemble user data chunks for this flow into a packet to send to the
   receiver.  While enough space remains in the packet and the flow is
   ready to transmit:

   1.   Starting at the head of the SEND_QUEUE, find the first eligible
        fragment entry;

   2.   Encode the entry into a User Data chunk (Section 2.3.11) or, if
        possible (Section 3.6.2.3.2), a Next User Data chunk
        (Section 2.3.12);

   3.   If present, set chunk.flowID to flow.F_FLOW_ID;

   4.   If present, set chunk.sequenceNumber to entry.SEQUENCE_NUMBER;

   5.   If present, set chunk.fsnOffset to entry.SEQUENCE_NUMBER - FSN;

   6.   Set chunk.fragmentControl to entry.FRA;

   7.   Set chunk.abandon to entry.ABANDONED;

   8.   If entry.SEQUENCE_NUMBER equals flow.F_FINAL_SN, set chunk.final
        to true; else set chunk.final to false;

   9.   If any options are being sent with this chunk, set
        chunk.optionsPresent to true, assemble the options into the
        chunk, and assemble a Marker to terminate the option list;

   10.  If entry.ABANDONED is true, set chunk.userData to empty;
        otherwise, set chunk.userData to entry.DATA;

   11.  If adding the assembled chunk to the packet would cause the
        packet to exceed the path MTU, do not assemble this chunk into
        the packet; enough space no longer remains in the packet; stop.
        Otherwise, continue:

   12.  Set entry.IN_FLIGHT to true;

   13.  Set entry.EVER_SENT to true;

   14.  Set entry.NAK_COUNT to 0;

   15.  Set entry.SENT_ABANDONED to entry.ABANDONED;

   16.  Set entry.TRANSMIT_SIZE to the size of the assembled chunk,
        including the chunk header;
Top   ToC   RFC7016 - Page 83
   17.  Assemble this chunk into the packet; and

   18.  If this flow or entry is considered Time Critical (real-time),
        set the timeCritical flag in the packet header (Section 2.2.4).

   Complete any other appropriate packet processing, and transmit the
   packet to the far end.

3.6.2.3.1. Startup Options
If STARTUP_OPTIONS is not empty, then when assembling the FIRST User Data chunk for this flow into a packet, add the encoded STARTUP_OPTIONS to that chunk's option list.
3.6.2.3.2. Send Next Data
The Next User Data chunk (Section 2.3.12) is a compact encoding for a user message fragment when multiple contiguous fragments are assembled into one packet. Using this chunk where possible can conserve space in a packet, potentially reducing transmission overhead or allowing additional information to be sent in a packet. If, after assembling a user message fragment of a flow into a packet (Section 3.6.2.3), the next eligible fragment to be selected for assembly into that packet belongs to the same flow, AND its sequence number is one greater than that of the fragment just assembled, it is RECOMMENDED that an implementation encode a Next User Data chunk instead of a User Data chunk. The FIRST fragment of a flow assembled into a packet MUST be encoded as a User Data chunk.
3.6.2.4. Processing Acknowledgements
A Data Acknowledgement Bitmap chunk (Section 2.3.13) or a Data Acknowledgement Ranges chunk (Section 2.3.14) encodes the acknowledgement of receipt of one or more sequence numbers of a flow, as well as the receiver's current receive window advertisement. On receipt of an acknowledgement chunk for a sending flow: 1. Set PRE_ACK_OUTSTANDING_BYTES to flow.F_OUTSTANDING_BYTES; 2. Set flow.STARTUP_OPTIONS to empty; 3. Set flow.RX_BUFFER_SIZE to chunk.bufferBytesAvailable;
Top   ToC   RFC7016 - Page 84
   4.  For each sequence number encoded in the acknowledgement, if
       there is an entry in flow.SEND_QUEUE with that sequence number
       and its IN_FLIGHT is true, then remove the entry from
       flow.SEND_QUEUE; and

   5.  Notify the congestion control and avoidance algorithms that
       PRE_ACK_OUTSTANDING_BYTES - flow.F_OUTSTANDING_BYTES were
       acknowledged.  Note that negative acknowledgements
       (Section 3.6.2.5) affect "TCP friendly" congestion control.

3.6.2.5. Negative Acknowledgement and Loss
A negative acknowledgement is inferred for an outstanding fragment if an acknowledgement is received for any other fragments sent after it in the same session. An implementation SHOULD consider a fragment to be lost once that fragment receives three negative acknowledgements. A lost fragment is no longer outstanding in the network. The following describes an OPTIONAL method for detecting negative acknowledgements. Let the session track the order in which fragments are transmitted across all its sending flows by way of a monotonically increasing Transmission Sequence Number (TSN) recorded with each fragment queue entry each time that fragment is transmitted. Let the session information context contain additional variables: o NEXT_TSN: the next TSN to record with a fragment's queue entry when it is transmitted, initially 1; o MAX_TSN_ACK: the highest acknowledged TSN, initially 0. Let each fragment queue entry contain an additional variable TSN, initially 0, to track its transmission order. On transmission of a message fragment into the network, set its entry.TSN to session.NEXT_TSN, and increment session.NEXT_TSN. On acknowledgement of an outstanding fragment, if its entry.TSN is greater than session.MAX_TSN_ACK, set session.MAX_TSN_ACK to entry.TSN. After processing all acknowledgements in a packet containing at least one acknowledgement, then for each sending flow in that session, for each entry in that flow's SEND_QUEUE, if entry.IN_FLIGHT is true and
Top   ToC   RFC7016 - Page 85
   entry.TSN is less than session.MAX_TSN_ACK, increment entry.NAK_COUNT
   and notify the congestion control and avoidance algorithms that a
   negative acknowledgement was detected in this packet.

   For each sending flow in that session, for each entry in that flow's
   SEND_QUEUE, if entry.IN_FLIGHT is true and entry.NAK_COUNT is at
   least 3, that fragment was lost in the network and is no longer
   considered to be in flight.  Set entry.IN_FLIGHT to false.  Notify
   the congestion control and avoidance algorithms of the loss.

3.6.2.6. Timeout
A fragment is considered lost and no longer in flight in the network if it has remained outstanding for at least ERTO. The following describes an OPTIONAL method to manage transmission timeouts. This method REQUIRES that either burst avoidance (Section 3.5.2.3) is implemented or the implementation's congestion control and avoidance algorithms will eventually stop sending new fragments into the network if acknowledgements are persistently not received. Let the session information context contain an alarm TIMEOUT_ALARM, initially unset. On sending a packet containing at least one User Data chunk, set or reset TIMEOUT_ALARM to fire in ERTO. On receiving a packet containing at least one acknowledgement, reset TIMEOUT_ALARM (if already set) to fire in ERTO. When TIMEOUT_ALARM fires: 1. Set WAS_LOSS = false; 2. For each sending flow in the session, and for each entry in that flow's SEND_QUEUE: 1. If entry.IN_FLIGHT is true, set WAS_LOSS = true; and 2. Set entry.IN_FLIGHT to false. 3. If WAS_LOSS is true, perform ERTO backoff (Section 3.5.2.2); and 4. Notify the congestion control and avoidance algorithms of the timeout and, if WAS_LOSS is true, that there was loss.
Top   ToC   RFC7016 - Page 86
3.6.2.7. Abandoning Data
The application can abandon queued messages at any time and for any reason. Example reasons include (but are not limited to) the following: one or more fragments of a message have remained in the SEND_QUEUE for longer than a specified message lifetime; a fragment has been retransmitted more than a specified retransmission limit; a prior message on which this message depends (such as a key frame in a prediction chain) was abandoned and not delivered. To abandon a message fragment, set its SEND_QUEUE entry's ABANDON flag to true. When abandoning a message fragment, abandon all fragments of the message to which it belongs. An abandoned fragment MUST NOT be un-abandoned.
3.6.2.7.1. Forward Sequence Number Update
Abandoned data may leave gaps in the sequence number space of a flow. Gaps may cause the receiver to hold completely received messages for ordered delivery to allow for retransmission of the missing fragments. User Data chunks (Section 2.3.11) encode a Forward Sequence Number (FSN) to instruct the receiver that fragments with sequence numbers less than or equal to the FSN will not be transmitted or retransmitted. When the receiver has gaps in the received sequence number space and no non-abandoned message fragments remain in the SEND_QUEUE, the sender SHOULD transmit a Forward Sequence Number Update (FSN Update) comprising a User Data chunk marked abandoned, whose sequence number is the FSN and whose fsnOffset is 0. An FSN Update allows the receiver to skip gaps that will not be repaired and deliver received messages to the user. An FSN Update may be thought of as a transmission or retransmission of abandoned sequence numbers without actually sending the data. The method described in Section 3.6.2.3 ("Sending Data") generates FSN Updates when appropriate.
Top   ToC   RFC7016 - Page 87
3.6.2.8. Examples
Sender | : 1 |<--- Ack ID=2, seq:0-16 2 |---> Data ID=2, seq#=25, fsnOff=9 (fsn=16) 3 |---> Data ID=2, seq#=26, fsnOff=10 (fsn=16) 4 |<--- Ack ID=2, seq:0-18 5 |---> Data ID=2, seq#=27, fsnOff=9 (fsn=18) 6 |---> Data ID=2, seq#=28, fsnOff=10 (fsn=18) | : There are 9 sequence numbers in flight with delayed acknowledgements. Figure 20: Normal Flow with No Loss
Top   ToC   RFC7016 - Page 88
    Sender
      |                   :
    1 |<---  Ack  ID=3, seq:0-30
    2 |--->  Data ID=3, seq#=45, fsnOff=15 (fsn=30)
    3 |<---  Ack  ID=3, seq:0-30, 32 (nack 31:1)
    4 |--->  Data ID=3, seq#=46, fsnOff=16 (fsn=30)
    5 |<---  Ack  ID=3, seq:0-30, 32, 34 (nack 31:2, 33:1)
    6 |<---  Ack  ID=3, seq:0-30, 32, 34-35 (nack 31:3=lost, 33:2)
    7 |--->  Data ID=3, seq#=47, fsnOff=15 (fsn=32, abandon 31)
    8 |<---  Ack  ID=3, seq:0-30, 32, 34-36 (nack 33:3=lost)
    9 |--->  Data ID=3, seq#=33, fsnOff=1 (fsn=32, retransmit 33)
   10 |<---  Ack  ID=3, seq:0-30, 32, 34-37
   11 |--->  Data ID=3, seq#=48, fsnOff=16 (fsn=32)
      |                   :
      |      (continues through seq#=59)
      |                   :
   12 |--->  Data ID=3, seq#=60, fsnOff=28(fsn=32)
   13 |<---  Ack  ID=3, seq:0-30, 34-46
   14 |--->  Data ID=3, seq#=61, fsnOff=29 (fsn=32)
   15 |<---  Ack  ID=3, seq:0-32, 34-47
   16 |--->  Data ID=3, seq#=62, fsnOff=30 (fsn=32)
   17 |<---  Ack  ID=3, seq:0-47
   18 |--->  Data ID=3, seq#=63, fsnOff=16 (fsn=47)
   19 |<---  Ack  ID=3, seq:0-49
   20 |--->  Data ID=3, seq#=64, fsnOff=15 (fsn=49)
      |                   :
   21 |<---  Ack  ID=3, seq:0-59
   22 |<---  Ack  ID=3, seq:0-59, 61 (nack 60:1)
   23 |<---  Ack  ID=3, seq:0-59, 61-62 (nack 60:2)
   24 |<---  Ack  ID=3, seq:0-59, 61-63 (nack 60:3=lost)
   25 |--->  Data ID=3, ABN=1, seq#=60, fsnOff=0 (fsn=60, abandon 60)
   26 |<---  Ack  ID=3, seq:0-59, 61-64
      |                   :
   27 |<---  Ack  ID=3, seq:0-64

   Flow with sequence numbers 31, 33, and 60 lost in transit, and a
   pause at 64.  33 is retransmitted; 31 and 60 are abandoned.  Note
   that line 25 is a Forward Sequence Number Update (Section 3.6.2.7.1).

                         Figure 21: Flow with Loss
Top   ToC   RFC7016 - Page 89
3.6.2.9. Flow Control
The flow receiver advertises the amount of new data it's willing to accept from the flow sender with the bufferBytesAvailable derived field of an acknowledgement (Sections 2.3.13 and 2.3.14). The flow sender MUST NOT send new data into the network if flow.F_OUTSTANDING_BYTES is greater than or equal to the most recently received buffer advertisement, unless flow.EXCEPTION is true (Section 3.6.2.3).
3.6.2.9.1. Buffer Probe
The flow sender is suspended if the most recently received buffer advertisement is zero and the flow hasn't been rejected by the receiver -- that is, while RX_BUFFER_SIZE is zero AND EXCEPTION is false. To guard against potentially lost acknowledgements that might reopen the receive window, a suspended flow sender SHOULD send a packet comprising a Buffer Probe chunk (Section 2.3.15) for this flow from time to time. If the receive window advertisement transitions from non-zero to zero, the flow sender MAY send a Buffer Probe immediately and SHOULD send a probe within one second. The initial period between Buffer Probes SHOULD be at least one second or ERTO, whichever is greater. The period between probes SHOULD increase over time, but the period between probes SHOULD NOT be more than one minute or ERTO, whichever is greater. The flow sender SHOULD stop sending Buffer Probes if it is no longer suspended.
3.6.2.10. Exception
The flow receiver can reject the flow at any time and for any reason. The flow receiver sends a Flow Exception Report (Section 2.3.16) when it has rejected a flow. On receiving a Flow Exception Report for a sending flow: 1. If the flow is F_OPEN, close the flow (Section 3.6.2.11) and notify the user that the far end reported an exception with the encoded exception code; 2. Set the EXCEPTION flag to true; and 3. For each entry in SEND_QUEUE, set entry.ABANDONED = true.
Top   ToC   RFC7016 - Page 90
3.6.2.11. Close
A sending flow is closed by the user or as a result of an exception. To close an F_OPEN flow: 1. Move to the F_CLOSING state; 2. If the SEND_QUEUE is not empty, AND the tail entry of the SEND_QUEUE has a sequence number of NEXT_SN - 1, AND the tail entry.EVER_SENT is false, set F_FINAL_SN to entry.SEQUENCE_NUMBER; else 3. The SEND_QUEUE is empty, OR the tail entry does not have a sequence number of NEXT_SN - 1, OR the tail entry.EVER_SENT is true: enqueue a new SEND_QUEUE entry with entry.SEQUENCE_NUMBER = flow.NEXT_SN, entry.FRA = 0, and entry.ABANDONED = true, and set flow.F_FINAL_SN to entry.SEQUENCE_NUMBER. An F_CLOSING sending flow is complete when its SEND_QUEUE transitions to empty, indicating that all sequence numbers, including the FINAL_SN, have been acknowledged by the other end. When an F_CLOSING sending flow becomes complete, move to the F_COMPLETE_LINGER state. A sending flow MUST remain in the F_COMPLETE_LINGER state for at least 130 seconds. After at least 130 seconds, move to the F_CLOSED state. The sending flow is now closed, its resources can be reclaimed, and its F_FLOW_ID MAY be used for a new sending flow.

3.6.3. Receiver

Each receiving flow comprises the flow-specific information context necessary to receive that flow's messages from the sending end and deliver completed messages to the user. Each receiving flow context includes at least: o RF_FLOW_ID: this flow's identifier; o SEQUENCE_SET: the set of all fragment sequence numbers seen in this receiving flow, whether received or abandoned, initially empty; o RF_FINAL_SN: the final fragment sequence number of the flow, initially having no value;
Top   ToC   RFC7016 - Page 91
   o  RECV_BUFFER: the message fragments waiting to be delivered to the
      user, sorted by sequence number in ascending order, initially
      empty; each message fragment entry comprising the following:

      *  SEQUENCE_NUMBER: the sequence number of this fragment;

      *  DATA: this fragment's user data; and

      *  FRA: the fragment control value for this message fragment,
         having one of the values enumerated for that purpose in
         Section 2.3.11 ("User Data Chunk").

   o  BUFFERED_SIZE: the sum of the lengths of each fragment in
      RECV_BUFFER plus any additional storage overhead for the fragments
      incurred by the implementation, in bytes;

   o  BUFFER_CAPACITY: the desired maximum size for the receive buffer,
      in bytes;

   o  PREV_RWND: the most recent receive window advertisement sent in an
      acknowledgement, in 1024-byte blocks, initially having no value;

   o  SHOULD_ACK: whether or not an acknowledgement should be sent for
      this flow, initially false;

   o  EXCEPTION_CODE: the exception code to report to the sender when
      the flow has been rejected, initially 0;

   o  The state, at any time being one of the following values: the open
      state RF_OPEN; the closing states RF_REJECTED and
      RF_COMPLETE_LINGER; and the closed state RF_CLOSED.
Top   ToC   RFC7016 - Page 92
   Note: The following diagram is only a summary of state transitions
   and their causing events, and is not a complete operational
   specification.

                                       +-+
                                       |X|
                                       +-+
                                        |rcv User Data for
                                        |  no existing flow
                                        v
                                   +---------+
                                   | RF_OPEN |
                                   +---------+
              rcv all sequence numbers|   |user reject,
                      0..RF_FINAL_SN  |   |rcv bad option,
                                      |   |no metadata at open,
                                      |   |association specified
                                      |   |  but not F_OPEN at open
                                  +---+   |
                                  |       v
                                  |  +-----------+
                                  |  |RF_REJECTED|
                                  |  +-----------+
                                  |       |rcv all sequence numbers
                                  |       |  0..RF_FINAL_SN
                                  v       v
                             +------------------+
                             |RF_COMPLETE_LINGER|
                             +------------------+
                                      | 120 seconds
                                      v
                                 +---------+
                                 |RF_CLOSED|
                                 +---------+

                  Figure 22: Receiving Flow State Diagram
Top   ToC   RFC7016 - Page 93
3.6.3.1. Startup
A new receiving flow starts on receipt of a User Data chunk (Section 2.3.11) encoding a flow ID not belonging to any other receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER states. On receipt of such a User Data chunk: 1. Set temporary variables METADATA, ASSOCIATED_FLOWID, and ASSOCIATION to each have no value; 2. Create a new receiving flow context in this session, setting its RF_FLOW_ID to the flow ID encoded in the opening User Data chunk, and set to the RF_OPEN state; 3. If the opening User Data chunk encodes a User's Per-Flow Metadata option (Section 2.3.11.1.1), set METADATA to option.userMetadata; 4. If the opening User Data chunk encodes a Return Flow Association option (Section 2.3.11.1.2), set ASSOCIATED_FLOWID to option.flowID; 5. If METADATA has no value, the receiver MUST reject the flow (Section 3.6.3.7), moving it to the RF_REJECTED state; 6. If ASSOCIATED_FLOWID has a value, then if there is no sending flow in the same session with a flow ID of ASSOCIATED_FLOWID, the receiver MUST reject the flow, moving it to the RF_REJECTED state; otherwise, set ASSOCIATION to the indicated sending flow; 7. If ASSOCIATION indicates a sending flow, AND that sending flow's state is not F_OPEN, the receiver MUST reject this receiving flow, moving it to the RF_REJECTED state; 8. If the opening User Data chunk encodes any unrecognized option with a type code less than 8192 (Section 2.3.11.1), the receiver MUST reject the flow, moving it to the RF_REJECTED state; 9. If this new receiving flow is still RF_OPEN, then notify the user that a new receiving flow has opened, including the METADATA and, if present, the ASSOCIATION, and set flow.BUFFER_CAPACITY according to the user;
Top   ToC   RFC7016 - Page 94
   10.  Perform the normal data processing (Section 3.6.3.2) for the
        opening User Data chunk; and

   11.  Set this session's ACK_NOW to true.

3.6.3.2. Receiving Data
A User Data chunk (Section 2.3.11) or a Next User Data chunk (Section 2.3.12) encodes one fragment of a user data message of a flow, as well as the flow's Forward Sequence Number and potentially optional parameters (Section 2.3.11.1). On receipt of a User Data or Next User Data chunk: 1. If chunk.flowID doesn't indicate an existing receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER state, perform the steps of Section 3.6.3.1 ("Startup") to start a new receiving flow; 2. Retrieve the receiving flow context for the flow indicated by chunk.flowID; 3. Set flow.SHOULD_ACK to true; 4. If the flow is RF_OPEN, AND the chunk encodes any unrecognized option with a type code less than 8192 (Section 2.3.11.1), the flow MUST be rejected: notify the user of an exception, and reject the flow (Section 3.6.3.7), moving it to the RF_REJECTED state; 5. If the flow is not in the RF_OPEN state, set session.ACK_NOW to true; 6. If flow.PREV_RWND has a value and that value is less than 2 blocks, set session.ACK_NOW to true; 7. If chunk.abandon is true, set session.ACK_NOW to true; 8. If flow.SEQUENCE_SET has any gaps (that is, if it doesn't contain every sequence number from 0 through and including the highest sequence number in the set), set session.ACK_NOW to true; 9. If flow.SEQUENCE_SET contains chunk.sequenceNumber, then this chunk is a duplicate: set session.ACK_NOW to true;
Top   ToC   RFC7016 - Page 95
   10.  If flow.SEQUENCE_SET doesn't contain chunk.sequenceNumber, AND
        chunk.final is true, AND flow.RF_FINAL_SN has no value, then set
        flow.RF_FINAL_SN to chunk.sequenceNumber, and set
        session.ACK_NOW to true;

   11.  If the flow is in the RF_OPEN state, AND flow.SEQUENCE_SET
        doesn't contain chunk.sequenceNumber, AND chunk.abandon is
        false, then create a new RECV_BUFFER entry for this chunk's data
        and set entry.SEQUENCE_NUMBER to chunk.sequenceNumber,
        entry.DATA to chunk.userData, and entry.FRA to
        chunk.fragmentControl, and insert this new entry into
        flow.RECV_BUFFER;

   12.  Add to flow.SEQUENCE_SET the range of sequence numbers from 0
        through and including the chunk.forwardSequenceNumber derived
        field;

   13.  Add chunk.sequenceNumber to flow.SEQUENCE_SET;

   14.  If flow.SEQUENCE_SET now has any gaps, set session.ACK_NOW
        to true;

   15.  If session.ACK_NOW is false and session.DELACK_ALARM is not set,
        set session.DELACK_ALARM to fire in 200 milliseconds; and

   16.  Attempt delivery of completed messages in this flow's
        RECV_BUFFER to the user (Section 3.6.3.3).

   After processing all chunks in a packet containing at least one User
   Data chunk, increment session.RX_DATA_PACKETS by one.  If
   session.RX_DATA_PACKETS is at least two, set session.ACK_NOW to true.

   A receiving flow that is not in the RF_CLOSED state is ready to send
   an acknowledgement if its SHOULD_ACK flag is set.  Acknowledgements
   for receiving flows that are ready are sent either opportunistically
   by piggybacking on a packet that's already sending user data or an
   acknowledgement (Section 3.6.3.4.6), or when the session's ACK_NOW
   flag is set (Section 3.6.3.4.5).

3.6.3.3. Buffering and Delivering Data
A receiving flow's information context contains a RECV_BUFFER for reordering, reassembling, and holding the user data messages of the flow. Only complete messages are delivered to the user; an implementation MUST NOT deliver partially received messages, except by special arrangement with the user.
Top   ToC   RFC7016 - Page 96
   Let the Cumulative Acknowledgement Sequence Number (CSN) be the
   highest number in the contiguous range of numbers in SEQUENCE_SET
   starting with 0.  For example, if SEQUENCE_SET contains {0, 1, 2, 3,
   5, 6}, the contiguous range starting with 0 is 0..3, so the CSN is 3.

   A message is complete if all of its fragments are present in the
   RECV_BUFFER.  The fragments of one message have contiguous sequence
   numbers.  A message can be either a single fragment, whose fragment
   control value is 0-whole, or two or more fragments where the first's
   fragment control value is 1-begin, followed by zero or more fragments
   with control value 3-middle, and terminated by a last fragment with
   control value 2-end.

   An incomplete message segment is a contiguous sequence of one or more
   fragments that do not form a complete message -- that is, a 1-begin
   followed by zero or more 3-middle fragments but with no 2-end, or
   zero or more 3-middle fragments followed by a 2-end but with no
   1-begin, or one or more 3-middle fragments with neither a 1-begin nor
   a 2-end.

   Incomplete message segments can either be in progress or abandoned.
   An incomplete segment is abandoned in the following cases:

   o  The sequence number of the segment's first fragment is less than
      or equal to the CSN, AND that fragment's control value is not
      1-begin; or

   o  The sequence number of the segment's last fragment is less than
      the CSN.

   Abandoned message segments will never be completed, so they SHOULD be
   removed from the RECV_BUFFER to make room in the advertised receive
   window and the receiver's memory for messages that can be completed.

   The user can suspend delivery of a flow's messages.  A suspended
   receiving flow holds completed messages in its RECV_BUFFER until the
   user resumes delivery.  A suspended flow can cause the receive window
   advertisement to go to zero even when the BUFFER_CAPACITY is
   non-zero; this is described in detail in Section 3.6.3.5
   ("Flow Control").

   When the receiving flow is not suspended, the original queuing order
   of the messages is recovered by delivering, in ascending sequence
   number order, complete messages in the RECV_BUFFER whose sequence
   numbers are less than or equal to the CSN.
Top   ToC   RFC7016 - Page 97
   The following describes a method for discarding abandoned message
   segments and delivering complete messages in original queuing order
   when the receiving flow is not suspended.

   While the first fragment entry in the RECV_BUFFER has a sequence
   number less than or equal to the CSN and delivery is still possible:

   1.  If entry.FRA is 0-whole, deliver entry.DATA to the user, and
       remove this entry from RECV_BUFFER; otherwise,

   2.  If entry.FRA is 2-end or 3-middle, this entry belongs to an
       abandoned segment, so remove and discard this entry from
       RECV_BUFFER; otherwise,

   3.  Entry.FRA is 1-begin.  Let LAST_ENTRY be the last RECV_BUFFER
       entry that is part of this message segment (LAST_ENTRY can be
       entry if the segment has only one fragment so far).  Then:

       1.  If LAST_ENTRY.FRA is 2-end, this segment is a complete
           message, so concatenate the DATA fields of each fragment
           entry of this segment in ascending sequence number order and
           deliver the complete message to the user, then remove the
           entries for this complete message from RECV_BUFFER;
           otherwise,

       2.  If LAST_ENTRY.SEQUENCE_NUMBER is less than CSN, this segment
           is incomplete and abandoned, so remove and discard the
           entries for this segment from RECV_BUFFER; otherwise,

       3.  LAST_ENTRY.SEQUENCE_NUMBER is equal to CSN and LAST_ENTRY.FRA
           is not 2-end: this segment is incomplete but still in
           progress.  Ordered delivery is no longer possible until at
           least one more fragment is received.  Stop.

   If flow.RF_FINAL_SN has a value and is equal to the CSN, AND
   RECV_BUFFER is empty, all complete messages have been delivered to
   the user, so notify the user that the flow is complete.

3.6.3.4. Acknowledging Data
A flow receiver SHOULD acknowledge all user data fragment sequence numbers seen in that flow. Acknowledgements drive the sender's congestion control and avoidance algorithms, clear data from the sender's buffers, and in some sender implementations clock new data into the network; therefore, the acknowledgements must be accurate and timely.
Top   ToC   RFC7016 - Page 98
3.6.3.4.1. Timing
For reasons similar to those discussed in Section 4.2.3.2 of RFC 1122 [RFC1122], it is advantageous to delay sending acknowledgements for a short time, so that multiple data fragments can be acknowledged in a single transmission. However, it is also advantageous for a sender to receive timely notification about the receiver's disposition of the flow, particularly in unusual or exceptional circumstances, so that the circumstances can be addressed if possible. Therefore, a flow receiver SHOULD send an acknowledgement for a flow as soon as is practical in any of the following circumstances: o On receipt of a User Data chunk that starts a new flow; o On receipt of a User Data or Next User Data chunk if the flow is not in the RF_OPEN state; o On receipt of a User Data chunk where, before processing the chunk, the SEQUENCE_SET of the indicated flow does not contain every sequence number between 0 and the highest sequence number in the set (that is, if there was a sequence number gap before processing the chunk); o On receipt of a User Data chunk where, after processing the chunk, the flow's SEQUENCE_SET does not contain every sequence number between 0 and the highest sequence number in the set (that is, if this chunk causes a sequence number gap); o On receipt of a Buffer Probe for the flow; o On receipt of a User Data chunk if the last acknowledgement sent for the flow indicated fewer than two bufferBlocksAvailable; o On receipt of a User Data or Next User Data chunk for the flow if, after processing the chunk, the flow's BUFFER_CAPACITY is not at least 1024 bytes greater than BUFFERED_SIZE; o On receipt of a User Data or Next User Data chunk for any sequence number that was already seen (that is, on receipt of a duplicate); o On the first receipt of the final sequence number of the flow; o On receipt of two packets in the session that contain user data for any flows since an acknowledgement was last sent, the new acknowledgements being for the flows having any User Data chunks in the received packets (that is, for every second packet containing user data);
Top   ToC   RFC7016 - Page 99
   o  After receipt of a User Data chunk for the flow, if an
      acknowledgement for any other flow is being sent (that is,
      consolidate acknowledgements);

   o  After receipt of a User Data chunk for the flow, if any user data
      for a sending flow is being sent in a packet and if there is space
      available in the same packet (that is, attempt to piggyback an
      acknowledgement with user data if possible);

   o  No longer than 200 milliseconds after receipt of a User Data chunk
      for the flow.

3.6.3.4.2. Size and Truncation
Including an encoded acknowledgement in a packet might cause the packet to exceed the path MTU. In that case: o If the packet is being sent primarily to send an acknowledgement, AND this is the first acknowledgement in the packet, truncate the acknowledgement so that the packet does not exceed the path MTU; otherwise, o The acknowledgement is being piggybacked in a packet with user data or with an acknowledgement for another flow: do not include this acknowledgement in the packet, and send it later.
3.6.3.4.3. Constructing
The Data Acknowledgement Bitmap chunk (Section 2.3.13) and Data Acknowledgement Ranges chunk (Section 2.3.14) encode a receiving flow's SEQUENCE_SET and its receive window advertisement. The two chunks are semantically equivalent; implementations SHOULD send whichever provides the most compact encoding of the SEQUENCE_SET. When assembling an acknowledgement for a receiving flow: 1. If the flow's state is RF_REJECTED, first assemble a Flow Exception Report chunk (Section 2.3.16) for flow.flowID; 2. Choose the acknowledgement chunk type that most compactly encodes flow.SEQUENCE_SET; 3. Use the method described in Section 3.6.3.5 ("Flow Control") to determine the value for the acknowledgement chunk's bufferBlocksAvailable field.
Top   ToC   RFC7016 - Page 100
3.6.3.4.4. Delayed Acknowledgement
As discussed in Section 3.6.3.4.1 ("Timing"), a flow receiver can delay sending an acknowledgement for up to 200 milliseconds after receiving user data. The method described in Section 3.6.3.2 ("Receiving Data") sets the session's DELACK_ALARM. When DELACK_ALARM fires, set ACK_NOW to true.
3.6.3.4.5. Obligatory Acknowledgement
One or more acknowledgements should be sent as soon as is practical when the session's ACK_NOW flag is set. While the ACK_NOW flag is set: 1. Choose a receiving flow that is ready to send an acknowledgement; 2. If there is no such flow, there is no work to do, set ACK_NOW to false, set RX_DATA_PACKETS to 0, clear the DELACK_ALARM, and stop; otherwise, 3. Start a new packet; 4. Assemble an acknowledgement for the flow and include it in the packet, truncating it if necessary so that the packet doesn't exceed the path MTU; 5. Set flow.SHOULD_ACK to false; 6. Set flow.PREV_RWND to the bufferBlocksAvailable field of the included acknowledgement chunk; 7. Attempt to piggyback acknowledgements for any other flows that are ready to send an acknowledgement into the packet, as described below; and 8. Send the packet.
3.6.3.4.6. Opportunistic Acknowledgement
When sending a packet with user data or an acknowledgement, any other receiving flows that are ready to send an acknowledgement should include their acknowledgements in the packet if possible.
Top   ToC   RFC7016 - Page 101
   To piggyback acknowledgements in a packet that is already being sent,
   where the packet contains user data or an acknowledgement, while
   there is at least one receiving flow that is ready to send an
   acknowledgement:

   1.  Assemble an acknowledgement for the flow;

   2.  If the acknowledgement cannot be included in the packet without
       exceeding the path MTU, the packet is full; stop.  Otherwise,

   3.  Include the acknowledgement in the packet;

   4.  Set flow.SHOULD_ACK to false;

   5.  Set flow.PREV_RWND to the bufferBlocksAvailable field of the
       included acknowledgement chunk; and

   6.  If there are no longer any receiving flows in the session that
       are ready to send an acknowledgement, set session.ACK_NOW to
       false, set session.RX_DATA_PACKETS to 0, and clear
       session.DELACK_ALARM.

3.6.3.4.7. Example
Figure 23 shows an example flow with sequence numbers 31 and 33 lost in transit; 31 is abandoned, and 33 is retransmitted. Receiver 1 |<--- Data ID=3, seq#=29, fsnOff=11 (fsn=18) 2 |<--- Data ID=3, seq#=30, fsnOff=12 (fsn=18) 3 |---> Ack ID=3, seq:0-30 4 |<--- Data ID=3, seq#=32, fsnOff=12 (fsn=20) 5 |---> Ack ID=3, seq:0-30, 32 6 |<--- Data ID=3, seq#=34, fsnOff=12 (fsn=22) 7 |---> Ack ID=3, seq:0-30, 32, 34 | : 8 |<--- Data ID=3, seq#=46, fsnOff=16 (fsn=30) 9 |---> Ack ID=3, seq:0-30, 32, 34-46 10 |<--- Data ID=3, seq#=47, fsnOff=15 (fsn=32) 11 |---> Ack ID=3, seq:0-32, 34-47 12 |<--- Data ID=3, seq#=33, fsnOff=1 (fsn=32) 13 |---> Ack ID=3, seq#=0-47 14 |<--- Data ID=3, seq#=48, fsnOff=16 (fsn=32) 15 |<--- Data ID=3, seq#=49, fsnOff=17 (fsn=32) 16 |---> Ack ID=3, seq#=0-49 | : Figure 23: Flow Example with Loss
Top   ToC   RFC7016 - Page 102
3.6.3.5. Flow Control
The flow receiver maintains a buffer for reassembling and reordering messages for delivery to the user (Section 3.6.3.3). The implementation and the user may wish to limit the amount of resources (including buffer memory) that a flow is allowed to use. RTMFP provides a means for each receiving flow to govern the amount of data sent by the sender, by way of the bufferBytesAvailable derived field of acknowledgement chunks (Sections 2.3.13 and 2.3.14). This derived field indicates the amount of data that the sender is allowed to have outstanding in the network, until instructed otherwise. This amount is also called the receive window. The flow receiver can suspend the sender by advertising a closed (zero length) receive window. The user can suspend delivery of messages from the receiving flow (Section 3.6.3.3). This can cause the receive buffer to fill. In order for progress to be made on completing a fragmented message or repairing a gap for sequenced delivery in a flow, the flow receiver MUST advertise at least one buffer block in an acknowledgement if it is not suspended, even if the amount of data in the buffer exceeds the buffer capacity, unless the buffer capacity is 0. Otherwise, deadlock can occur, as the receive buffer will stay full and won't drain because of a gap or incomplete message, and the gap or incomplete message can't be repaired or completed because the sender is suspended. The receive window is advertised in units of 1024-byte blocks. For example, advertisements for 1 byte, 1023 bytes, and 1024 bytes each require one block. An advertisement for 1025 bytes requires two blocks. The following describes the RECOMMENDED method of calculating the bufferBlocksAvailable field of an acknowledgement chunk for a receiving flow: 1. If BUFFERED_SIZE is greater than or equal to BUFFER_CAPACITY, set ADVERTISE_BYTES to 0; 2. If BUFFERED_SIZE is less than BUFFER_CAPACITY, set ADVERTISE_BYTES to BUFFER_CAPACITY - BUFFERED_SIZE; 3. Set ADVERTISE_BLOCKS to CEIL(ADVERTISE_BYTES / 1024);
Top   ToC   RFC7016 - Page 103
   4.  If ADVERTISE_BLOCKS is 0, AND BUFFER_CAPACITY is greater than 0,
       AND delivery to the user is not suspended, set ADVERTISE_BLOCKS
       to 1; and

   5.  Set the acknowledgement's bufferBlocksAvailable field to
       ADVERTISE_BLOCKS.

3.6.3.6. Receiving a Buffer Probe
A Buffer Probe chunk (Section 2.3.15) is sent by the flow sender (Section 3.6.2.9.1) to request the current receive window advertisement (in the form of an acknowledgement) from the flow receiver. On receipt of a Buffer Probe chunk: 1. If chunk.flowID doesn't belong to a receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER state, ignore this Buffer Probe; otherwise, 2. Retrieve the receiving flow context for the flow indicated by chunk.flowID; then 3. Set flow.SHOULD_ACK to true; and 4. Set session.ACK_NOW to true.
3.6.3.7. Rejecting a Flow
A receiver can reject an RF_OPEN flow at any time and for any reason. To reject a receiving flow in the RF_OPEN state: 1. Move to the RF_REJECTED state; 2. Discard all entries in flow.RECV_BUFFER, as they are no longer relevant; 3. If the user rejected the flow, set flow.EXCEPTION_CODE to the exception code indicated by the user; otherwise, the flow was rejected automatically by the implementation, so the exception code is 0; 4. Set flow.SHOULD_ACK to true; and 5. Set session.ACK_NOW to true.
Top   ToC   RFC7016 - Page 104
   The receiver indicates that it has rejected a flow by sending a Flow
   Exception Report chunk (Section 2.3.16) with every acknowledgement
   (Section 3.6.3.4.3) for a flow in the RF_REJECTED state.

3.6.3.8. Close
A receiving flow is complete when every sequence number from 0 through and including the final sequence number has been received -- that is, when flow.RF_FINAL_SN has a value and flow.SEQUENCE_SET contains every sequence number from 0 through flow.RF_FINAL_SN, inclusive. When an RF_OPEN or RF_REJECTED receiving flow becomes complete, move to the RF_COMPLETE_LINGER state, set flow.SHOULD_ACK to true, and set session.ACK_NOW to true. A receiving flow SHOULD remain in the RF_COMPLETE_LINGER state for 120 seconds. After 120 seconds, move to the RF_CLOSED state. The receiving flow is now closed, and its resources can be reclaimed once all complete messages in flow.RECV_BUFFER have been delivered to the user (Section 3.6.3.3). The same flow ID might be used for a new flow by the sender after this point. Discussion: The flow sender detects that the flow is complete on receiving an acknowledgement of all fragment sequence numbers of the flow. This can't happen until after the receiver has detected that the flow is complete and acknowledged all of the sequence numbers. The receiver's RF_COMPLETE_LINGER period is two minutes (one Maximum Segment Lifetime (MSL)); this period allows any in-flight packets to drain from the network without being misidentified and gives the sender an opportunity to retransmit any sequence numbers if the completing acknowledgement is lost. The sender's F_COMPLETE_LINGER period is at least two minutes plus 10 seconds and doesn't begin until the completing acknowledgement is received; therefore, the same flow identifier won't be reused by the flow sender for a new sending flow for at least 10 seconds after the flow receiver has closed the receiving flow context. This ensures correct operation independent of network delay, even when the sender's clock runs up to 8 percent faster than the receiver's.

4. IANA Considerations

This memo specifies chunk type code values (Section 2.3) and User Data option type code values (Section 2.3.11.1). These type code values are assigned and maintained by Adobe. Therefore, this memo has no IANA actions.
Top   ToC   RFC7016 - Page 105

5. Security Considerations

This memo specifies a general framework that can be used to establish a confidential and authenticated session between endpoints. A Cryptography Profile, not specified herein, defines the cryptographic algorithms, data formats, and semantics as used within this framework. Designing a Cryptography Profile to ensure that communications are protected to the degree required by the application-specific threat model is outside the scope of this specification. A block cipher in CBC mode is RECOMMENDED for packet encryption (Section 2.2.3). An attacker can predict the values of some fields from one plain RTMFP packet to the next or predict that some fields may be the same from one packet to the next. This SHOULD be considered in choosing and implementing a packet encryption cipher and mode. The well-known Default Session Key of a Cryptography Profile serves multiple purposes, including the scrambling of session startup packets to protect interior fields from undesirable modification by middleboxes such as NATs, increasing the effort required for casual passive observation of startup packets, and allowing different applications of RTMFP using different Default Session Keys to (intentionally or not) share network transport addresses without interference. The Default Session Key, being well known, MUST NOT be construed to contribute to the security of session startup; session startup is essentially in the clear. Section 3.5.4.2 describes an OPTIONAL method for processing a change of network address of a communicating peer. Securely processing address mobility using that method, or any substantially similar method, REQUIRES at least that the packet encryption function of the Cryptography Profile (Section 2.2.3) employs a cryptographic verification mechanism comprising secret information known only to the two endpoints. Without this constraint, that method, or any substantially similar method, becomes "session hijacking support". Flows and packet fragmentation imply semantics that could cause unbounded resource utilization in receivers, causing a denial of service. Implementations SHOULD guard against unbounded or excessive resource use and abort sessions that appear abusive. A rogue but popular Redirector (Section 3.5.1.4) could direct session initiators to flood a victim address or network with Initiator Hello packets, potentially causing a denial of service.
Top   ToC   RFC7016 - Page 106
   An attacker that can passively observe an IHello and that possesses a
   certificate matching the Endpoint Discriminator (without having to
   know the private key, if any, associated with it) can deny the
   initiator access to the desired responder by sending an RHello before
   the desired responder does, since only the first received RHello is
   selected by the initiator.  The attacker needn't forge the desired
   responder's source address, since the RHello is selected based on the
   tag echo and not the packet's source address.  This can simplify the
   attack in some network or host configurations.

   An attacker that can passively observe and record the packets of an
   established session can use traffic analysis techniques to infer the
   start and completion of flows without decrypting the packets.  The
   User Data fragments of flows have unique sequence numbers, so flows
   are immune to replay while they are open.  However, once a flow has
   completed and the linger period has concluded, the attacker could
   replay the recorded packets, opening a new flow in the receiver and
   duplicating the flow's data; this replay might have undesirable
   effects on the receiver's application.  The attacker could also infer
   that a new flow has begun reusing the recorded flow's identifier and
   replay the final sequence number or any of the other fragments in the
   flow, potentially denying or interfering with legitimate traffic to
   the receiver.  Therefore, the data integrity aspect of packet
   encryption SHOULD comprise anti-replay measures.

6. Acknowledgements

Special thanks go to Matthew Kaufman for his contributions to the creation and design of RTMFP. Thanks to Jari Arkko, Ben Campbell, Wesley Eddy, Stephen Farrell, Philipp Hancke, Bela Lubkin, Hilarie Orman, Richard Scheffenegger, and Martin Stiemerling for their detailed reviews of this memo.
Top   ToC   RFC7016 - Page 107

7. References

7.1. Normative References

[CBC] Dworkin, M., "Recommendation for Block Cipher Modes of Operation", NIST Special Publication 800-38A, December 2001, <http://csrc.nist.gov/publications/ nistpubs/800-38a/sp800-38a.pdf>. [RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980. [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981. [RFC1122] Braden, R., "Requirements for Internet Hosts - Communication Layers", STD 3, RFC 1122, October 1989. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", RFC 2460, December 1998. [RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC 2914, September 2000. [RFC4821] Mathis, M. and J. Heffner, "Packetization Layer Path MTU Discovery", RFC 4821, March 2007. [RFC5681] Allman, M., Paxson, V., and E. Blanton, "TCP Congestion Control", RFC 5681, September 2009.

7.2. Informative References

[RFC5389] Rosenberg, J., Mahy, R., Matthews, P., and D. Wing, "Session Traversal Utilities for NAT (STUN)", RFC 5389, October 2008. [ScalableTCP] Kelly, T., "Scalable TCP: Improving Performance in Highspeed Wide Area Networks", December 2002, <http://datatag.web.cern.ch/datatag/papers/ pfldnet2003-ctk.pdf>.
Top   ToC   RFC7016 - Page 108

Appendix A. Example Congestion Control Algorithm

As mandated in Section 3.5.2, an RTMFP is required to use TCP- compatible congestion control, but flexibility in exact implementation is allowed, within certain limits. This section describes an experimental window-based congestion control algorithm that is appropriate for real-time and bulk data transport in RTMFP. The algorithm includes slow start and congestion avoidance phases, including modified increase and decrease parameters. These parameters are further adjusted according to whether real-time data is being sent and whether Time Critical Reverse Notifications are received.

A.1. Discussion

RFC 5681 defines the standard window-based congestion control algorithms for TCP. These algorithms are appropriate for delay- insensitive bulk data transport but have undesirable behaviors for delay- and loss-sensitive applications. Among the undesirable behaviors are the cutting of the congestion window in half during a loss event, and the rapidity of the slow start algorithm's exponential growth. Cutting the congestion window in half requires a large channel headroom to support a real-time application and can cause a large amount of jitter from sender-side buffering. Doubling the congestion window during the slow start phase can lead to the congestion window temporarily growing to twice the size it should be, causing a period of excessive loss in the path. We found that a number of deployed TCP implementations use the method of equation (3) from Section 3.1 of RFC 5681; this method, when combined with the recommended behavior of acknowledging every other packet, causes the congestion window to grow at approximately half the rate that the recommended method specifies. In order to compete fairly with these deployed TCPs, we choose 768 bytes per round trip as the increment during the normal congestion avoidance phase; this is approximately half of the typical maximum segment size of 1500 bytes and is also easily subdivided. The sender may be sending real-time data to the far end. When sending real-time data, a smoother response to congestion is desired while still competing with reasonable fairness to other flows in the Internet. In order to scale the sending rate quickly, the slow start algorithm is desired, but slow start's normal rate of increase can cause excessive loss in the last round trip. Accordingly, slow start's exponential increase rate is adjusted to double approximately every 3 round trips instead of every round trip. The multiplicative decrease cuts the congestion window by one eighth on loss to maintain a smoother sending rate. The additive increase is done at half the
Top   ToC   RFC7016 - Page 109
   normal rate (incrementing at 384 bytes per round trip), to both
   compensate for the less aggressive loss response and probe the path
   capacity more gently.

   The far end may report that it is receiving real-time data from other
   peers, or the sender may be sending real-time data to other far ends.
   In these circumstances (if not sending real-time data to this far
   end), it is desirable to respond differently than the standard TCP
   algorithms specify, to both yield capacity to the real-time flows and
   avoid excessive losses while probing the path capacity.  Slow start's
   exponential increase is disabled, and the additive increase is done
   at half the normal rate (incrementing at 384 bytes per round trip).
   Multiplicative decrease is left at the normal rate (cutting by half)
   to yield to other flows.

   Since real-time messages may be small, and sent regularly, it is
   advantageous to spread congestion window increases out across the
   round-trip time instead of doing them all at once.  We divide the
   round trip into 16 segments with an additive increase of a useful
   size (48 bytes) per segment.

   Scalable TCP [ScalableTCP] describes experimental methods of
   modifying the additive increase and multiplicative decrease of the
   congestion window in large delay-bandwidth scenarios.  The congestion
   window is increased by 1% each round trip and decreased by one eighth
   on loss in the congestion avoidance phase in certain circumstances
   (specifically, when a 1% increase is larger than the normal additive-
   increase amount).  Those methods are adapted here.  The scalable
   increase amount is 48 bytes for every 4800 bytes acknowledged, to
   spread the increase out over the round trip.  The congestion window
   is decreased by one eighth on loss when it is at least 67200 bytes
   per round trip, which is seven eighths of 76800 (the point at which
   1% is greater than 768 bytes per round trip).  When sending real-time
   data to the far end, the scalable increase is 1% or 384 bytes per
   round trip, whichever is greater.  Otherwise, when notified that the
   far end is receiving real-time data from other peers, the scaled
   increase is adjusted to 0.5% or 384 bytes per round trip, whichever
   is greater.
Top   ToC   RFC7016 - Page 110

A.2. Algorithm

Let SMSS denote the Sender Maximum Segment Size [RFC5681], for example 1460 bytes. Let CWND_INIT denote the Initial Congestion Window (IW) according to Section 3.1 of RFC 5681, for example 4380 bytes. Let CWND_TIMEDOUT denote the congestion window after a timeout indicating lost data, being 1*SMSS (for example, 1460 bytes). Let the session information context contain additional variables: o CWND: the congestion window, initialized to CWND_INIT; o SSTHRESH: the slow start threshold, initialized to positive infinity; o ACKED_BYTES_ACCUMULATOR: a count of acknowledged bytes, initialized to 0; o ACKED_BYTES_THIS_PACKET: a count of acknowledged bytes observed in the current packet; o PRE_ACK_OUTSTANDING: the number of bytes outstanding in the network before processing any acknowledgements in the current packet; o ANY_LOSS: an indication of whether any loss has been detected in the current packet; o ANY_NAKS: an indication of whether any negative acknowledgements have been detected in the current packet; o ANY_ACKS: an indication of whether any acknowledgement chunks have been received in the current packet. Let FASTGROW_ALLOWED indicate whether the congestion window is allowed to grow at the normal rate versus a slower rate, being false if a Time Critical Reverse Notification has been received on this session within the last 800 milliseconds (Sections 2.2.4 and 3.5.2.1) or if a Time Critical Forward Notification has been sent on ANY session in the last 800 milliseconds, and otherwise being true. Let TC_SENT indicate whether a Time Critical Forward Notification has been sent on this session within the last 800 milliseconds. Implement the method described in Section 3.6.2.6 to manage transmission timeouts, including setting the TIMEOUT_ALARM.
Top   ToC   RFC7016 - Page 111
   On being notified that the TIMEOUT_ALARM has fired, perform the
   function shown in Figure 24:

   on TimeoutNotification(WAS_LOSS):
       set SSTHRESH to MAX(SSTHRESH, CWND * 3/4).
       set ACKED_BYTES_ACCUMULATOR to 0.
       if WAS_LOSS is true:
           set CWND to CWND_TIMEDOUT.
       else:
           set CWND to CWND_INIT.

         Figure 24: Pseudocode for Handling a Timeout Notification

   Before processing each received packet in this session:

   1.  Set ANY_LOSS to false;

   2.  Set ANY_NAKS to false;

   3.  Set ACKED_BYTES_THIS_PACKET to 0; and

   4.  Set PRE_ACK_OUTSTANDING to S_OUTSTANDING_BYTES.

   On notification of loss (Section 3.6.2.5), set ANY_LOSS to true.

   On notification of negative acknowledgement (Section 3.6.2.5), set
   ANY_NAKS to true.

   On notification of acknowledgement of data (Section 3.6.2.4), set
   ANY_ACKS to true, and add the count of acknowledged bytes to
   ACKED_BYTES_THIS_PACKET.
Top   ToC   RFC7016 - Page 112
   After processing all chunks in each received packet for this session,
   perform the function shown in Figure 25:

   if ANY_LOSS is true:
       if (TC_SENT is true) OR (PRE_ACK_OUTSTANDING > 67200 AND \
       FASTGROW_ALLOWED is true):
           set SSTHRESH to MAX(PRE_ACK_OUTSTANDING * 7/8, CWND_INIT).
       else:
           set SSTHRESH to MAX(PRE_ACK_OUTSTANDING * 1/2, CWND_INIT).
       set CWND to SSTHRESH.
       set ACKED_BYTES_ACCUMULATOR to 0.
   else if (ANY_ACKS is true) AND (ANY_NAKS is false) AND \
   (PRE_ACK_OUTSTANDING >= CWND):
       set var INCREASE to 0.
       var AITHRESH.
       if FASTGROW_ALLOWED is true:
           if CWND < SSTHRESH:
               set INCREASE to ACKED_BYTES_THIS_PACKET.
           else:
               add ACKED_BYTES_THIS_PACKET to ACKED_BYTES_ACCUMULATOR.
               set AITHRESH to MIN(MAX(CWND / 16, 64), 4800).
               while ACKED_BYTES_ACCUMULATOR >= AITHRESH:
                   subtract AITHRESH from ACKED_BYTES_ACCUMULATOR.
                   add 48 to INCREASE.
       else FASTGROW_ALLOWED is false:
           if CWND < SSTHRESH AND TC_SENT is true:
               set INCREASE to CEIL(ACKED_BYTES_THIS_PACKET / 4).
           else:
               var AITHRESH_CAP.
               if TC_SENT is true:
                   set AITHRESH_CAP to 2400.
               else:
                   set AITHRESH_CAP to 4800.
               add ACKED_BYTES_THIS_PACKET to ACKED_BYTES_ACCUMULATOR.
               set AITHRESH to MIN(MAX(CWND / 16, 64), AITHRESH_CAP).
               while ACKED_BYTES_ACCUMULATOR >= AITHRESH:
                   subtract AITHRESH from ACKED_BYTES_ACCUMULATOR.
                   add 24 to INCREASE.
       set CWND to MAX(CWND + MIN(INCREASE, SMSS), CWND_INIT).

          Figure 25: Pseudocode for Congestion Window Adjustment
                         after Processing a Packet
Top   ToC   RFC7016 - Page 113

Author's Address

Michael C. Thornburgh Adobe Systems Incorporated 345 Park Avenue San Jose, CA 95110-2704 US Phone: +1 408 536 6000 EMail: mthornbu@adobe.com URI: http://www.adobe.com/