RFC 9177
Constrained Application Protocol (CoAP) Block-Wise Transfer Options Supporting Robust Transmission
Title Block ๐
- RFC and title: RFC 9177, "Constrained Application Protocol (CoAP) Block-Wise Transfer Options Supporting Robust Transmission" ๐
- Authors: M. Boucadair (Orange) and J. Shallow ๐
- Category: Standards Track ๐ฅ
- ISSN: 2070-1721
- Date: March 2022 ๐ธ
- Obsoletes and updates: the title block doesn't list any RFCs that this one obsoletes or updates โจ
Abstract โจ
okay so this doc specifies two alternative CoAP block-wise transfer options, Q-Block1 and Q-Block2 ๐ฆ
they're similar to the CoAP Block1 and Block2 options from RFC 7959, but they're not the same thing. Q-Block1 and Q-Block2 are NOT meant to replace Block1 and Block2. their whole goal is to support Non-confirmable (NON) messages for big chunks of data with fewer packet interchanges, which is so efficient ๐ญ they also help you recover faster if any of the blocks get lost in transmission ๐
Status of This Memo ๐
this is an Internet Standards Track document ๐ฅ
it's a product of the Internet Engineering Task Force (IETF), so it represents the consensus of the IETF community. it got public review and was approved for publication by the Internet Engineering Steering Group (IESG). if you want more info on Internet Standards, check Section 2 of RFC 7841 ๐ซถ
for the current status, any errata, and how to give feedback on this doc, go to https://www.rfc-editor.org/info/rfc9177 ๐
Copyright Notice ๐
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved ๐
this document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date of publication. please actually read those, bestie, because they describe your rights and restrictions for this doc ๐ also, any Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions. they come without warranty, as described in the Revised BSD License โญ
Table of Contents ๐
1. Introduction
2. Terminology
3. Alternative CoAP Block-Wise Transfer Options
3.1. CoAP Response Code (4.08) Usage
3.2. Applicability Scope
4. The Q-Block1 and Q-Block2 Options
4.1. Properties of the Q-Block1 and Q-Block2 Options
4.2. Structure of the Q-Block1 and Q-Block2 Options
4.3. Using the Q-Block1 Option
4.4. Using the Q-Block2 Option
4.5. Using the Observe Option
4.6. Using the Size1 and Size2 Options
4.7. Using the Q-Block1 and Q-Block2 Options Together
4.8. Using the Q-Block2 Option with Multicast
5. The Use of the 4.08 (Request Entity Incomplete) Response Code
6. The Use of Tokens
7. Congestion Control for Unreliable Transports
7.1. Confirmable (CON)
7.2. Non-confirmable (NON)
8. Caching Considerations
9. HTTP Mapping Considerations
10. Examples with Non-confirmable Messages
10.1. Q-Block1 Option
10.1.1. A Simple Example
10.1.2. Handling MAX_PAYLOADS Limits
10.1.3. Handling MAX_PAYLOADS with Recovery
10.1.4. Handling Recovery if Failure Occurs
10.2. Q-Block2 Option
10.2.1. A Simple Example
10.2.2. Handling MAX_PAYLOADS Limits
10.2.3. Handling MAX_PAYLOADS with Recovery
10.2.4. Handling Recovery by Setting the M Bit
10.3. Q-Block1 and Q-Block2 Options
10.3.1. A Simple Example
10.3.2. Handling MAX_PAYLOADS Limits
10.3.3. Handling Recovery
11. Security Considerations
12. IANA Considerations
12.1. CoAP Option Numbers Registry
12.2. Media Type Registration
12.3. CoAP Content-Formats Registry
13. References
13.1. Normative References
13.2. Informative References
Appendix A. Examples with Confirmable Messages
A.1. Q-Block1 Option
A.2. Q-Block2 Option
Appendix B. Examples with Reliable Transports
B.1. Q-Block1 Option
B.2. Q-Block2 Option
Acknowledgments
Authors' Addresses
1. Introduction โจ
so CoAP [RFC7252] was inspired by HTTP, but it was designed to run over UDP instead of TCP ๐ฆ its message layer over UDP includes reliable delivery, simple congestion control, and flow control. CoAP has two message types (Section 1.2 of [RFC7252]): Confirmable (CON) and Non-confirmable (NON). the difference is the main character energy: every CON message will elicit an acknowledgment or a reset, but NON messages don't get that ๐
the CoAP spec recommends that a CoAP message should fit within a single IP packet, so you avoid IP fragmentation ๐ธ but what about data records that can't fit in one packet? that's where [RFC7959] came in. it introduced block-wise transfers plus the companion CoAP Block1 and Block2 options ๐ the catch is that this concept is designed to work exclusively with Confirmable messages (Section 1 of [RFC7959]) ๐ also, [RFC8323] further updated block-wise transfer for use over TCP, TLS, and WebSockets โจ
the CoAP Block1 and Block2 options work well when there are no, or minimal, packet losses ๐ซถ they operate synchronously, which means each individual block has to be requested. a CoAP endpoint can only ask for (or send) the next block once the transfer of the previous block has completed. so the packet transmission rate, and therefore the block transmission rate, is controlled by Round-Trip Times (RTTs) ๐ญ
now here's the problem. there's a requirement for blocks of data larger than a single IP datagram to be sent under network conditions with asymmetrical transient packet loss, where acknowledgment responses may get dropped ๐ one example is a Distributed Denial of Service (DDoS) attack, when DDoS mitigation agents that rely on CoAP need to talk to each other (e.g., [RFC9132] [DOTS-TELEMETRY]) ๐ [RFC7959] recommends using CON responses to handle potential packet loss, but that doesn't work in a "flooded pipe" DDoS situation (e.g., [RFC9132]) ๐ฅ
this document introduces the CoAP Q-Block1 and Q-Block2 options. they let block-wise transfers work with a series of Non-confirmable messages, instead of lock-stepping with Confirmable messages (Section 3) ๐ฆ basically, this doc fills a missing piece of [RFC7959]: block-wise transfers using Non-confirmable messages, where an entire body of data can be sent without needing intermediate acknowledgments from the peer. recovery is still available if it's needed ๐
like [RFC7959], this spec doesn't remove any of the constraints from the base CoAP specification [RFC7252] that it's strictly layered on top of ๐ง
2. Terminology ๐
okay the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐ so only the all-caps versions count as the real deal, not the lowercase ones ๐
you should be familiar with the terms and concepts in [RFC7252], [RFC7959], and [RFC8132] ๐ this document especially uses these key concepts:
- Token: used to match responses to requests independently from the underlying messages (Section 5.3.1 of [RFC7252]) ๐ง
- ETag: used as a resource-local identifier for telling apart representations of the same resource that vary over time (Section 5.10.6 of [RFC7252]) ๐ฆ
the terms "payload" and "body" are defined in [RFC7959]. so "payload" is the content of a single CoAP message (aka a single block being transferred), and "body" is the entire resource representation that's being transferred in a block-wise fashion ๐ธ
- Request-Tag: refers to an option that lets a CoAP server match message fragments that belong to the same request [RFC9175] ๐ซถ
- MAX_PAYLOADS: the maximum number of payloads that can be transmitted at any one time ๐ฅ
- MAX_PAYLOADS_SET: the set of blocks, identified by block numbers, that have the same numeric result when divided by MAX_PAYLOADS. for example, if MAX_PAYLOADS is set to 10, a MAX_PAYLOADS_SET could be blocks #0 to #9, #10 to #19, etc. depending on the overall data size, there could be fewer than MAX_PAYLOADS blocks in the final MAX_PAYLOADS_SET ๐
3. Alternative CoAP Block-Wise Transfer Options โจ
okay so this is where the main event happens ๐
This document introduces the CoAP Q-Block1 and Q-Block2 options. They're built to shine with NON requests and responses ๐ฆ
Bestie, NON messages make transmissions way faster ๐ Every block can be sent back-to-back, kinda like fragmented IP packets ๐ง, without waiting around for a response or the next request from the remote CoAP peer. Recovering missing blocks is quicker too, because several missing blocks can be requested in one single CoAP message ๐. Even when packet loss is asymmetrical, a body can still be sent and received by the peer ๐ซถ, whether it's one payload or several, as long as no recovery is needed ๐ธ.
A CoAP endpoint can acknowledge all of the blocks or just a subset of them ๐ Basically, the receiving endpoint either tells the sending endpoint that everything arrived, or it reports every block in the body that hasn't been received yet ๐. Then the sending endpoint only retransmits the blocks that got lost along the way ๐
Similar transmission rate perks can apply to Confirmable messages if NSTART is raised from 1 (Section 4.7 of [RFC7252]) ๐ฅ. But ngl, Confirmable messages won't work well when packet loss is asymmetrical ๐ฌ. Some examples with Confirmable messages are in Appendix A ๐
There's little, if any, benefit to using these options with CoAP running over a reliable connection [RFC8323] ๐. In that case there's no difference between CON and NON, because they aren't used. Some examples using a reliable transport are in Appendix B ๐ง
The Q-Block1 and Q-Block2 options work similarly to the CoAP Block1 and Block2 options, respectively ๐. They aren't a replacement for them, but they come with these perks โจ:
- They can operate in environments where packet loss is highly asymmetrical ๐.
- They enable faster transmissions of sets of blocks of data with fewer packet interchanges ๐.
- They support faster recovery should any of the blocks get lost in transmission ๐ช.
- They support sending an entire body using NON messages without requiring that an intermediate response be received from the peer ๐.
Now the not-so-cute part ๐. The disadvantages of using the CoAP Block1 and Block2 options are as follows:
- There is a loss of lock-stepping, so payloads are not always received in the correct order (blocks in ascending order) ๐.
- Additional congestion control measures need to be put in place for NON messages (Section 7.2) ๐ง.
- To reduce the transmission times for CON transmissions of large bodies, NSTART needs to be increased from 1, but this affects congestion control and incurs a requirement to retune other parameters (Section 4.7 of [RFC7252]). Such tuning is out of scope of this document ๐ ๏ธ.
- Mixing of NON and CON during an exchange of requests/responses using Q-Block options is not supported ๐ซ.
- The Q-Block options do not support stateless operation/random access ๐ .
- Proxying of Q-Block options is limited to caching full representations ๐ฆ.
- There is no multicast support ๐ญ.
The Q-Block1 and Q-Block2 options can be used instead of the Block1 and Block2 options when the different transmission properties are required ๐ฆ. If the new options aren't supported by a peer, transmissions can fall back to using the Block1 and Block2 options (Section 4.1) ๐.
The deviations from the Block1 and Block2 options are specified in Section 4. Pointers to the appropriate sections in [RFC7959] are provided ๐.
The spec refers to the base CoAP methods defined in Section 5.8 of [RFC7252], plus the new CoAP methods FETCH, PATCH, and iPATCH, which are introduced in [RFC8132] ๐ .
The No-Response option [RFC7967] was considered but got abandoned ๐ โโ๏ธ, since it doesn't apply to Q-Block2 responses. A unified solution is defined in the document โจ.
3.1. CoAP Response Code (4.08) Usage
This document adds a media type for the 4.08 (Request Entity Incomplete) response ๐จ, defining an additional message format for reporting on payloads using the Q-Block1 option that are not received by the server ๐งพ.
See Section 5 for more details ๐
3.2. Applicability Scope
The block-wise transfer specified in [RFC7959] covers the general case using Confirmable messages ๐, but it falls short when packet loss is highly asymmetrical or when there's no need for an acknowledgment ๐ค. In other words, there's a need for Non-confirmable support ๐ซถ.
The mechanism specified in this document provides roughly similar features to the Block1/Block2 options ๐ธ. It also has extra properties tailored to the intended use case of Non-confirmable transmission ๐. Concretely, this mechanism mainly targets applications such as DDoS Open Threat Signaling (DOTS) ๐ก๏ธ. Those apps can't use CON requests/responses because of potential packet loss, and they support application-specific mechanisms to check whether the remote peer isn't overloaded and is able to process the messages sent by a CoAP endpoint (e.g., DOTS heartbeats in Section 4.7 of [RFC9132]) ๐. Other use cases are when an application sends data but has no need for an acknowledgment of receipt, and any data transmission loss is not critical ๐ฌ.
The mechanism includes guards to stop a CoAP agent from overloading the network by adopting an aggressive sending rate ๐. These guards MUST be followed in addition to the existing CoAP congestion control, as specified in Section 4.7 of [RFC7252] ๐จ. See Section 7 for more details ๐.
Any usage outside the primary use case of Non-confirmable messages with block transfers should be carefully weighed against the potential loss of interoperability with generic CoAP applications (see the disadvantages listed in Section 3) โ๏ธ. It is hoped that the experience gained with this mechanism can feed future extensions of the block-wise mechanism that will both be generally applicable and serve this particular use case ๐.
It is not recommended that these options are used in the "NoSec" security mode (Section 9 of [RFC7252]) ๐, as the source endpoint needs to be trusted ๐ค. Using Object Security for Constrained RESTful Environments (OSCORE) [RFC8613] does provide a security context, and hence a trust of the source endpoint that prepared the inner OSCORE content ๐. However, even with OSCORE, using the NoSec mode with these options may still be inadequate, for reasons discussed in Section 11 โ ๏ธ.
4. The Q-Block1 and Q-Block2 Options โจ
4.1. Properties of the Q-Block1 and Q-Block2 Options โจ
okay so here's the property tea ๐ต for the Q-Block1 and Q-Block2 options! Table 1 is basically your cheat sheet, and it's formatted just like Table 4 of Section 5.10 of [RFC7252] ๐ . The C, U, N, and R columns stand for Critical, UnSafe, NoCacheKey, and Repeatable, which are all defined in Section 5.4 of [RFC7252] ๐ซถ. Only the Critical and UnSafe columns get marked for Q-Block1. For Q-Block2, it's Critical, UnSafe, and Repeatable ๐. Since these options are UnSafe, NoCacheKey has no meaning for them, so it gets a dash ๐.
+=====+===+===+===+===+==========+========+========+=========+
| No. | C | U | N | R | Name | Format | Length | Default |
+=====+===+===+===+===+==========+========+========+=========+
| 19 | x | x | - | | Q-Block1 | uint | 0-3 | (none) |
+-----+---+---+---+---+----------+--------+--------+---------+
| 31 | x | x | - | x | Q-Block2 | uint | 0-3 | (none) |
+-----+---+---+---+---+----------+--------+--------+---------+
Table 1: CoAP Q-Block1 and Q-Block2 Option Properties
Both options can show up in requests AND responses ๐ฆ. Q-Block1 is about the request payload, and Q-Block2 is about the response payload. When Content-Format shows up alongside either one, the option applies to the whole body, not to each individual payload. That means it has to be the same across all payloads of the same body ๐งฉ.
Q-Block1 is handy for payload-bearing requests (POST, PUT, FETCH, PATCH, and iPATCH) and their responses ๐ฆ. Q-Block2 is useful for GET, POST, PUT, FETCH, PATCH, and iPATCH requests, plus payload-bearing responses with codes 2.01, 2.02, 2.04, and 2.05 (Section 5.5 of [RFC7252]) ๐ธ.
A CoAP endpoint (or proxy) MUST support either both or neither of the Q-Block1 and Q-Block2 options. No halfsies, bestie ๐.
If Q-Block1 is in a request, or Q-Block2 comes back in a response, that's a block-wise transfer. The option tells you how this specific block fits into the entire body being moved around โจ. If it shows up in the opposite direction, it gives extra control over how that payload gets formed or how it was processed ๐.
To say they can handle Q-Block2 responses, the CoAP client MUST include the Q-Block2 option in a GET or similar request (e.g., FETCH), the Q-Block2 option in a PUT or similar request (e.g., POST), or the Q-Block1 option in a PUT or similar request. That way the server knows this client gets Q-Block stuff if it ever needs to send back a body spread across multiple payloads ๐ซถ. Otherwise, the server would use the Block2 option (if supported) to send back a message body that's too big to fit into a single IP packet [RFC7959] ๐ฆ๐ฅ.
How a client decides whether it needs Q-Block1 or Q-Block2 can be driven by a local configuration parameter, an application trigger (like DOTS), and so on ๐. Those considerations are out of the scope of this document, so we're not going there today ๐ฆ.
Implementing the Q-Block1 and Q-Block2 options is intended to be optional. HOWEVER, when either option is present in a CoAP message, it MUST be processed (or the message rejected). That's exactly why they're identified as critical options ๐.
With CoAP over UDP, how a request gets rejected for critical options depends on the message type ๐. A Confirmable message with an unrecognized critical option gets a 4.02 (Bad Option) response (Section 5.4.1 of [RFC7252]) ๐ . A Non-confirmable message with an unrecognized critical option is either rejected with a Reset message or just silently ignored (Sections 5.4.1 and 4.3 of [RFC7252]) ๐ป. So if you want a rejection message you can count on, it is REQUIRED that clients use a Confirmable message for figuring out support for the Q-Block1 and Q-Block2 options ๐ฏ. That Confirmable message can go out under the base CoAP congestion control setup from Section 4.7 of [RFC7252], which means NSTART doesn't need to be increased (Section 7.1) ๐ฆ.
Q-Block1 and Q-Block2 are unsafe to forward ๐. A CoAP proxy that doesn't understand the Q-Block1 (or Q-Block2) option must reject the request or response that uses either option (see Section 5.7.1 of [RFC7252]). Not a vibe.
Q-Block2 is repeatable when requesting retransmission of missing blocks, but not otherwise ๐. Outside of that case, any request carrying multiple Q-Block1 (or Q-Block2) options MUST be handled following the procedure in Section 5.4.5 of [RFC7252] ๐ .
Q-Block1 and Q-Block2, just like Block1 and Block2, are both class E and class U for OSCORE processing (Table 2) ๐. The Q-Block1 (or Q-Block2) option MAY be an Inner or Outer option (Section 4.1 of [RFC8613]). Inner and Outer values are independent of each other. Inner is encrypted and integrity protected between clients and servers, and it provides message body identification when requests get fragmented end-to-end. Outer is visible to proxies and labels message bodies when requests get fragmented hop-by-hop ๐ง.
+========+==========+===+===+
| Number | Name | E | U |
+========+==========+===+===+
| 19 | Q-Block1 | x | x |
+--------+----------+---+---+
| 31 | Q-Block2 | x | x |
+--------+----------+---+---+
Table 2: OSCORE
Protection of the
Q-Block1 and Q-Block2
Options
Heads up, bestie ๐จ: if Q-Block1 or Q-Block2 are included in a packet as Inner options, then Block1 or Block2 MUST NOT be included as Inner options. Similarly, there MUST NOT be a mix of Q-Block and Block options for the Outer options. Messages that don't play by these rules MUST be rejected with a 4.02 (Bad Option) ๐.
The Q-Block and Block options can be mixed across Inner and Outer options, since those get handled independently of each other ๐ธ. For clarity, if OSCORE isn't being used, there MUST NOT be a mix of Q-Block and Block options in the same packet. ๐
4.2. Structure of the Q-Block1 and Q-Block2 Options ๐
The structure of the Q-Block1 and Q-Block2 options follows the structure defined in Section 2.2 of [RFC7959] ๐งฑ.
There is no default value for these options ๐คท. The absence of one of them is equivalent to an option value of 0 with respect to the block number (NUM) and the more bit (M) that could be given in the option. In other words, it indicates that the current block is the first and only block of the transfer (block number is set to 0; M is unset). BUT, unlike the explicit value 0 (which would indicate a block size (SZX) of 0, and therefore a size value of 16 bytes), there is no specific size implied by the absence of the option. The size is left unspecified ๐. (As for any uint, the explicit value 0 is efficiently indicated by a zero-length option. That's why it's semantically different from the option being absent ๐ง .)
4.3. Using the Q-Block1 Option ๐
okay so the Q-Block1 option is for when the client wants to send a huge pile of data to the server using POST, PUT, FETCH, PATCH, or iPATCH ๐. This is the move when the data and headers together won't fit in a single packet ๐ฆ.
When Q-Block1 is in play, the client MUST include a Request-Tag option [RFC9175] ๐. The Request-Tag value MUST be the same for all of the requests carrying the body of data being sent ๐ฆ. The Request-Tag is opaque, which means nobody gets to peek inside, but the client MUST ensure it is unique for every different body of transmitted data ๐.
Implementation Note: It is suggested that the client treats the Request-Tag as an unsigned integer of 8 bytes in length. An implementation may want to consider limiting this to 4 bytes to reduce packet overhead size. The initial Request-Tag value should be randomly generated and then subsequently incremented by the client whenever a new body of data is being transmitted between peers. ๐ธ
Section 4.6 discusses the use of the Size1 option ๐.
For Confirmable transmission, the server keeps acknowledging each packet, but it doesn't need to send a response (whether separate or piggybacked) until the server has successfully received the whole body ๐ซถ. For Non-confirmable transmission, no response is required until either the server has successfully received the body or a timer expires with some of the payloads still missing ๐ญ. In that second case, a "retransmit missing payloads" response is needed. For reliable transports (e.g., [RFC8323]), a response is not required until the server has successfully received the body โจ.
Each individual message that carries a block of the body is treated as a new request (Section 6) ๐ง.
The client MUST send the payloads in order of increasing block number, starting from zero, until the body is complete (subject to any congestion control (Section 7)) ๐โโ๏ธ. On top of that, any missing payloads the server asks for must be separately transmitted with increasing block numbers ๐ .
Here are the response codes that get used ๐:
2.01 (Created) This response code indicates successful receipt of the entire body and that the resource was created ๐. The token to use MUST be one of the tokens that were received in a request for this block-wise exchange. However, it is desirable to provide the one used in the last received request, since that will aid any troubleshooting ๐. The client should then release all of the tokens used for this body. Note that the last received payload might not be the one with the highest block number ๐คทโโ๏ธ.
2.02 (Deleted) This response code indicates successful receipt of the entire body and that the resource was deleted when using POST (Section 5.8.2 of [RFC7252]) ๐๏ธ. The token to use MUST be one of the tokens that were received in a request for this block-wise exchange. However, it is desirable to provide the one used in the last received request. The client should then release all of the tokens used for this body.
2.04 (Changed) This response code indicates successful receipt of the entire body and that the resource was updated โ๏ธ. The token to use MUST be one of the tokens that were received in a request for this block-wise exchange. However, it is desirable to provide the one used in the last received request. The client should then release all of the tokens used for this body.
2.05 (Content) This response code indicates successful receipt of the entire FETCH request body (Section 2 of [RFC8132]) and that the appropriate representation of the resource is being returned ๐ฌ. The token to use MUST be one of the tokens that were received in a request for this block-wise exchange. However, it is desirable to provide the one used in the last received request.
If the FETCH request includes the Observe option, then the server MUST use the same token as used for the 2.05 (Content) response for returning any triggered Observe responses, so that the client can match them up ๐. The client should then release all of the tokens used for this body apart from the one used for tracking an observed resource.
2.31 (Continue) This response code can be used to indicate that all of the blocks up to and including the Q-Block1 option block NUM (all having the M bit set) have been successfully received ๐. The token to use MUST be one of the tokens that were received in a request for this latest MAX_PAYLOADS_SET block-wise exchange. However, it is desirable to provide the one used in the last received request. The client should then release all of the tokens used for this MAX_PAYLOADS_SET.
A response using this response code MUST NOT be generated for every received Q-Block1 option request ๐ โโ๏ธ. It SHOULD only be generated when all the payload requests are Non-confirmable and a MAX_PAYLOADS_SET has been received by the server. More details about the motivations for this optimization are discussed in Section 7.2 ๐ง .
This response code SHOULD NOT be generated for CON, as this may cause duplicated payloads to unnecessarily be sent ๐.
4.00 (Bad Request) This response code MUST be returned if the request does not include a Request-Tag option or a Size1 option but does include a Q-Block1 option ๐.
4.02 (Bad Option) This response code MUST be returned for a Confirmable request if the server does not support the Q-Block options. Note that a Reset message may be sent in case of a Non-confirmable request ๐ซ .
4.08 (Request Entity Incomplete) As a reminder, this response code returned without content type application/missing-blocks+cbor-seq (Section 12.3) is handled as in Section 2.9.2 of [RFC7959] ๐.
This response code returned with content type application/missing-blocks+cbor-seq indicates that some of the payloads are missing and need to be resent ๐งฉ. The client then retransmits the individual missing payloads using the same Request-Tag, Size1, and Q-Block1 options, specifying the same NUM, SZX, and M bit values as those sent initially in the original (but not received) packets.
The Request-Tag value to use is determined by taking the token in the 4.08 (Request Entity Incomplete) response, locating the matching client request, and then using its Request-Tag ๐.
The token to use in the 4.08 (Request Entity Incomplete) response MUST be one of the tokens that were received in a request for this block-wise body exchange. However, it is desirable to provide the one used in the last received request. See Section 5 for further information.
If the server has not received all the blocks of a body, but one or more NON payloads have been received, it SHOULD wait for NON_RECEIVE_TIMEOUT (Section 7.2) before sending a 4.08 (Request Entity Incomplete) response โณ.
4.13 (Request Entity Too Large) This response code can be returned under conditions similar to those discussed in Section 2.9.3 of [RFC7959] ๐.
This response code can be returned if there is insufficient space to create a response PDU with a block size of 16 bytes (SZX = 0) to send back all the response options as appropriate. In this case, the Size1 option is not included in the response ๐ซง.
Further considerations related to the transmission timings of the 4.08 (Request Entity Incomplete) and 2.31 (Continue) response codes are discussed in Section 7.2 โฐ.
If a server receives payloads with different Request-Tags for the same resource, it should continue to process all the bodies, as it has no way of determining which is the latest version or which body, if any, the client is terminating the transmission for ๐ค.
If the client elects to stop the transmission of a complete body, then absent any local policy, the client MUST "forget" all tracked tokens associated with the body's Request-Tag, so that a Reset message is generated for the invalid token in the 4.08 (Request Entity Incomplete) response ๐ป. On receipt of the Reset message, the server SHOULD delete the partial body ๐งน.
If the server receives a duplicate block with the same Request-Tag, it MUST ignore the payload of the packet but MUST still respond as if the block was received for the first time ๐ช.
A server SHOULD maintain a partial body (missing payloads) for NON_PARTIAL_TIMEOUT (Section 7.2) ๐.
4.4. Using the Q-Block2 Option ๐
In a request for any block number, an unset M bit means the request is just for that one block. โจ If the M bit is set, it means something different depending on the NUM value:
NUM is zero:This is a request for the entire body. ๐'NUM modulo MAX_PAYLOADS' is zero, while NUM is not zero:This is used to confirm that the currentMAX_PAYLOADS_SET(the latest block having block number NUM-1) has been successfully received, and that once the server gets this request, it can continue sending the nextMAX_PAYLOADS_SET(the first block having block number NUM). This is the 'Continue' Q-Block-2, and conceptually it has the same usage (continue sending the next set of data) as 2.31 (Continue) does for Q-Block1. ๐ฆAny other value of NUM:This is a request for that block and for all of the remaining blocks in the currentMAX_PAYLOADS_SET. ๐ธ
If the request includes multiple Q-Block2 options and they overlap (for example, M being set for this and later blocks, and unset for this individual block), so that one block gets requested more than once, the server MUST only send back one instance of that block. ๐ โโ๏ธ This behavior is meant to prevent amplification attacks, so it's a big deal, bestie. ๐ฅ
The payloads the server sends back as a response MUST all have the same ETag (Section 5.10.6 of [RFC7252]) for the same body. The server MUST NOT use the same ETag value for different representations of a resource. ๐ซ
The ETag is opaque, but the server MUST ensure it is unique for every different body of transmitted data. ๐
Implementation Note: It is suggested that the server treats the ETag as an unsigned integer of 8 bytes in length. An implementation may want to consider limiting this to 4 bytes to reduce packet overhead size. The initial ETag value should be randomly generated and then subsequently incremented by the server whenever a new body of data is being transmitted between peers. ๐
Section 4.6 discusses the use of the Size2 option. ๐ง
The client may elect to request any detected missing blocks, or it may just ignore the partial body. That decision is implementation specific. ๐คทโโ๏ธ
For NON payloads, the client SHOULD wait for NON_RECEIVE_TIMEOUT (Section 7.2) after the last received payload before requesting retransmission of any missing blocks. โณ Retransmission is requested by issuing a GET, POST, PUT, FETCH, PATCH, or iPATCH request that contains one or more Q-Block2 options defining the missing block(s). Generally, the M bit on the Q-Block2 option(s) SHOULD be unset, although the M bit MAY be set to request this and later blocks from this MAX_PAYLOADS_SET. See Section 10.2.4 for an example of this in action. ๐ Further considerations about transmission timing for missing requests are discussed in Section 7.2.
The missing block numbers the client requests MUST have an increasing block number in each additional Q-Block2 option, with no duplicates. The server SHOULD respond with a 4.00 (Bad Request) to requests that don't follow this behavior. ๐ โโ๏ธ The ordering rule is there to force the client to check for duplicates and remove them, and it also helps with troubleshooting. ๐ ๏ธ
If the client receives a duplicate block with the same ETag, it MUST silently ignore the payload. ๐คซ
A client SHOULD maintain a partial body (missing payloads) for NON_PARTIAL_TIMEOUT (Section 7.2), or as defined by the Max-Age option (or its default of 60 seconds (Section 5.6.1 of [RFC7252])), whichever is less. โฑ๏ธ When the partial body is released, the client should then release all of the tokens used for this body apart from the token used to track a resource that is being observed. ๐
The ETag option should not be used in the request for missing blocks, because the server could respond with a 2.03 (Valid) response with no payload. ๐ฌ It can be used in the request if the client wants to check the freshness of the locally cached body response. ๐ง
The server SHOULD maintain a cached copy of the body when using the Q-Block2 option, so it can facilitate retransmission of any missing payloads. ๐พ
If the server detects partway through a body transfer that the resource data has changed, and the server is not maintaining a cached copy of the old data, then the transmission is terminated. Any subsequent missing block requests MUST be responded to using the latest ETag and Size2 option values with the updated data. ๐
If the server responds during a body update with a different ETag option value (because the resource representation has changed), the client should treat the partial body with the old ETag as no longer fresh. ๐ฅ The client may then request all of the new data by specifying Q-Block2 with block number '0' and the M bit set. ๐
If the server transmits a new body of data (for example, a triggered Observe notification) with a new ETag to the same client as an additional response, the client should remove any partially received body held for a previous ETag for that resource, since it is unlikely the missing blocks can be retrieved. ๐๏ธ
If there is not enough space to create a response PDU with a block size of 16 bytes (SZX = 0) to send back all the response options as appropriate, a 4.13 (Request Entity Too Large) is returned without the Size1 option. ๐ฆ
For Confirmable traffic, the server typically acknowledges the initial request using an Acknowledgment (ACK) with a piggybacked payload, and then sends the subsequent payloads of the MAX_PAYLOADS_SET as CON responses. ๐จ These CON responses are individually ACKed by the client. The server will detect failure to send a packet and SHOULD terminate the body transfer, but after a MAX_TRANSMIT_SPAN delay, the client can issue a separate GET, POST, PUT, FETCH, PATCH, or iPATCH for any missing blocks as needed. ๐ซถ
4.5. Using the Observe Option ๐
For a request that uses Q-Block1, the Observe value [RFC7641] MUST be the same for all the payloads of the same body. This includes any missing payloads that are retransmitted. ๐
For a response that uses Q-Block2, the Observe value MUST be the same for all the payloads of the same body. This is different from Block2 usage, where the Observe value is only present in the first block (Section 3.4 of [RFC7959]). This includes payloads transmitted after the server receives the 'Continue' Q-Block2 option (Section 4.4). If a missing payload is requested by a client, then both the request and the response MUST NOT include the Observe option. ๐ซ๐
4.6. Using the Size1 and Size2 Options ๐
Section 4 of [RFC7959] defines two CoAP options: Size1, for indicating the size of the representation transferred in requests, and Size2, for indicating the size of the representation transferred in responses. ๐งฎ
For the Q-Block1 and Q-Block2 options, the Size1 or Size2 option values MUST exactly represent the size of the data on the body, so that any missing data can easily be determined. ๐ฏ
The Size1 option MUST be used with the Q-Block1 option when used in a request, and MUST be present in all payloads of the request, preserving the same value. The Size2 option MUST be used with the Q-Block2 option when used in a response, and MUST be present in all payloads of the response, preserving the same value. ๐ฏ
4.7. Using the Q-Block1 and Q-Block2 Options Together ๐ค
The behavior is similar to the one defined in Section 3.3 of [RFC7959], with Q-Block1 substituted for Block1 and Q-Block2 substituted for Block2. ๐
4.8. Using the Q-Block2 Option with Multicast ๐ก
Servers MUST ignore multicast requests that contain the Q-Block2 option. ๐ โโ๏ธ As a reminder, the Block2 option can be used as stated in Section 2.8 of [RFC7959]. ๐
5. The Use of the 4.08 (Request Entity Incomplete) Response Code ๐งฉ
The 4.08 (Request Entity Incomplete) response code has a new content type, "application/missing-blocks+cbor-seq", used to indicate that the server has not received all of the blocks of the request body that it needs to proceed. Such messages must not be treated by the client as a fatal error. ๐ซง
Likely causes are that the client has not sent all blocks, that some blocks were dropped during transmission, or that the client sent them a long enough time ago that the server has already discarded them. โ
The new data payload of the 4.08 (Request Entity Incomplete) response, with content type "application/missing-blocks+cbor-seq", is encoded as a Concise Binary Object Representation (CBOR) Sequence [RFC8742]. It comprises one or more missing block numbers, encoded as CBOR unsigned integers [RFC8949]. The missing block numbers MUST be unique in each 4.08 (Request Entity Incomplete) response when created by the server. The client MUST ignore any duplicates in the same 4.08 (Request Entity Incomplete) response. ๐
The Content-Format option (Section 5.10.3 of [RFC7252]) MUST be used in the 4.08 (Request Entity Incomplete) response. It MUST be set to "application/missing-blocks+cbor-seq" (Section 12.3). ๐ท๏ธ
The Concise Data Definition Language (CDDL) [RFC8610] (and see Section 4.1 of [RFC8742]) for the data describing these missing blocks is as follows: ๐
; This defines an array, the elements of which are to be used
; in a CBOR Sequence:
payload = [+ missing-block-number]
; A unique block number not received:
missing-block-number = uint
Figure 1: Structure of the Missing Blocks Payload
This CDDL syntax MUST be followed. ๐
It is desirable that the token used for the response is the token that was used in the last block number received so far with the same Request-Tag value. Using any received token with the same Request-Tag would be acceptable, but giving the one used in the last received payload will help with troubleshooting. ๐ต๏ธโโ๏ธ The client will use the token to work out which request was sent previously, so it can get the Request-Tag value that was used. ๐๏ธ
If the size of the 4.08 (Request Entity Incomplete) response packet is larger than that defined by Section 4.6 of [RFC7252], then the number of reported missing blocks MUST be limited so the response can fit into a single packet. In that case, the server can send subsequent 4.08 (Request Entity Incomplete) responses containing those additional missing blocks when it receives a new request providing a missing payload with the same Request-Tag. ๐ฌ
The missing blocks MUST be reported in ascending order without any duplicates. The client SHOULD silently drop 4.08 (Request Entity Incomplete) responses that don't follow this behavior. ๐๏ธ
Implementation Note: Consider limiting the number of missing payloads to MAX_PAYLOADS to minimize the need for congestion control. The CBOR Sequence does not include any array wrapper. ๐
A 4.08 (Request Entity Incomplete) response with content type "application/missing-blocks+cbor-seq" SHOULD NOT be used when using Confirmable requests or a reliable connection [RFC8323], because the client will be able to determine that there is a transmission failure of a particular payload, and hence that the server is missing that payload. โ
6. The Use of Tokens ๐
okay so bestie, every brand new request generally gets its own fresh Token ๐ฆ (and sometimes it must, see Section 4 of [RFC9175]). Any extra responses to a request all wear the same Token as the request they're answering, so you can always tell who's replying to who ๐
Implementation Note: 8-byte tokens are lowkey genius ๐ง You can keep the bottom 32 bits the same for the same body, and let the upper 32 bits hold the current body's request number, bumping it on every request (retransmits count too! ๐). That way clients don't have to track all the per-request state, e.g., per Section 3 of [RFC8974] ๐ But heads up: if you're using NoSec, Section 5.2 of [RFC8974] has to be considered for the security implications ๐
7. Congestion Control for Unreliable Transports ๐
so over an unreliable transport, every single block of one body MUST either all be Confirmable or all be Non-confirmable ๐ซถ Keeping them all the same type is what makes the congestion control procedure way simpler, it's giving clean โจ
quick reminder bestie: reliable transports don't need CoAP-specific congestion control at all, see [RFC8323] ๐ธ
7.1. Confirmable (CON) ๐
congestion control for CON requests and responses is spelled out in Section 4.7 of [RFC7252] ๐ If you want the faster transmission rates, NSTART has to go up from 1. BUT, and this is a big but ๐ญ, the other CON congestion control parameters will need retuning to match. This document doesn't specify that tuning, because the applicability scope here assumes that all requests and responses using Q-Block1 and Q-Block2 will be Non-confirmable (Section 3.2) apart from the initial Q-Block functionality negotiation ๐
after a packet fails to transmit because it got lost, and MAX_TRANSMIT_SPAN time has passed (Section 4.8.2 of [RFC7252]), it's up to the implementation whether to send any further requests for the missing data ๐คทโโ๏ธโจ
7.2. Non-confirmable (NON) ๐ฆ
okay bestie, this part is where we get into the NON flavour of things ๐
It brings in a whole crew of new parameters: MAX_PAYLOADS, NON_TIMEOUT, NON_TIMEOUT_RANDOM, NON_RECEIVE_TIMEOUT, NON_MAX_RETRANSMIT, NON_PROBING_WAIT, and NON_PARTIAL_TIMEOUT. They're mainly for NON (Table 3) โจ
Note: Randomness can naturally come from the traffic profile, from how PROBING_RATE gets computed (since it's an average), and from when the peer responds. Randomness is explicitly added to some of the congestion control parameters so that everything doesn't stay in sync when retrying ๐
MAX_PAYLOADS is configurable, with a default value of 10 ๐ Both CoAP endpoints MUST have the same value, because otherwise you get transmission delays in one direction. The value MAY be negotiated between the endpoints to a common value using a higher-level protocol, which is out of scope for this document. This is the maximum number of payloads that can be transmitted at any one time.
Note: The default of 10 is picked for reasons similar to the ones in Section 5 of [RFC6928], especially given the target application in Section 3.2 ๐ธ
NON_TIMEOUT is used to work out the delay between sending MAX_PAYLOADS_SET for the same body. By default, NON_TIMEOUT has the same value as ACK_TIMEOUT (Section 4.8 of [RFC7252]) ๐
NON_TIMEOUT_RANDOM is the initial actual delay between sending the first two MAX_PAYLOADS_SETs of the same body. The same delay is then reused for the subsequent MAX_PAYLOADS_SETs. It's a random duration (not a whole number of seconds) between NON_TIMEOUT and (NON_TIMEOUT * ACK_RANDOM_FACTOR). ACK_RANDOM_FACTOR is set to 1.5, as discussed in Section 4.8 of [RFC7252] โจ
NON_RECEIVE_TIMEOUT is the initial time to wait for a missing payload before requesting retransmission for the first time. Every time the missing payload gets re-requested, the Time-to-Wait value doubles ๐ง The time to wait is calculated like this:
Time-to-Wait = NON_RECEIVE_TIMEOUT * (2 ** (Re-Request-Count - 1))
NON_RECEIVE_TIMEOUT has a default value of twice NON_TIMEOUT. NON_RECEIVE_TIMEOUT MUST always be greater than NON_TIMEOUT_RANDOM by at least one second, so the sender of the payloads has the chance to start sending the next MAX_PAYLOADS_SET before the receiver times out ๐ซถ
NON_MAX_RETRANSMIT is the maximum number of times a request for retransmission of missing payloads can happen without a response from the remote peer. After that happens, the local endpoint SHOULD consider the body stale, remove any body, and release the tokens and Request-Tag on the client (or the ETag on the server). By default, NON_MAX_RETRANSMIT has the same value as MAX_RETRANSMIT (Section 4.8 of [RFC7252]) ๐
NON_PROBING_WAIT is used to limit the potential wait needed when using PROBING_RATE. By default, it's computed in a way that's similar to EXCHANGE_LIFETIME (Section 4.8.2 of [RFC7252]), but with ACK_TIMEOUT, MAX_RETRANSMIT, and PROCESSING_DELAY swapped out for NON_TIMEOUT, NON_MAX_RETRANSMIT, and NON_TIMEOUT_RANDOM, respectively:
NON_PROBING_WAIT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) - 1) *
ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT_RANDOM
NON_PARTIAL_TIMEOUT is used for expiring partially received bodies. By default, it's computed the same way as EXCHANGE_LIFETIME (Section 4.8.2 of [RFC7252]), but with ACK_TIMEOUT and MAX_RETRANSMIT swapped out for NON_TIMEOUT and NON_MAX_RETRANSMIT, respectively:
NON_PARTIAL_TIMEOUT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) -
1) * ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT
Here's the parameter cheat sheet ๐
+=====================+===================+
| Parameter Name | Default Value |
+=====================+===================+
| MAX_PAYLOADS | 10 |
+---------------------+-------------------+
| NON_MAX_RETRANSMIT | 4 |
+---------------------+-------------------+
| NON_TIMEOUT | 2 s |
+---------------------+-------------------+
| NON_TIMEOUT_RANDOM | between 2-3 s |
+---------------------+-------------------+
| NON_RECEIVE_TIMEOUT | 4 s |
+---------------------+-------------------+
| NON_PROBING_WAIT | between 247-248 s |
+---------------------+-------------------+
| NON_PARTIAL_TIMEOUT | 247 s |
+---------------------+-------------------+
Table 3: Congestion Control Parameters
Now PROBING_RATE ๐ฆ It's the parameter that says the average data rate a CoAP endpoint must not go over when it's sending to a peer that doesn't respond. A single body gets subjected to PROBING_RATE (Section 4.7 of [RFC7252]), not the individual packets. If the wait time between sending bodies that aren't being responded to, based on PROBING_RATE, goes over NON_PROBING_WAIT, then the wait time gets capped at NON_PROBING_WAIT โจ
Note: For the DOTS application in particular, PROBING_RATE and other transmission parameters are negotiated between peers. Even when they aren't negotiated, the DOTS application uses customized defaults, as discussed in Section 4.5.2 of [RFC9132]. Also,MAX_PAYLOADS,NON_MAX_RETRANSMIT,NON_TIMEOUT,NON_PROBING_WAIT, andNON_PARTIAL_TIMEOUTcan be negotiated between DOTS peers, e.g., as per [DOTS-QUICK-BLOCKS]. When explicit values are configured forNON_PROBING_WAITandNON_PARTIAL_TIMEOUT, those values get used without any jitter ๐
Every NON 4.08 (Request Entity Incomplete) response is subject to PROBING_RATE ๐ And so is every NON GET or FETCH request that uses a Q-Block2 option.
Sending lots of payloads for one body can cause congestion all by itself, so after every MAX_PAYLOADS_SET of a single body, a delay of NON_TIMEOUT_RANDOM MUST be introduced before the next MAX_PAYLOADS_SET gets sent. The exception is if a 'Continue' comes back from the peer for the current MAX_PAYLOADS_SET. In that case, the next MAX_PAYLOADS_SET MAY start transmitting immediately ๐โโ๏ธ
Note: Say the packets are 1500 bytes and theMAX_PAYLOADS_SEThas 10 payloads. That works out to1500 * 10 * 8 = 120 kbits. With a 2 second delay betweenMAX_PAYLOADS_SETs, that means an average speed requirement of 60 kbps for a single body if there are no responses at all. PROBING_RATE cuts that transmission rate down even further ๐
Sending a set of missing blocks for a body is limited to one MAX_PAYLOADS_SET at a time. So, a NON_TIMEOUT_RANDOM delay still gets observed between each MAX_PAYLOADS_SET ๐
For Q-Block1, if the server responds with a 2.31 (Continue) response code for the latest payload sent, the client can keep going with the next MAX_PAYLOADS_SET without any extra delay. But if the server responds with a 4.08 (Request Entity Incomplete) response code, the missing payloads SHOULD be retransmitted before the client goes into another NON_TIMEOUT_RANDOM delay before sending the next set of payloads ๐ซ
For the server receiving NON Q-Block1 requests, it SHOULD send back a 2.31 (Continue) response code on receipt of all of the MAX_PAYLOADS_SET, so the client doesn't unnecessarily hold up the transfer of the remaining blocks ๐ If not all of the MAX_PAYLOADS_SET arrived, the server SHOULD wait for NON_RECEIVE_TIMEOUT (exponentially scaled based on the repeat request count for a payload) before sending the 4.08 (Request Entity Incomplete) response code for the missing payload(s). If all of the MAX_PAYLOADS_SET arrived and a 2.31 (Continue) response code had been sent, but no more payloads showed up for NON_RECEIVE_TIMEOUT (exponentially scaled), the server SHOULD send a 4.08 (Request Entity Incomplete) response detailing the missing payloads after the block number that was indicated in the sent 2.31 (Continue) response code. And if the repeat response count of the 4.08 (Request Entity Incomplete) goes over NON_MAX_RETRANSMIT, the server SHOULD discard the partial body and stop requesting the missing payloads ๐ญ
It's likely the client will start sending the next MAX_PAYLOADS_SET before the server times out waiting for the last block of the previous one ๐ When a payload from the next MAX_PAYLOADS_SET arrives, the server SHOULD send a 4.08 (Request Entity Incomplete) response code that lists any missing payloads from earlier MAX_PAYLOADS_SETs. When the client gets that 4.08 (Request Entity Incomplete) response code, it SHOULD send the missing payloads before carrying on with the rest of the MAX_PAYLOADS_SET, and then go into another NON_TIMEOUT_RANDOM delay before sending the next MAX_PAYLOADS_SET ๐
For the client receiving NON Q-Block2 responses, it SHOULD send a 'Continue' Q-Block2 request (Section 4.4) for the next MAX_PAYLOADS_SET as soon as it has all of the current one. That stops the server from unnecessarily holding up the transfer of the remaining blocks ๐
Otherwise, the client SHOULD wait for NON_RECEIVE_TIMEOUT (exponentially scaled based on the repeat request count for a payload) before sending the request for the missing payload(s). If the repeat request count for a missing payload goes over NON_MAX_RETRANSMIT, the client SHOULD discard the partial body and stop requesting the missing payloads ๐
The server SHOULD recognize the 'Continue' Q-Block2 request as defined in Section 4.4, and just keep transmitting the body (including the Observe option, if that's appropriate for an unsolicited response). It shouldn't treat 'Continue' as a request for the remaining missing blocks ๐ฆ
Same energy from the other side: it's likely the server will start sending the next MAX_PAYLOADS_SET before the client times out waiting for the last block of the previous one โญ When the client gets a payload from the new MAX_PAYLOADS_SET, it SHOULD send a request indicating any missing payloads from earlier MAX_PAYLOADS_SETs. When the server gets that request, it SHOULD send the missing payloads before continuing with the rest of the MAX_PAYLOADS_SET, and then go into another NON_TIMEOUT_RANDOM delay before sending the next MAX_PAYLOADS_SET ๐ธ
Good news: the client does not need to acknowledge receipt of the entire body ๐ซถ
Note: If there's asymmetric traffic loss that stops responses from ever getting received, aNON_TIMEOUT_RANDOMdelay will be observed after every transmission ofMAX_PAYLOADS_SET. Even so, the endpoint receiving the body is still likely to receive the entire body ๐
8. Caching Considerations ๐พ
okay so caching block-based stuff is not straightforward in a proxy ๐ญ for the Q-Block1 and Q-Block2 options, to keep things simple, the proxy is expected to reassemble the whole body (using any appropriate recovery options for packet loss) before passing it onward to the right CoAP endpoint. this doesn't stop an implementation from doing fancier per-payload caching ๐ง , but how to do that is out of scope for this doc. sending the body onward doesn't need Q-Block1 or Q-Block2 either, because those options might not be supported on that link. so the proxy must fully support Q-Block1 and Q-Block2 ๐
how the body gets cached in the CoAP client (for Q-Block1 transmissions) or the CoAP server (for Q-Block2 transmissions) is implementation specific, bestie ๐
since the proxy caches the entire body, the Q-Block1 and Q-Block2 options get removed during block assembly, so they never reach the cache โจ
for Q-Block2 responses, the ETag option value is tied to the data and sent onward to the CoAP client, but it is NOT part of the cache key ๐ฆ
for requests with the Q-Block1 option, the Request-Tag option is linked to building the body from successive payloads, but it's also not part of the cache key ๐ for the onward transmission of the body over CoAP, a new Request-Tag SHOULD be generated and used. ideally that new Request-Tag replaces the one the client used ๐ธ
here's the tea: it's possible that two or more CoAP clients are updating the same resource at the same time, going through a common proxy to the same CoAP server, using the Q-Block1 (or Block1) option. if that happens, the first client to finish building its body makes the proxy start transmitting that body to the CoAP server with an appropriate Request-Tag value. when the next client finishes building its body, any partial body transmission already in progress to the CoAP server gets terminated, and the transmission of the new body representation starts with a new Request-Tag value ๐ฅ also, it cannot be assumed that the proxy will always receive a complete body from a client, so keep that in mind ๐
a proxy that supports the Q-Block2 option MUST be prepared to receive a GET or similar request that indicates one or more missing blocks. from its cache, the proxy will serve whichever missing blocks it has, the same way a server would send all the appropriate Q-Block2 responses ๐ if a body matching the cache key isn't in the cache, the proxy MUST request the entire body from the CoAP server using the information in the cache key. no skipping that step, periodt ๐
how long a CoAP endpoint (or proxy) keeps the body in its cache is implementation specific (for example, it might be based on Max-Age) โณ
9. HTTP Mapping Considerations ๐
quick reminder: the basic normative requirements on HTTP/CoAP mappings are defined in Section 10 of [RFC7252]. the implementation guidelines for HTTP/CoAP mappings are elaborated in [RFC8075] ๐
the rules defined in Section 5 of [RFC7959] are to be followed ๐ซถ
10. Examples with Non-confirmable Messages ๐ฆ
this section gives some sample flows to show how the Q-Block1 and Q-Block2 options work with NON. examples with CON are in Appendix A ๐
the examples in the following subsections assume MAX_PAYLOADS is set to 10 and NON_MAX_RETRANSMIT is set to 4 ๐
here's the cheat sheet for the figures in the next subsections, so you can read them like a pro ๐
T: Token value
O: Observe option value
M: Message ID
RT: Request-Tag
ET: ETag
QB1: Q-Block1 option values NUM/More/Size
QB2: Q-Block2 option values NUM/More/Size
Size: Actual block size encoded in SZX
\: Trimming long lines
[[]]: Comments
-->X: Message loss (request)
X<--: Message loss (response)
...: Passage of time
Payload N: Corresponds to the CoAP message that conveys a block
number (N-1) of a given block-wise exchange.
10.1. Q-Block1 Option โจ
10.1.1. A Simple Example ๐
okay so Figure 2 shows an example of a NON PUT request carrying the Q-Block1 option. all the blocks reach the server, no drama ๐ธ
CoAP CoAP
Client Server
| |
+--------->| NON PUT /path M:0x81 T:0xc0 RT=9 QB1:0/1/1024
+--------->| NON PUT /path M:0x82 T:0xc1 RT=9 QB1:1/1/1024
+--------->| NON PUT /path M:0x83 T:0xc2 RT=9 QB1:2/1/1024
+--------->| NON PUT /path M:0x84 T:0xc3 RT=9 QB1:3/0/1024
|<---------+ NON 2.04 M:0xf1 T:0xc3
| ... |
Figure 2: Example of a NON Request with the Q-Block1 option
(without Loss)
10.1.2. Handling MAX_PAYLOADS Limits ๐ง
Figure 3 shows an example of a NON PUT request carrying the Q-Block1 option. the number of payloads goes over MAX_PAYLOADS, but all the blocks still reach the server ๐
CoAP CoAP
Client Server
| |
+--------->| NON PUT /path M:0x01 T:0xf1 RT=10 QB1:0/1/1024
+--------->| NON PUT /path M:0x02 T:0xf2 RT=10 QB1:1/1/1024
+--------->| [[Payloads 3 - 9 not detailed]]
+--------->| NON PUT /path M:0x0a T:0xfa RT=10 QB1:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET receipt acknowledged by server]]
|<---------+ NON 2.31 M:0x81 T:0xfa
+--------->| NON PUT /path M:0x0b T:0xfb RT=10 QB1:10/0/1024
|<---------+ NON 2.04 M:0x82 T:0xfb
| ... |
Figure 3: Example of a MAX_PAYLOADS NON Request with the Q-Block1
Option (without Loss)
10.1.3. Handling MAX_PAYLOADS with Recovery ๐
now imagine the client is sending a brand new body, but some blocks get dropped on the way, like in Figure 4 ๐ฌ
CoAP CoAP
Client Server
| |
+--------->| NON PUT /path M:0x11 T:0xe1 RT=11 QB1:0/1/1024
+--->X | NON PUT /path M:0x12 T:0xe2 RT=11 QB1:1/1/1024
+--------->| [[Payloads 3 - 8 not detailed]]
+--------->| NON PUT /path M:0x19 T:0xe9 RT=11 QB1:8/1/1024
+--->X | NON PUT /path M:0x1a T:0xea RT=11 QB1:9/1/1024
[[Some of the MAX_PAYLOADS_SET has been received]]
| ... |
[[NON_TIMEOUT_RANDOM (client) delay expires]]
| [[Client starts sending next MAX_PAYLOADS_SET]]
+--->X | NON PUT /path M:0x1b T:0xeb RT=11 QB1:10/1/1024
+--------->| NON PUT /path M:0x1c T:0xec RT=11 QB1:11/1/1024
| |
Figure 4: Example of a MAX_PAYLOADS NON Request with the Q-Block1
Option (with Loss)
when the server sees a payload from the next MAX_PAYLOADS_SET, it realizes some blocks from the previous MAX_PAYLOADS_SET are missing. so it asks for all the missing blocks in one go (Figure 5) ๐ง it does this by listing which blocks from the previous MAX_PAYLOADS_SET haven't been received, in the data portion of the response (Section 5). the token used in the response should be the token that was used in the last received payload ๐ซถ the client can then work out the Request-Tag by matching the token with the sent request โจ
CoAP CoAP
Client Server
| |
|<---------+ NON 4.08 M:0x91 T:0xec [Missing 1,9]
| [[Client responds with missing payloads]]
+--------->| NON PUT /path M:0x1d T:0xed RT=11 QB1:1/1/1024
+--------->| NON PUT /path M:0x1e T:0xee RT=11 QB1:9/1/1024
| [[Client continues sending next MAX_PAYLOADS_SET]]
+--------->| NON PUT /path M:0x1f T:0xef RT=11 QB1:12/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[The server realizes a block is still missing and asks
| for the missing one]]
|<---------+ NON 4.08 M:0x92 T:0xef [Missing 10]
+--------->| NON PUT /path M:0x20 T:0xf0 RT=11 QB1:10/1/1024
|<---------+ NON 2.04 M:0x93 T:0xf0
| ... |
Figure 5: Example of a NON Request with the Q-Block1 Option
(Block Recovery)
10.1.4. Handling Recovery if Failure Occurs ๐
Figure 6 shows a NON PUT request carrying the Q-Block1 option where recovery kicks in but eventually fails ๐ญ
CoAP CoAP
Client Server
| |
+--------->| NON PUT /path M:0x91 T:0xd0 RT=12 QB1:0/1/1024
+--->X | NON PUT /path M:0x92 T:0xd1 RT=12 QB1:1/1/1024
+--------->| NON PUT /path M:0x93 T:0xd2 RT=12 QB1:2/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[The server realizes a block is missing and asks
| for the missing one. Retry #1]]
|<---------+ NON 4.08 M:0x01 T:0xd2 [Missing 1]
| ... |
[[2 * NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[The server realizes a block is still missing and asks
| for the missing one. Retry #2]]
|<---------+ NON 4.08 M:0x02 T:0xd2 [Missing 1]
| ... |
[[4 * NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[The server realizes a block is still missing and asks
| for the missing one. Retry #3]]
|<---------+ NON 4.08 M:0x03 T:0xd2 [Missing 1]
| ... |
[[8 * NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[The server realizes a block is still missing and asks
| for the missing one. Retry #4]]
|<---------+ NON 4.08 M:0x04 T:0xd2 [Missing 1]
| ... |
[[16 * NON_RECEIVE_TIMEOUT (server) delay expires]]
| [[NON_MAX_RETRANSMIT exceeded. Server stops requesting
| the missing blocks and releases partial body]]
| ... |
Figure 6: Example of a NON Request with the Q-Block1 Option (with
Eventual Failure)
10.2. Q-Block2 Option ๐
these examples include the Observe option so you can see how it's used ๐ but heads up: the Observe option is not required for Q-Block2 ๐
10.2.1. A Simple Example ๐
Figure 7 shows an example of the Q-Block2 option. the client sends a NON GET carrying the Observe and Q-Block2 options. the Q-Block2 option gives a block size hint (1024 bytes). the server replies using four (4) blocks, which get sent to the client with no loss, and each block carries a Q-Block2 option ๐ the same thing happens again when an Observe is triggered, and none of the notification blocks get lost either โจ
CoAP CoAP
Client Server
| |
+--------->| NON GET /path M:0x01 T:0xc0 O:0 QB2:0/1/1024
|<---------+ NON 2.05 M:0xf1 T:0xc0 O:1220 ET=19 QB2:0/1/1024
|<---------+ NON 2.05 M:0xf2 T:0xc0 O:1220 ET=19 QB2:1/1/1024
|<---------+ NON 2.05 M:0xf3 T:0xc0 O:1220 ET=19 QB2:2/1/1024
|<---------+ NON 2.05 M:0xf4 T:0xc0 O:1220 ET=19 QB2:3/0/1024
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0xf5 T:0xc0 O:1221 ET=20 QB2:0/1/1024
|<---------+ NON 2.05 M:0xf6 T:0xc0 O:1221 ET=20 QB2:1/1/1024
|<---------+ NON 2.05 M:0xf7 T:0xc0 O:1221 ET=20 QB2:2/1/1024
|<---------+ NON 2.05 M:0xf8 T:0xc0 O:1221 ET=20 QB2:3/0/1024
| ... |
Figure 7: Example of NON Notifications with the Q-Block2 Option
(without Loss)
10.2.2. Handling MAX_PAYLOADS Limits โจ
Okay bestie, Figure 8 is the same vibe as Figure 7, but now there are eleven (11) payloads, which is over MAX_PAYLOADS ๐ And the best part? Zero loss. Everything arrives. Iconic ๐ฆ
CoAP CoAP
Client Server
| |
+--------->| NON GET /path M:0x01 T:0xf0 O:0 QB2:0/1/1024
|<---------+ NON 2.05 M:0x81 T:0xf0 O:1234 ET=21 QB2:0/1/1024
|<---------+ NON 2.05 M:0x82 T:0xf0 O:1234 ET=21 QB2:1/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
|<---------+ NON 2.05 M:0x8a T:0xf0 O:1234 ET=21 QB2:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by client using
| 'Continue' Q-Block2]]
+--------->| NON GET /path M:0x02 T:0xf1 QB2:10/1/1024
|<---------+ NON 2.05 M:0x8b T:0xf0 O:1234 ET=21 QB2:10/0/1024
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0x91 T:0xf0 O:1235 ET=22 QB2:0/1/1024
|<---------+ NON 2.05 M:0x92 T:0xf0 O:1235 ET=22 QB2:1/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
|<---------+ NON 2.05 M:0x9a T:0xf0 O:1235 ET=22 QB2:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by client using
| 'Continue' Q-Block2]]
+--------->| NON GET /path M:0x03 T:0xf2 QB2:10/1/1024
|<---------+ NON 2.05 M:0x9b T:0xf0 O:1235 ET=22 QB2:10/0/1024
[[Body has been received]]
| ... |
Figure 8: Example of NON Notifications with the Q-Block2 Option
(without Loss)
10.2.3. Handling MAX_PAYLOADS with Recovery ๐ฅ
Figure 9 is where things get a little messy ๐ญ An Observe gets triggered, but some of the notification blocks go missing in transit. No panic though, because the client notices the gaps and asks for them again. It does this by listing the missing blocks as one or more Q-Block2 options. Main character energy for sure ๐
CoAP CoAP
Client Server
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0xa1 T:0xf0 O:1236 ET=23 QB2:0/1/1024
| X<---+ NON 2.05 M:0xa2 T:0xf0 O:1236 ET=23 QB2:1/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
| X<---+ NON 2.05 M:0xaa T:0xf0 O:1236 ET=23 QB2:9/1/1024
[[Some of the MAX_PAYLOADS_SET has been received]]
| ... |
[[NON_TIMEOUT_RANDOM (server) delay expires]]
| [[Server sends next MAX_PAYLOADS_SET]]
|<---------+ NON 2.05 M:0xab T:0xf0 O:1236 ET=23 QB2:10/0/1024
| [[On seeing a payload from the next MAX_PAYLOADS_SET,
| client realizes blocks are missing and asks for the
| missing ones in one go]]
+--------->| NON GET /path M:0x04 T:0xf3 QB2:1/0/1024\
| | QB2:9/0/1024
| X<---+ NON 2.05 M:0xac T:0xf3 ET=23 QB2:1/1/1024
|<---------+ NON 2.05 M:0xad T:0xf3 ET=23 QB2:9/1/1024
| ... |
[[NON_RECEIVE_TIMEOUT (client) delay expires]]
| [[Client realizes block is still missing and asks for
| missing block]]
+--------->| NON GET /path M:0x05 T:0xf4 QB2:1/0/1024
|<---------+ NON 2.05 M:0xae T:0xf4 ET=23 QB2:1/1/1024
[[Body has been received]]
| ... |
Figure 9: Example of NON Notifications with the Q-Block2 Option
(Block Recovery)
10.2.4. Handling Recovery by Setting the M Bit ๐ง
Figure 10 shows a case where an Observe is triggered, but only the first two notification blocks actually reach the client ๐ฅบ To get the missing blocks back, the client sends one request with a single Q-Block2 option that has the M bit set. One ask, all the blocks. Efficient and slay ๐
CoAP CoAP
Client Server
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0xb1 T:0xf0 O:1237 ET=24 QB2:0/1/1024
|<---------+ NON 2.05 M:0xb2 T:0xf0 O:1237 ET=24 QB2:1/1/1024
| X<---+ NON 2.05 M:0xb3 T:0xf0 O:1237 ET=24 QB2:2/1/1024
| X<---+ [[Payloads 4 - 9 not detailed]]
| X<---+ NON 2.05 M:0xb9 T:0xf0 O:1237 ET=24 QB2:9/1/1024
[[Some of the MAX_PAYLOADS_SET has been received]]
| ... |
[[NON_TIMEOUT_RANDOM (server) delay expires]]
| [[Server sends next MAX_PAYLOADS_SET]]
| X<---+ NON 2.05 M:0xba T:0xf0 O:1237 ET=24 QB2:10/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (client) delay expires]]
| [[Client realizes blocks are missing and asks for the
| missing ones in one go by setting the M bit]]
+--------->| NON GET /path M:0x06 T:0xf5 QB2:2/1/1024
|<---------+ NON 2.05 M:0xbb T:0xf5 ET=24 QB2:2/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
|<---------+ NON 2.05 M:0xc2 T:0xf5 ET=24 QB2:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by client using 'Continue'
| Q-Block2]]
+--------->| NON GET /path M:0x87 T:0xf6 QB2:10/1/1024
|<---------+ NON 2.05 M:0xc3 T:0xf0 O:1237 ET=24 QB2:10/0/1024
[[Body has been received]]
| ... |
Figure 10: Example of NON Notifications with the Q-Block2 Option
(Block Recovery with the M Bit Set)
10.3. Q-Block1 and Q-Block2 Options ๐
10.3.1. A Simple Example ๐
Figure 11 is a FETCH that uses both the Q-Block1 and Q-Block2 options, plus an Observe option, all at once ๐คฏ Nothing gets lost here, so it's a clean, smooth flow. Literally goals ๐
CoAP CoAP
Client Server
| |
+--------->| NON FETCH /path M:0x10 T:0x90 O:0 RT=30 QB1:0/1/1024
+--------->| NON FETCH /path M:0x11 T:0x91 O:0 RT=30 QB1:1/1/1024
+--------->| NON FETCH /path M:0x12 T:0x93 O:0 RT=30 QB1:2/0/1024
|<---------+ NON 2.05 M:0x60 T:0x93 O:1320 ET=90 QB2:0/1/1024
|<---------+ NON 2.05 M:0x61 T:0x93 O:1320 ET=90 QB2:1/1/1024
|<---------+ NON 2.05 M:0x62 T:0x93 O:1320 ET=90 QB2:2/1/1024
|<---------+ NON 2.05 M:0x63 T:0x93 O:1320 ET=90 QB2:3/0/1024
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0x64 T:0x93 O:1321 ET=91 QB2:0/1/1024
|<---------+ NON 2.05 M:0x65 T:0x93 O:1321 ET=91 QB2:1/1/1024
|<---------+ NON 2.05 M:0x66 T:0x93 O:1321 ET=91 QB2:2/1/1024
|<---------+ NON 2.05 M:0x67 T:0x93 O:1321 ET=91 QB2:3/0/1024
| ... |
Figure 11: Example of a NON FETCH with the Q-Block1 and Q-Block2
Options (without Loss)
10.3.2. Handling MAX_PAYLOADS Limits ๐
Figure 12 runs the same scenario as Figure 11, but now there are eleven (11) payloads in both directions, which is over MAX_PAYLOADS ๐ Still no loss, so everyone's fine.
CoAP CoAP
Client Server
| |
+--------->| NON FETCH /path M:0x30 T:0xa0 O:0 RT=10 QB1:0/1/1024
+--------->| NON FETCH /path M:0x31 T:0xa1 O:0 RT=10 QB1:1/1/1024
+--------->| [[Payloads 3 - 9 not detailed]]
+--------->| NON FETCH /path M:0x39 T:0xa9 O:0 RT=10 QB1:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by server]]
|<---------+ NON 2.31 M:0x80 T:0xa9
+--------->| NON FETCH /path M:0x3a T:0xaa O:0 RT=10 QB1:10/0/1024
|<---------+ NON 2.05 M:0x81 T:0xaa O:1334 ET=21 QB2:0/1/1024
|<---------+ NON 2.05 M:0x82 T:0xaa O:1334 ET=21 QB2:1/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
|<---------+ NON 2.05 M:0x8a T:0xaa O:1334 ET=21 QB2:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by client using
| 'Continue' Q-Block2]]
+--------->| NON FETCH /path M:0x3b T:0xab QB2:10/1/1024
|<---------+ NON 2.05 M:0x8b T:0xaa O:1334 ET=21 QB2:10/0/1024
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0x8c T:0xaa O:1335 ET=22 QB2:0/1/1024
|<---------+ NON 2.05 M:0x8d T:0xaa O:1335 ET=22 QB2:1/1/1024
|<---------+ [[Payloads 3 - 9 not detailed]]
|<---------+ NON 2.05 M:0x95 T:0xaa O:1335 ET=22 QB2:9/1/1024
[[MAX_PAYLOADS_SET has been received]]
| [[MAX_PAYLOADS_SET acknowledged by client using
| 'Continue' Q-Block2]]
+--------->| NON FETCH /path M:0x3c T:0xac QB2:10/1/1024
|<---------+ NON 2.05 M:0x96 T:0xaa O:1335 ET=22 QB2:10/0/1024
[[Body has been received]]
| ... |
Figure 12: Example of a NON FETCH with the Q-Block1 and Q-Block2
Options (without Loss)
Quick note ๐ Because 'Continue' was used, the server keeps the same token (0xaa). That's because 'Continue' isn't a request for a brand new set of packets. It's just the server being told to keep going with its transmission (Section 7.2) โจ
10.3.3. Handling Recovery โจ
okay so now picture this: some blocks just vanish into the void ๐ on the way over. Figure 13 shows exactly that mess.
CoAP CoAP
Client Server
| |
+--------->| NON FETCH /path M:0x50 T:0xc0 O:0 RT=31 QB1:0/1/1024
+--->X | NON FETCH /path M:0x51 T:0xc1 O:0 RT=31 QB1:1/1/1024
+--->X | NON FETCH /path M:0x52 T:0xc2 O:0 RT=31 QB1:2/1/1024
+--------->| NON FETCH /path M:0x53 T:0xc3 O:0 RT=31 QB1:3/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (server) delay expires]]
Figure 13: Example of a NON FETCH with the Q-Block1 and Q-Block2
Options (with Loss)
The server is like "wait, where did blocks 1 and 2 go?" ๐ So it asks for all the missing ones in one go (Figure 14). It does that by listing which blocks it hasn't gotten in the data portion of the response. The token on that response is the token from the last payload it actually received. The client can then figure out the Request-Tag by matching that token to the request it sent. Iconic detective work ๐ต๏ธโโ๏ธ๐ฅ
CoAP CoAP
Client Server
| |
|<---------+ NON 4.08 M:0xa0 T:0xc3 [Missing 1,2]
| [[Client responds with missing payloads]]
+--------->| NON FETCH /path M:0x54 T:0xc4 O:0 RT=31 QB1:1/1/1024
+--------->| NON FETCH /path M:0x55 T:0xc5 O:0 RT=31 QB1:2/1/1024
| [[Server received FETCH body,
| starts transmitting response body]]
|<---------+ NON 2.05 M:0xa1 T:0xc3 O:1236 ET=23 QB2:0/1/1024
| X<---+ NON 2.05 M:0xa2 T:0xc3 O:1236 ET=23 QB2:1/1/1024
|<---------+ NON 2.05 M:0xa3 T:0xc3 O:1236 ET=23 QB2:2/1/1024
| X<---+ NON 2.05 M:0xa4 T:0xc3 O:1236 ET=23 QB2:3/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (client) delay expires]]
| |
Figure 14: Example of a NON Request with the Q-Block1 Option
(Server Recovery)
Now the client notices that not every payload of the response came back ๐ญ so it asks for the missing blocks in one go (Figure 15). Note: following Section 2.7 of [RFC7959], the FETCH request does not include the Q-Block1 or any payload. Lowkey a glow-up for minimal requests โจ
CoAP CoAP
Client Server
| |
+--------->| NON FETCH /path M:0x56 T:0xc6 RT=31 QB2:1/0/1024\
| | QB2:3/0/1024
| [[Server receives FETCH request for missing payloads,
| starts transmitting missing blocks]]
| X<---+ NON 2.05 M:0xa5 T:0xc6 ET=23 QB2:1/1/1024
|<---------+ NON 2.05 M:0xa6 T:0xc6 ET=23 QB2:3/0/1024
| ... |
[[NON_RECEIVE_TIMEOUT (client) delay expires]]
| [[Client realizes block is still missing and asks for
| missing block]]
+--------->| NON FETCH /path M:0x57 T:0xc7 RT=31 QB2:1/0/1024
| [[Server receives FETCH request for missing payload,
| starts transmitting missing block]]
|<---------+ NON 2.05 M:0xa7 T:0xc7 ET=23 QB2:1/1/1024
[[Body has been received]]
| ... |
| [[Observe triggered]]
|<---------+ NON 2.05 M:0xa8 T:0xc3 O:1337 ET=24 QB2:0/1/1024
| X<---+ NON 2.05 M:0xa9 T:0xc3 O:1337 ET=24 QB2:1/1/1024
|<---------+ NON 2.05 M:0xaa T:0xc3 O:1337 ET=24 QB2:2/0/1024
[[NON_RECEIVE_TIMEOUT (client) delay expires]]
| [[Client realizes block is still missing and asks for
| missing block]]
+--------->| NON FETCH /path M:0x58 T:0xc8 RT=31 QB2:1/0/1024
| [[Server receives FETCH request for missing payload,
| starts transmitting missing block]]
|<---------+ NON 2.05 M:0xa7 T:0xc8 ET=24 QB2:1/1/1024
[[Body has been received]]
| ... |
Figure 15: Example of a NON Request with the Q-Block1 Option
(Client Recovery)
11. Security Considerations ๐
Okay, bestie, this part is serious, so read it with your whole brain ๐ง ๐ Security considerations discussed in Section 7 of [RFC7959] should be taken into account.
Security considerations discussed in Sections 11.3 and 11.4 of [RFC7252] should also be taken into account.
OSCORE gives end-to-end protection to all information that isn't required for proxy operations, and it requires that a security context gets set up (Section 3.1 of [RFC8613]). It can be trusted that the source endpoint is legitimate even if the NoSec mode is used. However, an intermediary node can modify the unprotected Outer Q-Block1 and/or Q-Block2 options to make a Q-Block transfer fail, or to keep requesting all the blocks by setting the M bit, which causes attack amplification. ๐ฑ As discussed in Section 12.1 of [RFC8613], applications need to consider that certain message fields and message types are not protected end to end and may be spoofed or manipulated. Therefore, it is NOT RECOMMENDED to use the NoSec mode if either the Q-Block1 or Q-Block2 option is used.
If OSCORE is not used, it is also NOT RECOMMENDED to use the NoSec mode if either the Q-Block1 or Q-Block2 option is used. ๐ซ
If NoSec is being used, Appendix D.5 of [RFC8613] discusses the security analysis and considerations for unprotected message fields, even if OSCORE is not being used.
Security considerations related to the use of Request-Tag are discussed in Section 5 of [RFC9175].
12. IANA Considerations ๐ธ
12.1. CoAP Option Numbers Registry
IANA has added the following entries to the "CoAP Option Numbers" subregistry [IANA-Options] defined in [RFC7252] within the "Constrained RESTful Environments (CoRE) Parameters" registry:
+========+==========+===========+
| Number | Name | Reference |
+========+==========+===========+
| 19 | Q-Block1 | RFC 9177 |
+--------+----------+-----------+
| 31 | Q-Block2 | RFC 9177 |
+--------+----------+-----------+
Table 4: Additions to CoAP
Option Numbers Registry
12.2. Media Type Registration
IANA has registered the "application/missing-blocks+cbor-seq" media type in the "Media Types" registry [IANA-MediaTypes]. This registration follows the procedures specified in [RFC6838]. Here's the full template, no cap ๐
Type name: application
Subtype name: missing-blocks+cbor-seq
Required parameters: N/A
Optional parameters: N/A
Encoding considerations: Must be encoded as a CBOR Sequence
[RFC8742], as defined in Section 5 of RFC 9177.
Security considerations: See Section 11 of RFC 9177.
Interoperability considerations: N/A
Published specification: RFC 9177
Applications that use this media type: Data serialization and
deserialization. In particular, the type is used by applications
relying upon block-wise transfers, allowing a server to specify
non-received blocks and request their retransmission, as defined
in Section 4 of RFC 9177.
Fragment identifier considerations: N/A
Additional information: N/A
Person & email address to contact for further information: IETF,
iesg@ietf.org
Intended usage: COMMON
Restrictions on usage: none
Author: See Authors' Addresses section of RFC 9177.
Change controller: IESG
Provisional registration? No
12.3. CoAP Content-Formats Registry
IANA has registered the following CoAP Content-Format for the "application/missing-blocks+cbor-seq" media type in the "CoAP Content-Formats" registry [IANA-Format] defined in [RFC7252] within the "Constrained RESTful Environments (CoRE) Parameters" registry:
+=====================================+==========+=====+===========+
| Media Type | Encoding | ID | Reference |
+=====================================+==========+=====+===========+
| application/missing-blocks+cbor-seq | - | 272 | RFC 9177 |
+-------------------------------------+----------+-----+-----------+
Table 5: Addition to CoAP Content-Format Registry
13. References ๐
13.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type
Specifications and Registration Procedures", BCP 13,
RFC 6838, DOI 10.17487/RFC6838, January 2013,
<https://www.rfc-editor.org/info/rfc6838>.
[RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained
Application Protocol (CoAP)", RFC 7252,
DOI 10.17487/RFC7252, June 2014,
<https://www.rfc-editor.org/info/rfc7252>.
[RFC7641] Hartke, K., "Observing Resources in the Constrained
Application Protocol (CoAP)", RFC 7641,
DOI 10.17487/RFC7641, September 2015,
<https://www.rfc-editor.org/info/rfc7641>.
[RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in
the Constrained Application Protocol (CoAP)", RFC 7959,
DOI 10.17487/RFC7959, August 2016,
<https://www.rfc-editor.org/info/rfc7959>.
[RFC8075] Castellani, A., Loreto, S., Rahman, A., Fossati, T., and
E. Dijk, "Guidelines for Mapping Implementations: HTTP to
the Constrained Application Protocol (CoAP)", RFC 8075,
DOI 10.17487/RFC8075, February 2017,
<https://www.rfc-editor.org/info/rfc8075>.
[RFC8132] van der Stok, P., Bormann, C., and A. Sehgal, "PATCH and
FETCH Methods for the Constrained Application Protocol
(CoAP)", RFC 8132, DOI 10.17487/RFC8132, April 2017,
<https://www.rfc-editor.org/info/rfc8132>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8323] Bormann, C., Lemay, S., Tschofenig, H., Hartke, K.,
Silverajan, B., and B. Raymor, Ed., "CoAP (Constrained
Application Protocol) over TCP, TLS, and WebSockets",
RFC 8323, DOI 10.17487/RFC8323, February 2018,
<https://www.rfc-editor.org/info/rfc8323>.
[RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data
Definition Language (CDDL): A Notational Convention to
Express Concise Binary Object Representation (CBOR) and
JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610,
June 2019, <https://www.rfc-editor.org/info/rfc8610>.
[RFC8613] Selander, G., Mattsson, J., Palombini, F., and L. Seitz,
"Object Security for Constrained RESTful Environments
(OSCORE)", RFC 8613, DOI 10.17487/RFC8613, July 2019,
<https://www.rfc-editor.org/info/rfc8613>.
[RFC8742] Bormann, C., "Concise Binary Object Representation (CBOR)
Sequences", RFC 8742, DOI 10.17487/RFC8742, February 2020,
<https://www.rfc-editor.org/info/rfc8742>.
[RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object
Representation (CBOR)", STD 94, RFC 8949,
DOI 10.17487/RFC8949, December 2020,
<https://www.rfc-editor.org/info/rfc8949>.
[RFC9175] Amsรผss, C., Preuร Mattsson, J., and G. Selander,
"Constrained Application Protocol (CoAP): Echo, Request-
Tag, and Token Processing", RFC 9175,
DOI 10.17487/RFC9175, February 2022,
<https://www.rfc-editor.org/info/rfc9175>.
13.2. Informative References ๐
Okay, this is the extra-credit reading list ๐ค Each citation is kept exactly as written.
[DOTS-QUICK-BLOCKS]Boucadair, M. and J. Shallow, "Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel Configuration Attributes for Robust Block Transmission", Work in Progress, Internet-Draft, draft-bosh-dots-quick-blocks-03, 29 June 2021,<https://datatracker.ietf.org/doc/html/draft-bosh-dots-quick-blocks-03>.[DOTS-TELEMETRY]Boucadair, M., Ed., Reddy.K, T., Ed., Doron, E., Chen, M., and J. Shallow, "Distributed Denial-of-Service Open Threat Signaling (DOTS) Telemetry", Work in Progress, Internet-Draft, draft-ietf-dots-telemetry-19, 4 January 2022,<https://datatracker.ietf.org/doc/html/draft-ietf-dots-telemetry-19>.[IANA-Format]IANA, "CoAP Content-Formats",<https://www.iana.org/assignments/core-parameters/>.[IANA-MediaTypes]IANA, "Media Types",<https://www.iana.org/assignments/media-types/>.[IANA-Options]IANA, "CoAP Option Numbers",<https://www.iana.org/assignments/core-parameters/>.[RFC6928]Chu, J., Dukkipati, N., Cheng, Y., and M. Mathis, "Increasing TCP's Initial Window", RFC 6928, DOI 10.17487/RFC6928, April 2013,<https://www.rfc-editor.org/info/rfc6928>.[RFC7967]Bhattacharyya, A., Bandyopadhyay, S., Pal, A., and T. Bose, "Constrained Application Protocol (CoAP) Option for No Server Response", RFC 7967, DOI 10.17487/RFC7967, August 2016,<https://www.rfc-editor.org/info/rfc7967>.[RFC8974]Hartke, K. and M. Richardson, "Extended Tokens and Stateless Clients in the Constrained Application Protocol (CoAP)", RFC 8974, DOI 10.17487/RFC8974, January 2021,<https://www.rfc-editor.org/info/rfc8974>.[RFC9132]Boucadair, M., Ed., Shallow, J., and T. Reddy.K, "Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel Specification", RFC 9132, DOI 10.17487/RFC9132, September 2021,<https://www.rfc-editor.org/info/rfc9132>.
Appendix A. Examples with Confirmable Messages ๐
Time for the CON (confirmable) examples! โจ These all assume NSTART has been bumped up to 3, and they follow the conventions from Section 10.
A.1. Q-Block1 Option ๐
Let's start with the Q-Block1 option riding along on a CON request. Every block gets acknowledged, which is what the "ACK" notes are showing ๐ซถ
CoAP CoAP
Client Server
| |
+--------->| CON PUT /path M:0x01 T:0xf0 RT=10 QB1:0/1/1024
+--------->| CON PUT /path M:0x02 T:0xf1 RT=10 QB1:1/1/1024
+--------->| CON PUT /path M:0x03 T:0xf2 RT=10 QB1:2/1/1024
[[NSTART(3) limit reached]]
|<---------+ ACK 0.00 M:0x01
+--------->| CON PUT /path M:0x04 T:0xf3 RT=10 QB1:3/0/1024
|<---------+ ACK 0.00 M:0x02
|<---------+ ACK 0.00 M:0x03
|<---------+ ACK 2.04 M:0x04
| |
Figure 16: Example of a CON Request with the Q-Block1 Option
(without Loss)
Now here's the spicy version ๐ถ๏ธ A brand new body of data is sent, but a few blocks get dropped on the way. The client just keeps retrying whichever blocks never got an ACK. Main character recovery arc ๐ฆ
CoAP CoAP
Client Server
| |
+--------->| CON PUT /path M:0x05 T:0xf4 RT=11 QB1:0/1/1024
+--->X | CON PUT /path M:0x06 T:0xf5 RT=11 QB1:1/1/1024
+--->X | CON PUT /path M:0x07 T:0xf6 RT=11 QB1:2/1/1024
[[NSTART(3) limit reached]]
|<---------+ ACK 0.00 M:0x05
+--------->| CON PUT /path M:0x08 T:0xf7 RT=11 QB1:3/1/1024
|<---------+ ACK 0.00 M:0x08
| ... |
[[ACK TIMEOUT (client) for M:0x06 delay expires]]
| [[Client retransmits packet]]
+--------->| CON PUT /path M:0x06 T:0xf5 RT=11 QB1:1/1/1024
[[ACK TIMEOUT (client) for M:0x07 delay expires]]
| [[Client retransmits packet]]
+--->X | CON PUT /path M:0x07 T:0xf6 RT=11 QB1:2/1/1024
|<---------+ ACK 0.00 M:0x06
| ... |
[[ACK TIMEOUT exponential backoff (client) delay expires]]
| [[Client retransmits packet]]
+--->X | CON PUT /path M:0x07 T:0xf6 RT=11 QB1:2/1/1024
| ... |
[[Either body transmission failure (acknowledge retry timeout)
or successfully transmitted]]
Figure 17: Example of a CON Request with the Q-Block1 Option
(Block Recovery)
Okay, so about the giving-up part ๐ It's up to the implementation whether the application stops trying to send this body of data once MAX_RETRANSMIT is hit for any payload. The other option is to separately try to start a new transmission of only the payloads that never got acknowledged, under these rough traffic conditions. Totally the implementation's call ๐
If transient network losses are possible, then the use of NON should be considered. ๐ฆ
A.2. Q-Block2 Option ๐ธ
Next up is the Q-Block2 option with Confirmable messages, shown in Figure 18. It's giving notifications, observe triggers, and a whole lot of retries ๐
Client Server
| |
+--------->| CON GET /path M:0x01 T:0xf0 O:0 QB2:0/1/1024
|<---------+ ACK 2.05 M:0x01 T:0xf0 O:1234 ET=21 QB2:0/1/1024
|<---------+ CON 2.05 M:0xe1 T:0xf0 O:1234 ET=21 QB2:1/1/1024
|<---------+ CON 2.05 M:0xe2 T:0xf0 O:1234 ET=21 QB2:2/1/1024
|<---------+ CON 2.05 M:0xe3 T:0xf0 O:1234 ET=21 QB2:3/0/1024
|--------->+ ACK 0.00 M:0xe1
|--------->+ ACK 0.00 M:0xe2
|--------->+ ACK 0.00 M:0xe3
| ... |
| [[Observe triggered]]
|<---------+ CON 2.05 M:0xe4 T:0xf0 O:1235 ET=22 QB2:0/1/1024
|<---------+ CON 2.05 M:0xe5 T:0xf0 O:1235 ET=22 QB2:1/1/1024
|<---------+ CON 2.05 M:0xe6 T:0xf0 O:1235 ET=22 QB2:2/1/1024
[[NSTART(3) limit reached]]
|--------->+ ACK 0.00 M:0xe4
|<---------+ CON 2.05 M:0xe7 T:0xf0 O:1235 ET=22 QB2:3/0/1024
|--------->+ ACK 0.00 M:0xe5
|--------->+ ACK 0.00 M:0xe6
|--------->+ ACK 0.00 M:0xe7
| ... |
| [[Observe triggered]]
|<---------+ CON 2.05 M:0xe8 T:0xf0 O:1236 ET=23 QB2:0/1/1024
| X<---+ CON 2.05 M:0xe9 T:0xf0 O:1236 ET=23 QB2:1/1/1024
| X<---+ CON 2.05 M:0xea T:0xf0 O:1236 ET=23 QB2:2/1/1024
[[NSTART(3) limit reached]]
|--------->+ ACK 0.00 M:0xe8
|<---------+ CON 2.05 M:0xeb T:0xf0 O:1236 ET=23 QB2:3/0/1024
|--------->+ ACK 0.00 M:0xeb
| ... |
[[ACK TIMEOUT (server) for M:0xe9 delay expires]]
| [[Server retransmits packet]]
|<---------+ CON 2.05 M:0xe9 T:0xf0 O:1236 ET=23 QB2:1/1/1024
[[ACK TIMEOUT (server) for M:0xea delay expires]]
| [[Server retransmits packet]]
| X<---+ CON 2.05 M:0xea T:0xf0 O:1236 ET=23 QB2:2/1/1024
|--------->+ ACK 0.00 M:0xe9
| ... |
[[ACK TIMEOUT exponential backoff (server) delay expires]]
| [[Server retransmits packet]]
| X<---+ CON 2.05 M:0xea T:0xf0 O:1236 ET=23 QB2:2/1/1024
| ... |
[[Either body transmission failure (acknowledge retry timeout)
or successfully transmitted]]
Figure 18: Example of CON Notifications with the Q-Block2 Option
The same caveat applies here ๐ It's up to the implementation whether the application process stops trying to send this particular body of data on reaching MAX_RETRANSMIT for any payload, or separately tries to initiate the new transmission of the payloads that have not been acknowledged under these adverse traffic conditions.
If transient network losses are possible, then the use of NON should be considered. ๐ง
Appendix B. Examples with Reliable Transports ๐
Now for the reliable-transport examples โจ The same conventions from Section 10 apply here too.
B.1. Q-Block1 Option ๐
Let's look at the Q-Block1 option over a reliable transport, shown in Figure 19. There's no acknowledgment of packets at the CoAP layer, just the final result ๐
CoAP CoAP
Client Server
| |
+--------->| PUT /path T:0xf0 RT=10 QB1:0/1/1024
+--------->| PUT /path T:0xf1 RT=10 QB1:1/1/1024
+--------->| PUT /path T:0xf2 RT=10 QB1:2/1/1024
+--------->| PUT /path T:0xf3 RT=10 QB1:3/0/1024
|<---------+ 2.04
| |
Figure 19: Example of a Reliable Request with the Q-Block1 Option
If transient network losses are possible, then the use of unreliable transport with NON should be considered. ๐
B.2. Q-Block2 Option ๐
Last one! The Q-Block2 option with a reliable transport is shown in Figure 20 ๐ง
Client Server
| |
+--------->| GET /path T:0xf0 O:0 QB2:0/1/1024
|<---------+ 2.05 T:0xf0 O:1234 ET=21 QB2:0/1/1024
|<---------+ 2.05 T:0xf0 O:1234 ET=21 QB2:1/1/1024
|<---------+ 2.05 T:0xf0 O:1234 ET=21 QB2:2/1/1024
|<---------+ 2.05 T:0xf0 O:1234 ET=21 QB2:3/0/1024
| ... |
| [[Observe triggered]]
|<---------+ 2.05 T:0xf0 O:1235 ET=22 QB2:0/1/1024
|<---------+ 2.05 T:0xf0 O:1235 ET=22 QB2:1/1/1024
|<---------+ 2.05 T:0xf0 O:1235 ET=22 QB2:2/1/1024
|<---------+ 2.05 T:0xf0 O:1235 ET=22 QB2:3/0/1024
| ... |
Figure 20: Example of Notifications with the Q-Block2 Option
If transient network losses are possible, then the use of unreliable transport with NON should be considered. ๐ฆ
Acknowledgments ๐ซถ
Big thanks to Achim Kraus, Jim Schaad, and Michael Richardson for their comments ๐
Special thanks to Christian Amsรผss, Carsten Bormann, and Marco Tiloca for their suggestions and several reviews, which improved this specification significantly โจ Thanks to Francesca Palombini for the AD review. Thanks to Pete Resnick for the Gen-ART review, Colin Perkins for the TSVART review, and Emmanuel Baccelli for the IOT-DIR review. Thanks to Martin Duke, รric Vyncke, Benjamin Kaduk, Roman Danyliw, John Scudder, and Lars Eggert for the IESG review ๐
Some text from [RFC7959] is reused for the readers' convenience. ๐ธ
Authors' Addresses ๐
Mohamed Boucadair Orange 35000 Rennes France Email: mohamed.boucadair@orange.com
Jon Shallow United Kingdom Email: supjps-ietf@jpshallow.com
๐ฆ where this page comes from
- ietf: rfc9177 2022-03
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms